From: Christoph Lameter page migration currently simply retries a couple of times if try_to_unmap() fails without inspecting the return code. However, SWAP_FAIL indicates that the page is in a vma that has the VM_LOCKED flag set (if ignore_refs ==1). We can check for that return code and avoid retrying the migration. migrate_page_remove_references() now needs to return a reason why the failure occured. So switch migrate_page_remove_references to use -Exx style error messages. Signed-off-by: Christoph Lameter Signed-off-by: Andrew Morton --- fs/buffer.c | 6 ++++-- mm/vmscan.c | 18 ++++++++++++------ 2 files changed, 16 insertions(+), 8 deletions(-) diff -puN fs/buffer.c~page-migration-fail-if-page-is-in-a-vma-flagged-vm_locked fs/buffer.c --- devel/fs/buffer.c~page-migration-fail-if-page-is-in-a-vma-flagged-vm_locked 2006-02-27 20:57:56.000000000 -0800 +++ devel-akpm/fs/buffer.c 2006-02-27 20:57:56.000000000 -0800 @@ -3060,6 +3060,7 @@ int buffer_migrate_page(struct page *new { struct address_space *mapping = page->mapping; struct buffer_head *bh, *head; + int rc; if (!mapping) return -EAGAIN; @@ -3069,8 +3070,9 @@ int buffer_migrate_page(struct page *new head = page_buffers(page); - if (migrate_page_remove_references(newpage, page, 3)) - return -EAGAIN; + rc = migrate_page_remove_references(newpage, page, 3); + if (rc) + return rc; bh = head; do { diff -puN mm/vmscan.c~page-migration-fail-if-page-is-in-a-vma-flagged-vm_locked mm/vmscan.c --- devel/mm/vmscan.c~page-migration-fail-if-page-is-in-a-vma-flagged-vm_locked 2006-02-27 20:57:56.000000000 -0800 +++ devel-akpm/mm/vmscan.c 2006-02-27 20:57:56.000000000 -0800 @@ -686,7 +686,7 @@ int migrate_page_remove_references(struc * the page. */ if (!mapping || page_mapcount(page) + nr_refs != page_count(page)) - return 1; + return -EAGAIN; /* * Establish swap ptes for anonymous pages or destroy pte @@ -707,13 +707,15 @@ int migrate_page_remove_references(struc * If the page was not migrated then the PageSwapCache bit * is still set and the operation may continue. */ - try_to_unmap(page, 1); + if (try_to_unmap(page, 1) == SWAP_FAIL) + /* A vma has VM_LOCKED set -> Permanent failure */ + return -EPERM; /* * Give up if we were unable to remove all mappings. */ if (page_mapcount(page)) - return 1; + return -EAGAIN; write_lock_irq(&mapping->tree_lock); @@ -724,7 +726,7 @@ int migrate_page_remove_references(struc if (!page_mapping(page) || page_count(page) != nr_refs || *radix_pointer != page) { write_unlock_irq(&mapping->tree_lock); - return 1; + return -EAGAIN; } /* @@ -799,10 +801,14 @@ EXPORT_SYMBOL(migrate_page_copy); */ int migrate_page(struct page *newpage, struct page *page) { + int rc; + BUG_ON(PageWriteback(page)); /* Writeback must be complete */ - if (migrate_page_remove_references(newpage, page, 2)) - return -EAGAIN; + rc = migrate_page_remove_references(newpage, page, 2); + + if (rc) + return rc; migrate_page_copy(newpage, page); _