diff options
Diffstat (limited to 'mm/mmap.c')
-rw-r--r-- | mm/mmap.c | 71 |
1 files changed, 52 insertions, 19 deletions
@@ -970,6 +970,7 @@ unsigned long do_mmap_pgoff(struct file * file, unsigned long addr, | |||
970 | return -EPERM; | 970 | return -EPERM; |
971 | vm_flags |= VM_LOCKED; | 971 | vm_flags |= VM_LOCKED; |
972 | } | 972 | } |
973 | |||
973 | /* mlock MCL_FUTURE? */ | 974 | /* mlock MCL_FUTURE? */ |
974 | if (vm_flags & VM_LOCKED) { | 975 | if (vm_flags & VM_LOCKED) { |
975 | unsigned long locked, lock_limit; | 976 | unsigned long locked, lock_limit; |
@@ -1137,10 +1138,12 @@ munmap_back: | |||
1137 | * The VM_SHARED test is necessary because shmem_zero_setup | 1138 | * The VM_SHARED test is necessary because shmem_zero_setup |
1138 | * will create the file object for a shared anonymous map below. | 1139 | * will create the file object for a shared anonymous map below. |
1139 | */ | 1140 | */ |
1140 | if (!file && !(vm_flags & VM_SHARED) && | 1141 | if (!file && !(vm_flags & VM_SHARED)) { |
1141 | vma_merge(mm, prev, addr, addr + len, vm_flags, | 1142 | vma = vma_merge(mm, prev, addr, addr + len, vm_flags, |
1142 | NULL, NULL, pgoff, NULL)) | 1143 | NULL, NULL, pgoff, NULL); |
1143 | goto out; | 1144 | if (vma) |
1145 | goto out; | ||
1146 | } | ||
1144 | 1147 | ||
1145 | /* | 1148 | /* |
1146 | * Determine the object being mapped and call the appropriate | 1149 | * Determine the object being mapped and call the appropriate |
@@ -1222,10 +1225,14 @@ out: | |||
1222 | mm->total_vm += len >> PAGE_SHIFT; | 1225 | mm->total_vm += len >> PAGE_SHIFT; |
1223 | vm_stat_account(mm, vm_flags, file, len >> PAGE_SHIFT); | 1226 | vm_stat_account(mm, vm_flags, file, len >> PAGE_SHIFT); |
1224 | if (vm_flags & VM_LOCKED) { | 1227 | if (vm_flags & VM_LOCKED) { |
1225 | mm->locked_vm += len >> PAGE_SHIFT; | 1228 | /* |
1226 | make_pages_present(addr, addr + len); | 1229 | * makes pages present; downgrades, drops, reacquires mmap_sem |
1227 | } | 1230 | */ |
1228 | if ((flags & MAP_POPULATE) && !(flags & MAP_NONBLOCK)) | 1231 | long nr_pages = mlock_vma_pages_range(vma, addr, addr + len); |
1232 | if (nr_pages < 0) | ||
1233 | return nr_pages; /* vma gone! */ | ||
1234 | mm->locked_vm += (len >> PAGE_SHIFT) - nr_pages; | ||
1235 | } else if ((flags & MAP_POPULATE) && !(flags & MAP_NONBLOCK)) | ||
1229 | make_pages_present(addr, addr + len); | 1236 | make_pages_present(addr, addr + len); |
1230 | return addr; | 1237 | return addr; |
1231 | 1238 | ||
@@ -1698,8 +1705,10 @@ find_extend_vma(struct mm_struct *mm, unsigned long addr) | |||
1698 | return vma; | 1705 | return vma; |
1699 | if (!prev || expand_stack(prev, addr)) | 1706 | if (!prev || expand_stack(prev, addr)) |
1700 | return NULL; | 1707 | return NULL; |
1701 | if (prev->vm_flags & VM_LOCKED) | 1708 | if (prev->vm_flags & VM_LOCKED) { |
1702 | make_pages_present(addr, prev->vm_end); | 1709 | if (mlock_vma_pages_range(prev, addr, prev->vm_end) < 0) |
1710 | return NULL; /* vma gone! */ | ||
1711 | } | ||
1703 | return prev; | 1712 | return prev; |
1704 | } | 1713 | } |
1705 | #else | 1714 | #else |
@@ -1725,8 +1734,10 @@ find_extend_vma(struct mm_struct * mm, unsigned long addr) | |||
1725 | start = vma->vm_start; | 1734 | start = vma->vm_start; |
1726 | if (expand_stack(vma, addr)) | 1735 | if (expand_stack(vma, addr)) |
1727 | return NULL; | 1736 | return NULL; |
1728 | if (vma->vm_flags & VM_LOCKED) | 1737 | if (vma->vm_flags & VM_LOCKED) { |
1729 | make_pages_present(addr, start); | 1738 | if (mlock_vma_pages_range(vma, addr, start) < 0) |
1739 | return NULL; /* vma gone! */ | ||
1740 | } | ||
1730 | return vma; | 1741 | return vma; |
1731 | } | 1742 | } |
1732 | #endif | 1743 | #endif |
@@ -1745,8 +1756,6 @@ static void remove_vma_list(struct mm_struct *mm, struct vm_area_struct *vma) | |||
1745 | long nrpages = vma_pages(vma); | 1756 | long nrpages = vma_pages(vma); |
1746 | 1757 | ||
1747 | mm->total_vm -= nrpages; | 1758 | mm->total_vm -= nrpages; |
1748 | if (vma->vm_flags & VM_LOCKED) | ||
1749 | mm->locked_vm -= nrpages; | ||
1750 | vm_stat_account(mm, vma->vm_flags, vma->vm_file, -nrpages); | 1759 | vm_stat_account(mm, vma->vm_flags, vma->vm_file, -nrpages); |
1751 | vma = remove_vma(vma); | 1760 | vma = remove_vma(vma); |
1752 | } while (vma); | 1761 | } while (vma); |
@@ -1912,6 +1921,20 @@ int do_munmap(struct mm_struct *mm, unsigned long start, size_t len) | |||
1912 | vma = prev? prev->vm_next: mm->mmap; | 1921 | vma = prev? prev->vm_next: mm->mmap; |
1913 | 1922 | ||
1914 | /* | 1923 | /* |
1924 | * unlock any mlock()ed ranges before detaching vmas | ||
1925 | */ | ||
1926 | if (mm->locked_vm) { | ||
1927 | struct vm_area_struct *tmp = vma; | ||
1928 | while (tmp && tmp->vm_start < end) { | ||
1929 | if (tmp->vm_flags & VM_LOCKED) { | ||
1930 | mm->locked_vm -= vma_pages(tmp); | ||
1931 | munlock_vma_pages_all(tmp); | ||
1932 | } | ||
1933 | tmp = tmp->vm_next; | ||
1934 | } | ||
1935 | } | ||
1936 | |||
1937 | /* | ||
1915 | * Remove the vma's, and unmap the actual pages | 1938 | * Remove the vma's, and unmap the actual pages |
1916 | */ | 1939 | */ |
1917 | detach_vmas_to_be_unmapped(mm, vma, prev, end); | 1940 | detach_vmas_to_be_unmapped(mm, vma, prev, end); |
@@ -2023,8 +2046,9 @@ unsigned long do_brk(unsigned long addr, unsigned long len) | |||
2023 | return -ENOMEM; | 2046 | return -ENOMEM; |
2024 | 2047 | ||
2025 | /* Can we just expand an old private anonymous mapping? */ | 2048 | /* Can we just expand an old private anonymous mapping? */ |
2026 | if (vma_merge(mm, prev, addr, addr + len, flags, | 2049 | vma = vma_merge(mm, prev, addr, addr + len, flags, |
2027 | NULL, NULL, pgoff, NULL)) | 2050 | NULL, NULL, pgoff, NULL); |
2051 | if (vma) | ||
2028 | goto out; | 2052 | goto out; |
2029 | 2053 | ||
2030 | /* | 2054 | /* |
@@ -2046,8 +2070,8 @@ unsigned long do_brk(unsigned long addr, unsigned long len) | |||
2046 | out: | 2070 | out: |
2047 | mm->total_vm += len >> PAGE_SHIFT; | 2071 | mm->total_vm += len >> PAGE_SHIFT; |
2048 | if (flags & VM_LOCKED) { | 2072 | if (flags & VM_LOCKED) { |
2049 | mm->locked_vm += len >> PAGE_SHIFT; | 2073 | if (!mlock_vma_pages_range(vma, addr, addr + len)) |
2050 | make_pages_present(addr, addr + len); | 2074 | mm->locked_vm += (len >> PAGE_SHIFT); |
2051 | } | 2075 | } |
2052 | return addr; | 2076 | return addr; |
2053 | } | 2077 | } |
@@ -2058,7 +2082,7 @@ EXPORT_SYMBOL(do_brk); | |||
2058 | void exit_mmap(struct mm_struct *mm) | 2082 | void exit_mmap(struct mm_struct *mm) |
2059 | { | 2083 | { |
2060 | struct mmu_gather *tlb; | 2084 | struct mmu_gather *tlb; |
2061 | struct vm_area_struct *vma = mm->mmap; | 2085 | struct vm_area_struct *vma; |
2062 | unsigned long nr_accounted = 0; | 2086 | unsigned long nr_accounted = 0; |
2063 | unsigned long end; | 2087 | unsigned long end; |
2064 | 2088 | ||
@@ -2066,6 +2090,15 @@ void exit_mmap(struct mm_struct *mm) | |||
2066 | arch_exit_mmap(mm); | 2090 | arch_exit_mmap(mm); |
2067 | mmu_notifier_release(mm); | 2091 | mmu_notifier_release(mm); |
2068 | 2092 | ||
2093 | if (mm->locked_vm) { | ||
2094 | vma = mm->mmap; | ||
2095 | while (vma) { | ||
2096 | if (vma->vm_flags & VM_LOCKED) | ||
2097 | munlock_vma_pages_all(vma); | ||
2098 | vma = vma->vm_next; | ||
2099 | } | ||
2100 | } | ||
2101 | vma = mm->mmap; | ||
2069 | lru_add_drain(); | 2102 | lru_add_drain(); |
2070 | flush_cache_mm(mm); | 2103 | flush_cache_mm(mm); |
2071 | tlb = tlb_gather_mmu(mm, 1); | 2104 | tlb = tlb_gather_mmu(mm, 1); |