|
@@ -176,7 +176,7 @@ static struct vm_area_struct *remove_vma(struct vm_area_struct *vma)
|
|
|
return next;
|
|
|
}
|
|
|
|
|
|
-static int do_brk(unsigned long addr, unsigned long len);
|
|
|
+static int do_brk(unsigned long addr, unsigned long len, struct list_head *uf);
|
|
|
|
|
|
SYSCALL_DEFINE1(brk, unsigned long, brk)
|
|
|
{
|
|
@@ -185,6 +185,7 @@ SYSCALL_DEFINE1(brk, unsigned long, brk)
|
|
|
struct mm_struct *mm = current->mm;
|
|
|
unsigned long min_brk;
|
|
|
bool populate;
|
|
|
+ LIST_HEAD(uf);
|
|
|
|
|
|
if (down_write_killable(&mm->mmap_sem))
|
|
|
return -EINTR;
|
|
@@ -222,7 +223,7 @@ SYSCALL_DEFINE1(brk, unsigned long, brk)
|
|
|
|
|
|
/* Always allow shrinking brk. */
|
|
|
if (brk <= mm->brk) {
|
|
|
- if (!do_munmap(mm, newbrk, oldbrk-newbrk))
|
|
|
+ if (!do_munmap(mm, newbrk, oldbrk-newbrk, &uf))
|
|
|
goto set_brk;
|
|
|
goto out;
|
|
|
}
|
|
@@ -232,13 +233,14 @@ SYSCALL_DEFINE1(brk, unsigned long, brk)
|
|
|
goto out;
|
|
|
|
|
|
/* Ok, looks good - let it rip. */
|
|
|
- if (do_brk(oldbrk, newbrk-oldbrk) < 0)
|
|
|
+ if (do_brk(oldbrk, newbrk-oldbrk, &uf) < 0)
|
|
|
goto out;
|
|
|
|
|
|
set_brk:
|
|
|
mm->brk = brk;
|
|
|
populate = newbrk > oldbrk && (mm->def_flags & VM_LOCKED) != 0;
|
|
|
up_write(&mm->mmap_sem);
|
|
|
+ userfaultfd_unmap_complete(mm, &uf);
|
|
|
if (populate)
|
|
|
mm_populate(oldbrk, newbrk - oldbrk);
|
|
|
return brk;
|
|
@@ -1304,7 +1306,8 @@ static inline int mlock_future_check(struct mm_struct *mm,
|
|
|
unsigned long do_mmap(struct file *file, unsigned long addr,
|
|
|
unsigned long len, unsigned long prot,
|
|
|
unsigned long flags, vm_flags_t vm_flags,
|
|
|
- unsigned long pgoff, unsigned long *populate)
|
|
|
+ unsigned long pgoff, unsigned long *populate,
|
|
|
+ struct list_head *uf)
|
|
|
{
|
|
|
struct mm_struct *mm = current->mm;
|
|
|
int pkey = 0;
|
|
@@ -1447,7 +1450,7 @@ unsigned long do_mmap(struct file *file, unsigned long addr,
|
|
|
vm_flags |= VM_NORESERVE;
|
|
|
}
|
|
|
|
|
|
- addr = mmap_region(file, addr, len, vm_flags, pgoff);
|
|
|
+ addr = mmap_region(file, addr, len, vm_flags, pgoff, uf);
|
|
|
if (!IS_ERR_VALUE(addr) &&
|
|
|
((vm_flags & VM_LOCKED) ||
|
|
|
(flags & (MAP_POPULATE | MAP_NONBLOCK)) == MAP_POPULATE))
|
|
@@ -1583,7 +1586,8 @@ static inline int accountable_mapping(struct file *file, vm_flags_t vm_flags)
|
|
|
}
|
|
|
|
|
|
unsigned long mmap_region(struct file *file, unsigned long addr,
|
|
|
- unsigned long len, vm_flags_t vm_flags, unsigned long pgoff)
|
|
|
+ unsigned long len, vm_flags_t vm_flags, unsigned long pgoff,
|
|
|
+ struct list_head *uf)
|
|
|
{
|
|
|
struct mm_struct *mm = current->mm;
|
|
|
struct vm_area_struct *vma, *prev;
|
|
@@ -1609,7 +1613,7 @@ unsigned long mmap_region(struct file *file, unsigned long addr,
|
|
|
/* Clear old maps */
|
|
|
while (find_vma_links(mm, addr, addr + len, &prev, &rb_link,
|
|
|
&rb_parent)) {
|
|
|
- if (do_munmap(mm, addr, len))
|
|
|
+ if (do_munmap(mm, addr, len, uf))
|
|
|
return -ENOMEM;
|
|
|
}
|
|
|
|
|
@@ -2579,7 +2583,8 @@ int split_vma(struct mm_struct *mm, struct vm_area_struct *vma,
|
|
|
* work. This now handles partial unmappings.
|
|
|
* Jeremy Fitzhardinge <jeremy@goop.org>
|
|
|
*/
|
|
|
-int do_munmap(struct mm_struct *mm, unsigned long start, size_t len)
|
|
|
+int do_munmap(struct mm_struct *mm, unsigned long start, size_t len,
|
|
|
+ struct list_head *uf)
|
|
|
{
|
|
|
unsigned long end;
|
|
|
struct vm_area_struct *vma, *prev, *last;
|
|
@@ -2603,6 +2608,13 @@ int do_munmap(struct mm_struct *mm, unsigned long start, size_t len)
|
|
|
if (vma->vm_start >= end)
|
|
|
return 0;
|
|
|
|
|
|
+ if (uf) {
|
|
|
+ int error = userfaultfd_unmap_prep(vma, start, end, uf);
|
|
|
+
|
|
|
+ if (error)
|
|
|
+ return error;
|
|
|
+ }
|
|
|
+
|
|
|
/*
|
|
|
* If we need to split any vma, do it now to save pain later.
|
|
|
*
|
|
@@ -2668,12 +2680,14 @@ int vm_munmap(unsigned long start, size_t len)
|
|
|
{
|
|
|
int ret;
|
|
|
struct mm_struct *mm = current->mm;
|
|
|
+ LIST_HEAD(uf);
|
|
|
|
|
|
if (down_write_killable(&mm->mmap_sem))
|
|
|
return -EINTR;
|
|
|
|
|
|
- ret = do_munmap(mm, start, len);
|
|
|
+ ret = do_munmap(mm, start, len, &uf);
|
|
|
up_write(&mm->mmap_sem);
|
|
|
+ userfaultfd_unmap_complete(mm, &uf);
|
|
|
return ret;
|
|
|
}
|
|
|
EXPORT_SYMBOL(vm_munmap);
|
|
@@ -2773,7 +2787,7 @@ SYSCALL_DEFINE5(remap_file_pages, unsigned long, start, unsigned long, size,
|
|
|
|
|
|
file = get_file(vma->vm_file);
|
|
|
ret = do_mmap_pgoff(vma->vm_file, start, size,
|
|
|
- prot, flags, pgoff, &populate);
|
|
|
+ prot, flags, pgoff, &populate, NULL);
|
|
|
fput(file);
|
|
|
out:
|
|
|
up_write(&mm->mmap_sem);
|
|
@@ -2799,7 +2813,7 @@ static inline void verify_mm_writelocked(struct mm_struct *mm)
|
|
|
* anonymous maps. eventually we may be able to do some
|
|
|
* brk-specific accounting here.
|
|
|
*/
|
|
|
-static int do_brk_flags(unsigned long addr, unsigned long request, unsigned long flags)
|
|
|
+static int do_brk_flags(unsigned long addr, unsigned long request, unsigned long flags, struct list_head *uf)
|
|
|
{
|
|
|
struct mm_struct *mm = current->mm;
|
|
|
struct vm_area_struct *vma, *prev;
|
|
@@ -2838,7 +2852,7 @@ static int do_brk_flags(unsigned long addr, unsigned long request, unsigned long
|
|
|
*/
|
|
|
while (find_vma_links(mm, addr, addr + len, &prev, &rb_link,
|
|
|
&rb_parent)) {
|
|
|
- if (do_munmap(mm, addr, len))
|
|
|
+ if (do_munmap(mm, addr, len, uf))
|
|
|
return -ENOMEM;
|
|
|
}
|
|
|
|
|
@@ -2885,9 +2899,9 @@ out:
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-static int do_brk(unsigned long addr, unsigned long len)
|
|
|
+static int do_brk(unsigned long addr, unsigned long len, struct list_head *uf)
|
|
|
{
|
|
|
- return do_brk_flags(addr, len, 0);
|
|
|
+ return do_brk_flags(addr, len, 0, uf);
|
|
|
}
|
|
|
|
|
|
int vm_brk_flags(unsigned long addr, unsigned long len, unsigned long flags)
|
|
@@ -2895,13 +2909,15 @@ int vm_brk_flags(unsigned long addr, unsigned long len, unsigned long flags)
|
|
|
struct mm_struct *mm = current->mm;
|
|
|
int ret;
|
|
|
bool populate;
|
|
|
+ LIST_HEAD(uf);
|
|
|
|
|
|
if (down_write_killable(&mm->mmap_sem))
|
|
|
return -EINTR;
|
|
|
|
|
|
- ret = do_brk_flags(addr, len, flags);
|
|
|
+ ret = do_brk_flags(addr, len, flags, &uf);
|
|
|
populate = ((mm->def_flags & VM_LOCKED) != 0);
|
|
|
up_write(&mm->mmap_sem);
|
|
|
+ userfaultfd_unmap_complete(mm, &uf);
|
|
|
if (populate && !ret)
|
|
|
mm_populate(addr, len);
|
|
|
return ret;
|