void vfs_mount_ref(fs_node_t* mount_root);
void vfs_mount_unref(fs_node_t* mount_root);
+/* Increment/decrement mount refcount by path (called on cwd/root changes). */
+void vfs_mount_ref_by_path(const char* path);
+void vfs_mount_unref_by_path(const char* path);
+
/* Check if the filesystem containing the given path is writable.
* Returns 0 if writable, -EROFS if MS_RDONLY is set. */
int vfs_require_writable_path(const char* path);
}
}
- /* Busy check: reject if any process has cwd in this mount */
- extern struct process* ready_queue_head;
- extern struct process* current_process;
- extern spinlock_t sched_lock;
-
- uintptr_t sched_fl = spin_lock_irqsave(&sched_lock);
-
- /* Check current process first */
- if (current_process && current_process->cwd[0] && path_is_mountpoint_prefix(mp, current_process->cwd)) {
- spin_unlock_irqrestore(&sched_lock, sched_fl);
+ /* Busy check: reject if refcount > 0 (files open or cwd/root in mount) */
+ if (g_mounts[idx].refcount > 0)
return -EBUSY;
- }
-
- /* Check all processes in ready queue */
- struct process* p = ready_queue_head;
- while (p) {
- /* Check if cwd is within this mount */
- if (p->cwd[0] && path_is_mountpoint_prefix(mp, p->cwd)) {
- spin_unlock_irqrestore(&sched_lock, sched_fl);
- return -EBUSY;
- }
- p = p->rq_next;
- }
- spin_unlock_irqrestore(&sched_lock, sched_fl);
/* Release the block device */
if (g_mounts[idx].bdev) {
spin_unlock_irqrestore(&g_vfs_lock, fl);
}
+/* Increment the refcount on the mount that contains the given path. */
+void vfs_mount_ref_by_path(const char* path) {
+ if (!path || !path[0]) return;
+
+ uintptr_t fl = spin_lock_irqsave(&g_vfs_lock);
+ int best_idx = -1;
+ size_t best_len = 0;
+
+ /* Find the most specific mount (longest prefix match) */
+ for (int i = 0; i < g_mount_count; i++) {
+ if (path_is_mountpoint_prefix(g_mounts[i].mountpoint, path)) {
+ size_t len = strlen(g_mounts[i].mountpoint);
+ if (len > best_len) {
+ best_len = len;
+ best_idx = i;
+ }
+ }
+ }
+
+ if (best_idx >= 0) {
+ g_mounts[best_idx].refcount++;
+ }
+ spin_unlock_irqrestore(&g_vfs_lock, fl);
+}
+
+/* Decrement the refcount on the mount that contains the given path. */
+void vfs_mount_unref_by_path(const char* path) {
+ if (!path || !path[0]) return;
+
+ uintptr_t fl = spin_lock_irqsave(&g_vfs_lock);
+ int best_idx = -1;
+ size_t best_len = 0;
+
+ /* Find the most specific mount (longest prefix match) */
+ for (int i = 0; i < g_mount_count; i++) {
+ if (path_is_mountpoint_prefix(g_mounts[i].mountpoint, path)) {
+ size_t len = strlen(g_mounts[i].mountpoint);
+ if (len > best_len) {
+ best_len = len;
+ best_idx = i;
+ }
+ }
+ }
+
+ if (best_idx >= 0) {
+ if (g_mounts[best_idx].refcount > 0)
+ g_mounts[best_idx].refcount--;
+ }
+ spin_unlock_irqrestore(&g_vfs_lock, fl);
+}
+
/* Check if the filesystem containing the given path is writable.
* Returns 0 if writable, -EROFS if MS_RDONLY is set. */
int vfs_require_writable_path(const char* path) {
void process_exit_notify(int status) {
if (!current_process) return;
+ /* Decrement mount refcount for the exiting process's cwd */
+ extern void vfs_mount_unref_by_path(const char* path);
+ vfs_mount_unref_by_path(current_process->cwd);
+
uintptr_t flags = spin_lock_irqsave(&sched_lock);
current_process->exit_status = status;
} else {
strcpy(proc->cwd, "/");
}
+
+ /* Increment mount refcount for the new process's cwd */
+ extern void vfs_mount_ref_by_path(const char* path);
+ vfs_mount_ref_by_path(proc->cwd);
proc->has_user_regs = 1;
memcpy(proc->user_regs, child_regs, ARCH_REGS_SIZE);
kernel_proc->wait_result_status = 0;
strcpy(kernel_proc->cwd, "/");
+
+ /* Increment mount refcount for kernel process's cwd */
+ extern void vfs_mount_ref_by_path(const char* path);
+ vfs_mount_ref_by_path(kernel_proc->cwd);
for (int i = 0; i < PROCESS_MAX_FILES; i++) {
kernel_proc->files[i] = NULL;
idle->addr_space = kernel_as;
idle->cpu_id = cpu;
strcpy(idle->cwd, "/");
+
+ /* Increment mount refcount for idle process's cwd */
+ extern void vfs_mount_ref_by_path(const char* path);
+ vfs_mount_ref_by_path(idle->cwd);
for (int i = 0; i < PROCESS_MAX_MMAPS; i++)
idle->mmaps[i].shmid = -1;
idle->kernel_stack = (uint32_t*)kstack;