Skip to content

Commit e0153fc

Browse files
Yang Shitorvalds
authored andcommitted
mm: move_pages: return valid node id in status if the page is already on the target node
Felix Abecassis reports move_pages() would return random status if the pages are already on the target node by the below test program: int main(void) { const long node_id = 1; const long page_size = sysconf(_SC_PAGESIZE); const int64_t num_pages = 8; unsigned long nodemask = 1 << node_id; long ret = set_mempolicy(MPOL_BIND, &nodemask, sizeof(nodemask)); if (ret < 0) return (EXIT_FAILURE); void **pages = malloc(sizeof(void*) * num_pages); for (int i = 0; i < num_pages; ++i) { pages[i] = mmap(NULL, page_size, PROT_WRITE | PROT_READ, MAP_PRIVATE | MAP_POPULATE | MAP_ANONYMOUS, -1, 0); if (pages[i] == MAP_FAILED) return (EXIT_FAILURE); } ret = set_mempolicy(MPOL_DEFAULT, NULL, 0); if (ret < 0) return (EXIT_FAILURE); int *nodes = malloc(sizeof(int) * num_pages); int *status = malloc(sizeof(int) * num_pages); for (int i = 0; i < num_pages; ++i) { nodes[i] = node_id; status[i] = 0xd0; /* simulate garbage values */ } ret = move_pages(0, num_pages, pages, nodes, status, MPOL_MF_MOVE); printf("move_pages: %ld\n", ret); for (int i = 0; i < num_pages; ++i) printf("status[%d] = %d\n", i, status[i]); } Then running the program would return nonsense status values: $ ./move_pages_bug move_pages: 0 status[0] = 208 status[1] = 208 status[2] = 208 status[3] = 208 status[4] = 208 status[5] = 208 status[6] = 208 status[7] = 208 This is because the status is not set if the page is already on the target node, but move_pages() should return valid status as long as it succeeds. The valid status may be errno or node id. We can't simply initialize status array to zero since the pages may be not on node 0. Fix it by updating status with node id which the page is already on. Link: http://lkml.kernel.org/r/[email protected] Fixes: a49bd4d ("mm, numa: rework do_pages_move") Signed-off-by: Yang Shi <[email protected]> Reported-by: Felix Abecassis <[email protected]> Tested-by: Felix Abecassis <[email protected]> Suggested-by: Michal Hocko <[email protected]> Reviewed-by: John Hubbard <[email protected]> Acked-by: Christoph Lameter <[email protected]> Acked-by: Michal Hocko <[email protected]> Reviewed-by: Vlastimil Babka <[email protected]> Cc: Mel Gorman <[email protected]> Cc: <[email protected]> [4.17+] Signed-off-by: Andrew Morton <[email protected]> Signed-off-by: Linus Torvalds <[email protected]>
1 parent 84029fd commit e0153fc

File tree

1 file changed

+17
-6
lines changed

1 file changed

+17
-6
lines changed

mm/migrate.c

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1512,9 +1512,11 @@ static int do_move_pages_to_node(struct mm_struct *mm,
15121512
/*
15131513
* Resolves the given address to a struct page, isolates it from the LRU and
15141514
* puts it to the given pagelist.
1515-
* Returns -errno if the page cannot be found/isolated or 0 when it has been
1516-
* queued or the page doesn't need to be migrated because it is already on
1517-
* the target node
1515+
* Returns:
1516+
* errno - if the page cannot be found/isolated
1517+
* 0 - when it doesn't have to be migrated because it is already on the
1518+
* target node
1519+
* 1 - when it has been queued
15181520
*/
15191521
static int add_page_for_migration(struct mm_struct *mm, unsigned long addr,
15201522
int node, struct list_head *pagelist, bool migrate_all)
@@ -1553,7 +1555,7 @@ static int add_page_for_migration(struct mm_struct *mm, unsigned long addr,
15531555
if (PageHuge(page)) {
15541556
if (PageHead(page)) {
15551557
isolate_huge_page(page, pagelist);
1556-
err = 0;
1558+
err = 1;
15571559
}
15581560
} else {
15591561
struct page *head;
@@ -1563,7 +1565,7 @@ static int add_page_for_migration(struct mm_struct *mm, unsigned long addr,
15631565
if (err)
15641566
goto out_putpage;
15651567

1566-
err = 0;
1568+
err = 1;
15671569
list_add_tail(&head->lru, pagelist);
15681570
mod_node_page_state(page_pgdat(head),
15691571
NR_ISOLATED_ANON + page_is_file_cache(head),
@@ -1640,8 +1642,17 @@ static int do_pages_move(struct mm_struct *mm, nodemask_t task_nodes,
16401642
*/
16411643
err = add_page_for_migration(mm, addr, current_node,
16421644
&pagelist, flags & MPOL_MF_MOVE_ALL);
1643-
if (!err)
1645+
1646+
if (!err) {
1647+
/* The page is already on the target node */
1648+
err = store_status(status, i, current_node, 1);
1649+
if (err)
1650+
goto out_flush;
16441651
continue;
1652+
} else if (err > 0) {
1653+
/* The page is successfully queued for migration */
1654+
continue;
1655+
}
16451656

16461657
err = store_status(status, i, err, 1);
16471658
if (err)

0 commit comments

Comments
 (0)