diff options
Diffstat (limited to 'mm')
-rw-r--r-- | mm/migrate.c | 30 | ||||
-rw-r--r-- | mm/truncate.c | 2 |
2 files changed, 25 insertions, 7 deletions
diff --git a/mm/migrate.c b/mm/migrate.c index 4ee4ccacf986..857a987e3690 100644 --- a/mm/migrate.c +++ b/mm/migrate.c | |||
@@ -640,15 +640,33 @@ static int unmap_and_move(new_page_t get_new_page, unsigned long private, | |||
640 | rcu_read_lock(); | 640 | rcu_read_lock(); |
641 | rcu_locked = 1; | 641 | rcu_locked = 1; |
642 | } | 642 | } |
643 | |||
643 | /* | 644 | /* |
644 | * This is a corner case handling. | 645 | * Corner case handling: |
645 | * When a new swap-cache is read into, it is linked to LRU | 646 | * 1. When a new swap-cache page is read into, it is added to the LRU |
646 | * and treated as swapcache but has no rmap yet. | 647 | * and treated as swapcache but it has no rmap yet. |
647 | * Calling try_to_unmap() against a page->mapping==NULL page is | 648 | * Calling try_to_unmap() against a page->mapping==NULL page will |
648 | * BUG. So handle it here. | 649 | * trigger a BUG. So handle it here. |
650 | * 2. An orphaned page (see truncate_complete_page) might have | ||
651 | * fs-private metadata. The page can be picked up due to memory | ||
652 | * offlining. Everywhere else except page reclaim, the page is | ||
653 | * invisible to the vm, so the page can not be migrated. So try to | ||
654 | * free the metadata, so the page can be freed. | ||
649 | */ | 655 | */ |
650 | if (!page->mapping) | 656 | if (!page->mapping) { |
657 | if (!PageAnon(page) && PagePrivate(page)) { | ||
658 | /* | ||
659 | * Go direct to try_to_free_buffers() here because | ||
660 | * a) that's what try_to_release_page() would do anyway | ||
661 | * b) we may be under rcu_read_lock() here, so we can't | ||
662 | * use GFP_KERNEL which is what try_to_release_page() | ||
663 | * needs to be effective. | ||
664 | */ | ||
665 | try_to_free_buffers(page); | ||
666 | } | ||
651 | goto rcu_unlock; | 667 | goto rcu_unlock; |
668 | } | ||
669 | |||
652 | /* Establish migration ptes or remove ptes */ | 670 | /* Establish migration ptes or remove ptes */ |
653 | try_to_unmap(page, 1); | 671 | try_to_unmap(page, 1); |
654 | 672 | ||
diff --git a/mm/truncate.c b/mm/truncate.c index 9838c050e2dd..c35c49e54fb6 100644 --- a/mm/truncate.c +++ b/mm/truncate.c | |||
@@ -84,7 +84,7 @@ EXPORT_SYMBOL(cancel_dirty_page); | |||
84 | 84 | ||
85 | /* | 85 | /* |
86 | * If truncate cannot remove the fs-private metadata from the page, the page | 86 | * If truncate cannot remove the fs-private metadata from the page, the page |
87 | * becomes anonymous. It will be left on the LRU and may even be mapped into | 87 | * becomes orphaned. It will be left on the LRU and may even be mapped into |
88 | * user pagetables if we're racing with filemap_fault(). | 88 | * user pagetables if we're racing with filemap_fault(). |
89 | * | 89 | * |
90 | * We need to bale out if page->mapping is no longer equal to the original | 90 | * We need to bale out if page->mapping is no longer equal to the original |