}
return 0;
}
+
+static void process_mount_ref_cwd(const struct process* proc) {
+ if (!proc) return;
+ extern void vfs_mount_ref_by_path(const char* path);
+ vfs_mount_ref_by_path(proc->cwd);
+}
+
+static void process_mount_unref_cwd(const struct process* proc) {
+ if (!proc) return;
+ extern void vfs_mount_unref_by_path(const char* path);
+ vfs_mount_unref_by_path(proc->cwd);
+}
+
+static void process_release_file_refs(struct process* proc) {
+ if (!proc) return;
+ for (int i = 0; i < PROCESS_MAX_FILES; i++) {
+ if (proc->files[i]) {
+ __sync_sub_and_fetch(&proc->files[i]->refcount, 1);
+ }
+ }
+}
#include "pmm.h"
#include "vmm.h"
#include "heap.h"
sleep_queue_remove(p);
alarm_queue_remove(p);
process_close_all_files_locked(p);
+ process_mount_unref_cwd(p);
p->exit_status = 128 + sig;
p->state = PROCESS_ZOMBIE;
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);
+ process_mount_unref_cwd(current_process);
uintptr_t flags = spin_lock_irqsave(&sched_lock);
} 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);
+
+ process_mount_ref_cwd(proc);
proc->has_user_regs = 1;
memcpy(proc->user_regs, child_regs, ARCH_REGS_SIZE);
if (!stack) {
/* Undo FD refcount bumps on failure */
if (current_process) {
- for (int i = 0; i < PROCESS_MAX_FILES; i++) {
- if (proc->files[i])
- __sync_sub_and_fetch(&proc->files[i]->refcount, 1);
- }
+ process_release_file_refs(proc);
}
+ process_mount_unref_cwd(proc);
kfree(proc);
spin_unlock_irqrestore(&sched_lock, flags);
return NULL;
if (!child_regs || !current_process) return NULL;
uintptr_t flags = spin_lock_irqsave(&sched_lock);
+ int added_parent_as_ref = 0;
struct process* proc = (struct process*)kmalloc(sizeof(*proc));
if (!proc) {
/* If this is the first thread, add the parent's own ref to the table */
if (current_process->as_refcount == 0) {
as_refcount_inc(proc->addr_space); /* parent's ref */
+ added_parent_as_ref = 1;
}
as_refcount_inc(proc->addr_space); /* child's ref */
current_process->as_refcount++;
/* CLONE_FS: share cwd */
strcpy(proc->cwd, current_process->cwd);
+ process_mount_ref_cwd(proc);
/* CLONE_FILES: share file descriptor table */
if (clone_flags & CLONE_FILES) {
/* Allocate kernel stack */
void* kstack = kstack_alloc();
if (!kstack) {
+ if (clone_flags & CLONE_FILES) {
+ process_release_file_refs(proc);
+ }
+ process_mount_unref_cwd(proc);
+ if (clone_flags & CLONE_VM) {
+ (void)as_refcount_dec(proc->addr_space);
+ if (current_process->as_refcount > 0) {
+ current_process->as_refcount--;
+ }
+ if (added_parent_as_ref) {
+ (void)as_refcount_dec(proc->addr_space);
+ }
+ }
if (!(clone_flags & CLONE_VM) && proc->addr_space) {
vmm_as_destroy(proc->addr_space);
}
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);
+
+ process_mount_ref_cwd(kernel_proc);
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);
+
+ process_mount_ref_cwd(idle);
for (int i = 0; i < PROCESS_MAX_MMAPS; i++)
idle->mmaps[i].shmid = -1;
idle->kernel_stack = (uint32_t*)kstack;
(uint32_t)(sizeof("[test] umount cwd OK\n") - 1));
}
+ {
+ struct timespec ts = {0, 10000000};
+
+ (void)sys_mkdir("/tmp/mnt_kill_cwd");
+ if (sys_mount("none", "/tmp/mnt_kill_cwd", "tmpfs", 0) < 0) {
+ sys_write(1, "[test] umount kill cwd: mount failed\n",
+ (uint32_t)(sizeof("[test] umount kill cwd: mount failed\n") - 1));
+ sys_exit(1);
+ }
+
+ int pid = sys_fork();
+ if (pid < 0) {
+ sys_write(1, "[test] umount kill cwd: fork failed\n",
+ (uint32_t)(sizeof("[test] umount kill cwd: fork failed\n") - 1));
+ sys_exit(1);
+ }
+
+ if (pid == 0) {
+ if (sys_chdir("/tmp/mnt_kill_cwd") < 0) {
+ sys_write(1, "[test] umount kill cwd: child chdir failed\n",
+ (uint32_t)(sizeof("[test] umount kill cwd: child chdir failed\n") - 1));
+ sys_exit(1);
+ }
+ for (;;) {
+ (void)sys_nanosleep(&ts, 0);
+ }
+ }
+
+ for (int i = 0; i < 5; i++) {
+ (void)sys_nanosleep(&ts, 0);
+ }
+
+ int rc = sys_umount2("/tmp/mnt_kill_cwd");
+ if (rc >= 0) {
+ sys_write(1, "[test] umount kill cwd: should fail with -EBUSY\n",
+ (uint32_t)(sizeof("[test] umount kill cwd: should fail with -EBUSY\n") - 1));
+ sys_exit(1);
+ }
+ if (sys_kill(pid, SIGKILL) < 0) {
+ sys_write(1, "[test] umount kill cwd: kill failed\n",
+ (uint32_t)(sizeof("[test] umount kill cwd: kill failed\n") - 1));
+ sys_exit(1);
+ }
+
+ int st = 0;
+ if (sys_waitpid(pid, &st, 0) != pid || st != (128 + SIGKILL)) {
+ sys_write(1, "[test] umount kill cwd: waitpid failed\n",
+ (uint32_t)(sizeof("[test] umount kill cwd: waitpid failed\n") - 1));
+ sys_exit(1);
+ }
+ if (sys_umount2("/tmp/mnt_kill_cwd") < 0) {
+ sys_write(1, "[test] umount kill cwd: umount failed\n",
+ (uint32_t)(sizeof("[test] umount kill cwd: umount failed\n") - 1));
+ sys_exit(1);
+ }
+
+ sys_write(1, "[test] umount kill cwd OK\n",
+ (uint32_t)(sizeof("[test] umount kill cwd OK\n") - 1));
+ }
+
// I13: clone — create a thread sharing address space
{