mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-30 03:27:44 -04:00
mm, migration: add destination page freeing callback
Memory migration uses a callback defined by the caller to determine how to allocate destination pages. When migration fails for a source page, however, it frees the destination page back to the system. This patch adds a memory migration callback defined by the caller to determine how to free destination pages. If a caller, such as memory compaction, builds its own freelist for migration targets, this can reuse already freed memory instead of scanning additional memory. If the caller provides a function to handle freeing of destination pages, it is called when page migration fails. If the caller passes NULL then freeing back to the system will be handled as usual. This patch introduces no functional change. Signed-off-by: David Rientjes <[email protected]> Reviewed-by: Naoya Horiguchi <[email protected]> Acked-by: Mel Gorman <[email protected]> Acked-by: Vlastimil Babka <[email protected]> Cc: Greg Thelen <[email protected]> Signed-off-by: Andrew Morton <[email protected]> Signed-off-by: Linus Torvalds <[email protected]>
This commit is contained in:
parent
93f39eea9c
commit
68711a7463
7 changed files with 53 additions and 27 deletions
55
mm/migrate.c
55
mm/migrate.c
|
|
@ -938,8 +938,9 @@ out:
|
|||
* Obtain the lock on page, remove all ptes and migrate the page
|
||||
* to the newly allocated page in newpage.
|
||||
*/
|
||||
static int unmap_and_move(new_page_t get_new_page, unsigned long private,
|
||||
struct page *page, int force, enum migrate_mode mode)
|
||||
static int unmap_and_move(new_page_t get_new_page, free_page_t put_new_page,
|
||||
unsigned long private, struct page *page, int force,
|
||||
enum migrate_mode mode)
|
||||
{
|
||||
int rc = 0;
|
||||
int *result = NULL;
|
||||
|
|
@ -983,11 +984,17 @@ out:
|
|||
page_is_file_cache(page));
|
||||
putback_lru_page(page);
|
||||
}
|
||||
|
||||
/*
|
||||
* Move the new page to the LRU. If migration was not successful
|
||||
* then this will free the page.
|
||||
* If migration was not successful and there's a freeing callback, use
|
||||
* it. Otherwise, putback_lru_page() will drop the reference grabbed
|
||||
* during isolation.
|
||||
*/
|
||||
putback_lru_page(newpage);
|
||||
if (rc != MIGRATEPAGE_SUCCESS && put_new_page)
|
||||
put_new_page(newpage, private);
|
||||
else
|
||||
putback_lru_page(newpage);
|
||||
|
||||
if (result) {
|
||||
if (rc)
|
||||
*result = rc;
|
||||
|
|
@ -1016,8 +1023,9 @@ out:
|
|||
* will wait in the page fault for migration to complete.
|
||||
*/
|
||||
static int unmap_and_move_huge_page(new_page_t get_new_page,
|
||||
unsigned long private, struct page *hpage,
|
||||
int force, enum migrate_mode mode)
|
||||
free_page_t put_new_page, unsigned long private,
|
||||
struct page *hpage, int force,
|
||||
enum migrate_mode mode)
|
||||
{
|
||||
int rc = 0;
|
||||
int *result = NULL;
|
||||
|
|
@ -1056,20 +1064,30 @@ static int unmap_and_move_huge_page(new_page_t get_new_page,
|
|||
if (!page_mapped(hpage))
|
||||
rc = move_to_new_page(new_hpage, hpage, 1, mode);
|
||||
|
||||
if (rc)
|
||||
if (rc != MIGRATEPAGE_SUCCESS)
|
||||
remove_migration_ptes(hpage, hpage);
|
||||
|
||||
if (anon_vma)
|
||||
put_anon_vma(anon_vma);
|
||||
|
||||
if (!rc)
|
||||
if (rc == MIGRATEPAGE_SUCCESS)
|
||||
hugetlb_cgroup_migrate(hpage, new_hpage);
|
||||
|
||||
unlock_page(hpage);
|
||||
out:
|
||||
if (rc != -EAGAIN)
|
||||
putback_active_hugepage(hpage);
|
||||
put_page(new_hpage);
|
||||
|
||||
/*
|
||||
* If migration was not successful and there's a freeing callback, use
|
||||
* it. Otherwise, put_page() will drop the reference grabbed during
|
||||
* isolation.
|
||||
*/
|
||||
if (rc != MIGRATEPAGE_SUCCESS && put_new_page)
|
||||
put_new_page(new_hpage, private);
|
||||
else
|
||||
put_page(new_hpage);
|
||||
|
||||
if (result) {
|
||||
if (rc)
|
||||
*result = rc;
|
||||
|
|
@ -1086,6 +1104,8 @@ out:
|
|||
* @from: The list of pages to be migrated.
|
||||
* @get_new_page: The function used to allocate free pages to be used
|
||||
* as the target of the page migration.
|
||||
* @put_new_page: The function used to free target pages if migration
|
||||
* fails, or NULL if no special handling is necessary.
|
||||
* @private: Private data to be passed on to get_new_page()
|
||||
* @mode: The migration mode that specifies the constraints for
|
||||
* page migration, if any.
|
||||
|
|
@ -1099,7 +1119,8 @@ out:
|
|||
* Returns the number of pages that were not migrated, or an error code.
|
||||
*/
|
||||
int migrate_pages(struct list_head *from, new_page_t get_new_page,
|
||||
unsigned long private, enum migrate_mode mode, int reason)
|
||||
free_page_t put_new_page, unsigned long private,
|
||||
enum migrate_mode mode, int reason)
|
||||
{
|
||||
int retry = 1;
|
||||
int nr_failed = 0;
|
||||
|
|
@ -1121,10 +1142,11 @@ int migrate_pages(struct list_head *from, new_page_t get_new_page,
|
|||
|
||||
if (PageHuge(page))
|
||||
rc = unmap_and_move_huge_page(get_new_page,
|
||||
private, page, pass > 2, mode);
|
||||
put_new_page, private, page,
|
||||
pass > 2, mode);
|
||||
else
|
||||
rc = unmap_and_move(get_new_page, private,
|
||||
page, pass > 2, mode);
|
||||
rc = unmap_and_move(get_new_page, put_new_page,
|
||||
private, page, pass > 2, mode);
|
||||
|
||||
switch(rc) {
|
||||
case -ENOMEM:
|
||||
|
|
@ -1273,7 +1295,7 @@ set_status:
|
|||
|
||||
err = 0;
|
||||
if (!list_empty(&pagelist)) {
|
||||
err = migrate_pages(&pagelist, new_page_node,
|
||||
err = migrate_pages(&pagelist, new_page_node, NULL,
|
||||
(unsigned long)pm, MIGRATE_SYNC, MR_SYSCALL);
|
||||
if (err)
|
||||
putback_movable_pages(&pagelist);
|
||||
|
|
@ -1729,7 +1751,8 @@ int migrate_misplaced_page(struct page *page, struct vm_area_struct *vma,
|
|||
|
||||
list_add(&page->lru, &migratepages);
|
||||
nr_remaining = migrate_pages(&migratepages, alloc_misplaced_dst_page,
|
||||
node, MIGRATE_ASYNC, MR_NUMA_MISPLACED);
|
||||
NULL, node, MIGRATE_ASYNC,
|
||||
MR_NUMA_MISPLACED);
|
||||
if (nr_remaining) {
|
||||
if (!list_empty(&migratepages)) {
|
||||
list_del(&page->lru);
|
||||
|
|
|
|||
Loading…
Reference in a new issue