From 51446cdd37e5be1e0767dc5dad16b98a36501433 Mon Sep 17 00:00:00 2001 From: Matheus Date: Mon, 3 Jul 2023 23:01:32 -0300 Subject: [PATCH] kernel: pipefs --- kernel-src/arch/x86-64/main.c | 2 + kernel-src/fs/pipefs.c | 264 +++++++++++++++++++++++++ kernel-src/include/kernel/pipefs.h | 20 ++ patches/mlibc/jinx-working-patch.patch | 20 +- 4 files changed, 302 insertions(+), 4 deletions(-) create mode 100644 kernel-src/fs/pipefs.c create mode 100644 kernel-src/include/kernel/pipefs.h diff --git a/kernel-src/arch/x86-64/main.c b/kernel-src/arch/x86-64/main.c index 9d02984a..a6ebd121 100644 --- a/kernel-src/arch/x86-64/main.c +++ b/kernel-src/arch/x86-64/main.c @@ -23,6 +23,7 @@ #include #include #include +#include static cpu_t bsp_cpu; @@ -50,6 +51,7 @@ void kernel_entry() { vfs_init(); tmpfs_init(); devfs_init(); + pipefs_init(); printf("mounting tmpfs on /\n"); __assert(vfs_mount(NULL, vfsroot, "/", "tmpfs", NULL) == 0); initrd_unpack(); diff --git a/kernel-src/fs/pipefs.c b/kernel-src/fs/pipefs.c new file mode 100644 index 00000000..fd26e176 --- /dev/null +++ b/kernel-src/fs/pipefs.c @@ -0,0 +1,264 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define BUFFER_SIZE 16 * PAGE_SIZE + +static scache_t *nodecache; +static uintmax_t currentinode; + +static vops_t vnops; + +int pipefs_open(vnode_t **node, int flags, cred_t *cred) { + VOP_LOCK(*node); + + pipenode_t *pipenode = (pipenode_t *)(*node); + + if (flags & V_FFLAGS_READ) { + ++pipenode->readers; + } + + if (flags & V_FFLAGS_WRITE) { + ++pipenode->writers; + } + + VOP_UNLOCK(*node); + return 0; +} + +int pipefs_close(vnode_t *node, int flags, cred_t *cred) { + VOP_LOCK(node); + pipenode_t *pipenode = (pipenode_t *)node; + + if (flags & V_FFLAGS_READ) { + --pipenode->readers; + } + + if (flags & V_FFLAGS_WRITE) { + --pipenode->writers; + } + + if (pipenode->readers == 0) + event_signal(&pipenode->writeevent); + + if (pipenode->writers == 0) + event_signal(&pipenode->readevent); + + VOP_UNLOCK(node); + return 0; +} + +int pipefs_read(vnode_t *node, void *buffer, size_t size, uintmax_t offset, int flags, size_t *readc, cred_t *cred) { + pipenode_t *pipenode = (pipenode_t *)node; + VOP_LOCK(node); + + int error = 0; + *readc = 0; + size_t datacount = 0; + + // wait until there is data to read or return if nonblock + while (datacount == 0) { + datacount = RINGBUFFER_DATACOUNT(&pipenode->data); + if (datacount == 0) { + if (pipenode->writers == 0) + goto leave; + + if (flags & V_FFLAGS_NONBLOCKING) { + error = EAGAIN; + goto leave; + } + + // to make it harder for a race condition to happen TODO figure out a way to fix this + bool status = interrupt_set(false); + VOP_UNLOCK(node); + + error = event_wait(&pipenode->writeevent, true); + interrupt_set(status); + if (error) + return error; + + VOP_LOCK(node); + } + } + + *readc = ringbuffer_read(&pipenode->data, buffer, size); + + if (*readc < datacount) + event_signal(&pipenode->writeevent); + + event_signal(&pipenode->readevent); + + leave: + VOP_UNLOCK(node); + return error; +} + +int pipefs_write(vnode_t *node, void *buffer, size_t size, uintmax_t offset, int flags, size_t *writec, cred_t *cred) { + pipenode_t *pipenode = (pipenode_t *)node; + VOP_LOCK(node); + + int error = 0; + *writec = 0; + + // wait until there is space to write data into or return if nonblock + size_t datacount = BUFFER_SIZE; + while (datacount == BUFFER_SIZE && pipenode->readers) { + datacount = RINGBUFFER_DATACOUNT(&pipenode->data); + if (datacount == BUFFER_SIZE) { + if (flags & V_FFLAGS_NONBLOCKING) { + error = EAGAIN; + goto leave; + } + + // to make it harder for a race condition to happen TODO figure out a way to fix this + bool status = interrupt_set(false); + VOP_UNLOCK(node); + + error = event_wait(&pipenode->readevent, true); + interrupt_set(status); + if (error) + return error; + + VOP_LOCK(node); + } + } + + if (pipenode->readers == 0) { + // TODO throw SIGPIPE + error = EPIPE; + goto leave; + } + + *writec = ringbuffer_write(&pipenode->data, buffer, size); + + if (datacount + *writec < BUFFER_SIZE) + event_signal(&pipenode->readevent); + + event_signal(&pipenode->writeevent); + + leave: + VOP_UNLOCK(node); + return error; +} + +int pipefs_poll(vnode_t *node, int events) { + pipenode_t *pipenode = (pipenode_t *)node; + int revents = 0; + VOP_LOCK(node); + + if (events & POLLIN) { + if (pipenode->writers == 0) + revents |= POLLHUP; + else if (RINGBUFFER_DATACOUNT(&pipenode->data) > 0) + revents |= POLLIN; + } + + if (events & POLLOUT) { + if (pipenode->readers == 0) + revents |= POLLERR; + else if (RINGBUFFER_DATACOUNT(&pipenode->data) < BUFFER_SIZE) + revents |= POLLOUT; + } + + VOP_UNLOCK(node); + return revents; +} + +int pipefs_getattr(vnode_t *node, vattr_t *attr, cred_t *cred) { + pipenode_t *pipenode = (pipenode_t *)node; + + VOP_LOCK(node); + *attr = pipenode->attr; + attr->type = node->type; + VOP_UNLOCK(node); + + return 0; +} + +int pipefs_setattr(vnode_t *node, vattr_t *attr, cred_t *cred) { + pipenode_t *pipenode = (pipenode_t *)node; + + VOP_LOCK(node); + pipenode->attr.gid = attr->gid; + pipenode->attr.uid = attr->uid; + pipenode->attr.mode = attr->mode; + pipenode->attr.atime = attr->atime; + pipenode->attr.mtime = attr->mtime; + pipenode->attr.ctime = attr->ctime; + VOP_UNLOCK(node); + return 0; +} + +int pipefs_inactive(vnode_t *node) { + pipenode_t *pipenode = (pipenode_t *)node; + VOP_LOCK(node); + ringbuffer_destroy(&pipenode->data); + slab_free(nodecache, node); + return 0; +} + + +static int pipefs_enodev() { + return ENODEV; +} + +static vops_t vnops = { + .create = pipefs_enodev, + .open = pipefs_open, + .close = pipefs_close, + .getattr = pipefs_getattr, + .setattr = pipefs_setattr, + .lookup = pipefs_enodev, + .poll = pipefs_poll, + .read = pipefs_read, + .write = pipefs_write, + .access = pipefs_enodev, + .unlink = pipefs_enodev, + .link = pipefs_enodev, + .symlink = pipefs_enodev, + .readlink = pipefs_enodev, + .inactive = pipefs_inactive, + .mmap = pipefs_enodev, + .munmap = pipefs_enodev, + .getdents = pipefs_enodev +}; + +static void ctor(scache_t *cache, void *obj) { + pipenode_t *node = obj; + memset(node, 0, sizeof(pipenode_t)); + node->vnode.refcount = 1; + SPINLOCK_INIT(node->vnode.lock); + node->vnode.ops = &vnops; + node->attr.inode = ++currentinode; + EVENT_INIT(&node->writeevent); + EVENT_INIT(&node->readevent); +} + +void pipefs_init() { + nodecache = slab_newcache(sizeof(pipenode_t), 0, ctor, ctor); + __assert(nodecache); +} + +int pipefs_newpipe(vnode_t **nodep) { + __assert(_cpu()->intstatus); + vnode_t *vnode = slab_allocate(nodecache); + pipenode_t *node = (pipenode_t *)vnode; + if (node == NULL) + return ENOMEM; + + int e = ringbuffer_init(&node->data, BUFFER_SIZE); + if (e) { + VOP_RELEASE(vnode); + return e; + } + + *nodep = vnode; + + return 0; +} diff --git a/kernel-src/include/kernel/pipefs.h b/kernel-src/include/kernel/pipefs.h new file mode 100644 index 00000000..3a94cb86 --- /dev/null +++ b/kernel-src/include/kernel/pipefs.h @@ -0,0 +1,20 @@ +#ifndef _PIPEFS_H +#define _PIPEFS_H + +#include +#include +#include +#include + +typedef struct pipenode_t { + vnode_t vnode; + vattr_t attr; + ringbuffer_t data; + size_t readers, writers; + event_t readevent, writeevent; +} pipenode_t; + +void pipefs_init(); +int pipefs_newpipe(vnode_t **nodep); + +#endif diff --git a/patches/mlibc/jinx-working-patch.patch b/patches/mlibc/jinx-working-patch.patch index a9ef1cae..d952feda 100644 --- a/patches/mlibc/jinx-working-patch.patch +++ b/patches/mlibc/jinx-working-patch.patch @@ -133,10 +133,10 @@ index 0000000..e5b087a + diff --git mlibc-workdir/sysdeps/astral/generic/generic.cpp mlibc-workdir/sysdeps/astral/generic/generic.cpp new file mode 100644 -index 0000000..e00428e +index 0000000..e76adfd --- /dev/null +++ mlibc-workdir/sysdeps/astral/generic/generic.cpp -@@ -0,0 +1,235 @@ +@@ -0,0 +1,246 @@ +#include +#include +#include @@ -192,6 +192,17 @@ index 0000000..e00428e + return 0; + } + ++ int sys_pipe(int *fds, int flags) { ++ long ret = 0; ++ long err = syscall(SYSCALL_PIPE2, &ret, flags); ++ if (err) ++ return err; ++ ++ fds[0] = ret & 0xffffffff; ++ fds[1] = (ret >> 32) & 0xffffffff; ++ return err; ++ } ++ + int sys_chdir(const char *path) { + long ret; + return syscall(SYSCALL_CHDIR, &ret, (uint64_t)path); @@ -391,10 +402,10 @@ index 0000000..990eca0 +#endif diff --git mlibc-workdir/sysdeps/astral/include/astral/syscall.h mlibc-workdir/sysdeps/astral/include/astral/syscall.h new file mode 100644 -index 0000000..e768d90 +index 0000000..e432092 --- /dev/null +++ mlibc-workdir/sysdeps/astral/include/astral/syscall.h -@@ -0,0 +1,45 @@ +@@ -0,0 +1,46 @@ +#ifndef _SYSCALL_H_INCLUDE +#define _SYSCALL_H_INCLUDE + @@ -420,6 +431,7 @@ index 0000000..e768d90 +#define SYSCALL_DUP3 19 +#define SYSCALL_FCNTL 20 +#define SYSCALL_CHDIR 21 ++#define SYSCALL_PIPE2 22 + +#include +#include