diff options
-rw-r--r-- | src/init/tests/main.c | 13 | ||||
-rw-r--r-- | src/kernel/proc.c | 19 | ||||
-rw-r--r-- | src/kernel/syscalls.c | 1 | ||||
-rw-r--r-- | src/kernel/vfs/mount.c | 1 | ||||
-rw-r--r-- | src/kernel/vfs/request.c | 16 | ||||
-rw-r--r-- | src/kernel/vfs/request.h | 4 |
6 files changed, 50 insertions, 4 deletions
diff --git a/src/init/tests/main.c b/src/init/tests/main.c index 34187fc..1c1e817 100644 --- a/src/init/tests/main.c +++ b/src/init/tests/main.c @@ -79,6 +79,18 @@ static void test_interrupted_fs(void) { } } +static void test_orphaned_fs(void) { + handle_t h = _syscall_fs_fork2(); + if (h) { + _syscall_mount(h, "/", 1); + int ret = _syscall_open("/", 1); + // no handler will ever be available to handle this call - the syscall should instantly return + _syscall_exit(ret < 0 ? 0 : -1); + } else { + _syscall_exit(0); + } +} + static void stress_fork(void) { /* run a lot of processes */ for (size_t i = 0; i < 2048; i++) { @@ -92,5 +104,6 @@ void test_all(void) { run_forked(test_await); run_forked(test_faults); run_forked(test_interrupted_fs); + run_forked(test_orphaned_fs); // run_forked(stress_fork); } diff --git a/src/kernel/proc.c b/src/kernel/proc.c index ad2a72b..9779478 100644 --- a/src/kernel/proc.c +++ b/src/kernel/proc.c @@ -54,6 +54,9 @@ struct process *process_fork(struct process *parent) { parent->handled_req = NULL; // TODO control this with a flag + if (child->controlled) + child->controlled->potential_handlers++; + child->id = next_pid++; return child; @@ -189,9 +192,21 @@ void process_transition(struct process *p, enum process_state state) { void process_kill(struct process *proc, int ret) { // TODO kill children + if (proc->controlled) { + proc->controlled->potential_handlers--; + if (proc->controlled->potential_handlers == 0) { + // orphaned + struct process *q = proc->controlled->queue; + while (q) { + assert(q->state == PS_WAITS4FS); + struct process *q2 = q->waits4fs.queue_next; + vfs_request_cancel(&q->waits4fs.req, ret); + q = q2; + } + } + } if (proc->handled_req) { - regs_savereturn(&proc->handled_req->caller->regs, -1); - process_transition(proc->handled_req->caller, PS_RUNNING); + vfs_request_cancel(proc->handled_req, ret); } process_transition(proc, PS_DEAD); proc->death_msg = ret; diff --git a/src/kernel/syscalls.c b/src/kernel/syscalls.c index 217fa77..31bd0de 100644 --- a/src/kernel/syscalls.c +++ b/src/kernel/syscalls.c @@ -189,6 +189,7 @@ handle_t _syscall_fs_fork2(void) { backend = kmalloc(sizeof *backend); // TODO never freed backend->type = VFS_BACK_USER; + backend->potential_handlers = 1; backend->handler = NULL; backend->queue = NULL; diff --git a/src/kernel/vfs/mount.c b/src/kernel/vfs/mount.c index c962ba5..423bf10 100644 --- a/src/kernel/vfs/mount.c +++ b/src/kernel/vfs/mount.c @@ -6,6 +6,7 @@ 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->potential_handlers = 1; *mount = (struct vfs_mount){ .prev = NULL, .prefix = "", diff --git a/src/kernel/vfs/request.c b/src/kernel/vfs/request.c index 687f456..277c353 100644 --- a/src/kernel/vfs/request.c +++ b/src/kernel/vfs/request.c @@ -14,7 +14,7 @@ int vfs_request_create(struct vfs_request req_) { process_current->waits4fs.req = req_; req = &process_current->waits4fs.req; - if (!req->backend) + if (!req->backend || !req->backend->potential_handlers) return vfs_request_finish(req, -1); switch (req->backend->type) { @@ -89,10 +89,22 @@ int vfs_request_finish(struct vfs_request *req, int ret) { ret = handle; } - if (req->input.kern) kfree(req->input.buf_kern); + if (req->input.kern) + kfree(req->input.buf_kern); assert(req->caller->state == PS_WAITS4FS || req->caller->state == PS_WAITS4IRQ); process_transition(req->caller, PS_RUNNING); regs_savereturn(&req->caller->regs, ret); return ret; } + +void vfs_request_cancel(struct vfs_request *req, int ret) { + if (req->input.kern) + kfree(req->input.buf_kern); + + // ret must always be negative, so it won't be confused with a success + if (ret > 0) ret = -ret; + if (ret == 0) ret = -1; + regs_savereturn(&req->caller->regs, ret); + process_transition(req->caller, PS_RUNNING); +} diff --git a/src/kernel/vfs/request.h b/src/kernel/vfs/request.h index ce5a7fb..1e3ef60 100644 --- a/src/kernel/vfs/request.h +++ b/src/kernel/vfs/request.h @@ -13,6 +13,8 @@ enum vfs_backend_type { struct vfs_backend { enum vfs_backend_type type; + size_t potential_handlers; // 0 - orphaned + // only used with VFS_BACK_USER struct process *handler; struct process *queue; @@ -45,3 +47,5 @@ struct vfs_request { int vfs_request_create(struct vfs_request); int vfs_request_accept(struct vfs_request *); int vfs_request_finish(struct vfs_request *, int ret); + +void vfs_request_cancel(struct vfs_request *, int ret); |