Skip to content

Commit

Permalink
kernel: do not rely on struct layout when downcasting
Browse files Browse the repository at this point in the history
  • Loading branch information
mosmeh committed Nov 1, 2024
1 parent 769e4a4 commit 2d489a7
Show file tree
Hide file tree
Showing 15 changed files with 109 additions and 73 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export CFLAGS := \
-nostdlib -ffreestanding \
-fno-omit-frame-pointer \
-U_FORTIFY_SOURCE \
-Wall -Wextra -pedantic \
-Wall -Wextra -pedantic -Wno-gnu-statement-expression-from-macro-expansion \
-O2 -g \
$(if $(GIT_HASH),-DYAGURA_VERSION=\"$(GIT_HASH)\") \
$(EXTRA_CFLAGS)
Expand Down
6 changes: 6 additions & 0 deletions common/extra.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@
#define SIZEOF_FIELD(t, f) sizeof(((t*)0)->f)
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))

#define CONTAINER_OF(ptr, type, member) \
({ \
const __typeof__(((type*)0)->member)* __mptr = (ptr); \
(type*)((char*)__mptr - offsetof(type, member)); \
})

#define ROUND_UP(x, align) (((x) + ((align) - 1)) & ~((align) - 1))
#define ROUND_DOWN(x, align) ((x) & ~((align) - 1))
#define DIV_CEIL(lhs, rhs) (((lhs) + (rhs) - 1) / (rhs))
Expand Down
16 changes: 10 additions & 6 deletions kernel/console/tty.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include "private.h"
#include <common/extra.h>
#include <common/string.h>
#include <kernel/api/signal.h>
#include <kernel/api/sys/ioctl.h>
Expand All @@ -9,20 +10,23 @@
#include <kernel/safe_string.h>
#include <kernel/task.h>

static struct tty* tty_from_file(struct file* file) {
return CONTAINER_OF(file->inode, struct tty, inode);
}

static bool can_read(struct tty* tty) {
return !ring_buf_is_empty(&tty->input_buf);
}

static bool unblock_read(struct file* file) {
struct tty* tty = (struct tty*)file->inode;
return can_read(tty);
return can_read(tty_from_file(file));
}

static ssize_t tty_pread(struct file* file, void* buf, size_t count,
uint64_t offset) {
(void)offset;

struct tty* tty = (struct tty*)file->inode;
struct tty* tty = tty_from_file(file);

for (;;) {
int rc = file_block(file, unblock_read, 0);
Expand Down Expand Up @@ -81,15 +85,15 @@ static void processed_echo(struct tty* tty, const char* buf, size_t count) {
static ssize_t tty_pwrite(struct file* file, const void* buf, size_t count,
uint64_t offset) {
(void)offset;
struct tty* tty = (struct tty*)file->inode;
struct tty* tty = tty_from_file(file);
spinlock_lock(&tty->lock);
processed_echo(tty, buf, count);
spinlock_unlock(&tty->lock);
return count;
}

static int tty_ioctl(struct file* file, int request, void* user_argp) {
struct tty* tty = (struct tty*)file->inode;
struct tty* tty = tty_from_file(file);
struct termios* termios = &tty->termios;
int ret = 0;
spinlock_lock(&tty->lock);
Expand Down Expand Up @@ -157,9 +161,9 @@ static int tty_ioctl(struct file* file, int request, void* user_argp) {
}

static short tty_poll(struct file* file, short events) {
struct tty* tty = (struct tty*)file->inode;
short revents = 0;
if (events & POLLIN) {
struct tty* tty = tty_from_file(file);
spinlock_lock(&tty->lock);
if (can_read(tty))
revents |= POLLIN;
Expand Down
4 changes: 2 additions & 2 deletions kernel/drivers/virtio/virtio.c
Original file line number Diff line number Diff line change
Expand Up @@ -243,9 +243,9 @@ struct virtio_device* virtio_device_create(const struct pci_addr* addr,
(volatile struct virtio_pci_common_cfg*)(common_cfg_space +
common_cfg_cap.offset);

struct virtio_pci_notify_cap notify_cap;
struct virtio_pci_notify_cap notify_cap = {0};
if (!virtio_find_pci_cap(addr, VIRTIO_PCI_CAP_NOTIFY_CFG,
(struct virtio_pci_cap*)&notify_cap)) {
&notify_cap.cap)) {
kprint("virtio: device is missing VIRTIO_PCI_CAP_NOTIFY_CFG\n");
goto fail_discovery;
}
Expand Down
12 changes: 8 additions & 4 deletions kernel/drivers/virtio/virtio_blk.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,21 +18,25 @@ typedef struct {
uint64_t capacity;
} virtio_blk_device;

static virtio_blk_device* device_from_inode(struct inode* inode) {
return CONTAINER_OF(inode, virtio_blk_device, inode);
}

static void virtio_blk_destroy_inode(struct inode* inode) {
virtio_blk_device* node = (virtio_blk_device*)inode;
virtio_blk_device* node = device_from_inode(inode);
virtio_device_destroy(node->virtio);
kfree(node);
}

static bool unblock_request(struct file* file) {
virtio_blk_device* node = (virtio_blk_device*)file->inode;
virtio_blk_device* node = device_from_inode(file->inode);
return node->virtio->virtqs[0]->num_free_descs >= 3;
}

static int submit_request(struct file* file, void* buffer, size_t count,
uint64_t sector, uint32_t type,
bool device_writable) {
virtio_blk_device* node = (virtio_blk_device*)file->inode;
virtio_blk_device* node = device_from_inode(file->inode);
struct virtq* virtq = node->virtio->virtqs[0];
struct virtio_blk_req_header header = {
.type = type,
Expand Down Expand Up @@ -80,7 +84,7 @@ static ssize_t virtio_blk_do_io(struct file* file, void* buffer, size_t count,
return -EINVAL;
uint64_t sector = offset / SECTOR_SIZE;

virtio_blk_device* node = (virtio_blk_device*)file->inode;
virtio_blk_device* node = device_from_inode(file->inode);
if (sector >= node->capacity)
return 0;
count = MIN(count, (node->capacity - sector) * SECTOR_SIZE);
Expand Down
28 changes: 18 additions & 10 deletions kernel/fs/fifo.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,22 @@ struct fifo {
atomic_size_t num_writers;
};

static struct fifo* fifo_from_inode(struct inode* inode) {
return CONTAINER_OF(inode, struct fifo, inode);
}

static struct fifo* fifo_from_file(struct file* file) {
return fifo_from_inode(file->inode);
}

static void fifo_destroy_inode(struct inode* inode) {
struct fifo* fifo = (struct fifo*)inode;
struct fifo* fifo = fifo_from_inode(inode);
ring_buf_destroy(&fifo->buf);
kfree(fifo);
}

static bool unblock_open(struct file* file) {
const struct fifo* fifo = (const struct fifo*)file->inode;
const struct fifo* fifo = fifo_from_file(file);
switch (file->flags & O_ACCMODE) {
case O_RDONLY:
return fifo->num_writers > 0;
Expand All @@ -36,7 +44,7 @@ static bool unblock_open(struct file* file) {
static int fifo_open(struct file* file, mode_t mode) {
(void)mode;

struct fifo* fifo = (struct fifo*)file->inode;
struct fifo* fifo = fifo_from_file(file);
switch (file->flags & O_ACCMODE) {
case O_RDONLY:
++fifo->num_readers;
Expand All @@ -61,7 +69,7 @@ static int fifo_open(struct file* file, mode_t mode) {
}

static int fifo_close(struct file* file) {
struct fifo* fifo = (struct fifo*)file->inode;
struct fifo* fifo = fifo_from_file(file);
switch (file->flags & O_ACCMODE) {
case O_RDONLY:
--fifo->num_readers;
Expand All @@ -76,15 +84,15 @@ static int fifo_close(struct file* file) {
}

static bool unblock_read(struct file* file) {
const struct fifo* fifo = (const struct fifo*)file->inode;
const struct fifo* fifo = fifo_from_file(file);
return fifo->num_writers == 0 || !ring_buf_is_empty(&fifo->buf);
}

static ssize_t fifo_pread(struct file* file, void* buffer, size_t count,
uint64_t offset) {
(void)offset;

struct fifo* fifo = (struct fifo*)file->inode;
struct fifo* fifo = fifo_from_file(file);
struct ring_buf* buf = &fifo->buf;

for (;;) {
Expand All @@ -107,15 +115,15 @@ static ssize_t fifo_pread(struct file* file, void* buffer, size_t count,
}

static bool unblock_write(struct file* file) {
const struct fifo* fifo = (const struct fifo*)file->inode;
const struct fifo* fifo = fifo_from_file(file);
return fifo->num_readers == 0 || !ring_buf_is_full(&fifo->buf);
}

static ssize_t fifo_pwrite(struct file* file, const void* buffer, size_t count,
uint64_t offset) {
(void)offset;

struct fifo* fifo = (struct fifo*)file->inode;
struct fifo* fifo = fifo_from_file(file);
struct ring_buf* buf = &fifo->buf;

for (;;) {
Expand Down Expand Up @@ -145,7 +153,7 @@ static ssize_t fifo_pwrite(struct file* file, const void* buffer, size_t count,

static short fifo_poll(struct file* file, short events) {
short revents = 0;
const struct fifo* fifo = (const struct fifo*)file->inode;
const struct fifo* fifo = fifo_from_file(file);
if ((events & POLLIN) && !ring_buf_is_empty(&fifo->buf))
revents |= POLLIN;
if ((events & POLLOUT) && !ring_buf_is_full(&fifo->buf))
Expand Down Expand Up @@ -190,5 +198,5 @@ struct inode* fifo_create(void) {
inode->mode = S_IFIFO;
inode->ref_count = 1;

return (struct inode*)fifo;
return inode;
}
3 changes: 2 additions & 1 deletion kernel/fs/fs.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include <kernel/panic.h>
#include <kernel/safe_string.h>
#include <kernel/sched.h>
#include <kernel/socket.h>

void inode_ref(struct inode* inode) {
ASSERT(inode);
Expand All @@ -27,7 +28,7 @@ void inode_destroy(struct inode* inode) {
ASSERT(inode->ref_count == 0 && inode->num_links == 0);
ASSERT(inode->fops->destroy_inode);
inode_unref(inode->fifo);
inode_unref((struct inode*)inode->bound_socket);
inode_unref(&inode->bound_socket->inode);
inode->fops->destroy_inode(inode);
}

Expand Down
20 changes: 12 additions & 8 deletions kernel/fs/proc/pid.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,12 @@ typedef struct {
pid_t pid;
} proc_pid_item_inode;

static proc_pid_item_inode* item_from_file(struct file* file) {
return CONTAINER_OF(file->inode, proc_pid_item_inode, item_inode.inode);
}

static int populate_cmdline(struct file* file, struct vec* vec) {
proc_pid_item_inode* node = (proc_pid_item_inode*)file->inode;
proc_pid_item_inode* node = item_from_file(file);
struct task* task = task_find_by_tid(node->pid);
if (!task)
return -ENOENT;
Expand Down Expand Up @@ -57,7 +61,7 @@ static int populate_cmdline(struct file* file, struct vec* vec) {
}

static int populate_comm(struct file* file, struct vec* vec) {
proc_pid_item_inode* node = (proc_pid_item_inode*)file->inode;
proc_pid_item_inode* node = item_from_file(file);
struct task* task = task_find_by_tid(node->pid);
if (!task)
return -ENOENT;
Expand All @@ -74,7 +78,7 @@ static int populate_comm(struct file* file, struct vec* vec) {
}

static int populate_cwd(struct file* file, struct vec* vec) {
proc_pid_item_inode* node = (proc_pid_item_inode*)file->inode;
proc_pid_item_inode* node = item_from_file(file);
struct task* task = task_find_by_tid(node->pid);
if (!task)
return -ENOENT;
Expand All @@ -96,7 +100,7 @@ static int populate_cwd(struct file* file, struct vec* vec) {
}

static int populate_environ(struct file* file, struct vec* vec) {
proc_pid_item_inode* node = (proc_pid_item_inode*)file->inode;
proc_pid_item_inode* node = item_from_file(file);
struct task* task = task_find_by_tid(node->pid);
if (!task)
return -ENOENT;
Expand Down Expand Up @@ -130,7 +134,7 @@ static int populate_environ(struct file* file, struct vec* vec) {
}

static int populate_maps(struct file* file, struct vec* vec) {
proc_pid_item_inode* node = (proc_pid_item_inode*)file->inode;
proc_pid_item_inode* node = item_from_file(file);
struct task* task = task_find_by_tid(node->pid);
if (!task)
return -ENOENT;
Expand Down Expand Up @@ -159,7 +163,7 @@ static int add_item(proc_dir_inode* parent, const proc_item_def* item_def,
pid_t pid) {
proc_pid_item_inode* node = kmalloc(sizeof(proc_pid_item_inode));
if (!node) {
inode_unref((struct inode*)parent);
inode_unref(&parent->inode);
return -ENOMEM;
}
*node = (proc_pid_item_inode){0};
Expand All @@ -174,7 +178,7 @@ static int add_item(proc_dir_inode* parent, const proc_item_def* item_def,
inode->ref_count = 1;

int rc = dentry_append(&parent->children, item_def->name, inode);
inode_unref((struct inode*)parent);
inode_unref(&parent->inode);
return rc;
}

Expand Down Expand Up @@ -215,6 +219,6 @@ struct inode* proc_pid_dir_inode_create(proc_dir_inode* parent, pid_t pid) {
return ERR_PTR(rc);
}

inode_unref((struct inode*)parent);
inode_unref(&parent->inode);
return inode;
}
4 changes: 4 additions & 0 deletions kernel/fs/proc/private.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ typedef struct {
struct dentry* children;
} proc_dir_inode;

static inline proc_dir_inode* proc_dir_from_inode(struct inode* inode) {
return CONTAINER_OF(inode, proc_dir_inode, inode);
}

void proc_dir_destroy_inode(struct inode* inode);
struct inode* proc_dir_lookup_child(struct inode* inode, const char* name);
int proc_dir_getdents(struct file*, getdents_callback_fn callback, void* ctx);
Expand Down
8 changes: 4 additions & 4 deletions kernel/fs/proc/proc.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ static int proc_item_open(struct file* file, mode_t mode) {
return -ENOMEM;
*vec = (struct vec){0};

proc_item_inode* node = (proc_item_inode*)file->inode;
proc_item_inode* node = CONTAINER_OF(file->inode, proc_item_inode, inode);
int rc = node->populate(file, vec);
if (IS_ERR(rc)) {
vec_destroy(vec);
Expand Down Expand Up @@ -45,21 +45,21 @@ const struct file_ops proc_item_fops = {
};

void proc_dir_destroy_inode(struct inode* inode) {
proc_dir_inode* node = (proc_dir_inode*)inode;
proc_dir_inode* node = proc_dir_from_inode(inode);
dentry_clear(node->children);
kfree(node);
}

struct inode* proc_dir_lookup_child(struct inode* inode, const char* name) {
proc_dir_inode* node = (proc_dir_inode*)inode;
proc_dir_inode* node = proc_dir_from_inode(inode);
struct inode* child = dentry_find(node->children, name);
inode_unref(inode);
return child;
}

int proc_dir_getdents(struct file* file, getdents_callback_fn callback,
void* ctx) {
proc_dir_inode* node = (proc_dir_inode*)file->inode;
proc_dir_inode* node = proc_dir_from_inode(file->inode);
mutex_lock(&file->offset_lock);
int rc = dentry_getdents(file, node->children, callback, ctx);
mutex_unlock(&file->offset_lock);
Expand Down
Loading

0 comments on commit 2d489a7

Please sign in to comment.