aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorShaohua Li <shaohua.li@intel.com>2008-02-05 01:29:33 -0500
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2008-02-05 12:44:19 -0500
commit62e1c55300f306e06478f460a7eefba085206e0b (patch)
treebe15b2e4801c837c5e20d43b8f29a53c0ba1391c
parent7786fa9ac5366214fb942a9e62c6e46b4272c22c (diff)
page migraton: handle orphaned pages
Orphaned page might have fs-private metadata, the page is truncated. As the page hasn't mapping, page migration refuse to migrate the page. It appears the page is only freed in page reclaim and if zone watermark is low, the page is never freed, as a result migration always fail. I thought we could free the metadata so such page can be freed in migration and make migration more reliable. [akpm@linux-foundation.org: go direct to try_to_free_buffers()] Signed-off-by: Shaohua Li <shaohua.li@intel.com> Acked-by: Nick Piggin <npiggin@suse.de> Acked-by: Christoph Lameter <clameter@sgi.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--mm/migrate.c30
-rw-r--r--mm/truncate.c2
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