summaryrefslogtreecommitdiff
path: root/src/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'src/kernel')
-rw-r--r--src/kernel/proc.c4
-rw-r--r--src/kernel/syscalls.c10
-rw-r--r--src/kernel/vfs/mount.c5
-rw-r--r--src/kernel/vfs/request.c61
-rw-r--r--src/kernel/vfs/request.h31
-rw-r--r--src/kernel/vfs/root.c13
-rw-r--r--src/kernel/vfs/root.h4
7 files changed, 78 insertions, 50 deletions
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 <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 *);