From: Tulio A M Mendes Date: Tue, 26 May 2026 02:42:57 +0000 (-0300) Subject: vfs: add cwd check to umount to prevent filesystem in use X-Git-Url: https://projects.tadryanom.me/?a=commitdiff_plain;h=62a90ada9646dd30c3e306d66e5e7a48010ac302;p=AdrOS.git vfs: add cwd check to umount to prevent filesystem in use Added busy check in vfs_umount_nolock to reject unmount if any process has its current working directory (cwd) within the mount being unmounted. Implementation details: - Checks current_process->cwd first (process executing umount) - Iterates over ready_queue_head to check all other processes - Uses path_is_mountpoint_prefix to determine if cwd is within mount - Returns -EBUSY if any process has cwd in the mount - Note: root directory check not implemented (would require vfs_getpath or storing root as path in process struct) Also added test I20 (umount cwd) to fulltest.c: - Mounts tmpfs to /tmp/mnt_cwd - Changes cwd into the mount - Verifies umount fails with -EBUSY - Changes cwd back to / - Verifies umount succeeds Updated test harnesses (smoke_test.exp, test_battery.exp) to include the new test pattern. Test results: - Smoke test: 124/124 PASS - Zero regressions --- diff --git a/src/kernel/fs.c b/src/kernel/fs.c index 493d4679..658f94cd 100644 --- a/src/kernel/fs.c +++ b/src/kernel/fs.c @@ -180,11 +180,20 @@ int vfs_umount_nolock(const char* mountpoint) { } } - /* Busy check: reject if any process has cwd or root in this mount */ + /* 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); + return -EBUSY; + } + + /* Check all processes in ready queue */ struct process* p = ready_queue_head; while (p) { /* Check if cwd is within this mount */ @@ -192,10 +201,6 @@ int vfs_umount_nolock(const char* mountpoint) { spin_unlock_irqrestore(&sched_lock, sched_fl); return -EBUSY; } - /* Check if root is within this mount (if different from cwd) */ - /* Note: root is not stored as a path in current process struct, - * so we only check cwd for now. A full implementation would require - * storing root as a path or implementing vfs_getpath. */ p = p->rq_next; } spin_unlock_irqrestore(&sched_lock, sched_fl); diff --git a/tests/smoke_test.exp b/tests/smoke_test.exp index 07a7929b..9a65c38c 100755 --- a/tests/smoke_test.exp +++ b/tests/smoke_test.exp @@ -161,6 +161,7 @@ set tests { {"mount replace rejection" "\\[test\\] mount replace rejection OK"} {"ftruncate readonly" "\\[test\\] ftruncate readonly OK"} {"mountpoint validation" "\\[test\\] mountpoint validation OK"} + {"umount cwd" "\\[test\\] umount cwd OK"} {"sigqueue" "\\[test\\] sigqueue OK"} {"clone" "\\[test\\] clone OK"} {"inotify_init1" "\\[test\\] inotify_init1 OK"} diff --git a/tests/test_battery.exp b/tests/test_battery.exp index 272d9706..86a27002 100644 --- a/tests/test_battery.exp +++ b/tests/test_battery.exp @@ -268,6 +268,7 @@ set patterns { {"mount replace rejection" "\\[test\\] mount replace rejection OK"} {"ftruncate readonly" "\\[test\\] ftruncate readonly OK"} {"mountpoint validation" "\\[test\\] mountpoint validation OK"} + {"umount cwd" "\\[test\\] umount cwd OK"} {"sigqueue" "\\[test\\] sigqueue OK"} {"clone" "\\[test\\] clone OK"} {"inotify_init1" "\\[test\\] inotify_init1 OK"} diff --git a/user/cmds/fulltest/fulltest.c b/user/cmds/fulltest/fulltest.c index 2cf57723..1a84a615 100644 --- a/user/cmds/fulltest/fulltest.c +++ b/user/cmds/fulltest/fulltest.c @@ -5262,6 +5262,44 @@ void _start(void) { (uint32_t)(sizeof("[test] mountpoint validation OK\n") - 1)); } + // I20: umount with active cwd — should fail with -EBUSY + { + (void)sys_mkdir("/tmp/mnt_cwd"); + if (sys_mount("none", "/tmp/mnt_cwd", "tmpfs", 0) < 0) { + sys_write(1, "[test] umount cwd: mount failed\n", + (uint32_t)(sizeof("[test] umount cwd: mount failed\n") - 1)); + sys_exit(1); + } + /* Change cwd into the mount */ + if (sys_chdir("/tmp/mnt_cwd") < 0) { + sys_write(1, "[test] umount cwd: chdir failed\n", + (uint32_t)(sizeof("[test] umount cwd: chdir failed\n") - 1)); + sys_exit(1); + } + /* umount should fail because cwd is in the mount */ + int rc = sys_umount2("/tmp/mnt_cwd"); + if (rc >= 0) { + sys_write(1, "[test] umount cwd: should fail with -EBUSY\n", + (uint32_t)(sizeof("[test] umount cwd: should fail with -EBUSY\n") - 1)); + sys_exit(1); + } + /* Change cwd back to / */ + if (sys_chdir("/") < 0) { + sys_write(1, "[test] umount cwd: chdir back failed\n", + (uint32_t)(sizeof("[test] umount cwd: chdir back failed\n") - 1)); + sys_exit(1); + } + /* Now umount should succeed */ + if (sys_umount2("/tmp/mnt_cwd") < 0) { + sys_write(1, "[test] umount cwd: umount failed\n", + (uint32_t)(sizeof("[test] umount cwd: umount failed\n") - 1)); + sys_exit(1); + } + sys_write(1, "[test] umount cwd OK\n", + (uint32_t)(sizeof("[test] umount cwd OK\n") - 1)); + } + + // I13: clone — create a thread sharing address space { /* We use a simple clone with CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND