diff options
Diffstat (limited to 'mm/mmap.c')
-rw-r--r-- | mm/mmap.c | 85 |
1 files changed, 47 insertions, 38 deletions
@@ -42,6 +42,7 @@ | |||
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 | #include <linux/userfaultfd_k.h> |
45 | #include <linux/moduleparam.h> | ||
45 | 46 | ||
46 | #include <asm/uaccess.h> | 47 | #include <asm/uaccess.h> |
47 | #include <asm/cacheflush.h> | 48 | #include <asm/cacheflush.h> |
@@ -69,6 +70,8 @@ const int mmap_rnd_compat_bits_max = CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MAX; | |||
69 | int mmap_rnd_compat_bits __read_mostly = CONFIG_ARCH_MMAP_RND_COMPAT_BITS; | 70 | int mmap_rnd_compat_bits __read_mostly = CONFIG_ARCH_MMAP_RND_COMPAT_BITS; |
70 | #endif | 71 | #endif |
71 | 72 | ||
73 | static bool ignore_rlimit_data = true; | ||
74 | core_param(ignore_rlimit_data, ignore_rlimit_data, bool, 0644); | ||
72 | 75 | ||
73 | static void unmap_region(struct mm_struct *mm, | 76 | static void unmap_region(struct mm_struct *mm, |
74 | struct vm_area_struct *vma, struct vm_area_struct *prev, | 77 | struct vm_area_struct *vma, struct vm_area_struct *prev, |
@@ -387,8 +390,9 @@ static long vma_compute_subtree_gap(struct vm_area_struct *vma) | |||
387 | } | 390 | } |
388 | 391 | ||
389 | #ifdef CONFIG_DEBUG_VM_RB | 392 | #ifdef CONFIG_DEBUG_VM_RB |
390 | static int browse_rb(struct rb_root *root) | 393 | static int browse_rb(struct mm_struct *mm) |
391 | { | 394 | { |
395 | struct rb_root *root = &mm->mm_rb; | ||
392 | int i = 0, j, bug = 0; | 396 | int i = 0, j, bug = 0; |
393 | struct rb_node *nd, *pn = NULL; | 397 | struct rb_node *nd, *pn = NULL; |
394 | unsigned long prev = 0, pend = 0; | 398 | unsigned long prev = 0, pend = 0; |
@@ -411,12 +415,14 @@ static int browse_rb(struct rb_root *root) | |||
411 | vma->vm_start, vma->vm_end); | 415 | vma->vm_start, vma->vm_end); |
412 | bug = 1; | 416 | bug = 1; |
413 | } | 417 | } |
418 | spin_lock(&mm->page_table_lock); | ||
414 | if (vma->rb_subtree_gap != vma_compute_subtree_gap(vma)) { | 419 | if (vma->rb_subtree_gap != vma_compute_subtree_gap(vma)) { |
415 | pr_emerg("free gap %lx, correct %lx\n", | 420 | pr_emerg("free gap %lx, correct %lx\n", |
416 | vma->rb_subtree_gap, | 421 | vma->rb_subtree_gap, |
417 | vma_compute_subtree_gap(vma)); | 422 | vma_compute_subtree_gap(vma)); |
418 | bug = 1; | 423 | bug = 1; |
419 | } | 424 | } |
425 | spin_unlock(&mm->page_table_lock); | ||
420 | i++; | 426 | i++; |
421 | pn = nd; | 427 | pn = nd; |
422 | prev = vma->vm_start; | 428 | prev = vma->vm_start; |
@@ -453,12 +459,16 @@ static void validate_mm(struct mm_struct *mm) | |||
453 | struct vm_area_struct *vma = mm->mmap; | 459 | struct vm_area_struct *vma = mm->mmap; |
454 | 460 | ||
455 | while (vma) { | 461 | while (vma) { |
462 | struct anon_vma *anon_vma = vma->anon_vma; | ||
456 | struct anon_vma_chain *avc; | 463 | struct anon_vma_chain *avc; |
457 | 464 | ||
458 | vma_lock_anon_vma(vma); | 465 | if (anon_vma) { |
459 | list_for_each_entry(avc, &vma->anon_vma_chain, same_vma) | 466 | anon_vma_lock_read(anon_vma); |
460 | anon_vma_interval_tree_verify(avc); | 467 | list_for_each_entry(avc, &vma->anon_vma_chain, same_vma) |
461 | vma_unlock_anon_vma(vma); | 468 | anon_vma_interval_tree_verify(avc); |
469 | anon_vma_unlock_read(anon_vma); | ||
470 | } | ||
471 | |||
462 | highest_address = vma->vm_end; | 472 | highest_address = vma->vm_end; |
463 | vma = vma->vm_next; | 473 | vma = vma->vm_next; |
464 | i++; | 474 | i++; |
@@ -472,7 +482,7 @@ static void validate_mm(struct mm_struct *mm) | |||
472 | mm->highest_vm_end, highest_address); | 482 | mm->highest_vm_end, highest_address); |
473 | bug = 1; | 483 | bug = 1; |
474 | } | 484 | } |
475 | i = browse_rb(&mm->mm_rb); | 485 | i = browse_rb(mm); |
476 | if (i != mm->map_count) { | 486 | if (i != mm->map_count) { |
477 | if (i != -1) | 487 | if (i != -1) |
478 | pr_emerg("map_count %d rb %d\n", mm->map_count, i); | 488 | pr_emerg("map_count %d rb %d\n", mm->map_count, i); |
@@ -2139,32 +2149,27 @@ static int acct_stack_growth(struct vm_area_struct *vma, unsigned long size, uns | |||
2139 | int expand_upwards(struct vm_area_struct *vma, unsigned long address) | 2149 | int expand_upwards(struct vm_area_struct *vma, unsigned long address) |
2140 | { | 2150 | { |
2141 | struct mm_struct *mm = vma->vm_mm; | 2151 | struct mm_struct *mm = vma->vm_mm; |
2142 | int error; | 2152 | int error = 0; |
2143 | 2153 | ||
2144 | if (!(vma->vm_flags & VM_GROWSUP)) | 2154 | if (!(vma->vm_flags & VM_GROWSUP)) |
2145 | return -EFAULT; | 2155 | return -EFAULT; |
2146 | 2156 | ||
2147 | /* | 2157 | /* Guard against wrapping around to address 0. */ |
2148 | * We must make sure the anon_vma is allocated | 2158 | if (address < PAGE_ALIGN(address+4)) |
2149 | * so that the anon_vma locking is not a noop. | 2159 | address = PAGE_ALIGN(address+4); |
2150 | */ | 2160 | else |
2161 | return -ENOMEM; | ||
2162 | |||
2163 | /* We must make sure the anon_vma is allocated. */ | ||
2151 | if (unlikely(anon_vma_prepare(vma))) | 2164 | if (unlikely(anon_vma_prepare(vma))) |
2152 | return -ENOMEM; | 2165 | return -ENOMEM; |
2153 | vma_lock_anon_vma(vma); | ||
2154 | 2166 | ||
2155 | /* | 2167 | /* |
2156 | * vma->vm_start/vm_end cannot change under us because the caller | 2168 | * vma->vm_start/vm_end cannot change under us because the caller |
2157 | * is required to hold the mmap_sem in read mode. We need the | 2169 | * is required to hold the mmap_sem in read mode. We need the |
2158 | * anon_vma lock to serialize against concurrent expand_stacks. | 2170 | * anon_vma lock to serialize against concurrent expand_stacks. |
2159 | * Also guard against wrapping around to address 0. | ||
2160 | */ | 2171 | */ |
2161 | if (address < PAGE_ALIGN(address+4)) | 2172 | anon_vma_lock_write(vma->anon_vma); |
2162 | address = PAGE_ALIGN(address+4); | ||
2163 | else { | ||
2164 | vma_unlock_anon_vma(vma); | ||
2165 | return -ENOMEM; | ||
2166 | } | ||
2167 | error = 0; | ||
2168 | 2173 | ||
2169 | /* Somebody else might have raced and expanded it already */ | 2174 | /* Somebody else might have raced and expanded it already */ |
2170 | if (address > vma->vm_end) { | 2175 | if (address > vma->vm_end) { |
@@ -2182,7 +2187,7 @@ int expand_upwards(struct vm_area_struct *vma, unsigned long address) | |||
2182 | * updates, but we only hold a shared mmap_sem | 2187 | * updates, but we only hold a shared mmap_sem |
2183 | * lock here, so we need to protect against | 2188 | * lock here, so we need to protect against |
2184 | * concurrent vma expansions. | 2189 | * concurrent vma expansions. |
2185 | * vma_lock_anon_vma() doesn't help here, as | 2190 | * anon_vma_lock_write() doesn't help here, as |
2186 | * we don't guarantee that all growable vmas | 2191 | * we don't guarantee that all growable vmas |
2187 | * in a mm share the same root anon vma. | 2192 | * in a mm share the same root anon vma. |
2188 | * So, we reuse mm->page_table_lock to guard | 2193 | * So, we reuse mm->page_table_lock to guard |
@@ -2205,7 +2210,7 @@ int expand_upwards(struct vm_area_struct *vma, unsigned long address) | |||
2205 | } | 2210 | } |
2206 | } | 2211 | } |
2207 | } | 2212 | } |
2208 | vma_unlock_anon_vma(vma); | 2213 | anon_vma_unlock_write(vma->anon_vma); |
2209 | khugepaged_enter_vma_merge(vma, vma->vm_flags); | 2214 | khugepaged_enter_vma_merge(vma, vma->vm_flags); |
2210 | validate_mm(mm); | 2215 | validate_mm(mm); |
2211 | return error; | 2216 | return error; |
@@ -2221,25 +2226,21 @@ int expand_downwards(struct vm_area_struct *vma, | |||
2221 | struct mm_struct *mm = vma->vm_mm; | 2226 | struct mm_struct *mm = vma->vm_mm; |
2222 | int error; | 2227 | int error; |
2223 | 2228 | ||
2224 | /* | ||
2225 | * We must make sure the anon_vma is allocated | ||
2226 | * so that the anon_vma locking is not a noop. | ||
2227 | */ | ||
2228 | if (unlikely(anon_vma_prepare(vma))) | ||
2229 | return -ENOMEM; | ||
2230 | |||
2231 | address &= PAGE_MASK; | 2229 | address &= PAGE_MASK; |
2232 | error = security_mmap_addr(address); | 2230 | error = security_mmap_addr(address); |
2233 | if (error) | 2231 | if (error) |
2234 | return error; | 2232 | return error; |
2235 | 2233 | ||
2236 | vma_lock_anon_vma(vma); | 2234 | /* We must make sure the anon_vma is allocated. */ |
2235 | if (unlikely(anon_vma_prepare(vma))) | ||
2236 | return -ENOMEM; | ||
2237 | 2237 | ||
2238 | /* | 2238 | /* |
2239 | * vma->vm_start/vm_end cannot change under us because the caller | 2239 | * vma->vm_start/vm_end cannot change under us because the caller |
2240 | * is required to hold the mmap_sem in read mode. We need the | 2240 | * is required to hold the mmap_sem in read mode. We need the |
2241 | * anon_vma lock to serialize against concurrent expand_stacks. | 2241 | * anon_vma lock to serialize against concurrent expand_stacks. |
2242 | */ | 2242 | */ |
2243 | anon_vma_lock_write(vma->anon_vma); | ||
2243 | 2244 | ||
2244 | /* Somebody else might have raced and expanded it already */ | 2245 | /* Somebody else might have raced and expanded it already */ |
2245 | if (address < vma->vm_start) { | 2246 | if (address < vma->vm_start) { |
@@ -2257,7 +2258,7 @@ int expand_downwards(struct vm_area_struct *vma, | |||
2257 | * updates, but we only hold a shared mmap_sem | 2258 | * updates, but we only hold a shared mmap_sem |
2258 | * lock here, so we need to protect against | 2259 | * lock here, so we need to protect against |
2259 | * concurrent vma expansions. | 2260 | * concurrent vma expansions. |
2260 | * vma_lock_anon_vma() doesn't help here, as | 2261 | * anon_vma_lock_write() doesn't help here, as |
2261 | * we don't guarantee that all growable vmas | 2262 | * we don't guarantee that all growable vmas |
2262 | * in a mm share the same root anon vma. | 2263 | * in a mm share the same root anon vma. |
2263 | * So, we reuse mm->page_table_lock to guard | 2264 | * So, we reuse mm->page_table_lock to guard |
@@ -2278,7 +2279,7 @@ int expand_downwards(struct vm_area_struct *vma, | |||
2278 | } | 2279 | } |
2279 | } | 2280 | } |
2280 | } | 2281 | } |
2281 | vma_unlock_anon_vma(vma); | 2282 | anon_vma_unlock_write(vma->anon_vma); |
2282 | khugepaged_enter_vma_merge(vma, vma->vm_flags); | 2283 | khugepaged_enter_vma_merge(vma, vma->vm_flags); |
2283 | validate_mm(mm); | 2284 | validate_mm(mm); |
2284 | return error; | 2285 | return error; |
@@ -2982,9 +2983,17 @@ bool may_expand_vm(struct mm_struct *mm, vm_flags_t flags, unsigned long npages) | |||
2982 | if (mm->total_vm + npages > rlimit(RLIMIT_AS) >> PAGE_SHIFT) | 2983 | if (mm->total_vm + npages > rlimit(RLIMIT_AS) >> PAGE_SHIFT) |
2983 | return false; | 2984 | return false; |
2984 | 2985 | ||
2985 | if ((flags & (VM_WRITE | VM_SHARED | (VM_STACK_FLAGS & | 2986 | if (is_data_mapping(flags) && |
2986 | (VM_GROWSUP | VM_GROWSDOWN)))) == VM_WRITE) | 2987 | mm->data_vm + npages > rlimit(RLIMIT_DATA) >> PAGE_SHIFT) { |
2987 | return mm->data_vm + npages <= rlimit(RLIMIT_DATA); | 2988 | if (ignore_rlimit_data) |
2989 | pr_warn_once("%s (%d): VmData %lu exceed data ulimit " | ||
2990 | "%lu. Will be forbidden soon.\n", | ||
2991 | current->comm, current->pid, | ||
2992 | (mm->data_vm + npages) << PAGE_SHIFT, | ||
2993 | rlimit(RLIMIT_DATA)); | ||
2994 | else | ||
2995 | return false; | ||
2996 | } | ||
2988 | 2997 | ||
2989 | return true; | 2998 | return true; |
2990 | } | 2999 | } |
@@ -2993,11 +3002,11 @@ void vm_stat_account(struct mm_struct *mm, vm_flags_t flags, long npages) | |||
2993 | { | 3002 | { |
2994 | mm->total_vm += npages; | 3003 | mm->total_vm += npages; |
2995 | 3004 | ||
2996 | if ((flags & (VM_EXEC | VM_WRITE)) == VM_EXEC) | 3005 | if (is_exec_mapping(flags)) |
2997 | mm->exec_vm += npages; | 3006 | mm->exec_vm += npages; |
2998 | else if (flags & (VM_STACK_FLAGS & (VM_GROWSUP | VM_GROWSDOWN))) | 3007 | else if (is_stack_mapping(flags)) |
2999 | mm->stack_vm += npages; | 3008 | mm->stack_vm += npages; |
3000 | else if ((flags & (VM_WRITE | VM_SHARED)) == VM_WRITE) | 3009 | else if (is_data_mapping(flags)) |
3001 | mm->data_vm += npages; | 3010 | mm->data_vm += npages; |
3002 | } | 3011 | } |
3003 | 3012 | ||