diff options
| -rw-r--r-- | fs/dax.c | 71 | ||||
| -rw-r--r-- | include/linux/dax.h | 3 | ||||
| -rw-r--r-- | mm/truncate.c | 75 |
3 files changed, 125 insertions, 24 deletions
| @@ -451,16 +451,37 @@ void dax_wake_mapping_entry_waiter(struct address_space *mapping, | |||
| 451 | __wake_up(wq, TASK_NORMAL, wake_all ? 0 : 1, &key); | 451 | __wake_up(wq, TASK_NORMAL, wake_all ? 0 : 1, &key); |
| 452 | } | 452 | } |
| 453 | 453 | ||
| 454 | static int __dax_invalidate_mapping_entry(struct address_space *mapping, | ||
| 455 | pgoff_t index, bool trunc) | ||
| 456 | { | ||
| 457 | int ret = 0; | ||
| 458 | void *entry; | ||
| 459 | struct radix_tree_root *page_tree = &mapping->page_tree; | ||
| 460 | |||
| 461 | spin_lock_irq(&mapping->tree_lock); | ||
| 462 | entry = get_unlocked_mapping_entry(mapping, index, NULL); | ||
| 463 | if (!entry || !radix_tree_exceptional_entry(entry)) | ||
| 464 | goto out; | ||
| 465 | if (!trunc && | ||
| 466 | (radix_tree_tag_get(page_tree, index, PAGECACHE_TAG_DIRTY) || | ||
| 467 | radix_tree_tag_get(page_tree, index, PAGECACHE_TAG_TOWRITE))) | ||
| 468 | goto out; | ||
| 469 | radix_tree_delete(page_tree, index); | ||
| 470 | mapping->nrexceptional--; | ||
| 471 | ret = 1; | ||
| 472 | out: | ||
| 473 | put_unlocked_mapping_entry(mapping, index, entry); | ||
| 474 | spin_unlock_irq(&mapping->tree_lock); | ||
| 475 | return ret; | ||
| 476 | } | ||
| 454 | /* | 477 | /* |
| 455 | * Delete exceptional DAX entry at @index from @mapping. Wait for radix tree | 478 | * Delete exceptional DAX entry at @index from @mapping. Wait for radix tree |
| 456 | * entry to get unlocked before deleting it. | 479 | * entry to get unlocked before deleting it. |
| 457 | */ | 480 | */ |
| 458 | int dax_delete_mapping_entry(struct address_space *mapping, pgoff_t index) | 481 | int dax_delete_mapping_entry(struct address_space *mapping, pgoff_t index) |
| 459 | { | 482 | { |
| 460 | void *entry; | 483 | int ret = __dax_invalidate_mapping_entry(mapping, index, true); |
| 461 | 484 | ||
| 462 | spin_lock_irq(&mapping->tree_lock); | ||
| 463 | entry = get_unlocked_mapping_entry(mapping, index, NULL); | ||
| 464 | /* | 485 | /* |
| 465 | * This gets called from truncate / punch_hole path. As such, the caller | 486 | * This gets called from truncate / punch_hole path. As such, the caller |
| 466 | * must hold locks protecting against concurrent modifications of the | 487 | * must hold locks protecting against concurrent modifications of the |
| @@ -468,16 +489,46 @@ int dax_delete_mapping_entry(struct address_space *mapping, pgoff_t index) | |||
| 468 | * caller has seen exceptional entry for this index, we better find it | 489 | * caller has seen exceptional entry for this index, we better find it |
| 469 | * at that index as well... | 490 | * at that index as well... |
| 470 | */ | 491 | */ |
| 471 | if (WARN_ON_ONCE(!entry || !radix_tree_exceptional_entry(entry))) { | 492 | WARN_ON_ONCE(!ret); |
| 472 | spin_unlock_irq(&mapping->tree_lock); | 493 | return ret; |
| 473 | return 0; | 494 | } |
| 474 | } | 495 | |
| 475 | radix_tree_delete(&mapping->page_tree, index); | 496 | /* |
| 497 | * Invalidate exceptional DAX entry if easily possible. This handles DAX | ||
| 498 | * entries for invalidate_inode_pages() so we evict the entry only if we can | ||
| 499 | * do so without blocking. | ||
| 500 | */ | ||
| 501 | int dax_invalidate_mapping_entry(struct address_space *mapping, pgoff_t index) | ||
| 502 | { | ||
| 503 | int ret = 0; | ||
| 504 | void *entry, **slot; | ||
| 505 | struct radix_tree_root *page_tree = &mapping->page_tree; | ||
| 506 | |||
| 507 | spin_lock_irq(&mapping->tree_lock); | ||
| 508 | entry = __radix_tree_lookup(page_tree, index, NULL, &slot); | ||
| 509 | if (!entry || !radix_tree_exceptional_entry(entry) || | ||
| 510 | slot_locked(mapping, slot)) | ||
| 511 | goto out; | ||
| 512 | if (radix_tree_tag_get(page_tree, index, PAGECACHE_TAG_DIRTY) || | ||
| 513 | radix_tree_tag_get(page_tree, index, PAGECACHE_TAG_TOWRITE)) | ||
| 514 | goto out; | ||
| 515 | radix_tree_delete(page_tree, index); | ||
| 476 | mapping->nrexceptional--; | 516 | mapping->nrexceptional--; |
| 517 | ret = 1; | ||
| 518 | out: | ||
| 477 | spin_unlock_irq(&mapping->tree_lock); | 519 | spin_unlock_irq(&mapping->tree_lock); |
| 478 | dax_wake_mapping_entry_waiter(mapping, index, entry, true); | 520 | if (ret) |
| 521 | dax_wake_mapping_entry_waiter(mapping, index, entry, true); | ||
| 522 | return ret; | ||
| 523 | } | ||
| 479 | 524 | ||
| 480 | return 1; | 525 | /* |
| 526 | * Invalidate exceptional DAX entry if it is clean. | ||
| 527 | */ | ||
| 528 | int dax_invalidate_mapping_entry_sync(struct address_space *mapping, | ||
| 529 | pgoff_t index) | ||
| 530 | { | ||
| 531 | return __dax_invalidate_mapping_entry(mapping, index, false); | ||
| 481 | } | 532 | } |
| 482 | 533 | ||
| 483 | /* | 534 | /* |
diff --git a/include/linux/dax.h b/include/linux/dax.h index f97bcfe79472..24ad71173995 100644 --- a/include/linux/dax.h +++ b/include/linux/dax.h | |||
| @@ -41,6 +41,9 @@ ssize_t dax_iomap_rw(struct kiocb *iocb, struct iov_iter *iter, | |||
| 41 | int dax_iomap_fault(struct vm_area_struct *vma, struct vm_fault *vmf, | 41 | int dax_iomap_fault(struct vm_area_struct *vma, struct vm_fault *vmf, |
| 42 | struct iomap_ops *ops); | 42 | struct iomap_ops *ops); |
| 43 | int dax_delete_mapping_entry(struct address_space *mapping, pgoff_t index); | 43 | int dax_delete_mapping_entry(struct address_space *mapping, pgoff_t index); |
| 44 | int dax_invalidate_mapping_entry(struct address_space *mapping, pgoff_t index); | ||
| 45 | int dax_invalidate_mapping_entry_sync(struct address_space *mapping, | ||
| 46 | pgoff_t index); | ||
| 44 | void dax_wake_mapping_entry_waiter(struct address_space *mapping, | 47 | void dax_wake_mapping_entry_waiter(struct address_space *mapping, |
| 45 | pgoff_t index, void *entry, bool wake_all); | 48 | pgoff_t index, void *entry, bool wake_all); |
| 46 | 49 | ||
diff --git a/mm/truncate.c b/mm/truncate.c index fd97f1dbce29..dd7b24e083c5 100644 --- a/mm/truncate.c +++ b/mm/truncate.c | |||
| @@ -24,20 +24,12 @@ | |||
| 24 | #include <linux/rmap.h> | 24 | #include <linux/rmap.h> |
| 25 | #include "internal.h" | 25 | #include "internal.h" |
| 26 | 26 | ||
| 27 | static void clear_exceptional_entry(struct address_space *mapping, | 27 | static void clear_shadow_entry(struct address_space *mapping, pgoff_t index, |
| 28 | pgoff_t index, void *entry) | 28 | void *entry) |
| 29 | { | 29 | { |
| 30 | struct radix_tree_node *node; | 30 | struct radix_tree_node *node; |
| 31 | void **slot; | 31 | void **slot; |
| 32 | 32 | ||
| 33 | /* Handled by shmem itself */ | ||
| 34 | if (shmem_mapping(mapping)) | ||
| 35 | return; | ||
| 36 | |||
| 37 | if (dax_mapping(mapping)) { | ||
| 38 | dax_delete_mapping_entry(mapping, index); | ||
| 39 | return; | ||
| 40 | } | ||
| 41 | spin_lock_irq(&mapping->tree_lock); | 33 | spin_lock_irq(&mapping->tree_lock); |
| 42 | /* | 34 | /* |
| 43 | * Regular page slots are stabilized by the page lock even | 35 | * Regular page slots are stabilized by the page lock even |
| @@ -55,6 +47,56 @@ unlock: | |||
| 55 | spin_unlock_irq(&mapping->tree_lock); | 47 | spin_unlock_irq(&mapping->tree_lock); |
| 56 | } | 48 | } |
| 57 | 49 | ||
| 50 | /* | ||
| 51 | * Unconditionally remove exceptional entry. Usually called from truncate path. | ||
| 52 | */ | ||
| 53 | static void truncate_exceptional_entry(struct address_space *mapping, | ||
| 54 | pgoff_t index, void *entry) | ||
| 55 | { | ||
| 56 | /* Handled by shmem itself */ | ||
| 57 | if (shmem_mapping(mapping)) | ||
| 58 | return; | ||
| 59 | |||
| 60 | if (dax_mapping(mapping)) { | ||
| 61 | dax_delete_mapping_entry(mapping, index); | ||
| 62 | return; | ||
| 63 | } | ||
| 64 | clear_shadow_entry(mapping, index, entry); | ||
| 65 | } | ||
| 66 | |||
| 67 | /* | ||
| 68 | * Invalidate exceptional entry if easily possible. This handles exceptional | ||
| 69 | * entries for invalidate_inode_pages() so for DAX it evicts only unlocked and | ||
| 70 | * clean entries. | ||
| 71 | */ | ||
| 72 | static int invalidate_exceptional_entry(struct address_space *mapping, | ||
| 73 | pgoff_t index, void *entry) | ||
| 74 | { | ||
| 75 | /* Handled by shmem itself */ | ||
| 76 | if (shmem_mapping(mapping)) | ||
| 77 | return 1; | ||
| 78 | if (dax_mapping(mapping)) | ||
| 79 | return dax_invalidate_mapping_entry(mapping, index); | ||
| 80 | clear_shadow_entry(mapping, index, entry); | ||
| 81 | return 1; | ||
| 82 | } | ||
| 83 | |||
| 84 | /* | ||
| 85 | * Invalidate exceptional entry if clean. This handles exceptional entries for | ||
| 86 | * invalidate_inode_pages2() so for DAX it evicts only clean entries. | ||
| 87 | */ | ||
| 88 | static int invalidate_exceptional_entry2(struct address_space *mapping, | ||
| 89 | pgoff_t index, void *entry) | ||
| 90 | { | ||
| 91 | /* Handled by shmem itself */ | ||
| 92 | if (shmem_mapping(mapping)) | ||
| 93 | return 1; | ||
| 94 | if (dax_mapping(mapping)) | ||
| 95 | return dax_invalidate_mapping_entry_sync(mapping, index); | ||
| 96 | clear_shadow_entry(mapping, index, entry); | ||
| 97 | return 1; | ||
| 98 | } | ||
| 99 | |||
| 58 | /** | 100 | /** |
| 59 | * do_invalidatepage - invalidate part or all of a page | 101 | * do_invalidatepage - invalidate part or all of a page |
| 60 | * @page: the page which is affected | 102 | * @page: the page which is affected |
| @@ -262,7 +304,8 @@ void truncate_inode_pages_range(struct address_space *mapping, | |||
| 262 | break; | 304 | break; |
| 263 | 305 | ||
| 264 | if (radix_tree_exceptional_entry(page)) { | 306 | if (radix_tree_exceptional_entry(page)) { |
| 265 | clear_exceptional_entry(mapping, index, page); | 307 | truncate_exceptional_entry(mapping, index, |
| 308 | page); | ||
| 266 | continue; | 309 | continue; |
| 267 | } | 310 | } |
| 268 | 311 | ||
| @@ -351,7 +394,8 @@ void truncate_inode_pages_range(struct address_space *mapping, | |||
| 351 | } | 394 | } |
| 352 | 395 | ||
| 353 | if (radix_tree_exceptional_entry(page)) { | 396 | if (radix_tree_exceptional_entry(page)) { |
| 354 | clear_exceptional_entry(mapping, index, page); | 397 | truncate_exceptional_entry(mapping, index, |
| 398 | page); | ||
| 355 | continue; | 399 | continue; |
| 356 | } | 400 | } |
| 357 | 401 | ||
| @@ -470,7 +514,8 @@ unsigned long invalidate_mapping_pages(struct address_space *mapping, | |||
| 470 | break; | 514 | break; |
| 471 | 515 | ||
| 472 | if (radix_tree_exceptional_entry(page)) { | 516 | if (radix_tree_exceptional_entry(page)) { |
| 473 | clear_exceptional_entry(mapping, index, page); | 517 | invalidate_exceptional_entry(mapping, index, |
| 518 | page); | ||
| 474 | continue; | 519 | continue; |
| 475 | } | 520 | } |
| 476 | 521 | ||
| @@ -592,7 +637,9 @@ int invalidate_inode_pages2_range(struct address_space *mapping, | |||
| 592 | break; | 637 | break; |
| 593 | 638 | ||
| 594 | if (radix_tree_exceptional_entry(page)) { | 639 | if (radix_tree_exceptional_entry(page)) { |
| 595 | clear_exceptional_entry(mapping, index, page); | 640 | if (!invalidate_exceptional_entry2(mapping, |
| 641 | index, page)) | ||
| 642 | ret = -EBUSY; | ||
| 596 | continue; | 643 | continue; |
| 597 | } | 644 | } |
| 598 | 645 | ||
