diff --git a/kernel/include/memobj.h b/kernel/include/memobj.h index 34347c6f..63ce923f 100644 --- a/kernel/include/memobj.h +++ b/kernel/include/memobj.h @@ -31,6 +31,7 @@ enum { /* for memobj.flags */ MF_HAS_PAGER = 0x0001, MF_SHMDT_OK = 0x0002, + MF_IS_REMOVABLE = 0x0004, }; struct memobj { @@ -120,6 +121,11 @@ static inline int memobj_has_pager(struct memobj *obj) return !!(obj->flags & MF_HAS_PAGER); } +static inline int memobj_is_removable(struct memobj *obj) +{ + return !!(obj->flags & MF_IS_REMOVABLE); +} + int fileobj_create(int fd, struct memobj **objp, int *maxprotp); struct shmid_ds; int shmobj_create(struct shmid_ds *ds, struct memobj **objp); diff --git a/kernel/shmobj.c b/kernel/shmobj.c index b12338c5..1bd0ed9d 100644 --- a/kernel/shmobj.c +++ b/kernel/shmobj.c @@ -33,11 +33,13 @@ static ihk_spinlock_t shmobj_list_lock_body = SPIN_LOCK_UNLOCKED; static memobj_release_func_t shmobj_release; static memobj_ref_func_t shmobj_ref; static memobj_get_page_func_t shmobj_get_page; +static memobj_invalidate_page_func_t shmobj_invalidate_page; static struct memobj_ops shmobj_ops = { .release = &shmobj_release, .ref = &shmobj_ref, .get_page = &shmobj_get_page, + .invalidate_page = &shmobj_invalidate_page, }; static struct shmobj *to_shmobj(struct memobj *memobj) @@ -158,7 +160,7 @@ int shmobj_create_indexed(struct shmid_ds *ds, struct shmobj **objp) error = shmobj_create(ds, &obj); if (!error) { - obj->flags |= MF_SHMDT_OK; + obj->flags |= MF_SHMDT_OK | MF_IS_REMOVABLE; *objp = to_shmobj(obj); } return error; @@ -369,3 +371,30 @@ out: memobj, off, p2align, physp, error); return error; } + +static int shmobj_invalidate_page(struct memobj *memobj, uintptr_t phys, + size_t pgsize) +{ + struct shmobj *obj = to_shmobj(memobj); + int error; + struct page *page; + + dkprintf("shmobj_invalidate_page(%p,%#lx,%#lx)\n", memobj, phys, pgsize); + + if (!(page = phys_to_page(phys)) + || !(page = page_list_lookup(obj, page->offset))) { + error = 0; + goto out; + } + + if (ihk_atomic_read(&page->count) == 1) { + if (page_unmap(page)) { + ihk_mc_free_pages(phys_to_virt(phys), pgsize/PAGE_SIZE); + } + } + + error = 0; +out: + dkprintf("shmobj_invalidate_page(%p,%#lx,%#lx):%d\n", memobj, phys, pgsize, error); + return error; +} diff --git a/kernel/syscall.c b/kernel/syscall.c index 5b81fd08..b5912ba1 100644 --- a/kernel/syscall.c +++ b/kernel/syscall.c @@ -2691,6 +2691,8 @@ SYSCALL_DECLARE(madvise) uintptr_t addr; struct vm_range *range; int error; + uintptr_t s; + uintptr_t e; dkprintf("[%d]sys_madvise(%lx,%lx,%x)\n", ihk_mc_get_processor_id(), start, len0, advice); @@ -2732,10 +2734,7 @@ SYSCALL_DECLARE(madvise) case MADV_DONTNEED: case MADV_DONTFORK: case MADV_DOFORK: - break; - case MADV_REMOVE: - error = -EACCES; break; case MADV_HWPOISON: @@ -2777,7 +2776,17 @@ SYSCALL_DECLARE(madvise) goto out; } - if (!range->memobj || !memobj_has_pager(range->memobj)) { + if (advice == MADV_REMOVE) { + if (!range->memobj || !memobj_is_removable(range->memobj)) { + dkprintf("sys_madvise(%lx,%lx,%x):" + "not removable [%lx-%lx)\n", + start, len0, advice, + range->start, range->end); + error = -EACCES; + goto out; + } + } + else if (!range->memobj || !memobj_has_pager(range->memobj)) { dkprintf("[%d]sys_madvise(%lx,%lx,%x):has not pager" "[%lx-%lx) %lx\n", ihk_mc_get_processor_id(), start, @@ -2797,6 +2806,28 @@ SYSCALL_DECLARE(madvise) error = -EINVAL; goto out; } + + s = start; + if (s < range->start) { + s = range->start; + } + e = end; + if (range->end < e) { + e = range->end; + } + + if (advice == MADV_REMOVE) { + error = invalidate_process_memory_range( + thread->vm, range, s, e); + if (error) { + kprintf("sys_madvise(%lx,%lx,%x):[%lx-%lx):" + "invalidate failed. %d\n", + start, len0, advice, + range->start, range->end, + error); + goto out; + } + } } error = 0;