From 390aec5ca22e62d128e71d1dee312a2f0a82ab68 Mon Sep 17 00:00:00 2001 From: dzwdz Date: Fri, 19 Aug 2022 19:44:36 +0200 Subject: syscall/fs_wait: return a handle for each request --- src/kernel/handle.c | 2 ++ src/kernel/handle.h | 3 +++ src/kernel/proc.c | 9 --------- src/kernel/proc.h | 1 - src/kernel/syscalls.c | 43 +++++++++++++++++++++++-------------------- src/kernel/vfs/request.c | 9 +++++---- 6 files changed, 33 insertions(+), 34 deletions(-) (limited to 'src/kernel') diff --git a/src/kernel/handle.c b/src/kernel/handle.c index d95962c..b21ebdc 100644 --- a/src/kernel/handle.c +++ b/src/kernel/handle.c @@ -31,6 +31,8 @@ void handle_close(struct handle *h) { pipe_invalidate_end(h->pipe.sister); h->pipe.sister->pipe.sister = NULL; } + } else if (h->type == HANDLE_FS_REQ) { + if (h->req) vfsreq_finish_short(h->req, -1); } if (h->backend) diff --git a/src/kernel/handle.h b/src/kernel/handle.h index 54ef412..6b095e5 100644 --- a/src/kernel/handle.h +++ b/src/kernel/handle.h @@ -4,6 +4,7 @@ enum handle_type; // forward declaration for proc.h #include #include +#include #include enum handle_type { @@ -11,6 +12,7 @@ enum handle_type { HANDLE_FILE, HANDLE_PIPE, HANDLE_FS_FRONT, + HANDLE_FS_REQ, }; struct handle { @@ -18,6 +20,7 @@ struct handle { struct vfs_backend *backend; // HANDLE_FILE | HANDLE_FS_FRONT void __user *file_id; // only applicable to HANDLE_FILE bool ro; /* currently only for HANDLE_FILE */ + struct vfs_request *req; /* HANDLE_FS_REQ */ struct { struct process *queued; bool write_end; diff --git a/src/kernel/proc.c b/src/kernel/proc.c index ebd7cce..ed7180b 100644 --- a/src/kernel/proc.c +++ b/src/kernel/proc.c @@ -74,10 +74,6 @@ struct process *process_fork(struct process *parent, int flags) { child->id = next_pid++; - // TODO control this with a flag - child->handled_req = parent->handled_req; - parent->handled_req = NULL; - if ((flags & FORK_NEWFS) == 0 && parent->controlled) { child->controlled = parent->controlled; child->controlled->potential_handlers++; @@ -122,11 +118,6 @@ static bool unref(uint64_t *refcount) { void process_kill(struct process *p, int ret) { if (p->state != PS_DEAD) { - if (p->handled_req) { - vfsreq_finish_short(p->handled_req, -1); - p->handled_req = NULL; - } - if (p->controlled) { // TODO vfs_backend_user_handlerdown assert(p->controlled->potential_handlers > 0); diff --git a/src/kernel/proc.h b/src/kernel/proc.h index f445eab..780c8ee 100644 --- a/src/kernel/proc.h +++ b/src/kernel/proc.h @@ -59,7 +59,6 @@ struct process { /* vfs_backend controlled (not exclusively) by this process */ struct vfs_backend *controlled; - struct vfs_request *handled_req; struct { void *buf; diff --git a/src/kernel/syscalls.c b/src/kernel/syscalls.c index d6b23d0..33f56cd 100644 --- a/src/kernel/syscalls.c +++ b/src/kernel/syscalls.c @@ -259,7 +259,7 @@ long _syscall_close(handle_t hid) { SYSCALL_RETURN(0); } -long _syscall_fs_wait(char __user *buf, long max_len, struct fs_wait_response __user *res) { +handle_t _syscall_fs_wait(char __user *buf, long max_len, struct fs_wait_response __user *res) { struct vfs_backend *backend = process_current->controlled; // TODO can be used to tell if you're init if (!backend) SYSCALL_RETURN(-1); @@ -276,25 +276,28 @@ long _syscall_fs_wait(char __user *buf, long max_len, struct fs_wait_response __ return -1; // dummy } -long _syscall_fs_respond(void __user *buf, long ret, int flags) { - struct vfs_request *req = process_current->handled_req; - if (!req) SYSCALL_RETURN(-1); - - if (req->output.len > 0 && ret > 0) { - // if this vfsop outputs data and ret is positive, it's the length of the buffer - // TODO document - ret = min(ret, capped_cast32(req->output.len)); - struct virt_cpy_error err; - virt_cpy(req->caller->pages, req->output.buf, - process_current->pages, buf, ret, &err); - - if (err.read_fail) - panic_unimplemented(); - /* write failures are ignored */ +long _syscall_fs_respond(handle_t hid, void __user *buf, long ret, int flags) { + struct handle *h = process_handle_get(process_current, hid); + if (!h || h->type != HANDLE_FS_REQ) SYSCALL_RETURN(-EBADF); + struct vfs_request *req = h->req; + if (req) { + if (req->output.len > 0 && ret > 0) { + // if this vfsop outputs data and ret is positive, it's the length of the buffer + // TODO document + // TODO move to vfsreq_finish + ret = min(ret, capped_cast32(req->output.len)); + struct virt_cpy_error err; + virt_cpy(req->caller->pages, req->output.buf, + process_current->pages, buf, ret, &err); + + if (err.read_fail) + panic_unimplemented(); + /* write failures are ignored */ + } + vfsreq_finish(req, buf, ret, flags, process_current); } - - process_current->handled_req = NULL; - vfsreq_finish(req, buf, ret, flags, process_current); + h->req = NULL; + process_handle_close(process_current, hid); SYSCALL_RETURN(0); } @@ -400,7 +403,7 @@ long _syscall(long num, long a, long b, long c, long d, long e) { break; case _SYSCALL_REMOVE: _syscall_remove(a); break; case _SYSCALL_CLOSE: _syscall_close(a); break; case _SYSCALL_FS_WAIT: _syscall_fs_wait((userptr_t)a, b, (userptr_t)c); - break; case _SYSCALL_FS_RESPOND: _syscall_fs_respond((userptr_t)a, b, c); + break; case _SYSCALL_FS_RESPOND: _syscall_fs_respond(a, (userptr_t)b, c, d); break; case _SYSCALL_MEMFLAG: _syscall_memflag((userptr_t)a, b, c); break; case _SYSCALL_PIPE: _syscall_pipe((userptr_t)a, b); break; case _SYSCALL_SLEEP: _syscall_sleep(a); diff --git a/src/kernel/vfs/request.c b/src/kernel/vfs/request.c index a3be057..959b051 100644 --- a/src/kernel/vfs/request.c +++ b/src/kernel/vfs/request.c @@ -99,8 +99,6 @@ void vfs_backend_user_accept(struct vfs_request *req) { assert(req && req->backend && req->backend->user.handler); handler = req->backend->user.handler; assert(handler->state == PS_WAITS4REQUEST); - if (handler->handled_req) - panic_unimplemented(); // the virt_cpy calls aren't present in all kernel backends // it's a way to tell apart kernel and user backends apart @@ -134,10 +132,13 @@ void vfs_backend_user_accept(struct vfs_request *req) { panic_unimplemented(); } + struct handle *h; + handle_t hid = process_handle_init(handler, HANDLE_FS_REQ, &h); + if (hid < 0) panic_unimplemented(); + h->req = req; process_transition(handler, PS_RUNNING); - handler->handled_req = req; + regs_savereturn(&handler->regs, hid); req->backend->user.handler = NULL; - regs_savereturn(&handler->regs, 0); return; } -- cgit v1.2.3