From 41d6e7230e20651a4509040c6efe39791fd72251 Mon Sep 17 00:00:00 2001 From: Matheus Date: Sun, 18 Sep 2022 16:21:19 -0300 Subject: [PATCH] fd: new abstraction --- src/fs/fd.c | 123 +++++++++++++++++++++++++++++++++++++ src/include/kernel/fd.h | 17 ++++- src/include/kernel/sched.h | 5 +- src/sys/sched/scheduler.c | 26 ++++---- src/sys/syscalls/close.c | 35 ++--------- src/sys/syscalls/fstat.c | 22 +++---- src/sys/syscalls/isatty.c | 22 +++---- src/sys/syscalls/lseek.c | 24 +++----- src/sys/syscalls/open.c | 48 ++++----------- src/sys/syscalls/read.c | 23 +++---- src/sys/syscalls/write.c | 22 +++---- 11 files changed, 216 insertions(+), 151 deletions(-) create mode 100644 src/fs/fd.c diff --git a/src/fs/fd.c b/src/fs/fd.c new file mode 100644 index 00000000..7a1afe52 --- /dev/null +++ b/src/fs/fd.c @@ -0,0 +1,123 @@ +#include +#include +#include +#include + +// XXX limit the max fd number + +int fd_release(fd_t* fd){ + spinlock_release(&fd->lock); + return 0; +} + +int fd_access(fdtable_t* fdtable, fd_t** fd, int ifd){ + spinlock_acquire(&fdtable->lock); + + if(ifd >= fdtable->fdcount || fdtable->fd[ifd] == NULL){ + spinlock_release(&fdtable->lock); + return EBADF; + } + + *fd = fdtable->fd[ifd]; + fd_t* efd = *fd; + spinlock_acquire(&efd->lock); + spinlock_release(&fdtable->lock); + + return 0; + +} + +int fd_alloc(fdtable_t* fdtable, fd_t** fd, int* ifd){ + spinlock_acquire(&fdtable->lock); + + // find fd to use + + bool ok = false; + + for(uintmax_t i = fdtable->firstfreefd; i < fdtable->fdcount; ++i){ + if(!fdtable->fd[i]){ + fdtable->firstfreefd = i; + *ifd = i; + ok = true; + break; + } + } + + // resize table + + if(!ok){ + + fd_t** tmp = realloc(fdtable->fd, sizeof(fd_t*)*(fdtable->fdcount + 1)); + + if(!tmp){ + spinlock_release(&fdtable->lock); + return ENOMEM; + } + + fdtable->fd = tmp; + *ifd = fdtable->fdcount; + ++fdtable->fdcount; + + } + + fd_t* tmp = alloc(sizeof(fd_t)); + + if(!tmp){ + spinlock_release(&fdtable->lock); + return ENOMEM; + } + + spinlock_acquire(&tmp->lock); + tmp->refcount = 1; + + + fdtable->fd[*ifd] = tmp; + + spinlock_release(&fdtable->lock); + + *fd = tmp; + + return 0; + +} + +int fd_free(fdtable_t* fdtable, int ifd){ + spinlock_acquire(&fdtable->lock); + + if(ifd >= fdtable->fdcount || fdtable->fd[ifd] == NULL){ + spinlock_release(&fdtable->lock); + return EBADF; + } + + fd_t* fd = fdtable->fd[ifd]; + spinlock_acquire(&fd->lock); + + if(--fd->refcount > 0){ + spinlock_release(&fd->lock); + spinlock_release(&fdtable->lock); + return 0; + } + + fdtable->fd[ifd] = NULL; + + spinlock_release(&fdtable->lock); + + int err = vfs_close(fd->node); + + free(fd); + + return err; + +} + +int fd_tableinit(fdtable_t* fdtable){ + + fdtable->fd = alloc(sizeof(fd_t*)*3); + + if(!fdtable->fd) return ENOMEM; + + fdtable->fdcount = 3; + + return 0; + +} diff --git a/src/include/kernel/fd.h b/src/include/kernel/fd.h index 00f374eb..7880d766 100644 --- a/src/include/kernel/fd.h +++ b/src/include/kernel/fd.h @@ -29,14 +29,29 @@ #define O_RSYNC 04010000 #define O_TMPFILE 020000000 - +#include +#include typedef struct { + uintmax_t refcount; vnode_t* node; off_t offset; int flags; int lock; + mode_t mode; } fd_t; +typedef struct { + int lock; + size_t fdcount; + uintmax_t firstfreefd; + fd_t** fd; +} fdtable_t; + +int fd_alloc(fdtable_t* fdtable, fd_t** fd, int* ifd); +int fd_free(fdtable_t* fdtable, int ifd); +int fd_access(fdtable_t* fdtable, fd_t** fd, int ifd); +int fd_release(fd_t* fd); +int fd_tableinit(fdtable_t* fdtable); #endif diff --git a/src/include/kernel/sched.h b/src/include/kernel/sched.h index ba66501f..85876f65 100644 --- a/src/include/kernel/sched.h +++ b/src/include/kernel/sched.h @@ -46,10 +46,7 @@ typedef struct _proc_t{ pid_t pid; gid_t gid; uid_t uid; - fd_t* fds; - int fdlock; - size_t fdcount; - off_t firstfreefd; + fdtable_t fdtable; thread_t** threads; size_t threadcount; dirnode_t* root; diff --git a/src/sys/sched/scheduler.c b/src/sys/sched/scheduler.c index 484480de..57eb6e34 100644 --- a/src/sys/sched/scheduler.c +++ b/src/sys/sched/scheduler.c @@ -10,7 +10,6 @@ #include #include -#define PROC_START_FD_COUNT 3 #define THREAD_QUANTUM 10000 // queue 0: interrupt threads @@ -34,18 +33,11 @@ static proc_t* allocproc(size_t threadcount){ return NULL; } - proc->fds = alloc(sizeof(fd_t) * PROC_START_FD_COUNT); - - if(!proc->fds){ + if(fd_tableinit(&proc->fdtable)){ free(proc->threads); free(proc); return NULL; } - - proc->fdcount = PROC_START_FD_COUNT; - proc->firstfreefd = PROC_START_FD_COUNT; - - return proc; @@ -362,11 +354,15 @@ void sched_runinit(){ proc->root = vfs_root(); proc->cwd = vfs_root(); - proc->pid = 1; + proc->pid = 1; - fd_t* stdinfd = &proc->fds[0]; - fd_t* stdoutfd = &proc->fds[1]; - fd_t* stderrfd = &proc->fds[2]; + int tmp; + + fd_t *stdinfd, *stdoutfd, *stderrfd; + + fd_alloc(&proc->fdtable, &stdinfd, &tmp); + fd_alloc(&proc->fdtable, &stdoutfd, &tmp); + fd_alloc(&proc->fdtable, &stderrfd, &tmp); #define CONSOLE_PATH "dev/console" @@ -417,6 +413,10 @@ void sched_runinit(){ arch_regs_setupuser(thread->regs, entry, stack, true); + fd_release(stdinfd); + fd_release(stdoutfd); + fd_release(stderrfd); + timer_add(&arch_getcls()->schedreq, THREAD_QUANTUM, true); switch_thread(thread); diff --git a/src/sys/syscalls/close.c b/src/sys/syscalls/close.c index efb66176..a496a44e 100644 --- a/src/sys/syscalls/close.c +++ b/src/sys/syscalls/close.c @@ -6,40 +6,17 @@ syscallret syscall_close(int ifd){ syscallret retv; - retv.ret = -1; + retv.ret = 0; + retv.errno = 0; proc_t* proc = arch_getcls()->thread->proc; - fd_t* fd = proc->fds + ifd; + int err = fd_free(&proc->fdtable, ifd); - spinlock_acquire(&proc->fdlock); - - if(proc->fdcount <= ifd || fd->node == NULL || (fd->flags & FD_FLAGS_READ) == 0){ - spinlock_release(&proc->fdlock); - retv.errno = EBADF; - return retv; - } - - spinlock_acquire(&fd->lock); - spinlock_release(&proc->fdlock); - - int ret = vfs_close(fd->node); - - if(ret){ - retv.errno = ret; - goto _ret; + if(err){ + retv.errno = err; + retv.ret = -1; } - // the fd table isn't resized on a close - // although that can be added if it becomes an issue - - fd->node = NULL; - - retv.ret = 0; - retv.errno = 0; - - _ret: - - spinlock_release(&fd->lock); return retv; } diff --git a/src/sys/syscalls/fstat.c b/src/sys/syscalls/fstat.c index 3f63416b..684fc2b6 100644 --- a/src/sys/syscalls/fstat.c +++ b/src/sys/syscalls/fstat.c @@ -17,22 +17,18 @@ syscallret syscall_fstat(int ifd, stat* st){ proc_t* proc = arch_getcls()->thread->proc; - fd_t* fd = proc->fds + ifd; - - spinlock_acquire(&proc->fdlock); - - if(proc->fdcount <= ifd || fd->node == NULL || (fd->flags & FD_FLAGS_READ) == 0){ - spinlock_release(&proc->fdlock); - retv.errno = EBADF; - return retv; - } - - spinlock_acquire(&fd->lock); - spinlock_release(&proc->fdlock); + fd_t* fd; + int err = fd_access(&proc->fdtable, &fd, ifd); + + if(err){ + retv.errno = err; + return retv; + } + memcpy(st, &fd->node->st, sizeof(stat)); // XXX user memcpy - spinlock_release(&fd->lock); + fd_release(fd); retv.errno = 0; retv.ret = 0; diff --git a/src/sys/syscalls/isatty.c b/src/sys/syscalls/isatty.c index 89bec527..253e14d6 100644 --- a/src/sys/syscalls/isatty.c +++ b/src/sys/syscalls/isatty.c @@ -12,26 +12,22 @@ syscallret syscall_isatty(int ifd){ proc_t* proc = arch_getcls()->thread->proc; - fd_t* fd = proc->fds + ifd; + fd_t* fd; + + int ret = fd_access(&proc->fdtable, &fd, ifd); - spinlock_acquire(&proc->fdlock); - - if(proc->fdcount <= ifd || fd->node == NULL){ - spinlock_release(&proc->fdlock); - retv.errno = EBADF; - return retv; - } + if(ret){ + retv.errno = ret; + return retv; + } - spinlock_acquire(&fd->lock); - spinlock_release(&proc->fdlock); - - int ret = vfs_isatty(fd->node); + ret = vfs_isatty(fd->node); retv.errno = ret; retv.ret = retv.errno == ENOTTY ? 0 : 1; - spinlock_release(&fd->lock); + fd_release(fd); return retv; diff --git a/src/sys/syscalls/lseek.c b/src/sys/syscalls/lseek.c index 11046956..02f0d655 100644 --- a/src/sys/syscalls/lseek.c +++ b/src/sys/syscalls/lseek.c @@ -15,20 +15,16 @@ syscallret syscall_lseek(int ifd, off_t offset, int whence){ proc_t* proc = arch_getcls()->thread->proc; - fd_t* fd = proc->fds + ifd; - - spinlock_acquire(&proc->fdlock); - - if(proc->fdcount <= ifd || fd->node == NULL){ - spinlock_release(&proc->fdlock); - retv.errno = EBADF; - return retv; - } - - spinlock_acquire(&fd->lock); - spinlock_release(&proc->fdlock); + fd_t* fd; - int type = GETTYPE(fd->node->st.st_mode); + int ret = fd_access(&proc->fdtable, &fd, ifd); + + if(ret){ + retv.errno = ret; + return retv; + } + + int type = GETTYPE(fd->mode); if(type == TYPE_SOCKET || type == TYPE_FIFO){ retv.errno = ESPIPE; @@ -71,7 +67,7 @@ syscallret syscall_lseek(int ifd, off_t offset, int whence){ retv.ret = newoffset; _ret: - spinlock_release(&fd->lock); + fd_release(fd); return retv; } diff --git a/src/sys/syscalls/open.c b/src/sys/syscalls/open.c index 4ce3710e..fed4ac62 100644 --- a/src/sys/syscalls/open.c +++ b/src/sys/syscalls/open.c @@ -29,43 +29,17 @@ syscallret syscall_open(const char* pathname, int flags, mode_t mode){ proc_t* proc = arch_getcls()->thread->proc; - spinlock_acquire(&proc->fdlock); + int ifd; + fd_t* fd; - fd_t* fd = NULL; + int err = fd_alloc(&proc->fdtable, &fd, &ifd); - // find fd to use - - for(uintmax_t i = 0; i < proc->fdcount; ++i){ - spinlock_acquire(&proc->fds[i].lock); - if(!proc->fds[i].node){ - fd = &proc->fds[i].node; - break; - } - spinlock_release(&proc->fds[i].lock); + if(err){ + retv.errno = err; + free(name); + return retv; } - // resize table - - if(!fd){ - - fd_t* tmp = realloc(proc->fds, sizeof(fd_t)*proc->fdcount + 1); - - if(!tmp){ - spinlock_release(&proc->fdlock); - retv.errno = ENOMEM; - return retv; - } - - proc->fds = tmp; - - fd = &proc->fds[proc->fdcount]; - ++proc->fdcount; - spinlock_acquire(&fd->lock); - - } - - spinlock_release(&proc->fdlock); - fd->flags = flags + 1; // 1 is added to make O_RDONLY etc easier to lookup fd->offset = 0; @@ -94,11 +68,11 @@ syscallret syscall_open(const char* pathname, int flags, mode_t mode){ fd->node = file; - spinlock_release(&fd->lock); - + fd_release(fd); + free(name); retv.errno = 0; - retv.ret = ((uintptr_t)fd - (uintptr_t)proc->fds) / sizeof(fd_t); + retv.ret = ifd; return retv; @@ -106,7 +80,7 @@ syscallret syscall_open(const char* pathname, int flags, mode_t mode){ if(file) vfs_close(file); - spinlock_release(&fd->lock); + fd_release(fd); fd->node = NULL; free(name); return retv; diff --git a/src/sys/syscalls/read.c b/src/sys/syscalls/read.c index 7c61d293..89b278bb 100644 --- a/src/sys/syscalls/read.c +++ b/src/sys/syscalls/read.c @@ -19,34 +19,29 @@ syscallret syscall_read(int ifd, void* buff, size_t count){ proc_t* proc = arch_getcls()->thread->proc; - fd_t* fd = proc->fds + ifd; + fd_t* fd; - spinlock_acquire(&proc->fdlock); - - if(proc->fdcount <= ifd || fd->node == NULL || (fd->flags & FD_FLAGS_READ) == 0){ - spinlock_release(&proc->fdlock); - retv.errno = EBADF; + int err = fd_access(&proc->fdtable, &fd, ifd); + + if(err){ + retv.errno = err; return retv; } - spinlock_acquire(&fd->lock); - spinlock_release(&proc->fdlock); - void* kbuff = alloc(count); if(!kbuff){ - spinlock_release(&fd->lock); + fd_release(fd); retv.errno = ENOMEM; return retv; } - int err; size_t readc = vfs_read(&err, fd->node, kbuff, count, fd->offset); - if(err){ - spinlock_release(&fd->lock); + if(err){ + fd_release(fd); free(kbuff); retv.errno = err; return retv; @@ -54,7 +49,7 @@ syscallret syscall_read(int ifd, void* buff, size_t count){ fd->offset += readc; - spinlock_release(&fd->lock); + fd_release(fd); memcpy(buff, kbuff, count); // XXX user version for safety diff --git a/src/sys/syscalls/write.c b/src/sys/syscalls/write.c index b8e40052..c2168690 100644 --- a/src/sys/syscalls/write.c +++ b/src/sys/syscalls/write.c @@ -22,24 +22,20 @@ syscallret syscall_write(int ifd, void* buff, size_t count){ proc_t* proc = arch_getcls()->thread->proc; - fd_t* fd = proc->fds + ifd; + fd_t* fd; - spinlock_acquire(&proc->fdlock); + int err = fd_access(&proc->fdtable, &fd, ifd); - if(proc->fdcount <= ifd || fd->node == NULL || (fd->flags & FD_FLAGS_WRITE) == 0){ - spinlock_release(&proc->fdlock); - retv.errno = EBADF; + if(err){ + retv.errno = err; return retv; - } - - spinlock_acquire(&fd->lock); - spinlock_release(&proc->fdlock); + } void* kbuff = alloc(count); if(!kbuff){ - spinlock_release(&fd->lock); - retv.errno = ENOMEM; + fd_release(fd); + retv.errno = ENOMEM; return retv; } @@ -48,7 +44,7 @@ syscallret syscall_write(int ifd, void* buff, size_t count){ if(fd->flags & O_APPEND) fd->offset = fd->node->st.st_size; - int err; + size_t writec = vfs_write(&err, fd->node, kbuff, count, fd->offset); @@ -66,7 +62,7 @@ syscallret syscall_write(int ifd, void* buff, size_t count){ retv.ret = writec; _ret: - spinlock_release(&fd->lock); + fd_release(fd); free(kbuff); return retv; }