summaryrefslogtreecommitdiff
path: root/src/kernel
diff options
context:
space:
mode:
authordzwdz2022-08-19 19:44:36 +0200
committerdzwdz2022-08-19 19:44:36 +0200
commit390aec5ca22e62d128e71d1dee312a2f0a82ab68 (patch)
tree2a79bb1ee35dab3006a947f595891fbcfefa4bfb /src/kernel
parent6bea8cd391125734339dfb83db498a8651c9f7f7 (diff)
syscall/fs_wait: return a handle for each request
Diffstat (limited to 'src/kernel')
-rw-r--r--src/kernel/handle.c2
-rw-r--r--src/kernel/handle.h3
-rw-r--r--src/kernel/proc.c9
-rw-r--r--src/kernel/proc.h1
-rw-r--r--src/kernel/syscalls.c43
-rw-r--r--src/kernel/vfs/request.c9
6 files changed, 33 insertions, 34 deletions
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 <camellia/types.h>
#include <kernel/vfs/mount.h>
+#include <kernel/vfs/request.h>
#include <stddef.h>
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;
}