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/proc.c | 4 ++-- src/kernel/syscalls.c | 10 ++++---- 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 ++-- 7 files changed, 78 insertions(+), 50 deletions(-) (limited to 'src') diff --git a/src/kernel/proc.c b/src/kernel/proc.c index ebe291a..7c41eb2 100644 --- a/src/kernel/proc.c +++ b/src/kernel/proc.c @@ -257,9 +257,9 @@ void process_kill(struct process *p, int ret) { } p->controlled->queue = NULL; } - if (p->controlled->handler == p) { + if (p->controlled->user.handler == p) { assert(p->state == PS_WAITS4REQUEST); - p->controlled->handler = NULL; + p->controlled->user.handler = NULL; } vfs_backend_refdown(p->controlled); diff --git a/src/kernel/syscalls.c b/src/kernel/syscalls.c index 1e33632..1ec8ed9 100644 --- a/src/kernel/syscalls.c +++ b/src/kernel/syscalls.c @@ -180,10 +180,10 @@ handle_t _syscall_fs_fork2(void) { process_current->handles[front] = handle_init(HANDLE_FS_FRONT); backend = kmalloc(sizeof *backend); // TODO never freed - backend->type = VFS_BACK_USER; + backend->is_user = true; backend->potential_handlers = 1; backend->refcount = 2; // child + handle - backend->handler = NULL; + backend->user.handler = NULL; backend->queue = NULL; child = process_fork(process_current, 0); @@ -200,15 +200,15 @@ int _syscall_fs_wait(char __user *buf, int max_len, struct fs_wait_response __us if (!backend) return -1; process_transition(process_current, PS_WAITS4REQUEST); - assert(!backend->handler); // TODO allow multiple processes to wait on the same backend - backend->handler = process_current; + assert(!backend->user.handler); // TODO allow multiple processes to wait on the same backend + backend->user.handler = process_current; /* checking the validity of those pointers here would make * vfs_backend_accept simpler. TODO? */ process_current->awaited_req.buf = buf; process_current->awaited_req.max_len = max_len; process_current->awaited_req.res = res; - return vfs_backend_accept(backend); + return vfs_backend_tryaccept(backend); } int _syscall_fs_respond(char __user *buf, int ret) { 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 #include #include +#include #include 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 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 #include -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 -// 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