diff options
Diffstat (limited to 'mm')
-rw-r--r-- | mm/filemap_xip.c | 30 | ||||
-rw-r--r-- | mm/memory.c | 1 |
2 files changed, 29 insertions, 2 deletions
diff --git a/mm/filemap_xip.c b/mm/filemap_xip.c index c175f9f25210..59e1c5585748 100644 --- a/mm/filemap_xip.c +++ b/mm/filemap_xip.c | |||
@@ -256,8 +256,20 @@ again: | |||
256 | __xip_unmap(mapping, vmf->pgoff); | 256 | __xip_unmap(mapping, vmf->pgoff); |
257 | 257 | ||
258 | found: | 258 | found: |
259 | /* | ||
260 | * We must recheck i_size under i_mmap_rwsem to prevent races | ||
261 | * with truncation | ||
262 | */ | ||
263 | i_mmap_lock_read(mapping); | ||
264 | size = (i_size_read(inode) + PAGE_CACHE_SIZE - 1) >> | ||
265 | PAGE_CACHE_SHIFT; | ||
266 | if (unlikely(vmf->pgoff >= size)) { | ||
267 | i_mmap_unlock_read(mapping); | ||
268 | return VM_FAULT_SIGBUS; | ||
269 | } | ||
259 | err = vm_insert_mixed(vma, (unsigned long)vmf->virtual_address, | 270 | err = vm_insert_mixed(vma, (unsigned long)vmf->virtual_address, |
260 | xip_pfn); | 271 | xip_pfn); |
272 | i_mmap_unlock_read(mapping); | ||
261 | if (err == -ENOMEM) | 273 | if (err == -ENOMEM) |
262 | return VM_FAULT_OOM; | 274 | return VM_FAULT_OOM; |
263 | /* | 275 | /* |
@@ -281,16 +293,30 @@ found: | |||
281 | } | 293 | } |
282 | if (error != -ENODATA) | 294 | if (error != -ENODATA) |
283 | goto out; | 295 | goto out; |
296 | |||
297 | /* | ||
298 | * We must recheck i_size under i_mmap_rwsem to prevent races | ||
299 | * with truncation | ||
300 | */ | ||
301 | i_mmap_lock_read(mapping); | ||
302 | size = (i_size_read(inode) + PAGE_CACHE_SIZE - 1) >> | ||
303 | PAGE_CACHE_SHIFT; | ||
304 | if (unlikely(vmf->pgoff >= size)) { | ||
305 | ret = VM_FAULT_SIGBUS; | ||
306 | goto unlock; | ||
307 | } | ||
284 | /* not shared and writable, use xip_sparse_page() */ | 308 | /* not shared and writable, use xip_sparse_page() */ |
285 | page = xip_sparse_page(); | 309 | page = xip_sparse_page(); |
286 | if (!page) | 310 | if (!page) |
287 | goto out; | 311 | goto unlock; |
288 | err = vm_insert_page(vma, (unsigned long)vmf->virtual_address, | 312 | err = vm_insert_page(vma, (unsigned long)vmf->virtual_address, |
289 | page); | 313 | page); |
290 | if (err == -ENOMEM) | 314 | if (err == -ENOMEM) |
291 | goto out; | 315 | goto unlock; |
292 | 316 | ||
293 | ret = VM_FAULT_NOPAGE; | 317 | ret = VM_FAULT_NOPAGE; |
318 | unlock: | ||
319 | i_mmap_unlock_read(mapping); | ||
294 | out: | 320 | out: |
295 | write_seqcount_end(&xip_sparse_seq); | 321 | write_seqcount_end(&xip_sparse_seq); |
296 | mutex_unlock(&xip_sparse_mutex); | 322 | mutex_unlock(&xip_sparse_mutex); |
diff --git a/mm/memory.c b/mm/memory.c index 99275325f303..1b04e13b9993 100644 --- a/mm/memory.c +++ b/mm/memory.c | |||
@@ -2329,6 +2329,7 @@ void unmap_mapping_range(struct address_space *mapping, | |||
2329 | details.last_index = ULONG_MAX; | 2329 | details.last_index = ULONG_MAX; |
2330 | 2330 | ||
2331 | 2331 | ||
2332 | /* DAX uses i_mmap_lock to serialise file truncate vs page fault */ | ||
2332 | i_mmap_lock_write(mapping); | 2333 | i_mmap_lock_write(mapping); |
2333 | if (unlikely(!RB_EMPTY_ROOT(&mapping->i_mmap))) | 2334 | if (unlikely(!RB_EMPTY_ROOT(&mapping->i_mmap))) |
2334 | unmap_mapping_range_tree(&mapping->i_mmap, &details); | 2335 | unmap_mapping_range_tree(&mapping->i_mmap, &details); |