summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authordzwdz2022-05-03 20:31:50 +0200
committerdzwdz2022-05-03 20:31:50 +0200
commit9692ed2f93777e1060837b97687509f8a22c2b60 (patch)
tree967dd6c85e7f07dbc9277bc0d2a534a49091de26 /src
parentbeb55e5fcaa5098943352bd07eb27cf8b00e336c (diff)
kernel: reference count mount objects, free them on process kills
Diffstat (limited to 'src')
-rw-r--r--src/kernel/proc.c7
-rw-r--r--src/kernel/syscalls.c7
-rw-r--r--src/kernel/vfs/mount.c16
-rw-r--r--src/kernel/vfs/mount.h6
4 files changed, 34 insertions, 2 deletions
diff --git a/src/kernel/proc.c b/src/kernel/proc.c
index ba19943..90570b8 100644
--- a/src/kernel/proc.c
+++ b/src/kernel/proc.c
@@ -72,6 +72,9 @@ struct process *process_fork(struct process *parent, int flags) {
// no overflow check - if you manage to get 2^32 references to a handle you have bigger problems
}
+ assert(child->mount);
+ child->mount->refs++;
+
child->id = next_pid++;
return child;
@@ -104,6 +107,10 @@ void process_free(struct process *p) {
while (p->child)
process_free(p->child);
+ // also could be done on kill
+ vfs_mount_remref(p->mount);
+ p->mount = NULL;
+
if (!p->parent) return;
process_forget(p);
pagedir_free(p->pages); // TODO could be done on kill
diff --git a/src/kernel/syscalls.c b/src/kernel/syscalls.c
index 57286f1..7748bc5 100644
--- a/src/kernel/syscalls.c
+++ b/src/kernel/syscalls.c
@@ -109,12 +109,17 @@ int _syscall_mount(handle_t hid, const char __user *path, int len) {
} // otherwise backend == NULL
// append to mount list
+ // TODO move to kernel/vfs/mount.c
mount = kmalloc(sizeof *mount);
mount->prev = process_current->mount;
- mount->prefix = path_buf;
+ mount->prefix = path_buf; // owned
mount->prefix_len = len;
mount->backend = backend;
+ mount->refs = 1;
process_current->mount = mount;
+
+ kmalloc_sanity(mount);
+ kmalloc_sanity(mount->prefix);
return 0;
fail:
diff --git a/src/kernel/vfs/mount.c b/src/kernel/vfs/mount.c
index 423bf10..3fe192d 100644
--- a/src/kernel/vfs/mount.c
+++ b/src/kernel/vfs/mount.c
@@ -1,4 +1,5 @@
#include <kernel/mem/alloc.h>
+#include <kernel/panic.h>
#include <kernel/vfs/mount.h>
#include <shared/mem.h>
@@ -9,9 +10,10 @@ struct vfs_mount *vfs_mount_seed(void) {
backend->potential_handlers = 1;
*mount = (struct vfs_mount){
.prev = NULL,
- .prefix = "",
+ .prefix = NULL,
.prefix_len = 0,
.backend = backend,
+ .refs = 1, // never to be freed
};
return mount;
}
@@ -36,3 +38,15 @@ struct vfs_mount *vfs_mount_resolve(
}
return top;
}
+
+void vfs_mount_remref(struct vfs_mount *mnt) {
+ assert(mnt);
+ assert(mnt->refs > 0);
+ if (--(mnt->refs) > 0) return;
+
+ struct vfs_mount *prev = mnt->prev;
+ kfree(mnt->prefix);
+ kfree(mnt);
+
+ if (prev) vfs_mount_remref(prev);
+}
diff --git a/src/kernel/vfs/mount.h b/src/kernel/vfs/mount.h
index 5fb6d16..96a2d7b 100644
--- a/src/kernel/vfs/mount.h
+++ b/src/kernel/vfs/mount.h
@@ -7,9 +7,15 @@ struct vfs_mount {
char *prefix;
size_t prefix_len;
struct vfs_backend *backend;
+ size_t refs; /* counts all references, atm from:
+ * - struct vfs_mount
+ * - struct proc
+ */
};
// prepares init's filesystem view
struct vfs_mount *vfs_mount_seed(void);
struct vfs_mount *vfs_mount_resolve(
struct vfs_mount *top, const char *path, size_t path_len);
+/** Decrements the reference count, potentially freeing the mount. */
+void vfs_mount_remref(struct vfs_mount *mnt);