diff options
Diffstat (limited to 'mm')
-rw-r--r-- | mm/memory.c | 2 | ||||
-rw-r--r-- | mm/mlock.c | 47 | ||||
-rw-r--r-- | mm/mmap.c | 48 | ||||
-rw-r--r-- | mm/page-writeback.c | 21 | ||||
-rw-r--r-- | mm/shmem.c | 2 | ||||
-rw-r--r-- | mm/slub.c | 2 |
6 files changed, 45 insertions, 77 deletions
diff --git a/mm/memory.c b/mm/memory.c index 22bfa7a47a0b..baa999e87cd2 100644 --- a/mm/memory.c +++ b/mm/memory.c | |||
@@ -1999,7 +1999,7 @@ gotten: | |||
1999 | * Don't let another task, with possibly unlocked vma, | 1999 | * Don't let another task, with possibly unlocked vma, |
2000 | * keep the mlocked page. | 2000 | * keep the mlocked page. |
2001 | */ | 2001 | */ |
2002 | if (vma->vm_flags & VM_LOCKED) { | 2002 | if ((vma->vm_flags & VM_LOCKED) && old_page) { |
2003 | lock_page(old_page); /* for LRU manipulation */ | 2003 | lock_page(old_page); /* for LRU manipulation */ |
2004 | clear_page_mlock(old_page); | 2004 | clear_page_mlock(old_page); |
2005 | unlock_page(old_page); | 2005 | unlock_page(old_page); |
diff --git a/mm/mlock.c b/mm/mlock.c index 2904a347e476..028ec482fdd4 100644 --- a/mm/mlock.c +++ b/mm/mlock.c | |||
@@ -294,14 +294,10 @@ static inline int __mlock_posix_error_return(long retval) | |||
294 | * | 294 | * |
295 | * return number of pages [> 0] to be removed from locked_vm on success | 295 | * return number of pages [> 0] to be removed from locked_vm on success |
296 | * of "special" vmas. | 296 | * of "special" vmas. |
297 | * | ||
298 | * return negative error if vma spanning @start-@range disappears while | ||
299 | * mmap semaphore is dropped. Unlikely? | ||
300 | */ | 297 | */ |
301 | long mlock_vma_pages_range(struct vm_area_struct *vma, | 298 | long mlock_vma_pages_range(struct vm_area_struct *vma, |
302 | unsigned long start, unsigned long end) | 299 | unsigned long start, unsigned long end) |
303 | { | 300 | { |
304 | struct mm_struct *mm = vma->vm_mm; | ||
305 | int nr_pages = (end - start) / PAGE_SIZE; | 301 | int nr_pages = (end - start) / PAGE_SIZE; |
306 | BUG_ON(!(vma->vm_flags & VM_LOCKED)); | 302 | BUG_ON(!(vma->vm_flags & VM_LOCKED)); |
307 | 303 | ||
@@ -314,20 +310,8 @@ long mlock_vma_pages_range(struct vm_area_struct *vma, | |||
314 | if (!((vma->vm_flags & (VM_DONTEXPAND | VM_RESERVED)) || | 310 | if (!((vma->vm_flags & (VM_DONTEXPAND | VM_RESERVED)) || |
315 | is_vm_hugetlb_page(vma) || | 311 | is_vm_hugetlb_page(vma) || |
316 | vma == get_gate_vma(current))) { | 312 | vma == get_gate_vma(current))) { |
317 | long error; | ||
318 | downgrade_write(&mm->mmap_sem); | ||
319 | |||
320 | error = __mlock_vma_pages_range(vma, start, end, 1); | ||
321 | 313 | ||
322 | up_read(&mm->mmap_sem); | 314 | return __mlock_vma_pages_range(vma, start, end, 1); |
323 | /* vma can change or disappear */ | ||
324 | down_write(&mm->mmap_sem); | ||
325 | vma = find_vma(mm, start); | ||
326 | /* non-NULL vma must contain @start, but need to check @end */ | ||
327 | if (!vma || end > vma->vm_end) | ||
328 | return -ENOMEM; | ||
329 | |||
330 | return 0; /* hide other errors from mmap(), et al */ | ||
331 | } | 315 | } |
332 | 316 | ||
333 | /* | 317 | /* |
@@ -438,41 +422,14 @@ success: | |||
438 | vma->vm_flags = newflags; | 422 | vma->vm_flags = newflags; |
439 | 423 | ||
440 | if (lock) { | 424 | if (lock) { |
441 | /* | ||
442 | * mmap_sem is currently held for write. Downgrade the write | ||
443 | * lock to a read lock so that other faults, mmap scans, ... | ||
444 | * while we fault in all pages. | ||
445 | */ | ||
446 | downgrade_write(&mm->mmap_sem); | ||
447 | |||
448 | ret = __mlock_vma_pages_range(vma, start, end, 1); | 425 | ret = __mlock_vma_pages_range(vma, start, end, 1); |
449 | 426 | ||
450 | /* | 427 | if (ret > 0) { |
451 | * Need to reacquire mmap sem in write mode, as our callers | ||
452 | * expect this. We have no support for atomically upgrading | ||
453 | * a sem to write, so we need to check for ranges while sem | ||
454 | * is unlocked. | ||
455 | */ | ||
456 | up_read(&mm->mmap_sem); | ||
457 | /* vma can change or disappear */ | ||
458 | down_write(&mm->mmap_sem); | ||
459 | *prev = find_vma(mm, start); | ||
460 | /* non-NULL *prev must contain @start, but need to check @end */ | ||
461 | if (!(*prev) || end > (*prev)->vm_end) | ||
462 | ret = -ENOMEM; | ||
463 | else if (ret > 0) { | ||
464 | mm->locked_vm -= ret; | 428 | mm->locked_vm -= ret; |
465 | ret = 0; | 429 | ret = 0; |
466 | } else | 430 | } else |
467 | ret = __mlock_posix_error_return(ret); /* translate if needed */ | 431 | ret = __mlock_posix_error_return(ret); /* translate if needed */ |
468 | } else { | 432 | } else { |
469 | /* | ||
470 | * TODO: for unlocking, pages will already be resident, so | ||
471 | * we don't need to wait for allocations/reclaim/pagein, ... | ||
472 | * However, unlocking a very large region can still take a | ||
473 | * while. Should we downgrade the semaphore for both lock | ||
474 | * AND unlock ? | ||
475 | */ | ||
476 | __mlock_vma_pages_range(vma, start, end, 0); | 433 | __mlock_vma_pages_range(vma, start, end, 0); |
477 | } | 434 | } |
478 | 435 | ||
@@ -1090,6 +1090,15 @@ int vma_wants_writenotify(struct vm_area_struct *vma) | |||
1090 | mapping_cap_account_dirty(vma->vm_file->f_mapping); | 1090 | mapping_cap_account_dirty(vma->vm_file->f_mapping); |
1091 | } | 1091 | } |
1092 | 1092 | ||
1093 | /* | ||
1094 | * We account for memory if it's a private writeable mapping, | ||
1095 | * and VM_NORESERVE wasn't set. | ||
1096 | */ | ||
1097 | static inline int accountable_mapping(unsigned int vm_flags) | ||
1098 | { | ||
1099 | return (vm_flags & (VM_NORESERVE | VM_SHARED | VM_WRITE)) == VM_WRITE; | ||
1100 | } | ||
1101 | |||
1093 | unsigned long mmap_region(struct file *file, unsigned long addr, | 1102 | unsigned long mmap_region(struct file *file, unsigned long addr, |
1094 | unsigned long len, unsigned long flags, | 1103 | unsigned long len, unsigned long flags, |
1095 | unsigned int vm_flags, unsigned long pgoff, | 1104 | unsigned int vm_flags, unsigned long pgoff, |
@@ -1117,23 +1126,24 @@ munmap_back: | |||
1117 | if (!may_expand_vm(mm, len >> PAGE_SHIFT)) | 1126 | if (!may_expand_vm(mm, len >> PAGE_SHIFT)) |
1118 | return -ENOMEM; | 1127 | return -ENOMEM; |
1119 | 1128 | ||
1120 | if (flags & MAP_NORESERVE) | 1129 | /* |
1130 | * Set 'VM_NORESERVE' if we should not account for the | ||
1131 | * memory use of this mapping. We only honor MAP_NORESERVE | ||
1132 | * if we're allowed to overcommit memory. | ||
1133 | */ | ||
1134 | if ((flags & MAP_NORESERVE) && sysctl_overcommit_memory != OVERCOMMIT_NEVER) | ||
1135 | vm_flags |= VM_NORESERVE; | ||
1136 | if (!accountable) | ||
1121 | vm_flags |= VM_NORESERVE; | 1137 | vm_flags |= VM_NORESERVE; |
1122 | 1138 | ||
1123 | if (accountable && (!(flags & MAP_NORESERVE) || | 1139 | /* |
1124 | sysctl_overcommit_memory == OVERCOMMIT_NEVER)) { | 1140 | * Private writable mapping: check memory availability |
1125 | if (vm_flags & VM_SHARED) { | 1141 | */ |
1126 | /* Check memory availability in shmem_file_setup? */ | 1142 | if (accountable_mapping(vm_flags)) { |
1127 | vm_flags |= VM_ACCOUNT; | 1143 | charged = len >> PAGE_SHIFT; |
1128 | } else if (vm_flags & VM_WRITE) { | 1144 | if (security_vm_enough_memory(charged)) |
1129 | /* | 1145 | return -ENOMEM; |
1130 | * Private writable mapping: check memory availability | 1146 | vm_flags |= VM_ACCOUNT; |
1131 | */ | ||
1132 | charged = len >> PAGE_SHIFT; | ||
1133 | if (security_vm_enough_memory(charged)) | ||
1134 | return -ENOMEM; | ||
1135 | vm_flags |= VM_ACCOUNT; | ||
1136 | } | ||
1137 | } | 1147 | } |
1138 | 1148 | ||
1139 | /* | 1149 | /* |
@@ -1184,14 +1194,6 @@ munmap_back: | |||
1184 | goto free_vma; | 1194 | goto free_vma; |
1185 | } | 1195 | } |
1186 | 1196 | ||
1187 | /* We set VM_ACCOUNT in a shared mapping's vm_flags, to inform | ||
1188 | * shmem_zero_setup (perhaps called through /dev/zero's ->mmap) | ||
1189 | * that memory reservation must be checked; but that reservation | ||
1190 | * belongs to shared memory object, not to vma: so now clear it. | ||
1191 | */ | ||
1192 | if ((vm_flags & (VM_SHARED|VM_ACCOUNT)) == (VM_SHARED|VM_ACCOUNT)) | ||
1193 | vma->vm_flags &= ~VM_ACCOUNT; | ||
1194 | |||
1195 | /* Can addr have changed?? | 1197 | /* Can addr have changed?? |
1196 | * | 1198 | * |
1197 | * Answer: Yes, several device drivers can do it in their | 1199 | * Answer: Yes, several device drivers can do it in their |
diff --git a/mm/page-writeback.c b/mm/page-writeback.c index b493db7841dc..dc32dae01e5f 100644 --- a/mm/page-writeback.c +++ b/mm/page-writeback.c | |||
@@ -1051,13 +1051,22 @@ continue_unlock: | |||
1051 | } | 1051 | } |
1052 | } | 1052 | } |
1053 | 1053 | ||
1054 | if (wbc->sync_mode == WB_SYNC_NONE) { | 1054 | if (nr_to_write > 0) |
1055 | wbc->nr_to_write--; | 1055 | nr_to_write--; |
1056 | if (wbc->nr_to_write <= 0) { | 1056 | else if (wbc->sync_mode == WB_SYNC_NONE) { |
1057 | done = 1; | 1057 | /* |
1058 | break; | 1058 | * We stop writing back only if we are not |
1059 | } | 1059 | * doing integrity sync. In case of integrity |
1060 | * sync we have to keep going because someone | ||
1061 | * may be concurrently dirtying pages, and we | ||
1062 | * might have synced a lot of newly appeared | ||
1063 | * dirty pages, but have not synced all of the | ||
1064 | * old dirty pages. | ||
1065 | */ | ||
1066 | done = 1; | ||
1067 | break; | ||
1060 | } | 1068 | } |
1069 | |||
1061 | if (wbc->nonblocking && bdi_write_congested(bdi)) { | 1070 | if (wbc->nonblocking && bdi_write_congested(bdi)) { |
1062 | wbc->encountered_congestion = 1; | 1071 | wbc->encountered_congestion = 1; |
1063 | done = 1; | 1072 | done = 1; |
diff --git a/mm/shmem.c b/mm/shmem.c index 5d0de96c9789..19d566ccdeea 100644 --- a/mm/shmem.c +++ b/mm/shmem.c | |||
@@ -2628,7 +2628,7 @@ struct file *shmem_file_setup(char *name, loff_t size, unsigned long flags) | |||
2628 | goto close_file; | 2628 | goto close_file; |
2629 | 2629 | ||
2630 | #ifdef CONFIG_SHMEM | 2630 | #ifdef CONFIG_SHMEM |
2631 | SHMEM_I(inode)->flags = flags & VM_ACCOUNT; | 2631 | SHMEM_I(inode)->flags = (flags & VM_NORESERVE) ? 0 : VM_ACCOUNT; |
2632 | #endif | 2632 | #endif |
2633 | d_instantiate(dentry, inode); | 2633 | d_instantiate(dentry, inode); |
2634 | inode->i_size = size; | 2634 | inode->i_size = size; |
@@ -1996,7 +1996,7 @@ static struct kmem_cache_cpu *alloc_kmem_cache_cpu(struct kmem_cache *s, | |||
1996 | static void free_kmem_cache_cpu(struct kmem_cache_cpu *c, int cpu) | 1996 | static void free_kmem_cache_cpu(struct kmem_cache_cpu *c, int cpu) |
1997 | { | 1997 | { |
1998 | if (c < per_cpu(kmem_cache_cpu, cpu) || | 1998 | if (c < per_cpu(kmem_cache_cpu, cpu) || |
1999 | c > per_cpu(kmem_cache_cpu, cpu) + NR_KMEM_CACHE_CPU) { | 1999 | c >= per_cpu(kmem_cache_cpu, cpu) + NR_KMEM_CACHE_CPU) { |
2000 | kfree(c); | 2000 | kfree(c); |
2001 | return; | 2001 | return; |
2002 | } | 2002 | } |