diff options
author | Andrea Arcangeli <aarcange@redhat.com> | 2015-09-04 18:46:24 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2015-09-04 19:54:41 -0400 |
commit | 19a809afe2fe089317226bbe5c5a1ce7f53dcdca (patch) | |
tree | 578abd63bf6a68dce4d7e20be1641e0111890914 /mm | |
parent | 6b251fc96cf2cdf1ce4b5db055547e2a5679bc77 (diff) |
userfaultfd: teach vma_merge to merge across vma->vm_userfaultfd_ctx
vma->vm_userfaultfd_ctx is yet another vma parameter that vma_merge
must be aware about so that we can merge vmas back like they were
originally before arming the userfaultfd on some memory range.
Signed-off-by: Andrea Arcangeli <aarcange@redhat.com>
Acked-by: Pavel Emelyanov <xemul@parallels.com>
Cc: Sanidhya Kashyap <sanidhya.gatech@gmail.com>
Cc: zhang.zhanghailiang@huawei.com
Cc: "Kirill A. Shutemov" <kirill@shutemov.name>
Cc: Andres Lagar-Cavilla <andreslc@google.com>
Cc: Dave Hansen <dave.hansen@intel.com>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: Rik van Riel <riel@redhat.com>
Cc: Mel Gorman <mgorman@suse.de>
Cc: Andy Lutomirski <luto@amacapital.net>
Cc: Hugh Dickins <hughd@google.com>
Cc: Peter Feiner <pfeiner@google.com>
Cc: "Dr. David Alan Gilbert" <dgilbert@redhat.com>
Cc: Johannes Weiner <hannes@cmpxchg.org>
Cc: "Huangpeng (Peter)" <peter.huangpeng@huawei.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'mm')
-rw-r--r-- | mm/madvise.c | 3 | ||||
-rw-r--r-- | mm/mempolicy.c | 4 | ||||
-rw-r--r-- | mm/mlock.c | 3 | ||||
-rw-r--r-- | mm/mmap.c | 40 | ||||
-rw-r--r-- | mm/mprotect.c | 3 |
5 files changed, 35 insertions, 18 deletions
diff --git a/mm/madvise.c b/mm/madvise.c index 64bb8a22110c..911357973905 100644 --- a/mm/madvise.c +++ b/mm/madvise.c | |||
@@ -103,7 +103,8 @@ static long madvise_behavior(struct vm_area_struct *vma, | |||
103 | 103 | ||
104 | pgoff = vma->vm_pgoff + ((start - vma->vm_start) >> PAGE_SHIFT); | 104 | pgoff = vma->vm_pgoff + ((start - vma->vm_start) >> PAGE_SHIFT); |
105 | *prev = vma_merge(mm, *prev, start, end, new_flags, vma->anon_vma, | 105 | *prev = vma_merge(mm, *prev, start, end, new_flags, vma->anon_vma, |
106 | vma->vm_file, pgoff, vma_policy(vma)); | 106 | vma->vm_file, pgoff, vma_policy(vma), |
107 | vma->vm_userfaultfd_ctx); | ||
107 | if (*prev) { | 108 | if (*prev) { |
108 | vma = *prev; | 109 | vma = *prev; |
109 | goto success; | 110 | goto success; |
diff --git a/mm/mempolicy.c b/mm/mempolicy.c index 99d4c1d0b858..a7f1e0d1d6b8 100644 --- a/mm/mempolicy.c +++ b/mm/mempolicy.c | |||
@@ -722,8 +722,8 @@ static int mbind_range(struct mm_struct *mm, unsigned long start, | |||
722 | pgoff = vma->vm_pgoff + | 722 | pgoff = vma->vm_pgoff + |
723 | ((vmstart - vma->vm_start) >> PAGE_SHIFT); | 723 | ((vmstart - vma->vm_start) >> PAGE_SHIFT); |
724 | prev = vma_merge(mm, prev, vmstart, vmend, vma->vm_flags, | 724 | prev = vma_merge(mm, prev, vmstart, vmend, vma->vm_flags, |
725 | vma->anon_vma, vma->vm_file, pgoff, | 725 | vma->anon_vma, vma->vm_file, pgoff, |
726 | new_pol); | 726 | new_pol, vma->vm_userfaultfd_ctx); |
727 | if (prev) { | 727 | if (prev) { |
728 | vma = prev; | 728 | vma = prev; |
729 | next = vma->vm_next; | 729 | next = vma->vm_next; |
diff --git a/mm/mlock.c b/mm/mlock.c index 6fd2cf15e868..25936680064f 100644 --- a/mm/mlock.c +++ b/mm/mlock.c | |||
@@ -510,7 +510,8 @@ static int mlock_fixup(struct vm_area_struct *vma, struct vm_area_struct **prev, | |||
510 | 510 | ||
511 | pgoff = vma->vm_pgoff + ((start - vma->vm_start) >> PAGE_SHIFT); | 511 | pgoff = vma->vm_pgoff + ((start - vma->vm_start) >> PAGE_SHIFT); |
512 | *prev = vma_merge(mm, *prev, start, end, newflags, vma->anon_vma, | 512 | *prev = vma_merge(mm, *prev, start, end, newflags, vma->anon_vma, |
513 | vma->vm_file, pgoff, vma_policy(vma)); | 513 | vma->vm_file, pgoff, vma_policy(vma), |
514 | vma->vm_userfaultfd_ctx); | ||
514 | if (*prev) { | 515 | if (*prev) { |
515 | vma = *prev; | 516 | vma = *prev; |
516 | goto success; | 517 | goto success; |
@@ -41,6 +41,7 @@ | |||
41 | #include <linux/notifier.h> | 41 | #include <linux/notifier.h> |
42 | #include <linux/memory.h> | 42 | #include <linux/memory.h> |
43 | #include <linux/printk.h> | 43 | #include <linux/printk.h> |
44 | #include <linux/userfaultfd_k.h> | ||
44 | 45 | ||
45 | #include <asm/uaccess.h> | 46 | #include <asm/uaccess.h> |
46 | #include <asm/cacheflush.h> | 47 | #include <asm/cacheflush.h> |
@@ -919,7 +920,8 @@ again: remove_next = 1 + (end > next->vm_end); | |||
919 | * per-vma resources, so we don't attempt to merge those. | 920 | * per-vma resources, so we don't attempt to merge those. |
920 | */ | 921 | */ |
921 | static inline int is_mergeable_vma(struct vm_area_struct *vma, | 922 | static inline int is_mergeable_vma(struct vm_area_struct *vma, |
922 | struct file *file, unsigned long vm_flags) | 923 | struct file *file, unsigned long vm_flags, |
924 | struct vm_userfaultfd_ctx vm_userfaultfd_ctx) | ||
923 | { | 925 | { |
924 | /* | 926 | /* |
925 | * VM_SOFTDIRTY should not prevent from VMA merging, if we | 927 | * VM_SOFTDIRTY should not prevent from VMA merging, if we |
@@ -935,6 +937,8 @@ static inline int is_mergeable_vma(struct vm_area_struct *vma, | |||
935 | return 0; | 937 | return 0; |
936 | if (vma->vm_ops && vma->vm_ops->close) | 938 | if (vma->vm_ops && vma->vm_ops->close) |
937 | return 0; | 939 | return 0; |
940 | if (!is_mergeable_vm_userfaultfd_ctx(vma, vm_userfaultfd_ctx)) | ||
941 | return 0; | ||
938 | return 1; | 942 | return 1; |
939 | } | 943 | } |
940 | 944 | ||
@@ -965,9 +969,11 @@ static inline int is_mergeable_anon_vma(struct anon_vma *anon_vma1, | |||
965 | */ | 969 | */ |
966 | static int | 970 | static int |
967 | can_vma_merge_before(struct vm_area_struct *vma, unsigned long vm_flags, | 971 | can_vma_merge_before(struct vm_area_struct *vma, unsigned long vm_flags, |
968 | struct anon_vma *anon_vma, struct file *file, pgoff_t vm_pgoff) | 972 | struct anon_vma *anon_vma, struct file *file, |
973 | pgoff_t vm_pgoff, | ||
974 | struct vm_userfaultfd_ctx vm_userfaultfd_ctx) | ||
969 | { | 975 | { |
970 | if (is_mergeable_vma(vma, file, vm_flags) && | 976 | if (is_mergeable_vma(vma, file, vm_flags, vm_userfaultfd_ctx) && |
971 | is_mergeable_anon_vma(anon_vma, vma->anon_vma, vma)) { | 977 | is_mergeable_anon_vma(anon_vma, vma->anon_vma, vma)) { |
972 | if (vma->vm_pgoff == vm_pgoff) | 978 | if (vma->vm_pgoff == vm_pgoff) |
973 | return 1; | 979 | return 1; |
@@ -984,9 +990,11 @@ can_vma_merge_before(struct vm_area_struct *vma, unsigned long vm_flags, | |||
984 | */ | 990 | */ |
985 | static int | 991 | static int |
986 | can_vma_merge_after(struct vm_area_struct *vma, unsigned long vm_flags, | 992 | can_vma_merge_after(struct vm_area_struct *vma, unsigned long vm_flags, |
987 | struct anon_vma *anon_vma, struct file *file, pgoff_t vm_pgoff) | 993 | struct anon_vma *anon_vma, struct file *file, |
994 | pgoff_t vm_pgoff, | ||
995 | struct vm_userfaultfd_ctx vm_userfaultfd_ctx) | ||
988 | { | 996 | { |
989 | if (is_mergeable_vma(vma, file, vm_flags) && | 997 | if (is_mergeable_vma(vma, file, vm_flags, vm_userfaultfd_ctx) && |
990 | is_mergeable_anon_vma(anon_vma, vma->anon_vma, vma)) { | 998 | is_mergeable_anon_vma(anon_vma, vma->anon_vma, vma)) { |
991 | pgoff_t vm_pglen; | 999 | pgoff_t vm_pglen; |
992 | vm_pglen = vma_pages(vma); | 1000 | vm_pglen = vma_pages(vma); |
@@ -1029,7 +1037,8 @@ struct vm_area_struct *vma_merge(struct mm_struct *mm, | |||
1029 | struct vm_area_struct *prev, unsigned long addr, | 1037 | struct vm_area_struct *prev, unsigned long addr, |
1030 | unsigned long end, unsigned long vm_flags, | 1038 | unsigned long end, unsigned long vm_flags, |
1031 | struct anon_vma *anon_vma, struct file *file, | 1039 | struct anon_vma *anon_vma, struct file *file, |
1032 | pgoff_t pgoff, struct mempolicy *policy) | 1040 | pgoff_t pgoff, struct mempolicy *policy, |
1041 | struct vm_userfaultfd_ctx vm_userfaultfd_ctx) | ||
1033 | { | 1042 | { |
1034 | pgoff_t pglen = (end - addr) >> PAGE_SHIFT; | 1043 | pgoff_t pglen = (end - addr) >> PAGE_SHIFT; |
1035 | struct vm_area_struct *area, *next; | 1044 | struct vm_area_struct *area, *next; |
@@ -1056,14 +1065,17 @@ struct vm_area_struct *vma_merge(struct mm_struct *mm, | |||
1056 | if (prev && prev->vm_end == addr && | 1065 | if (prev && prev->vm_end == addr && |
1057 | mpol_equal(vma_policy(prev), policy) && | 1066 | mpol_equal(vma_policy(prev), policy) && |
1058 | can_vma_merge_after(prev, vm_flags, | 1067 | can_vma_merge_after(prev, vm_flags, |
1059 | anon_vma, file, pgoff)) { | 1068 | anon_vma, file, pgoff, |
1069 | vm_userfaultfd_ctx)) { | ||
1060 | /* | 1070 | /* |
1061 | * OK, it can. Can we now merge in the successor as well? | 1071 | * OK, it can. Can we now merge in the successor as well? |
1062 | */ | 1072 | */ |
1063 | if (next && end == next->vm_start && | 1073 | if (next && end == next->vm_start && |
1064 | mpol_equal(policy, vma_policy(next)) && | 1074 | mpol_equal(policy, vma_policy(next)) && |
1065 | can_vma_merge_before(next, vm_flags, | 1075 | can_vma_merge_before(next, vm_flags, |
1066 | anon_vma, file, pgoff+pglen) && | 1076 | anon_vma, file, |
1077 | pgoff+pglen, | ||
1078 | vm_userfaultfd_ctx) && | ||
1067 | is_mergeable_anon_vma(prev->anon_vma, | 1079 | is_mergeable_anon_vma(prev->anon_vma, |
1068 | next->anon_vma, NULL)) { | 1080 | next->anon_vma, NULL)) { |
1069 | /* cases 1, 6 */ | 1081 | /* cases 1, 6 */ |
@@ -1084,7 +1096,8 @@ struct vm_area_struct *vma_merge(struct mm_struct *mm, | |||
1084 | if (next && end == next->vm_start && | 1096 | if (next && end == next->vm_start && |
1085 | mpol_equal(policy, vma_policy(next)) && | 1097 | mpol_equal(policy, vma_policy(next)) && |
1086 | can_vma_merge_before(next, vm_flags, | 1098 | can_vma_merge_before(next, vm_flags, |
1087 | anon_vma, file, pgoff+pglen)) { | 1099 | anon_vma, file, pgoff+pglen, |
1100 | vm_userfaultfd_ctx)) { | ||
1088 | if (prev && addr < prev->vm_end) /* case 4 */ | 1101 | if (prev && addr < prev->vm_end) /* case 4 */ |
1089 | err = vma_adjust(prev, prev->vm_start, | 1102 | err = vma_adjust(prev, prev->vm_start, |
1090 | addr, prev->vm_pgoff, NULL); | 1103 | addr, prev->vm_pgoff, NULL); |
@@ -1570,8 +1583,8 @@ unsigned long mmap_region(struct file *file, unsigned long addr, | |||
1570 | /* | 1583 | /* |
1571 | * Can we just expand an old mapping? | 1584 | * Can we just expand an old mapping? |
1572 | */ | 1585 | */ |
1573 | vma = vma_merge(mm, prev, addr, addr + len, vm_flags, NULL, file, pgoff, | 1586 | vma = vma_merge(mm, prev, addr, addr + len, vm_flags, |
1574 | NULL); | 1587 | NULL, file, pgoff, NULL, NULL_VM_UFFD_CTX); |
1575 | if (vma) | 1588 | if (vma) |
1576 | goto out; | 1589 | goto out; |
1577 | 1590 | ||
@@ -2757,7 +2770,7 @@ static unsigned long do_brk(unsigned long addr, unsigned long len) | |||
2757 | 2770 | ||
2758 | /* Can we just expand an old private anonymous mapping? */ | 2771 | /* Can we just expand an old private anonymous mapping? */ |
2759 | vma = vma_merge(mm, prev, addr, addr + len, flags, | 2772 | vma = vma_merge(mm, prev, addr, addr + len, flags, |
2760 | NULL, NULL, pgoff, NULL); | 2773 | NULL, NULL, pgoff, NULL, NULL_VM_UFFD_CTX); |
2761 | if (vma) | 2774 | if (vma) |
2762 | goto out; | 2775 | goto out; |
2763 | 2776 | ||
@@ -2913,7 +2926,8 @@ struct vm_area_struct *copy_vma(struct vm_area_struct **vmap, | |||
2913 | if (find_vma_links(mm, addr, addr + len, &prev, &rb_link, &rb_parent)) | 2926 | if (find_vma_links(mm, addr, addr + len, &prev, &rb_link, &rb_parent)) |
2914 | return NULL; /* should never get here */ | 2927 | return NULL; /* should never get here */ |
2915 | new_vma = vma_merge(mm, prev, addr, addr + len, vma->vm_flags, | 2928 | new_vma = vma_merge(mm, prev, addr, addr + len, vma->vm_flags, |
2916 | vma->anon_vma, vma->vm_file, pgoff, vma_policy(vma)); | 2929 | vma->anon_vma, vma->vm_file, pgoff, vma_policy(vma), |
2930 | vma->vm_userfaultfd_ctx); | ||
2917 | if (new_vma) { | 2931 | if (new_vma) { |
2918 | /* | 2932 | /* |
2919 | * Source vma may have been merged into new_vma | 2933 | * Source vma may have been merged into new_vma |
diff --git a/mm/mprotect.c b/mm/mprotect.c index e7d6f1171ecb..ef5be8eaab00 100644 --- a/mm/mprotect.c +++ b/mm/mprotect.c | |||
@@ -292,7 +292,8 @@ mprotect_fixup(struct vm_area_struct *vma, struct vm_area_struct **pprev, | |||
292 | */ | 292 | */ |
293 | pgoff = vma->vm_pgoff + ((start - vma->vm_start) >> PAGE_SHIFT); | 293 | pgoff = vma->vm_pgoff + ((start - vma->vm_start) >> PAGE_SHIFT); |
294 | *pprev = vma_merge(mm, *pprev, start, end, newflags, | 294 | *pprev = vma_merge(mm, *pprev, start, end, newflags, |
295 | vma->anon_vma, vma->vm_file, pgoff, vma_policy(vma)); | 295 | vma->anon_vma, vma->vm_file, pgoff, vma_policy(vma), |
296 | vma->vm_userfaultfd_ctx); | ||
296 | if (*pprev) { | 297 | if (*pprev) { |
297 | vma = *pprev; | 298 | vma = *pprev; |
298 | goto success; | 299 | goto success; |