From 3beaeaadf36de4e494d0b40ad31e3c5c503c596e Mon Sep 17 00:00:00 2001
From: dzwdz
Date: Thu, 5 May 2022 19:58:49 +0200
Subject: kernel/vfs: refactor vfs_backend to allow multiple kernel backends

---
 src/kernel/vfs/mount.c   |  5 +++-
 src/kernel/vfs/request.c | 61 +++++++++++++++++++++++++++++-------------------
 src/kernel/vfs/request.h | 31 ++++++++++++++----------
 src/kernel/vfs/root.c    | 13 +++++++----
 src/kernel/vfs/root.h    |  4 ++--
 5 files changed, 71 insertions(+), 43 deletions(-)

(limited to 'src/kernel/vfs')

diff --git a/src/kernel/vfs/mount.c b/src/kernel/vfs/mount.c
index d13c3d6..a6c5970 100644
--- a/src/kernel/vfs/mount.c
+++ b/src/kernel/vfs/mount.c
@@ -1,14 +1,17 @@
 #include <kernel/mem/alloc.h>
 #include <kernel/panic.h>
 #include <kernel/vfs/mount.h>
+#include <kernel/vfs/root.h>
 #include <shared/mem.h>
 
 struct vfs_mount *vfs_mount_seed(void) {
 	struct vfs_mount   *mount   = kmalloc(sizeof *mount);
 	struct vfs_backend *backend = kmalloc(sizeof *backend);
-	backend->type = VFS_BACK_ROOT;
+	backend->is_user = false;
 	backend->potential_handlers = 1;
 	backend->refcount = 1;
+	backend->kern.ready  = vfs_root_ready;
+	backend->kern.accept = vfs_root_accept;
 	*mount = (struct vfs_mount){
 		.prev = NULL,
 		.prefix = NULL,
diff --git a/src/kernel/vfs/request.c b/src/kernel/vfs/request.c
index fb196ee..5ad3b82 100644
--- a/src/kernel/vfs/request.c
+++ b/src/kernel/vfs/request.c
@@ -7,9 +7,8 @@
 #include <shared/mem.h>
 
 int vfsreq_create(struct vfs_request req_) {
-	struct vfs_request *req = kmalloc(sizeof *req);
+	struct vfs_request *req = kmalloc(sizeof *req); // freed in vfsreq_finish
 	memcpy(req, &req_, sizeof *req);
-	/* freed in vfsreq_finish */
 
 	if (req->backend)
 		req->backend->refcount++;
@@ -22,21 +21,12 @@ int vfsreq_create(struct vfs_request req_) {
 	if (!req->backend || !req->backend->potential_handlers)
 		return vfsreq_finish(req, -1);
 
-	switch (req->backend->type) {
-		case VFS_BACK_ROOT:
-			return vfs_root_handler(req);
-		case VFS_BACK_USER: {
-			struct vfs_request **iter = &req->backend->queue;
-			while (*iter != NULL) // find free spot in queue
-				iter = &(*iter)->queue_next;
-			*iter = req;
-
-			vfs_backend_accept(req->backend);
-			return -1; // isn't passed to the caller process anyways
-		}
-		default:
-			panic_invalid_state();
-	}
+	struct vfs_request **iter = &req->backend->queue;
+	while (*iter != NULL) // find free spot in queue
+		iter = &(*iter)->queue_next;
+	*iter = req;
+
+	return vfs_backend_tryaccept(req->backend);
 }
 
 int vfsreq_finish(struct vfs_request *req, int ret) {
@@ -76,18 +66,41 @@ int vfsreq_finish(struct vfs_request *req, int ret) {
 	return ret;
 }
 
-int vfs_backend_accept(struct vfs_backend *backend) {
+int vfs_backend_tryaccept(struct vfs_backend *backend) {
 	struct vfs_request *req = backend->queue;
-	struct process *handler = backend->handler;
+	if (!req) return -1;
+
+	/* ensure backend is ready to accept request */
+	if (backend->is_user) {
+		if (!backend->user.handler) return -1;
+	} else {
+		assert(backend->kern.ready);
+		if (!backend->kern.ready(backend)) return -1;
+	}
+
+	backend->queue = req->queue_next;
+
+	if (backend->is_user) {
+		return vfs_backend_user_accept(req);
+	} else {
+		assert(backend->kern.accept);
+		return backend->kern.accept(req);
+	}
+}
+
+int vfs_backend_user_accept(struct vfs_request *req) {
+	struct process *handler;
 	struct fs_wait_response res = {0};
 	int len = 0;
 
-	if (!handler) return -1;
+	assert(req && req->backend && req->backend->user.handler);
+	handler = req->backend->user.handler;
 	assert(handler->state == PS_WAITS4REQUEST);
-	assert(!handler->handled_req);
+	assert(handler->handled_req == NULL);
 
-	if (!req) return -1;
-	backend->queue = req->queue_next;
+	// the virt_cpy calls aren't present in all kernel backends
+	// it's a way to tell apart kernel and user backends apart
+	// TODO check validity of memory regions somewhere else
 
 	if (req->input.buf) {
 		len = min(req->input.len, handler->awaited_req.max_len);
@@ -108,7 +121,7 @@ int vfs_backend_accept(struct vfs_backend *backend) {
 
 	process_transition(handler, PS_RUNNING);
 	handler->handled_req = req;
-	req->backend->handler = NULL;
+	req->backend->user.handler = NULL;
 	regs_savereturn(&handler->regs, 0);
 	return 0;
 fail:
diff --git a/src/kernel/vfs/request.h b/src/kernel/vfs/request.h
index af1310b..e62f28f 100644
--- a/src/kernel/vfs/request.h
+++ b/src/kernel/vfs/request.h
@@ -4,11 +4,6 @@
 #include <stdbool.h>
 #include <stddef.h>
 
-enum vfs_backend_type {
-	VFS_BACK_ROOT,
-	VFS_BACK_USER,
-};
-
 // describes something which can act as an access function
 struct vfs_backend {
 	size_t refcount;
@@ -19,13 +14,22 @@ struct vfs_backend {
 	 *   struct handle
 	 */
 
-	enum vfs_backend_type type;
-
 	size_t potential_handlers; // 0 - orphaned
-
-	// only used with VFS_BACK_USER
-	struct process *handler;
 	struct vfs_request *queue;
+	bool is_user;
+
+	union {
+		struct {
+			struct process *handler;
+		} user;
+		struct {
+			bool (*ready)(struct vfs_backend *);
+
+			// return value might be passed to caller
+			// TODO make return void
+			int (*accept)(struct vfs_request *);
+		} kern;
+	};
 };
 
 // describes an in-process vfs call
@@ -57,7 +61,10 @@ struct vfs_request {
 int vfsreq_create(struct vfs_request);
 int vfsreq_finish(struct vfs_request *, int ret);
 
-/** Try to accept an enqueued request */
-int vfs_backend_accept(struct vfs_backend *);
+/** Try to accept an enqueued request
+ * @return same as _syscall_fs_wait, passed to it. except on calls to kern backend, where it returns the result of the fs op - also gets directly passed to caller. it's a mess */
+// TODO fix the return value mess
+int vfs_backend_tryaccept(struct vfs_backend *);
+int vfs_backend_user_accept(struct vfs_request *req);
 
 void vfs_backend_refdown(struct vfs_backend *);
diff --git a/src/kernel/vfs/root.c b/src/kernel/vfs/root.c
index 419d0f4..701d4e6 100644
--- a/src/kernel/vfs/root.c
+++ b/src/kernel/vfs/root.c
@@ -50,7 +50,7 @@ static void req_preprocess(struct vfs_request *req, size_t max_len) {
 
 
 static void wait_callback(struct process *proc) {
-	vfs_root_handler(proc->waits4irq.req);
+	vfs_root_accept(proc->waits4irq.req);
 }
 
 static bool wait_setup(struct vfs_request *req, bool *ready, bool (*ready_fn)()) {
@@ -174,7 +174,7 @@ static int handle(struct vfs_request *req, bool *ready) {
 	}
 }
 
-int vfs_root_handler(struct vfs_request *req) {
+int vfs_root_accept(struct vfs_request *req) {
 	if (req->caller) {
 		/* this introduces a difference between the root vfs and emulated ones:
 		 *
@@ -189,11 +189,16 @@ int vfs_root_handler(struct vfs_request *req) {
 		 */
 		bool ready = true;
 		int ret = handle(req, &ready);
-		if (ready)
+		if (ready) {
 			return vfsreq_finish(req, ret);
-		else
+		} else {
 			return -1;
+		}
 	} else {
 		return vfsreq_finish(req, -1);
 	}
 }
+
+bool vfs_root_ready(struct vfs_backend *self) {
+	return true;
+}
diff --git a/src/kernel/vfs/root.h b/src/kernel/vfs/root.h
index 501185e..f10fb85 100644
--- a/src/kernel/vfs/root.h
+++ b/src/kernel/vfs/root.h
@@ -1,5 +1,5 @@
 #pragma once
 #include <kernel/vfs/request.h>
 
-// the VFS provided to init
-int vfs_root_handler(struct vfs_request *);
+int vfs_root_accept(struct vfs_request *);
+bool vfs_root_ready(struct vfs_backend *);
-- 
cgit v1.2.3