aboutsummaryrefslogtreecommitdiffstats
path: root/mm
diff options
context:
space:
mode:
Diffstat (limited to 'mm')
-rw-r--r--mm/fremap.c22
1 files changed, 14 insertions, 8 deletions
diff --git a/mm/fremap.c b/mm/fremap.c
index a0aaf0e56800..2db886e31044 100644
--- a/mm/fremap.c
+++ b/mm/fremap.c
@@ -160,15 +160,11 @@ SYSCALL_DEFINE5(remap_file_pages, unsigned long, start, unsigned long, size,
160 /* 160 /*
161 * Make sure the vma is shared, that it supports prefaulting, 161 * Make sure the vma is shared, that it supports prefaulting,
162 * and that the remapped range is valid and fully within 162 * and that the remapped range is valid and fully within
163 * the single existing vma. vm_private_data is used as a 163 * the single existing vma.
164 * swapout cursor in a VM_NONLINEAR vma.
165 */ 164 */
166 if (!vma || !(vma->vm_flags & VM_SHARED)) 165 if (!vma || !(vma->vm_flags & VM_SHARED))
167 goto out; 166 goto out;
168 167
169 if (vma->vm_private_data && !(vma->vm_flags & VM_NONLINEAR))
170 goto out;
171
172 if (!vma->vm_ops || !vma->vm_ops->remap_pages) 168 if (!vma->vm_ops || !vma->vm_ops->remap_pages)
173 goto out; 169 goto out;
174 170
@@ -177,6 +173,13 @@ SYSCALL_DEFINE5(remap_file_pages, unsigned long, start, unsigned long, size,
177 173
178 /* Must set VM_NONLINEAR before any pages are populated. */ 174 /* Must set VM_NONLINEAR before any pages are populated. */
179 if (!(vma->vm_flags & VM_NONLINEAR)) { 175 if (!(vma->vm_flags & VM_NONLINEAR)) {
176 /*
177 * vm_private_data is used as a swapout cursor
178 * in a VM_NONLINEAR vma.
179 */
180 if (vma->vm_private_data)
181 goto out;
182
180 /* Don't need a nonlinear mapping, exit success */ 183 /* Don't need a nonlinear mapping, exit success */
181 if (pgoff == linear_page_index(vma, start)) { 184 if (pgoff == linear_page_index(vma, start)) {
182 err = 0; 185 err = 0;
@@ -184,6 +187,7 @@ SYSCALL_DEFINE5(remap_file_pages, unsigned long, start, unsigned long, size,
184 } 187 }
185 188
186 if (!has_write_lock) { 189 if (!has_write_lock) {
190get_write_lock:
187 up_read(&mm->mmap_sem); 191 up_read(&mm->mmap_sem);
188 down_write(&mm->mmap_sem); 192 down_write(&mm->mmap_sem);
189 has_write_lock = 1; 193 has_write_lock = 1;
@@ -199,7 +203,7 @@ SYSCALL_DEFINE5(remap_file_pages, unsigned long, start, unsigned long, size,
199 unsigned long addr; 203 unsigned long addr;
200 struct file *file = get_file(vma->vm_file); 204 struct file *file = get_file(vma->vm_file);
201 205
202 flags &= MAP_NONBLOCK; 206 flags = (flags & MAP_NONBLOCK) | MAP_POPULATE;
203 addr = mmap_region(file, start, size, 207 addr = mmap_region(file, start, size,
204 flags, vma->vm_flags, pgoff); 208 flags, vma->vm_flags, pgoff);
205 fput(file); 209 fput(file);
@@ -225,6 +229,8 @@ SYSCALL_DEFINE5(remap_file_pages, unsigned long, start, unsigned long, size,
225 * drop PG_Mlocked flag for over-mapped range 229 * drop PG_Mlocked flag for over-mapped range
226 */ 230 */
227 vm_flags_t saved_flags = vma->vm_flags; 231 vm_flags_t saved_flags = vma->vm_flags;
232 if (!has_write_lock)
233 goto get_write_lock;
228 munlock_vma_pages_range(vma, start, start + size); 234 munlock_vma_pages_range(vma, start, start + size);
229 vma->vm_flags = saved_flags; 235 vma->vm_flags = saved_flags;
230 } 236 }
@@ -232,13 +238,13 @@ SYSCALL_DEFINE5(remap_file_pages, unsigned long, start, unsigned long, size,
232 mmu_notifier_invalidate_range_start(mm, start, start + size); 238 mmu_notifier_invalidate_range_start(mm, start, start + size);
233 err = vma->vm_ops->remap_pages(vma, start, size, pgoff); 239 err = vma->vm_ops->remap_pages(vma, start, size, pgoff);
234 mmu_notifier_invalidate_range_end(mm, start, start + size); 240 mmu_notifier_invalidate_range_end(mm, start, start + size);
235 if (!err && !(flags & MAP_NONBLOCK)) { 241 if (!err) {
236 if (vma->vm_flags & VM_LOCKED) { 242 if (vma->vm_flags & VM_LOCKED) {
237 /* 243 /*
238 * might be mapping previously unmapped range of file 244 * might be mapping previously unmapped range of file
239 */ 245 */
240 mlock_vma_pages_range(vma, start, start + size); 246 mlock_vma_pages_range(vma, start, start + size);
241 } else { 247 } else if (!(flags & MAP_NONBLOCK)) {
242 if (unlikely(has_write_lock)) { 248 if (unlikely(has_write_lock)) {
243 downgrade_write(&mm->mmap_sem); 249 downgrade_write(&mm->mmap_sem);
244 has_write_lock = 0; 250 has_write_lock = 0;