diff options
author | nthnluu <nate1299@me.com> | 2024-01-28 21:20:27 -0500 |
---|---|---|
committer | nthnluu <nate1299@me.com> | 2024-01-28 21:20:27 -0500 |
commit | c63f340d90800895f007de64b7d2d14624263331 (patch) | |
tree | 2c0849fa597dd6da831c8707b6f2603403778d7b /kernel/fs/file.c |
Created student weenix repository
Diffstat (limited to 'kernel/fs/file.c')
-rw-r--r-- | kernel/fs/file.c | 115 |
1 files changed, 115 insertions, 0 deletions
diff --git a/kernel/fs/file.c b/kernel/fs/file.c new file mode 100644 index 0000000..4e79a3d --- /dev/null +++ b/kernel/fs/file.c @@ -0,0 +1,115 @@ +#include "fs/file.h" +#include "fs/vfs.h" +#include "fs/vnode.h" +#include "kernel.h" +#include "mm/slab.h" +#include "util/debug.h" +#include "util/string.h" + +static slab_allocator_t *file_allocator; + +void file_init(void) +{ + file_allocator = slab_allocator_create("file", sizeof(file_t)); +} + +void fref(file_t *f) +{ + KASSERT(f->f_mode <= FMODE_MAX_VALUE && f->f_vnode); + + f->f_refcount++; + + if (f->f_vnode) + { + dbg(DBG_FREF, "fref: 0x%p, 0x%p ino %u, up to %lu\n", f, + f->f_vnode->vn_fs, f->f_vnode->vn_vno, f->f_refcount); + } + else + { + dbg(DBG_FREF, "fref: 0x%p up to %lu\n", f, f->f_refcount); + } +} + +/* + * Create a file, initialize its members, vref the vnode, call acquire() on the + * vnode if the function pointer is non-NULL, and set the file descriptor in + * curproc->p_files. + * + * On successful return, the vnode's refcount should be incremented by one, + * the file's refcount should be 1, and curproc->p_files[fd] should point to + * the file being returned. + */ +file_t *fcreate(int fd, vnode_t *vnode, unsigned int mode) +{ + KASSERT(!curproc->p_files[fd]); + file_t *file = slab_obj_alloc(file_allocator); + if (!file) + return NULL; + memset(file, 0, sizeof(file_t)); + file->f_mode = mode; + + vref(file->f_vnode = vnode); + if (vnode->vn_ops->acquire) + vnode->vn_ops->acquire(vnode, file); + + curproc->p_files[fd] = file; + fref(file); + return file; +} + +/* + * Perform bounds checking on the fd, use curproc->p_files to get the file, + * fref it if it exists, and return. + */ +file_t *fget(int fd) +{ + if (fd < 0 || fd >= NFILES) + return NULL; + file_t *file = curproc->p_files[fd]; + if (file) + fref(file); + return file; +} + +/* + * Decrement the refcount, and set *filep to NULL. + * + * If the refcount drops to 0, call release on the vnode if the function pointer + * is non-null, vput() file's vnode, and free the file memory. + * + * Regardless of the ending refcount, *filep == NULL on return. + */ +void fput(file_t **filep) +{ + file_t *file = *filep; + *filep = NULL; + + KASSERT(file && file->f_mode <= FMODE_MAX_VALUE); + KASSERT(file->f_refcount > 0); + if (file->f_refcount != 1) + KASSERT(file->f_vnode); + + file->f_refcount--; + + if (file->f_vnode) + { + dbg(DBG_FREF, "fput: 0x%p, 0x%p ino %u, down to %lu\n", file, + file->f_vnode->vn_fs, file->f_vnode->vn_vno, file->f_refcount); + } + else + { + dbg(DBG_FREF, "fput: 0x%p down to %lu\n", file, file->f_refcount); + } + + if (!file->f_refcount) + { + if (file->f_vnode) + { + vlock(file->f_vnode); + if (file->f_vnode->vn_ops->release) + file->f_vnode->vn_ops->release(file->f_vnode, file); + vput_locked(&file->f_vnode); + } + slab_obj_free(file_allocator, file); + } +} |