diff --git a/kernel/include/process.h b/kernel/include/process.h index 7196b2cc..ab409aa4 100644 --- a/kernel/include/process.h +++ b/kernel/include/process.h @@ -29,6 +29,7 @@ #define VR_IO_NOCACHE 0x100 #define VR_REMOTE 0x200 #define VR_WRITE_COMBINED 0x400 +#define VR_DONTFORK 0x800 #define VR_DEMAND_PAGING 0x1000 #define VR_PRIVATE 0x2000 #define VR_LOCKED 0x4000 diff --git a/kernel/process.c b/kernel/process.c index 2e5570de..286e5544 100644 --- a/kernel/process.c +++ b/kernel/process.c @@ -571,6 +571,9 @@ static int copy_user_ranges(struct process_vm *vm, struct process_vm *orgvm) break; } + if(src_range->flag & VR_DONTFORK) + continue; + range = kmalloc(sizeof(struct vm_range), IHK_MC_AP_NOWAIT); if (!range) { goto err_rollback; diff --git a/kernel/syscall.c b/kernel/syscall.c index 864a6499..9ee92dec 100644 --- a/kernel/syscall.c +++ b/kernel/syscall.c @@ -3479,6 +3479,90 @@ SYSCALL_DECLARE(mincore) return 0; } /* sys_mincore() */ +static int +set_memory_range_flag(struct vm_range *range, unsigned long arg) +{ + range->flag |= arg; + return 0; +} + +static int +clear_memory_range_flag(struct vm_range *range, unsigned long arg) +{ + range->flag &= ~arg; + return 0; +} + +static int +change_attr_process_memory_range(struct process_vm *vm, + uintptr_t start, uintptr_t end, + int (*change_proc)(struct vm_range *, + unsigned long), + unsigned long arg) +{ + uintptr_t addr; + int error; + struct vm_range *range; + struct vm_range *prev; + struct vm_range *next; + int join_flag = 0; + + error = 0; + range = lookup_process_memory_range(vm, start, start + PAGE_SIZE); + if(!range){ + error = -ENOMEM; + goto out; + } + + prev = previous_process_memory_range(vm, range); + if(!prev) + prev = range; + for (addr = start; addr < end; addr = range->end) { + if (range->start < addr) { + if((error = split_process_memory_range(vm, range, addr, &range))) { + break; + } + } + if (end < range->end) { + if((error = split_process_memory_range(vm, range, end, NULL))) { + break; + } + } + + if(!(error = change_proc(range, arg))){ + break; + } + range = next_process_memory_range(vm, range); + } + if(error){ + next = next_process_memory_range(vm, range); + if(!next) + next = range; + } + else{ + next = range; + } + + while(prev != next){ + int wkerr; + + range = next_process_memory_range(vm, prev); + if(!range) + break; + wkerr = join_process_memory_range(vm, prev, range); + if(range == next) + join_flag = 1; + if (wkerr) { + if(join_flag) + break; + prev = range; + } + } + +out: + return error; +} + SYSCALL_DECLARE(madvise) { const uintptr_t start = (uintptr_t)ihk_mc_syscall_arg0(ctx); @@ -3587,6 +3671,7 @@ SYSCALL_DECLARE(madvise) goto out; } } + else if(advice == MADV_DONTFORK || advice == MADV_DOFORK); else if (!range->memobj || !memobj_has_pager(range->memobj)) { dkprintf("[%d]sys_madvise(%lx,%lx,%x):has not pager" "[%lx-%lx) %lx\n", @@ -3631,6 +3716,27 @@ SYSCALL_DECLARE(madvise) } } + if(advice == MADV_DONTFORK){ + error = change_attr_process_memory_range(thread->vm, start, end, + set_memory_range_flag, + VR_DONTFORK); + if(error){ + goto out; + } + } + if(advice == MADV_DOFORK){ + error = change_attr_process_memory_range(thread->vm, start, end, + clear_memory_range_flag, + VR_DONTFORK); + if(error){ + goto out; + } + } + if(advice == MADV_DONTFORK || + advice == MADV_DOFORK){ + error = syscall_generic_forwarding(__NR_madvise, ctx); + } + error = 0; out: ihk_mc_spinlock_unlock_noirq(&thread->vm->memory_range_lock);