From 881be872675e4cff153c27c641980451c4a3f479 Mon Sep 17 00:00:00 2001
From: dzwdz
Date: Sun, 14 Jul 2024 19:40:31 +0200
Subject: kernel: make the adhoc VfsQueue queues use ReqQueue instead

I'm still not sure if I should use sys/queue.h for this.
But yeah, this is more consistent, and it will also let me switch over to O(1)
insertions later on.
---
 src/kernel/arch/amd64/driver/ps2.c     | 16 +++++-----
 src/kernel/arch/amd64/driver/rtl8139.c |  6 ++--
 src/kernel/arch/amd64/driver/serial.c  |  8 ++---
 src/kernel/proc.c                      |  8 ++---
 src/kernel/syscalls.c                  | 14 ++++----
 src/kernel/vfs/mount.c                 |  1 -
 src/kernel/vfs/procfs.c                |  1 -
 src/kernel/vfs/request.c               | 58 ++++++++++++++--------------------
 src/kernel/vfs/request.h               | 34 +++++++++-----------
 9 files changed, 64 insertions(+), 82 deletions(-)

(limited to 'src/kernel')

diff --git a/src/kernel/arch/amd64/driver/ps2.c b/src/kernel/arch/amd64/driver/ps2.c
index 86fcffd..0713293 100644
--- a/src/kernel/arch/amd64/driver/ps2.c
+++ b/src/kernel/arch/amd64/driver/ps2.c
@@ -58,8 +58,8 @@ void ps2_init(void) {
 	irq_fn[IRQ_PS2KB] = ps2_irq;
 	irq_fn[IRQ_PS2MOUSE] = ps2_irq;
 
-	postqueue_init(&kb_queue);
-	postqueue_init(&mouse_queue);
+	reqqueue_init(&kb_queue);
+	reqqueue_init(&mouse_queue);
 
 	vfs_root_register("/dev/ps2/", accept);
 }
@@ -70,10 +70,10 @@ static void ps2_irq(void) {
 		if (!(status & 1)) break; /* read while data available */
 		if (status & (1 << 5)) {
 			ring_put1b((void*)&mouse_backlog, port_in8(PS2));
-			postqueue_ringreadall(&mouse_queue, (void*)&mouse_backlog);
+			reqqueue_ringreadall(&mouse_queue, (void*)&mouse_backlog);
 		} else {
 			ring_put1b((void*)&kb_backlog, port_in8(PS2));
-			postqueue_ringreadall(&kb_queue, (void*)&kb_backlog);
+			reqqueue_ringreadall(&kb_queue, (void*)&kb_backlog);
 		}
 	}
 }
@@ -101,11 +101,11 @@ static void accept(VfsReq *req) {
 				ret = req_readcopy(req, data, sizeof data);
 				vfsreq_finish_short(req, ret);
 			} else if ((long __force)req->id == H_KB) {
-				postqueue_join(&kb_queue, req);
-				postqueue_ringreadall(&kb_queue, (void*)&kb_backlog);
+				reqqueue_join(&kb_queue, req);
+				reqqueue_ringreadall(&kb_queue, (void*)&kb_backlog);
 			} else if ((long __force)req->id == H_MOUSE) {
-				postqueue_join(&mouse_queue, req);
-				postqueue_ringreadall(&mouse_queue, (void*)&mouse_backlog);
+				reqqueue_join(&mouse_queue, req);
+				reqqueue_ringreadall(&mouse_queue, (void*)&mouse_backlog);
 			} else panic_invalid_state();
 			break;
 		default:
diff --git a/src/kernel/arch/amd64/driver/rtl8139.c b/src/kernel/arch/amd64/driver/rtl8139.c
index bce1071..c952d8a 100644
--- a/src/kernel/arch/amd64/driver/rtl8139.c
+++ b/src/kernel/arch/amd64/driver/rtl8139.c
@@ -86,7 +86,7 @@ void rtl8139_init(uint32_t bdf) {
 		mac[i] = port_in8(iobase + Mac + i);
 	}
 
-	postqueue_init(&blocked_on);
+	reqqueue_init(&blocked_on);
 
 	vfs_root_register("/dev/eth/", accept);
 }
@@ -102,7 +102,7 @@ static void rtl8139_irq(void) {
 	/* bit 0 of cmd - Rx Buffer Empty
 	 * not a do while() because sometimes the bit is empty on IRQ. no clue why. */
 	while (!(port_in8(iobase + Cmd) & 1)) {
-		VfsReq *req = postqueue_pop(&blocked_on);
+		VfsReq *req = reqqueue_pop(&blocked_on);
 		if (req) {
 			accept(req);
 		} else {
@@ -206,7 +206,7 @@ static void accept(VfsReq *req) {
 		} else if (id == HandleNet) {
 			ret = try_rx(req->caller, req->output.buf, req->output.len);
 			if (ret == WAIT) {
-				postqueue_join(&blocked_on, req);
+				reqqueue_join(&blocked_on, req);
 				rx_irq_enable(true);
 			} else {
 				vfsreq_finish_short(req, ret);
diff --git a/src/kernel/arch/amd64/driver/serial.c b/src/kernel/arch/amd64/driver/serial.c
index eb347d0..76ec33b 100644
--- a/src/kernel/arch/amd64/driver/serial.c
+++ b/src/kernel/arch/amd64/driver/serial.c
@@ -22,7 +22,7 @@ void serial_init(void) {
 	if (COM1_exists) {
 		vfs_root_register("/dev/com1", accept);
 	}
-	postqueue_init(&hung_reads);
+	reqqueue_init(&hung_reads);
 }
 
 static bool serial_selftest(void) {
@@ -58,7 +58,7 @@ void serial_preinit(void) {
 
 static void serial_irq(void) {
 	ring_put1b((void*)&backlog, port_in8(COM1));
-	postqueue_ringreadall(&hung_reads, (void*)&backlog);
+	reqqueue_ringreadall(&hung_reads, (void*)&backlog);
 }
 
 
@@ -81,8 +81,8 @@ static void accept(VfsReq *req) {
 			vfsreq_finish_short(req, valid ? 0 : -1);
 			break;
 		case VFSOP_READ:
-			postqueue_join(&hung_reads, req);
-			postqueue_ringreadall(&hung_reads, (void*)&backlog);
+			reqqueue_join(&hung_reads, req);
+			reqqueue_ringreadall(&hung_reads, (void*)&backlog);
 			break;
 		case VFSOP_WRITE:
 			if (req->caller && !req->flags) {
diff --git a/src/kernel/proc.c b/src/kernel/proc.c
index 9a9a84f..61c1dad 100644
--- a/src/kernel/proc.c
+++ b/src/kernel/proc.c
@@ -86,8 +86,9 @@ Proc *proc_fork(Proc *parent, int flags) {
 
 	if ((flags & FORK_NEWFS) == 0 && parent->controlled) {
 		child->controlled = parent->controlled;
-		assert(child->controlled->provhcnt);
-		child->controlled->provhcnt++;
+		assert(child->controlled->is_user);
+		assert(child->controlled->user.provhcnt);
+		child->controlled->user.provhcnt++;
 	}
 
 	child->mount = parent->mount;
@@ -211,8 +212,7 @@ static bool unref(uint64_t *refcount) {
 void proc_kill(Proc *p, int ret) {
 	if (proc_alive(p)) {
 		if (p->controlled) {
-			// TODO vfs_backend_user_handlerdown
-			assert(p->controlled->provhcnt > 0);
+			assert(p->controlled->is_user);
 			if (p->controlled->user.handler == p) {
 				assert(p->state == PS_WAITS4REQUEST);
 				p->controlled->user.handler = NULL;
diff --git a/src/kernel/syscalls.c b/src/kernel/syscalls.c
index 39115e7..1e1cd2f 100644
--- a/src/kernel/syscalls.c
+++ b/src/kernel/syscalls.c
@@ -39,11 +39,11 @@ long _sys_fork(int flags, hid_t __user *fs_front) {
 		}
 
 		h->backend = kzalloc(sizeof *h->backend, "user fs");
-		h->backend->is_user = true;
-		h->backend->provhcnt = 1; /* child */
 		h->backend->usehcnt = 1; /* handle */
+		h->backend->is_user = true;
+		h->backend->user.provhcnt = 1;
 		h->backend->user.handler = NULL;
-		h->backend->queue = NULL;
+		reqqueue_init(&h->backend->user.queue);
 		child->controlled = h->backend;
 
 		if (fs_front) {
@@ -261,6 +261,7 @@ hid_t _sys_fs_wait(char __user *buf, long max_len, struct ufs_request __user *re
 		/* nothing on the other end. EPIPE seems fitting */
 		SYSCALL_RETURN(-EPIPE);
 	}
+	assert(backend->is_user);
 
 	proc_setstate(proc_cur, PS_WAITS4REQUEST);
 	if (backend->user.handler)
@@ -270,11 +271,8 @@ hid_t _sys_fs_wait(char __user *buf, long max_len, struct ufs_request __user *re
 	proc_cur->awaited_req.max_len = max_len;
 	proc_cur->awaited_req.res     = res;
 
-	// TODO maybe i should use the postqueue stuff here
-	if (backend->queue) {
-		VfsReq *req = backend->queue;
-		backend->queue = req->queue_next;
-		req->queue_next = NULL;
+	VfsReq *req = reqqueue_pop(&backend->user.queue);
+	if (req) {
 		vfsback_useraccept(req);
 	}
 
diff --git a/src/kernel/vfs/mount.c b/src/kernel/vfs/mount.c
index 15d1382..fa5d65b 100644
--- a/src/kernel/vfs/mount.c
+++ b/src/kernel/vfs/mount.c
@@ -15,7 +15,6 @@ void vfs_root_register(const char *path, void (*accept)(VfsReq *)) {
 	*backend = (VfsBackend) {
 		.is_user = false,
 		.usehcnt = 1,
-		.provhcnt = 1,
 		.kern.accept = accept,
 	};
 	*mount = (VfsMount){
diff --git a/src/kernel/vfs/procfs.c b/src/kernel/vfs/procfs.c
index 79dfdc0..86042cd 100644
--- a/src/kernel/vfs/procfs.c
+++ b/src/kernel/vfs/procfs.c
@@ -185,7 +185,6 @@ procfs_backend(Proc *proc)
 	VfsBackend *be = kzalloc(sizeof(VfsBackend), "kern fs");
 	*be = (VfsBackend) {
 		.is_user = false,
-		.provhcnt = 1,
 		.usehcnt = 1,
 		.kern.accept = procfs_accept,
 		.kern.data = proc,
diff --git a/src/kernel/vfs/request.c b/src/kernel/vfs/request.c
index 8f44afb..58e2987 100644
--- a/src/kernel/vfs/request.c
+++ b/src/kernel/vfs/request.c
@@ -52,8 +52,7 @@ vfsreq_dispatchcopy(VfsReq tmpl)
 		vfsreq_finish_short(req, -EINVAL);
 		return;
 	}
-	assert(req->queue_next == NULL);
-	assert(req->postqueue_next == NULL);
+	assert(req->reqqueue_next == NULL);
 
 	if (backend == NULL) {
 		/* null mount - probably never had a real backend */
@@ -111,8 +110,7 @@ vfsreq_finish(VfsReq *req, char __user *stored, long ret, int flags, Proc *handl
 		vfsback_userdown(req->backend);
 	}
 
-	assert(req->queue_next == NULL);
-	assert(req->postqueue_next == NULL);
+	assert(req->reqqueue_next == NULL);
 
 	if (req->caller) {
 		assert(req->caller->state == PS_WAITS4FS);
@@ -134,17 +132,11 @@ vfsback_useraccept(VfsReq *req)
 	backend = req->backend;
 	assert(backend);
 	assert(backend->is_user);
-	if (backend->provhcnt == 0) {
+	if (backend->user.provhcnt == 0) {
 		vfsreq_finish_short(req, -EPIPE);
 		return;
 	} else if (backend->user.handler == NULL) {
-		/* queue the request up */
-		// TODO use postqueue
-		VfsReq **it = &backend->queue;
-		while (*it != NULL) { /* find a free spot in queue */
-			it = &(*it)->queue_next;
-		}
-		*it = req;
+		reqqueue_join(&backend->user.queue, req);
 		return;
 	}
 
@@ -194,8 +186,8 @@ vfsback_useraccept(VfsReq *req)
 static void
 vfsback_checkfree(VfsBackend *b)
 {
-	if (b->usehcnt == 0 && b->provhcnt == 0) {
-		assert(!b->queue);
+	if (b->is_user && b->usehcnt == 0 && b->user.provhcnt == 0) {
+		assert(b->user.queue.head == NULL);
 		kfree(b);
 	}
 }
@@ -227,54 +219,52 @@ void
 vfsback_provdown(VfsBackend *b)
 {
 	assert(b);
-	assert(0 < b->provhcnt);
-	b->provhcnt--;
-	if (b->provhcnt == 0) {
+	assert(b->is_user);
+	assert(0 < b->user.provhcnt);
+	b->user.provhcnt--;
+	if (b->user.provhcnt == 0) {
+		assert(b->is_user);
 		/* discard everything in the queue */
-		VfsReq *q = b->queue;
-		while (q) {
-			VfsReq *q2 = q->queue_next;
-			q->queue_next = NULL;
+		VfsReq *q;
+		while ((q = reqqueue_pop(&b->user.queue))) {
 			vfsreq_finish_short(q, -EPIPE);
-			q = q2;
 		}
-		b->queue = NULL;
 	}
 	vfsback_checkfree(b);
 }
 
 void
-postqueue_init(ReqQueue *q)
+reqqueue_init(ReqQueue *q)
 {
 	q->head = NULL;
 }
 
 void
-postqueue_join(ReqQueue *q, VfsReq *req)
+reqqueue_join(ReqQueue *q, VfsReq *req)
 {
-	if (req->postqueue_next)
+	if (req->reqqueue_next)
 		panic_invalid_state();
 
 	VfsReq **it = &q->head;
 	while (*it != NULL) {
-		it = &(*it)->postqueue_next;
+		it = &(*it)->reqqueue_next;
 	}
 	*it = req;
 }
 
 VfsReq *
-postqueue_pop(ReqQueue *q)
+reqqueue_pop(ReqQueue *q)
 {
 	VfsReq *req = q->head;
 	if (req) {
-		q->head = req->postqueue_next;
-		req->postqueue_next = NULL;
+		q->head = req->reqqueue_next;
+		req->reqqueue_next = NULL;
 	}
 	return req;
 }
 
 void
-postqueue_ringreadall(ReqQueue *q, ring_t *r)
+reqqueue_ringreadall(ReqQueue *q, ring_t *r)
 {
 	VfsReq **queue = &q->head; /* whatever */
 	VfsReq *req;
@@ -283,15 +273,15 @@ postqueue_ringreadall(ReqQueue *q, ring_t *r)
 	if (ring_used(r) == 0) return;
 
 	/* read as much as the biggest request wants */
-	for (req = *queue; req; req = req->postqueue_next)
+	for (req = *queue; req; req = req->reqqueue_next)
 		mlen = max(mlen, req->output.len);
 	mlen = min(mlen, sizeof tmp);
 	mlen = ring_get(r, tmp, mlen);
 
 	while (*queue) {
 		req = *queue;
-		*queue = req->postqueue_next;
-		req->postqueue_next = NULL;
+		*queue = req->reqqueue_next;
+		req->reqqueue_next = NULL;
 
 		size_t ret = min(mlen, req->output.len);
 		assert(req->type == VFSOP_READ);
diff --git a/src/kernel/vfs/request.h b/src/kernel/vfs/request.h
index 616c044..6786e72 100644
--- a/src/kernel/vfs/request.h
+++ b/src/kernel/vfs/request.h
@@ -4,6 +4,10 @@
 #include <stdbool.h>
 #include <stddef.h>
 
+struct ReqQueue {
+	VfsReq *head;
+};
+
 struct VfsBackend {
 	/* amount of using references
 	 *  VfsMount
@@ -11,17 +15,15 @@ struct VfsBackend {
 	 *  Handle
 	 * once it reaches 0, it'll never increase */
 	size_t usehcnt; /* VfsMount */
-	/* amount of providing references
-	 *  Proc
-	 * 0 - orphaned, will never increase */
-	// TODO move this into .user
-	size_t provhcnt;
 
-	VfsReq *queue;
 	bool is_user;
 	union {
 		struct {
 			Proc *handler;
+			ReqQueue queue; /* kernel backends keep their own queues */
+			/* amount of processes that control this backend
+			 * won't ever increase if it becomes 0 */
+			size_t provhcnt;
 		} user;
 		struct {
 			void (*accept)(VfsReq *);
@@ -56,10 +58,7 @@ struct VfsReq {
 	Proc *caller;
 	VfsBackend *backend;
 
-	VfsReq *queue_next;
-	VfsReq *postqueue_next; /* used by kernel backends */
-	/* only one of these queues is in use at a given moment, they could
-	 * be merged into a single field */
+	VfsReq *reqqueue_next;
 };
 
 /** Assigns the vfs_request to the caller, and dispatches the call */
@@ -79,13 +78,10 @@ void vfsback_userdown(VfsBackend *);
 /** Decrements the "provider" reference count. */
 void vfsback_provdown(VfsBackend *);
 
-struct ReqQueue {
-	VfsReq *head;
-};
-void postqueue_init(ReqQueue *q);
-void postqueue_join(ReqQueue *q, VfsReq *req);
-VfsReq *postqueue_pop(ReqQueue *q);
+void reqqueue_init(ReqQueue *q);
+void reqqueue_join(ReqQueue *q, VfsReq *req);
+VfsReq *reqqueue_pop(ReqQueue *q);
 
-/** If there are any pending read requests, and the ring buffer isn't empty, fulfill them
- * all with a single read. */
-void postqueue_ringreadall(ReqQueue *q, ring_t *r);
+/** If there are any pending read requests, and the ring buffer isn't empty,
+ *  fulfill them all with a single read. */
+void reqqueue_ringreadall(ReqQueue *q, ring_t *r);
-- 
cgit v1.2.3