summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/kernel/handle.c25
-rw-r--r--src/kernel/handle.h1
-rw-r--r--src/kernel/mem/alloc.c2
-rw-r--r--src/kernel/proc.c12
-rw-r--r--src/kernel/syscalls.c4
-rw-r--r--src/kernel/vfs/mount.c3
-rw-r--r--src/kernel/vfs/request.c17
-rw-r--r--src/kernel/vfs/request.h10
8 files changed, 60 insertions, 14 deletions
diff --git a/src/kernel/handle.c b/src/kernel/handle.c
index 91832a0..f5255c0 100644
--- a/src/kernel/handle.c
+++ b/src/kernel/handle.c
@@ -16,19 +16,22 @@ void handle_close(struct handle *h) {
assert(h->refcount > 0);
if (--(h->refcount) > 0) return;
- if (h->type == HANDLE_FILE) {
- vfs_request_create((struct vfs_request) {
- .type = VFSOP_CLOSE,
- .id = h->file.id,
- .caller = NULL,
- .backend = h->file.backend,
- });
+ switch (h->type) {
+ case HANDLE_FILE:
+ vfs_request_create((struct vfs_request) {
+ .type = VFSOP_CLOSE,
+ .id = h->file.id,
+ .caller = NULL,
+ .backend = h->file.backend,
+ });
+ vfs_backend_refdown(h->file.backend);
+ break;
+ case HANDLE_FS_FRONT:
+ vfs_backend_refdown(h->fs.backend);
+ break;
+ case HANDLE_INVALID: panic_invalid_state();
}
- // TODO handle close(HANDLE_FS_FRONT)
-
- // TODO count allocations and frees
-
// TODO sanity check to check if refcount is true. handle_sanity?
// TODO tests which would catch premature frees
diff --git a/src/kernel/handle.h b/src/kernel/handle.h
index df5ad36..3b75894 100644
--- a/src/kernel/handle.h
+++ b/src/kernel/handle.h
@@ -16,6 +16,7 @@ enum handle_type {
struct handle {
enum handle_type type;
union {
+ // TODO consolidate backend fields
struct {
struct vfs_backend *backend;
int id;
diff --git a/src/kernel/mem/alloc.c b/src/kernel/mem/alloc.c
index 0daf935..3925689 100644
--- a/src/kernel/mem/alloc.c
+++ b/src/kernel/mem/alloc.c
@@ -53,7 +53,7 @@ void mem_debugprint(void) {
kprintf("%08x %05x", iter, iter->page_amt);
for (size_t i = 0; i < 4; i++)
kprintf(" k/%08x", iter->stacktrace[i]);
- kprintf("\n");
+ kprintf("\n peek 0x%x\n", *(uint32_t*)(&iter[1]));
total++;
}
kprintf(" total 0x%x\n", total);
diff --git a/src/kernel/proc.c b/src/kernel/proc.c
index 90570b8..40399d8 100644
--- a/src/kernel/proc.c
+++ b/src/kernel/proc.c
@@ -63,8 +63,10 @@ struct process *process_fork(struct process *parent, int flags) {
parent->handled_req = NULL; // TODO control this with a flag
- if (child->controlled)
+ if (child->controlled) {
child->controlled->potential_handlers++;
+ child->controlled->refcount++;
+ }
for (handle_t h = 0; h < HANDLE_MAX; h++) {
if (child->handles[h])
@@ -111,6 +113,11 @@ void process_free(struct process *p) {
vfs_mount_remref(p->mount);
p->mount = NULL;
+ if (p->controlled) {
+ vfs_backend_refdown(p->controlled);
+ p->controlled = NULL;
+ }
+
if (!p->parent) return;
process_forget(p);
pagedir_free(p->pages); // TODO could be done on kill
@@ -273,11 +280,14 @@ void process_kill(struct process *p, int ret) {
vfs_request_cancel(q, ret);
q = q2;
}
+ p->controlled->queue = NULL;
}
if (p->controlled->handler == p) {
assert(p->state == PS_WAITS4REQUEST);
p->controlled->handler = NULL;
}
+
+ vfs_backend_refdown(p->controlled);
p->controlled = NULL;
}
diff --git a/src/kernel/syscalls.c b/src/kernel/syscalls.c
index 7748bc5..ca717ae 100644
--- a/src/kernel/syscalls.c
+++ b/src/kernel/syscalls.c
@@ -106,6 +106,7 @@ int _syscall_mount(handle_t hid, const char __user *path, int len) {
struct handle *handle = process_handle_get(process_current, hid, HANDLE_FS_FRONT);
if (!handle) goto fail;
backend = handle->fs.backend;
+ backend->refcount++;
} // otherwise backend == NULL
// append to mount list
@@ -177,15 +178,16 @@ handle_t _syscall_fs_fork2(void) {
front = process_find_handle(process_current, 1);
if (front < 0) return -1;
process_current->handles[front] = handle_init(HANDLE_FS_FRONT);
- process_current->handles[front]->type = HANDLE_FS_FRONT;
backend = kmalloc(sizeof *backend); // TODO never freed
backend->type = VFS_BACK_USER;
backend->potential_handlers = 1;
+ backend->refcount = 2; // child + handle
backend->handler = NULL;
backend->queue = NULL;
child = process_fork(process_current, 0);
+ if (child->controlled) vfs_backend_refdown(child->controlled);
child->controlled = backend;
regs_savereturn(&child->regs, 0);
diff --git a/src/kernel/vfs/mount.c b/src/kernel/vfs/mount.c
index 3fe192d..d13c3d6 100644
--- a/src/kernel/vfs/mount.c
+++ b/src/kernel/vfs/mount.c
@@ -8,6 +8,7 @@ struct vfs_mount *vfs_mount_seed(void) {
struct vfs_backend *backend = kmalloc(sizeof *backend);
backend->type = VFS_BACK_ROOT;
backend->potential_handlers = 1;
+ backend->refcount = 1;
*mount = (struct vfs_mount){
.prev = NULL,
.prefix = NULL,
@@ -45,6 +46,8 @@ void vfs_mount_remref(struct vfs_mount *mnt) {
if (--(mnt->refs) > 0) return;
struct vfs_mount *prev = mnt->prev;
+ if (mnt->backend)
+ vfs_backend_refdown(mnt->backend);
kfree(mnt->prefix);
kfree(mnt);
diff --git a/src/kernel/vfs/request.c b/src/kernel/vfs/request.c
index 1f3193f..edb1fce 100644
--- a/src/kernel/vfs/request.c
+++ b/src/kernel/vfs/request.c
@@ -11,6 +11,9 @@ int vfs_request_create(struct vfs_request req_) {
memcpy(req, &req_, sizeof *req);
/* freed in vfs_request_finish or vfs_request_cancel */
+ if (req->backend)
+ req->backend->refcount++;
+
if (req->caller) {
process_transition(req->caller, PS_WAITS4FS);
req->caller->waits4fs.req = req;
@@ -87,6 +90,7 @@ int vfs_request_finish(struct vfs_request *req, int ret) {
struct handle *backing = handle_init(HANDLE_FILE);
backing->file.backend = req->backend;
+ req->backend->refcount++;
backing->file.id = ret;
req->caller->handles[handle] = backing;
ret = handle;
@@ -101,11 +105,13 @@ int vfs_request_finish(struct vfs_request *req, int ret) {
process_transition(req->caller, PS_RUNNING);
}
+ vfs_backend_refdown(req->backend);
kfree(req);
return ret;
}
void vfs_request_cancel(struct vfs_request *req, int ret) {
+ // TODO merge with vfs_request_finish
if (req->caller) {
assert(req->caller->state == PS_WAITS4FS);
@@ -118,5 +124,16 @@ void vfs_request_cancel(struct vfs_request *req, int ret) {
regs_savereturn(&req->caller->regs, ret);
process_transition(req->caller, PS_RUNNING);
}
+
+ vfs_backend_refdown(req->backend);
kfree(req);
}
+
+void vfs_backend_refdown(struct vfs_backend *b) {
+ assert(b);
+ assert(b->refcount > 0);
+ if (--(b->refcount) > 0) return;
+
+ assert(!b->queue);
+ kfree(b);
+}
diff --git a/src/kernel/vfs/request.h b/src/kernel/vfs/request.h
index 657ae85..69dad07 100644
--- a/src/kernel/vfs/request.h
+++ b/src/kernel/vfs/request.h
@@ -11,6 +11,14 @@ enum vfs_backend_type {
// describes something which can act as an access function
struct vfs_backend {
+ size_t refcount;
+ /* references:
+ * struct vfs_mount
+ * struct vfs_request
+ * struct process
+ * struct handle
+ */
+
enum vfs_backend_type type;
size_t potential_handlers; // 0 - orphaned
@@ -52,3 +60,5 @@ int vfs_backend_accept(struct vfs_backend *);
int vfs_request_finish(struct vfs_request *, int ret);
void vfs_request_cancel(struct vfs_request *, int ret);
+
+void vfs_backend_refdown(struct vfs_backend *);