Commit c3096e67 authored by Hugh Dickins's avatar Hugh Dickins Committed by Matthew Wilcox (Oracle)

mm/migrate: __unmap_and_move() push good newpage to LRU

Compaction, NUMA page movement, THP collapse/split, and memory failure
do isolate unevictable pages from their "LRU", losing the record of
mlock_count in doing so (isolators are likely to use page->lru for their
own private lists, so mlock_count has to be presumed lost).

That's unfortunate, and we should put in some work to correct that: one
can imagine a function to build up the mlock_count again - but it would
require i_mmap_rwsem for read, so be careful where it's called.  Or
page_referenced_one() and try_to_unmap_one() might do that extra work.

But one place that can very easily be improved is page migration's
__unmap_and_move(): a small adjustment to where the successful new page
is put back on LRU, and its mlock_count (if any) is built back up by
remove_migration_ptes().
Signed-off-by: default avatarHugh Dickins <hughd@google.com>
Acked-by: default avatarVlastimil Babka <vbabka@suse.cz>
Signed-off-by: default avatarMatthew Wilcox (Oracle) <willy@infradead.org>
parent 34b67923
...@@ -1032,6 +1032,21 @@ static int __unmap_and_move(struct page *page, struct page *newpage, ...@@ -1032,6 +1032,21 @@ static int __unmap_and_move(struct page *page, struct page *newpage,
if (!page_mapped(page)) if (!page_mapped(page))
rc = move_to_new_page(newpage, page, mode); rc = move_to_new_page(newpage, page, mode);
/*
* When successful, push newpage to LRU immediately: so that if it
* turns out to be an mlocked page, remove_migration_ptes() will
* automatically build up the correct newpage->mlock_count for it.
*
* We would like to do something similar for the old page, when
* unsuccessful, and other cases when a page has been temporarily
* isolated from the unevictable LRU: but this case is the easiest.
*/
if (rc == MIGRATEPAGE_SUCCESS) {
lru_cache_add(newpage);
if (page_was_mapped)
lru_add_drain();
}
if (page_was_mapped) if (page_was_mapped)
remove_migration_ptes(page, remove_migration_ptes(page,
rc == MIGRATEPAGE_SUCCESS ? newpage : page, false); rc == MIGRATEPAGE_SUCCESS ? newpage : page, false);
...@@ -1045,20 +1060,12 @@ static int __unmap_and_move(struct page *page, struct page *newpage, ...@@ -1045,20 +1060,12 @@ static int __unmap_and_move(struct page *page, struct page *newpage,
unlock_page(page); unlock_page(page);
out: out:
/* /*
* If migration is successful, decrease refcount of the newpage * If migration is successful, decrease refcount of the newpage,
* which will not free the page because new page owner increased * which will not free the page because new page owner increased
* refcounter. As well, if it is LRU page, add the page to LRU * refcounter.
* list in here. Use the old state of the isolated source page to
* determine if we migrated a LRU page. newpage was already unlocked
* and possibly modified by its owner - don't rely on the page
* state.
*/ */
if (rc == MIGRATEPAGE_SUCCESS) { if (rc == MIGRATEPAGE_SUCCESS)
if (unlikely(!is_lru)) put_page(newpage);
put_page(newpage);
else
putback_lru_page(newpage);
}
return rc; return rc;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment