mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-30 03:27:44 -04:00
mmap: handle mlocked pages during map, remap, unmap
Originally by Nick Piggin <[email protected]> Remove mlocked pages from the LRU using "unevictable infrastructure" during mmap(), munmap(), mremap() and truncate(). Try to move back to normal LRU lists on munmap() when last mlocked mapping removed. Remove PageMlocked() status when page truncated from file. [[email protected]: cleanup] [[email protected]: fix double unlock_page()] [[email protected]: split LRU: munlock rework] [[email protected]: mlock: fix __mlock_vma_pages_range comment block] [[email protected]: remove bogus kerneldoc token] Signed-off-by: Nick Piggin <[email protected]> Signed-off-by: Lee Schermerhorn <[email protected]> Signed-off-by: Rik van Riel <[email protected]> Signed-off-by: KOSAKI Motohiro <[email protected]> Signed-off-by: KAMEZAWA Hiroyuki <[email protected]> Signed-off-by: Andrew Morton <[email protected]> Signed-off-by: Linus Torvalds <[email protected]>
This commit is contained in:
parent
8edb08caf6
commit
ba470de431
6 changed files with 180 additions and 160 deletions
71
mm/mmap.c
71
mm/mmap.c
|
|
@ -970,6 +970,7 @@ unsigned long do_mmap_pgoff(struct file * file, unsigned long addr,
|
|||
return -EPERM;
|
||||
vm_flags |= VM_LOCKED;
|
||||
}
|
||||
|
||||
/* mlock MCL_FUTURE? */
|
||||
if (vm_flags & VM_LOCKED) {
|
||||
unsigned long locked, lock_limit;
|
||||
|
|
@ -1137,10 +1138,12 @@ munmap_back:
|
|||
* The VM_SHARED test is necessary because shmem_zero_setup
|
||||
* will create the file object for a shared anonymous map below.
|
||||
*/
|
||||
if (!file && !(vm_flags & VM_SHARED) &&
|
||||
vma_merge(mm, prev, addr, addr + len, vm_flags,
|
||||
NULL, NULL, pgoff, NULL))
|
||||
goto out;
|
||||
if (!file && !(vm_flags & VM_SHARED)) {
|
||||
vma = vma_merge(mm, prev, addr, addr + len, vm_flags,
|
||||
NULL, NULL, pgoff, NULL);
|
||||
if (vma)
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Determine the object being mapped and call the appropriate
|
||||
|
|
@ -1222,10 +1225,14 @@ out:
|
|||
mm->total_vm += len >> PAGE_SHIFT;
|
||||
vm_stat_account(mm, vm_flags, file, len >> PAGE_SHIFT);
|
||||
if (vm_flags & VM_LOCKED) {
|
||||
mm->locked_vm += len >> PAGE_SHIFT;
|
||||
make_pages_present(addr, addr + len);
|
||||
}
|
||||
if ((flags & MAP_POPULATE) && !(flags & MAP_NONBLOCK))
|
||||
/*
|
||||
* makes pages present; downgrades, drops, reacquires mmap_sem
|
||||
*/
|
||||
long nr_pages = mlock_vma_pages_range(vma, addr, addr + len);
|
||||
if (nr_pages < 0)
|
||||
return nr_pages; /* vma gone! */
|
||||
mm->locked_vm += (len >> PAGE_SHIFT) - nr_pages;
|
||||
} else if ((flags & MAP_POPULATE) && !(flags & MAP_NONBLOCK))
|
||||
make_pages_present(addr, addr + len);
|
||||
return addr;
|
||||
|
||||
|
|
@ -1698,8 +1705,10 @@ find_extend_vma(struct mm_struct *mm, unsigned long addr)
|
|||
return vma;
|
||||
if (!prev || expand_stack(prev, addr))
|
||||
return NULL;
|
||||
if (prev->vm_flags & VM_LOCKED)
|
||||
make_pages_present(addr, prev->vm_end);
|
||||
if (prev->vm_flags & VM_LOCKED) {
|
||||
if (mlock_vma_pages_range(prev, addr, prev->vm_end) < 0)
|
||||
return NULL; /* vma gone! */
|
||||
}
|
||||
return prev;
|
||||
}
|
||||
#else
|
||||
|
|
@ -1725,8 +1734,10 @@ find_extend_vma(struct mm_struct * mm, unsigned long addr)
|
|||
start = vma->vm_start;
|
||||
if (expand_stack(vma, addr))
|
||||
return NULL;
|
||||
if (vma->vm_flags & VM_LOCKED)
|
||||
make_pages_present(addr, start);
|
||||
if (vma->vm_flags & VM_LOCKED) {
|
||||
if (mlock_vma_pages_range(vma, addr, start) < 0)
|
||||
return NULL; /* vma gone! */
|
||||
}
|
||||
return vma;
|
||||
}
|
||||
#endif
|
||||
|
|
@ -1745,8 +1756,6 @@ static void remove_vma_list(struct mm_struct *mm, struct vm_area_struct *vma)
|
|||
long nrpages = vma_pages(vma);
|
||||
|
||||
mm->total_vm -= nrpages;
|
||||
if (vma->vm_flags & VM_LOCKED)
|
||||
mm->locked_vm -= nrpages;
|
||||
vm_stat_account(mm, vma->vm_flags, vma->vm_file, -nrpages);
|
||||
vma = remove_vma(vma);
|
||||
} while (vma);
|
||||
|
|
@ -1911,6 +1920,20 @@ int do_munmap(struct mm_struct *mm, unsigned long start, size_t len)
|
|||
}
|
||||
vma = prev? prev->vm_next: mm->mmap;
|
||||
|
||||
/*
|
||||
* unlock any mlock()ed ranges before detaching vmas
|
||||
*/
|
||||
if (mm->locked_vm) {
|
||||
struct vm_area_struct *tmp = vma;
|
||||
while (tmp && tmp->vm_start < end) {
|
||||
if (tmp->vm_flags & VM_LOCKED) {
|
||||
mm->locked_vm -= vma_pages(tmp);
|
||||
munlock_vma_pages_all(tmp);
|
||||
}
|
||||
tmp = tmp->vm_next;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove the vma's, and unmap the actual pages
|
||||
*/
|
||||
|
|
@ -2023,8 +2046,9 @@ unsigned long do_brk(unsigned long addr, unsigned long len)
|
|||
return -ENOMEM;
|
||||
|
||||
/* Can we just expand an old private anonymous mapping? */
|
||||
if (vma_merge(mm, prev, addr, addr + len, flags,
|
||||
NULL, NULL, pgoff, NULL))
|
||||
vma = vma_merge(mm, prev, addr, addr + len, flags,
|
||||
NULL, NULL, pgoff, NULL);
|
||||
if (vma)
|
||||
goto out;
|
||||
|
||||
/*
|
||||
|
|
@ -2046,8 +2070,8 @@ unsigned long do_brk(unsigned long addr, unsigned long len)
|
|||
out:
|
||||
mm->total_vm += len >> PAGE_SHIFT;
|
||||
if (flags & VM_LOCKED) {
|
||||
mm->locked_vm += len >> PAGE_SHIFT;
|
||||
make_pages_present(addr, addr + len);
|
||||
if (!mlock_vma_pages_range(vma, addr, addr + len))
|
||||
mm->locked_vm += (len >> PAGE_SHIFT);
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
|
|
@ -2058,7 +2082,7 @@ EXPORT_SYMBOL(do_brk);
|
|||
void exit_mmap(struct mm_struct *mm)
|
||||
{
|
||||
struct mmu_gather *tlb;
|
||||
struct vm_area_struct *vma = mm->mmap;
|
||||
struct vm_area_struct *vma;
|
||||
unsigned long nr_accounted = 0;
|
||||
unsigned long end;
|
||||
|
||||
|
|
@ -2066,6 +2090,15 @@ void exit_mmap(struct mm_struct *mm)
|
|||
arch_exit_mmap(mm);
|
||||
mmu_notifier_release(mm);
|
||||
|
||||
if (mm->locked_vm) {
|
||||
vma = mm->mmap;
|
||||
while (vma) {
|
||||
if (vma->vm_flags & VM_LOCKED)
|
||||
munlock_vma_pages_all(vma);
|
||||
vma = vma->vm_next;
|
||||
}
|
||||
}
|
||||
vma = mm->mmap;
|
||||
lru_add_drain();
|
||||
flush_cache_mm(mm);
|
||||
tlb = tlb_gather_mmu(mm, 1);
|
||||
|
|
|
|||
Loading…
Reference in a new issue