kernel: pipefs

This commit is contained in:
Matheus
2023-07-03 23:01:32 -03:00
parent 42b130bfe0
commit 51446cdd37
4 changed files with 302 additions and 4 deletions
+2
View File
@@ -23,6 +23,7 @@
#include <kernel/keyboard.h>
#include <kernel/console.h>
#include <kernel/dpc.h>
#include <kernel/pipefs.h>
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();
+264
View File
@@ -0,0 +1,264 @@
#include <kernel/vfs.h>
#include <kernel/pipefs.h>
#include <kernel/slab.h>
#include <kernel/alloc.h>
#include <kernel/timekeeper.h>
#include <kernel/vmm.h>
#include <logging.h>
#include <errno.h>
#include <kernel/abi.h>
#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;
}
+20
View File
@@ -0,0 +1,20 @@
#ifndef _PIPEFS_H
#define _PIPEFS_H
#include <kernel/vfs.h>
#include <ringbuffer.h>
#include <semaphore.h>
#include <event.h>
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