diff options
author | dzwdz | 2023-01-06 21:11:44 +0100 |
---|---|---|
committer | dzwdz | 2023-01-06 21:11:44 +0100 |
commit | a1a4ab33cd75f0bc1d5e71989b01ba3446c998ae (patch) | |
tree | 4796f9ffc780dcb0336ed7c66c0cb42584320d61 /src/kernel/vfs | |
parent | e0c7bad47a54d865ef6194643e2cd20f6094e507 (diff) |
kernel: basic procfs
Diffstat (limited to 'src/kernel/vfs')
-rw-r--r-- | src/kernel/vfs/procfs.c | 122 | ||||
-rw-r--r-- | src/kernel/vfs/procfs.h | 4 | ||||
-rw-r--r-- | src/kernel/vfs/request.c | 4 | ||||
-rw-r--r-- | src/kernel/vfs/request.h | 2 |
4 files changed, 131 insertions, 1 deletions
diff --git a/src/kernel/vfs/procfs.c b/src/kernel/vfs/procfs.c new file mode 100644 index 0000000..e434c45 --- /dev/null +++ b/src/kernel/vfs/procfs.c @@ -0,0 +1,122 @@ +#include <camellia/errno.h> +#include <kernel/mem/virt.h> +#include <kernel/panic.h> +#include <kernel/proc.h> +#include <kernel/vfs/procfs.h> +#include <kernel/vfs/request.h> +#include <shared/mem.h> + +static uint32_t openpath(const char *path, size_t len, struct process *root); +static struct process *findgid(uint32_t gid, struct process *root); +static void procfs_accept(struct vfs_request *req); +static void procfs_cleanup(struct vfs_backend *be); + +static uint32_t +openpath(const char *path, size_t len, struct process *p) +{ + if (len == 0) return 0; + path++, len--; + + while (len) { + uint32_t cid = 0; + for (; 0 < len && *path != '/'; path++, len--) { + char c = *path; + if (!('0' <= c && c <= '9')) { + return 0; + } + cid = cid * 10 + *path - '0'; + } + if (len == 0) { + return 0; + } + assert(*path == '/'); + path++, len--; + + p = p->child; + if (!p) return 0; + while (p->cid != cid) { + p = p->sibling; + if (!p) return 0; + } + } + return p->globalid; +} + +static struct process * +findgid(uint32_t gid, struct process *root) +{ + for (struct process *p = root; p; p = process_next(p)) { + if (p->globalid == gid) return p; + } + return NULL; +} + +static void +procfs_accept(struct vfs_request *req) +{ + struct process *root = req->backend->kern.data; + struct process *p; + char buf[512]; + assert(root); + if (req->type == VFSOP_OPEN) { + int gid; + assert(req->input.kern); + gid = openpath(req->input.buf_kern, req->input.len, root); + vfsreq_finish_short(req, gid == 0 ? -ENOENT : gid); + return; + } + p = findgid((uintptr_t)req->id, root); + if (!p) { + vfsreq_finish_short(req, -EGENERIC); + return; + } + + if (req->type == VFSOP_READ) { + // TODO port dirbuild to kernel + int pos = 0; + if (req->offset != 0) { + vfsreq_finish_short(req, -ENOSYS); + return; + } + for (struct process *iter = p->child; iter; iter = iter->sibling) { + assert(pos < 512); + // processes could possibly be identified by unique identifiers instead + // e.g. an encrypted gid, or just a randomly generated one + // con: would require bringing in a crypto library + pos += snprintf(buf + pos, 512 - pos, "%d/", iter->cid) + 1; + if (512 <= pos) { + vfsreq_finish_short(req, -1); + } + } + assert(0 <= pos && (size_t)pos <= sizeof buf); + virt_cpy_to(req->caller->pages, req->output.buf, buf, pos); + vfsreq_finish_short(req, pos); + } else { + vfsreq_finish_short(req, -ENOSYS); + } +} + +static void +procfs_cleanup(struct vfs_backend *be) +{ + struct process *p = be->kern.data; + assert(p); + p->refcount--; +} + +struct vfs_backend * +procfs_backend(struct process *proc) +{ + struct vfs_backend *be = kzalloc(sizeof(struct vfs_backend)); + *be = (struct vfs_backend) { + .is_user = false, + .potential_handlers = 1, + .refcount = 1, + .kern.accept = procfs_accept, + .kern.data = proc, + .kern.cleanup = procfs_cleanup, + }; + proc->refcount++; + assert(proc->refcount); /* overflow */ + return be; +} diff --git a/src/kernel/vfs/procfs.h b/src/kernel/vfs/procfs.h new file mode 100644 index 0000000..5ee4e96 --- /dev/null +++ b/src/kernel/vfs/procfs.h @@ -0,0 +1,4 @@ +#pragma once +#include <kernel/vfs/request.h> + +struct vfs_backend *procfs_backend(struct process *proc); diff --git a/src/kernel/vfs/request.c b/src/kernel/vfs/request.c index a129f2e..2288de5 100644 --- a/src/kernel/vfs/request.c +++ b/src/kernel/vfs/request.c @@ -155,7 +155,9 @@ void vfs_backend_refdown(struct vfs_backend *b) { assert(b); assert(b->refcount > 0); if (--(b->refcount) > 0) return; - assert(!b->queue); + if (!b->is_user && b->kern.cleanup) { + b->kern.cleanup(b); + } kfree(b); } diff --git a/src/kernel/vfs/request.h b/src/kernel/vfs/request.h index db707d0..ef7c83a 100644 --- a/src/kernel/vfs/request.h +++ b/src/kernel/vfs/request.h @@ -22,6 +22,8 @@ struct vfs_backend { } user; struct { void (*accept)(struct vfs_request *); + void (*cleanup)(struct vfs_backend *); + void *data; } kern; }; }; |