summaryrefslogtreecommitdiff
path: root/src/kernel/vfs
diff options
context:
space:
mode:
authordzwdz2023-01-06 21:11:44 +0100
committerdzwdz2023-01-06 21:11:44 +0100
commita1a4ab33cd75f0bc1d5e71989b01ba3446c998ae (patch)
tree4796f9ffc780dcb0336ed7c66c0cb42584320d61 /src/kernel/vfs
parente0c7bad47a54d865ef6194643e2cd20f6094e507 (diff)
kernel: basic procfs
Diffstat (limited to 'src/kernel/vfs')
-rw-r--r--src/kernel/vfs/procfs.c122
-rw-r--r--src/kernel/vfs/procfs.h4
-rw-r--r--src/kernel/vfs/request.c4
-rw-r--r--src/kernel/vfs/request.h2
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;
};
};