diff --git a/etc/make/conf.mk b/etc/make/conf.mk index 09c8ede..948247c 100644 --- a/etc/make/conf.mk +++ b/etc/make/conf.mk @@ -78,6 +78,7 @@ OBJS+=$(O)/fs/vfs.o \ $(O)/fs/vfs_ops.o \ $(O)/fs/vfs_access.o \ $(O)/fs/fs_class.o \ + $(O)/fs/ofile.o \ $(O)/fs/node.o \ $(O)/fs/tar.o \ $(O)/fs/sysfs.o \ diff --git a/fs/ofile.c b/fs/ofile.c new file mode 100644 index 0000000..37e7995 --- /dev/null +++ b/fs/ofile.c @@ -0,0 +1,45 @@ +#include "sys/mem/slab.h" +#include "sys/assert.h" +#include "fs/ofile.h" +#include "fs/vfs.h" + +static struct slab_cache *ofile_cache = NULL; + +struct ofile *ofile_create(void) { + struct ofile *of; + + if (!ofile_cache) { + ofile_cache = slab_cache_get(sizeof(struct ofile)); + } + + // Also sets refcount to zero + of = slab_calloc(ofile_cache); + _assert(of); + return of; +} + +void ofile_destroy(struct ofile *of) { + _assert(!of->refcount); + slab_free(ofile_cache, of); +} + +void ofile_close(struct vfs_ioctx *ioctx, struct ofile *of) { + // An ofile should be open before closing + _assert(of->refcount > 0); + --of->refcount; + if (of->refcount == 0) { + if (of->flags & OF_SOCKET) { + //net_close(&thr->ioctx, thr->fds[fd]); + } else { + vfs_close(ioctx, of); + } + ofile_destroy(of); + } +} + +struct ofile *ofile_dup(struct ofile *of) { + _assert(of); + _assert(of->refcount >= 0); + ++of->refcount; + return of; +} diff --git a/fs/vfs_ops.c b/fs/vfs_ops.c index 1a4a0e4..d266002 100644 --- a/fs/vfs_ops.c +++ b/fs/vfs_ops.c @@ -75,7 +75,6 @@ static int vfs_opendir(struct vfs_ioctx *ctx, struct ofile *fd) { fd->flags |= OF_MEMDIR | OF_MEMDIR_DOT; fd->file.pos = (size_t) node->first_child; - ++fd->file.refcount; ++node->open_count; return 0; @@ -89,7 +88,6 @@ static int vfs_opendir(struct vfs_ioctx *ctx, struct ofile *fd) { return res; } - ++fd->file.refcount; ++node->open_count; return 0; @@ -196,7 +194,6 @@ int vfs_open_vnode(struct vfs_ioctx *ctx, struct ofile *fd, struct vnode *node, return -EACCES; } - fd->file.refcount = 0; fd->file.pos = 0; fd->file.vnode = node; fd->flags = OF_DIRECTORY | OF_READABLE; @@ -228,7 +225,6 @@ int vfs_open_vnode(struct vfs_ioctx *ctx, struct ofile *fd, struct vnode *node, } } - fd->file.refcount = 0; fd->file.pos = 0; fd->file.vnode = node; fd->flags = 0; @@ -253,7 +249,6 @@ int vfs_open_vnode(struct vfs_ioctx *ctx, struct ofile *fd, struct vnode *node, } } - ++fd->file.refcount; ++fd->file.vnode->open_count; return 0; @@ -479,13 +474,12 @@ void vfs_close(struct vfs_ioctx *ctx, struct ofile *fd) { _assert(ctx); _assert(fd); _assert(!(fd->flags & OF_SOCKET)); + _assert(!(fd->refcount)); _assert(fd->file.vnode); - _assert(fd->file.refcount > 0); --fd->file.vnode->open_count; - --fd->file.refcount; - if (!fd->file.refcount && fd->file.vnode->op && fd->file.vnode->op->close) { + if (fd->file.vnode->op && fd->file.vnode->op->close) { fd->file.vnode->op->close(fd); } } diff --git a/include/fs/ofile.h b/include/fs/ofile.h index 6e6af31..f04f71c 100644 --- a/include/fs/ofile.h +++ b/include/fs/ofile.h @@ -11,11 +11,13 @@ #define OF_MEMDIR_DOTDOT (1 << 5) #define OF_SOCKET (1 << 6) +struct vfs_ioctx; + struct ofile { int flags; + int refcount; union { struct { - int refcount; struct vnode *vnode; size_t pos; void *priv_data; @@ -23,3 +25,8 @@ struct ofile { struct socket socket; }; }; + +struct ofile *ofile_create(void); +struct ofile *ofile_dup(struct ofile *of); +void ofile_destroy(struct ofile *of); +void ofile_close(struct vfs_ioctx *ctx, struct ofile *of); diff --git a/sys/char/pipe.c b/sys/char/pipe.c index 89d0979..b35f4c8 100644 --- a/sys/char/pipe.c +++ b/sys/char/pipe.c @@ -24,11 +24,8 @@ static struct vnode_operations pipe_vnode_ops = { }; int pipe_create(struct ofile **_read, struct ofile **_write) { - // TODO: ofile_create - struct ofile *read_end = kmalloc(sizeof(struct ofile)); - _assert(read_end); - struct ofile *write_end = kmalloc(sizeof(struct ofile)); - _assert(write_end); + struct ofile *read_end = ofile_create(); + struct ofile *write_end = ofile_create(); struct ring *pipe_ring = kmalloc(sizeof(struct ring)); _assert(pipe_ring); @@ -41,12 +38,10 @@ int pipe_create(struct ofile **_read, struct ofile **_write) { read_end->flags = OF_READABLE; read_end->file.vnode = vnode; - read_end->file.refcount = 1; read_end->file.priv_data = pipe_ring; write_end->flags = OF_WRITABLE; write_end->file.vnode = vnode; - write_end->file.refcount = 1; write_end->file.priv_data = pipe_ring; *_read = read_end; diff --git a/sys/init.c b/sys/init.c index 2f88436..3150c86 100644 --- a/sys/init.c +++ b/sys/init.c @@ -31,8 +31,8 @@ static void user_init_func(void *arg) { } // Open STDOUT_FILENO and STDERR_FILENO - struct ofile *fd_stdout = kmalloc(sizeof(struct ofile)); - struct ofile *fd_stdin = kmalloc(sizeof(struct ofile)); + struct ofile *fd_stdout = ofile_create(); + struct ofile *fd_stdin = ofile_create(); if ((res = dev_find(DEV_CLASS_CHAR, "tty0", &tty_dev)) != 0) { kerror("tty0: %s\n", kstrerror(res)); @@ -49,14 +49,12 @@ static void user_init_func(void *arg) { panic("Fail\n"); } - thread_self->fds[0] = fd_stdin; - thread_self->fds[1] = fd_stdout; - thread_self->fds[2] = fd_stdout; - // Duplicate the FD - ++fd_stdout->file.refcount; + thread_self->fds[0] = ofile_dup(fd_stdin); + thread_self->fds[1] = ofile_dup(fd_stdout); + thread_self->fds[2] = ofile_dup(fd_stdout); - _assert(fd_stdin->file.refcount == 1); - _assert(fd_stdout->file.refcount == 2); + _assert(fd_stdin->refcount == 1); + _assert(fd_stdout->refcount == 2); const char *argp[] = { "/init", NULL diff --git a/sys/mod.c b/sys/mod.c index b88b31f..43ff16c 100644 --- a/sys/mod.c +++ b/sys/mod.c @@ -384,7 +384,7 @@ int sys_module_unload(const char *name) { int sys_module_load(const char *path, const char *params) { struct vfs_ioctx kernel_ioctx = {0, 0, 0}; int res; - struct ofile fd; + struct ofile fd = {0}; struct thread *thr = thread_self; if (thr->ioctx.uid != 0) { diff --git a/sys/sys_file.c b/sys/sys_file.c index f4f7dc3..0ccc76f 100644 --- a/sys/sys_file.c +++ b/sys/sys_file.c @@ -143,15 +143,16 @@ int sys_open(const char *filename, int flags, int mode) { return -EMFILE; } - struct ofile *ofile = kmalloc(sizeof(struct ofile)); - _assert(ofile); + struct ofile *ofile = ofile_create(); if ((res = vfs_open(&thr->ioctx, ofile, filename, flags, mode)) != 0) { - kfree(ofile); + ofile_destroy(ofile); return res; } - thr->fds[fd] = ofile; + thr->fds[fd] = ofile_dup(ofile); + _assert(thr->fds[fd]->refcount == 1); + return fd; } @@ -167,16 +168,7 @@ void sys_close(int fd) { return; } - if (thr->fds[fd]->flags & OF_SOCKET) { - net_close(&thr->ioctx, thr->fds[fd]); - kfree(thr->fds[fd]); - } else { - vfs_close(&thr->ioctx, thr->fds[fd]); - _assert(thr->fds[fd]->file.refcount >= 0); - if (!thr->fds[fd]->file.refcount) { - kfree(thr->fds[fd]); - } - } + ofile_close(&thr->ioctx, thr->fds[fd]); thr->fds[fd] = NULL; } @@ -294,10 +286,7 @@ int sys_dup2(int from, int to) { sys_close(to); _assert(!thr->fds[to]); - thr->fds[to] = thr->fds[from]; - if (!(thr->fds[from]->flags & OF_SOCKET)) { - ++thr->fds[from]->file.refcount; - } + thr->fds[to] = ofile_dup(thr->fds[from]); return to; } diff --git a/sys/sys_net.c b/sys/sys_net.c index 9eea43c..fd2d927 100644 --- a/sys/sys_net.c +++ b/sys/sys_net.c @@ -38,11 +38,10 @@ int sys_socket(int domain, int type, int protocol) { return -EMFILE; } - struct ofile *ofile = kmalloc(sizeof(struct ofile)); - _assert(ofile); + struct ofile *ofile = ofile_create(); if ((res = net_open(&thr->ioctx, ofile, domain, type, protocol)) != 0) { - kfree(ofile); + ofile_destroy(ofile); return res; } diff --git a/sys/thread.c b/sys/thread.c index 0204d1a..2232ced 100644 --- a/sys/thread.c +++ b/sys/thread.c @@ -80,17 +80,13 @@ static void thread_ioctx_empty(struct thread *thr) { void thread_ioctx_fork(struct thread *dst, struct thread *src) { thread_ioctx_empty(dst); - // TODO: increase refcount (when cwd has one) dst->ioctx.cwd_vnode = src->ioctx.cwd_vnode; dst->ioctx.gid = src->ioctx.gid; dst->ioctx.uid = src->ioctx.uid; for (int i = 0; i < THREAD_MAX_FDS; ++i) { if (src->fds[i]) { - dst->fds[i] = src->fds[i]; - if (!(dst->fds[i]->flags & OF_SOCKET)) { - ++dst->fds[i]->file.refcount; - } + dst->fds[i] = ofile_dup(src->fds[i]); } } } @@ -165,16 +161,7 @@ void thread_cleanup(struct thread *thr) { kdebug("Cleaning up %d\n", thr->pid); for (size_t i = 0; i < THREAD_MAX_FDS; ++i) { if (thr->fds[i]) { - - if (thr->fds[i]->flags & OF_SOCKET) { - net_close(&thr->ioctx, thr->fds[i]); - } else { - vfs_close(&thr->ioctx, thr->fds[i]); - _assert(thr->fds[i]->file.refcount >= 0); - if (thr->fds[i]->file.refcount == 0) { - kfree(thr->fds[i]); - } - } + ofile_close(&thr->ioctx, thr->fds[i]); thr->fds[i] = NULL; } } @@ -569,7 +556,7 @@ static int procv_setup(struct thread *thr, int sys_execve(const char *path, const char **argv, const char **envp) { struct thread *thr = thread_self; _assert(thr); - struct ofile fd; + struct ofile fd = {0}; struct stat st; uintptr_t entry; size_t argc;