From 8436f5a5ac3a65d7ec4a6de6245490ae0431618f Mon Sep 17 00:00:00 2001 From: NAKAMURA Gou Date: Tue, 11 Jun 2013 13:44:23 +0900 Subject: [PATCH] add remove_process_memory_range() --- kernel/include/process.h | 2 + kernel/process.c | 90 ++++++++++++++++++++++++++++++++++++++++ kernel/syscall.c | 8 +++- 3 files changed, 98 insertions(+), 2 deletions(-) diff --git a/kernel/include/process.h b/kernel/include/process.h index b3e0b44d..4d12eaa3 100644 --- a/kernel/include/process.h +++ b/kernel/include/process.h @@ -98,6 +98,8 @@ void free_process_memory(struct process *proc); int add_process_memory_range(struct process *process, unsigned long start, unsigned long end, unsigned long phys, unsigned long flag); +int remove_process_memory_range( + struct process *process, unsigned long start, unsigned long end); int remove_process_region(struct process *proc, unsigned long start, unsigned long end); struct program_load_desc; diff --git a/kernel/process.c b/kernel/process.c index 991f435c..55297e32 100644 --- a/kernel/process.c +++ b/kernel/process.c @@ -171,6 +171,96 @@ err: return -ENOMEM; } +int remove_process_memory_range(struct process *process, unsigned long start, unsigned long end) +{ + struct process_vm * const vm = process->vm; + struct vm_range *range; + struct vm_range *next; + int error; + unsigned long freestart; + unsigned long freephys; + unsigned long freesize; + struct vm_range *freerange; + struct vm_range *newrange; + + list_for_each_entry_safe(range, next, &vm->vm_range_list, list) { + if ((range->end <= start) || (end <= range->start)) { + /* no overlap */ + continue; + } + + error = 0; + freerange = NULL; + freesize = 0; + + if (start <= range->start) { + /* partial or whole delete from range->start */ + freestart = range->start; + freephys = range->phys; + freesize = end - range->start; + + if (freesize >= (range->end - range->start)) { + freesize = range->end - range->start; + list_del(&range->list); + freerange = range; + } + else { + range->start += freesize; + range->phys += freesize; + } + } + else if (range->end <= end) { + /* partial delete up to range->end */ + freestart = start; + freephys = range->phys + (start - range->start); + freesize = range->end - start; + + range->end = start; + } + else { + /* delete the middle part of the 'range' */ + freestart = start; + freephys = range->phys + (start - range->start); + freesize = end - start; + + newrange = kmalloc(sizeof(struct vm_range), IHK_MC_AP_NOWAIT); + if (!newrange) { + kprintf("remove_process_memory_range:kmalloc failed\n"); + return -ENOMEM; + } + INIT_LIST_HEAD(&range->list); + newrange->start = end; + newrange->end = range->end; + newrange->phys = range->phys + (end - range->start); + newrange->flag = range->flag; + list_add_tail(&newrange->list, &vm->vm_range_list); + + range->end = start; + } + + if (freesize > 0) { + error = remove_process_region(process, freestart, (freestart + freesize)); + if (error) { + kprintf("remove_process_memory_range:remove_process_region failed: %d\n", error); + /* through */ + } + + if (!(range->flag & (VR_REMOTE | VR_IO_NOCACHE | VR_RESERVED))) { + // XXX: need TLB shootdown? + ihk_mc_free_pages(phys_to_virt(freephys), freesize>>PAGE_SHIFT); + } + } + if (freerange != NULL) { + ihk_mc_free(freerange); + } + if (error) { + return error; + } + } + + return 0; +} + int add_process_memory_range(struct process *process, unsigned long start, unsigned long end, unsigned long phys, unsigned long flag) diff --git a/kernel/syscall.c b/kernel/syscall.c index ea1f2b5d..c8e620ac 100644 --- a/kernel/syscall.c +++ b/kernel/syscall.c @@ -506,12 +506,16 @@ SYSCALL_DECLARE(mmap) SYSCALL_DECLARE(munmap) { unsigned long address, len; + int error; address = ihk_mc_syscall_arg0(ctx); len = ihk_mc_syscall_arg1(ctx); - return remove_process_region(cpu_local_var(current), address, - address + len); + ihk_mc_spinlock_lock_noirq(&cpu_local_var(current)->vm->memory_range_lock); + error = remove_process_memory_range(cpu_local_var(current), address, address+len); + ihk_mc_spinlock_unlock_noirq(&cpu_local_var(current)->vm->memory_range_lock); + + return error; } SYSCALL_DECLARE(mprotect)