diff options
Diffstat (limited to 'mm/mmap.c')
-rw-r--r-- | mm/mmap.c | 46 |
1 files changed, 31 insertions, 15 deletions
@@ -176,7 +176,7 @@ static struct vm_area_struct *remove_vma(struct vm_area_struct *vma) | |||
176 | return next; | 176 | return next; |
177 | } | 177 | } |
178 | 178 | ||
179 | static int do_brk(unsigned long addr, unsigned long len); | 179 | static int do_brk(unsigned long addr, unsigned long len, struct list_head *uf); |
180 | 180 | ||
181 | SYSCALL_DEFINE1(brk, unsigned long, brk) | 181 | SYSCALL_DEFINE1(brk, unsigned long, brk) |
182 | { | 182 | { |
@@ -185,6 +185,7 @@ SYSCALL_DEFINE1(brk, unsigned long, brk) | |||
185 | struct mm_struct *mm = current->mm; | 185 | struct mm_struct *mm = current->mm; |
186 | unsigned long min_brk; | 186 | unsigned long min_brk; |
187 | bool populate; | 187 | bool populate; |
188 | LIST_HEAD(uf); | ||
188 | 189 | ||
189 | if (down_write_killable(&mm->mmap_sem)) | 190 | if (down_write_killable(&mm->mmap_sem)) |
190 | return -EINTR; | 191 | return -EINTR; |
@@ -222,7 +223,7 @@ SYSCALL_DEFINE1(brk, unsigned long, brk) | |||
222 | 223 | ||
223 | /* Always allow shrinking brk. */ | 224 | /* Always allow shrinking brk. */ |
224 | if (brk <= mm->brk) { | 225 | if (brk <= mm->brk) { |
225 | if (!do_munmap(mm, newbrk, oldbrk-newbrk)) | 226 | if (!do_munmap(mm, newbrk, oldbrk-newbrk, &uf)) |
226 | goto set_brk; | 227 | goto set_brk; |
227 | goto out; | 228 | goto out; |
228 | } | 229 | } |
@@ -232,13 +233,14 @@ SYSCALL_DEFINE1(brk, unsigned long, brk) | |||
232 | goto out; | 233 | goto out; |
233 | 234 | ||
234 | /* Ok, looks good - let it rip. */ | 235 | /* Ok, looks good - let it rip. */ |
235 | if (do_brk(oldbrk, newbrk-oldbrk) < 0) | 236 | if (do_brk(oldbrk, newbrk-oldbrk, &uf) < 0) |
236 | goto out; | 237 | goto out; |
237 | 238 | ||
238 | set_brk: | 239 | set_brk: |
239 | mm->brk = brk; | 240 | mm->brk = brk; |
240 | populate = newbrk > oldbrk && (mm->def_flags & VM_LOCKED) != 0; | 241 | populate = newbrk > oldbrk && (mm->def_flags & VM_LOCKED) != 0; |
241 | up_write(&mm->mmap_sem); | 242 | up_write(&mm->mmap_sem); |
243 | userfaultfd_unmap_complete(mm, &uf); | ||
242 | if (populate) | 244 | if (populate) |
243 | mm_populate(oldbrk, newbrk - oldbrk); | 245 | mm_populate(oldbrk, newbrk - oldbrk); |
244 | return brk; | 246 | return brk; |
@@ -1304,7 +1306,8 @@ static inline int mlock_future_check(struct mm_struct *mm, | |||
1304 | unsigned long do_mmap(struct file *file, unsigned long addr, | 1306 | unsigned long do_mmap(struct file *file, unsigned long addr, |
1305 | unsigned long len, unsigned long prot, | 1307 | unsigned long len, unsigned long prot, |
1306 | unsigned long flags, vm_flags_t vm_flags, | 1308 | unsigned long flags, vm_flags_t vm_flags, |
1307 | unsigned long pgoff, unsigned long *populate) | 1309 | unsigned long pgoff, unsigned long *populate, |
1310 | struct list_head *uf) | ||
1308 | { | 1311 | { |
1309 | struct mm_struct *mm = current->mm; | 1312 | struct mm_struct *mm = current->mm; |
1310 | int pkey = 0; | 1313 | int pkey = 0; |
@@ -1447,7 +1450,7 @@ unsigned long do_mmap(struct file *file, unsigned long addr, | |||
1447 | vm_flags |= VM_NORESERVE; | 1450 | vm_flags |= VM_NORESERVE; |
1448 | } | 1451 | } |
1449 | 1452 | ||
1450 | addr = mmap_region(file, addr, len, vm_flags, pgoff); | 1453 | addr = mmap_region(file, addr, len, vm_flags, pgoff, uf); |
1451 | if (!IS_ERR_VALUE(addr) && | 1454 | if (!IS_ERR_VALUE(addr) && |
1452 | ((vm_flags & VM_LOCKED) || | 1455 | ((vm_flags & VM_LOCKED) || |
1453 | (flags & (MAP_POPULATE | MAP_NONBLOCK)) == MAP_POPULATE)) | 1456 | (flags & (MAP_POPULATE | MAP_NONBLOCK)) == MAP_POPULATE)) |
@@ -1583,7 +1586,8 @@ static inline int accountable_mapping(struct file *file, vm_flags_t vm_flags) | |||
1583 | } | 1586 | } |
1584 | 1587 | ||
1585 | unsigned long mmap_region(struct file *file, unsigned long addr, | 1588 | unsigned long mmap_region(struct file *file, unsigned long addr, |
1586 | unsigned long len, vm_flags_t vm_flags, unsigned long pgoff) | 1589 | unsigned long len, vm_flags_t vm_flags, unsigned long pgoff, |
1590 | struct list_head *uf) | ||
1587 | { | 1591 | { |
1588 | struct mm_struct *mm = current->mm; | 1592 | struct mm_struct *mm = current->mm; |
1589 | struct vm_area_struct *vma, *prev; | 1593 | struct vm_area_struct *vma, *prev; |
@@ -1609,7 +1613,7 @@ unsigned long mmap_region(struct file *file, unsigned long addr, | |||
1609 | /* Clear old maps */ | 1613 | /* Clear old maps */ |
1610 | while (find_vma_links(mm, addr, addr + len, &prev, &rb_link, | 1614 | while (find_vma_links(mm, addr, addr + len, &prev, &rb_link, |
1611 | &rb_parent)) { | 1615 | &rb_parent)) { |
1612 | if (do_munmap(mm, addr, len)) | 1616 | if (do_munmap(mm, addr, len, uf)) |
1613 | return -ENOMEM; | 1617 | return -ENOMEM; |
1614 | } | 1618 | } |
1615 | 1619 | ||
@@ -2579,7 +2583,8 @@ int split_vma(struct mm_struct *mm, struct vm_area_struct *vma, | |||
2579 | * work. This now handles partial unmappings. | 2583 | * work. This now handles partial unmappings. |
2580 | * Jeremy Fitzhardinge <jeremy@goop.org> | 2584 | * Jeremy Fitzhardinge <jeremy@goop.org> |
2581 | */ | 2585 | */ |
2582 | int do_munmap(struct mm_struct *mm, unsigned long start, size_t len) | 2586 | int do_munmap(struct mm_struct *mm, unsigned long start, size_t len, |
2587 | struct list_head *uf) | ||
2583 | { | 2588 | { |
2584 | unsigned long end; | 2589 | unsigned long end; |
2585 | struct vm_area_struct *vma, *prev, *last; | 2590 | struct vm_area_struct *vma, *prev, *last; |
@@ -2603,6 +2608,13 @@ int do_munmap(struct mm_struct *mm, unsigned long start, size_t len) | |||
2603 | if (vma->vm_start >= end) | 2608 | if (vma->vm_start >= end) |
2604 | return 0; | 2609 | return 0; |
2605 | 2610 | ||
2611 | if (uf) { | ||
2612 | int error = userfaultfd_unmap_prep(vma, start, end, uf); | ||
2613 | |||
2614 | if (error) | ||
2615 | return error; | ||
2616 | } | ||
2617 | |||
2606 | /* | 2618 | /* |
2607 | * If we need to split any vma, do it now to save pain later. | 2619 | * If we need to split any vma, do it now to save pain later. |
2608 | * | 2620 | * |
@@ -2668,12 +2680,14 @@ int vm_munmap(unsigned long start, size_t len) | |||
2668 | { | 2680 | { |
2669 | int ret; | 2681 | int ret; |
2670 | struct mm_struct *mm = current->mm; | 2682 | struct mm_struct *mm = current->mm; |
2683 | LIST_HEAD(uf); | ||
2671 | 2684 | ||
2672 | if (down_write_killable(&mm->mmap_sem)) | 2685 | if (down_write_killable(&mm->mmap_sem)) |
2673 | return -EINTR; | 2686 | return -EINTR; |
2674 | 2687 | ||
2675 | ret = do_munmap(mm, start, len); | 2688 | ret = do_munmap(mm, start, len, &uf); |
2676 | up_write(&mm->mmap_sem); | 2689 | up_write(&mm->mmap_sem); |
2690 | userfaultfd_unmap_complete(mm, &uf); | ||
2677 | return ret; | 2691 | return ret; |
2678 | } | 2692 | } |
2679 | EXPORT_SYMBOL(vm_munmap); | 2693 | EXPORT_SYMBOL(vm_munmap); |
@@ -2773,7 +2787,7 @@ SYSCALL_DEFINE5(remap_file_pages, unsigned long, start, unsigned long, size, | |||
2773 | 2787 | ||
2774 | file = get_file(vma->vm_file); | 2788 | file = get_file(vma->vm_file); |
2775 | ret = do_mmap_pgoff(vma->vm_file, start, size, | 2789 | ret = do_mmap_pgoff(vma->vm_file, start, size, |
2776 | prot, flags, pgoff, &populate); | 2790 | prot, flags, pgoff, &populate, NULL); |
2777 | fput(file); | 2791 | fput(file); |
2778 | out: | 2792 | out: |
2779 | up_write(&mm->mmap_sem); | 2793 | up_write(&mm->mmap_sem); |
@@ -2799,7 +2813,7 @@ static inline void verify_mm_writelocked(struct mm_struct *mm) | |||
2799 | * anonymous maps. eventually we may be able to do some | 2813 | * anonymous maps. eventually we may be able to do some |
2800 | * brk-specific accounting here. | 2814 | * brk-specific accounting here. |
2801 | */ | 2815 | */ |
2802 | static int do_brk_flags(unsigned long addr, unsigned long request, unsigned long flags) | 2816 | static int do_brk_flags(unsigned long addr, unsigned long request, unsigned long flags, struct list_head *uf) |
2803 | { | 2817 | { |
2804 | struct mm_struct *mm = current->mm; | 2818 | struct mm_struct *mm = current->mm; |
2805 | struct vm_area_struct *vma, *prev; | 2819 | struct vm_area_struct *vma, *prev; |
@@ -2838,7 +2852,7 @@ static int do_brk_flags(unsigned long addr, unsigned long request, unsigned long | |||
2838 | */ | 2852 | */ |
2839 | while (find_vma_links(mm, addr, addr + len, &prev, &rb_link, | 2853 | while (find_vma_links(mm, addr, addr + len, &prev, &rb_link, |
2840 | &rb_parent)) { | 2854 | &rb_parent)) { |
2841 | if (do_munmap(mm, addr, len)) | 2855 | if (do_munmap(mm, addr, len, uf)) |
2842 | return -ENOMEM; | 2856 | return -ENOMEM; |
2843 | } | 2857 | } |
2844 | 2858 | ||
@@ -2885,9 +2899,9 @@ out: | |||
2885 | return 0; | 2899 | return 0; |
2886 | } | 2900 | } |
2887 | 2901 | ||
2888 | static int do_brk(unsigned long addr, unsigned long len) | 2902 | static int do_brk(unsigned long addr, unsigned long len, struct list_head *uf) |
2889 | { | 2903 | { |
2890 | return do_brk_flags(addr, len, 0); | 2904 | return do_brk_flags(addr, len, 0, uf); |
2891 | } | 2905 | } |
2892 | 2906 | ||
2893 | int vm_brk_flags(unsigned long addr, unsigned long len, unsigned long flags) | 2907 | 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) | |||
2895 | struct mm_struct *mm = current->mm; | 2909 | struct mm_struct *mm = current->mm; |
2896 | int ret; | 2910 | int ret; |
2897 | bool populate; | 2911 | bool populate; |
2912 | LIST_HEAD(uf); | ||
2898 | 2913 | ||
2899 | if (down_write_killable(&mm->mmap_sem)) | 2914 | if (down_write_killable(&mm->mmap_sem)) |
2900 | return -EINTR; | 2915 | return -EINTR; |
2901 | 2916 | ||
2902 | ret = do_brk_flags(addr, len, flags); | 2917 | ret = do_brk_flags(addr, len, flags, &uf); |
2903 | populate = ((mm->def_flags & VM_LOCKED) != 0); | 2918 | populate = ((mm->def_flags & VM_LOCKED) != 0); |
2904 | up_write(&mm->mmap_sem); | 2919 | up_write(&mm->mmap_sem); |
2920 | userfaultfd_unmap_complete(mm, &uf); | ||
2905 | if (populate && !ret) | 2921 | if (populate && !ret) |
2906 | mm_populate(addr, len); | 2922 | mm_populate(addr, len); |
2907 | return ret; | 2923 | return ret; |