summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/init/tests/main.c13
-rw-r--r--src/kernel/proc.c19
-rw-r--r--src/kernel/syscalls.c1
-rw-r--r--src/kernel/vfs/mount.c1
-rw-r--r--src/kernel/vfs/request.c16
-rw-r--r--src/kernel/vfs/request.h4
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);