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 <clameter@sgi.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
{
struct address_space *mapping = page->mapping;
struct buffer_head *bh, *head;
{
struct address_space *mapping = page->mapping;
struct buffer_head *bh, *head;
if (!mapping)
return -EAGAIN;
if (!mapping)
return -EAGAIN;
head = page_buffers(page);
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;
* the page.
*/
if (!mapping || page_mapcount(page) + nr_refs != page_count(page))
* the page.
*/
if (!mapping || page_mapcount(page) + nr_refs != page_count(page))
/*
* Establish swap ptes for anonymous pages or destroy pte
/*
* Establish swap ptes for anonymous pages or destroy pte
* If the page was not migrated then the PageSwapCache bit
* is still set and the operation may continue.
*/
* If the page was not migrated then the PageSwapCache bit
* is still set and the operation may continue.
*/
+ 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))
/*
* Give up if we were unable to remove all mappings.
*/
if (page_mapcount(page))
write_lock_irq(&mapping->tree_lock);
write_lock_irq(&mapping->tree_lock);
if (!page_mapping(page) || page_count(page) != nr_refs ||
*radix_pointer != page) {
write_unlock_irq(&mapping->tree_lock);
if (!page_mapping(page) || page_count(page) != nr_refs ||
*radix_pointer != page) {
write_unlock_irq(&mapping->tree_lock);
*/
int migrate_page(struct page *newpage, struct page *page)
{
*/
int migrate_page(struct page *newpage, struct page *page)
{
BUG_ON(PageWriteback(page)); /* Writeback must be complete */
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);
migrate_page_copy(newpage, page);