diff options
-rw-r--r-- | mm/fremap.c | 22 |
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) { |
190 | get_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; |