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); |
