Skip to content

Commit e5bfff8

Browse files
yhuang-intelakpm00
authored andcommitted
migrate_pages: separate hugetlb folios migration
This is a preparation patch to batch the folio unmapping and moving for the non-hugetlb folios. Based on that we can batch the TLB shootdown during the folio migration and make it possible to use some hardware accelerator for the folio copying. In this patch the hugetlb folios and non-hugetlb folios migration is separated in migrate_pages() to make it easy to change the non-hugetlb folios migration implementation. Link: https://lkml.kernel.org/r/[email protected] Signed-off-by: "Huang, Ying" <[email protected]> Reviewed-by: Baolin Wang <[email protected]> Reviewed-by: Xin Hao <[email protected]> Cc: Zi Yan <[email protected]> Cc: Yang Shi <[email protected]> Cc: Oscar Salvador <[email protected]> Cc: Matthew Wilcox <[email protected]> Cc: Bharata B Rao <[email protected]> Cc: Alistair Popple <[email protected]> Cc: Minchan Kim <[email protected]> Cc: Mike Kravetz <[email protected]> Cc: Hyeonggon Yoo <[email protected]> Signed-off-by: Andrew Morton <[email protected]>
1 parent 5b85593 commit e5bfff8

File tree

1 file changed

+119
-22
lines changed

1 file changed

+119
-22
lines changed

mm/migrate.c

Lines changed: 119 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1414,6 +1414,8 @@ static inline int try_split_folio(struct folio *folio, struct list_head *split_f
14141414
return rc;
14151415
}
14161416

1417+
#define NR_MAX_MIGRATE_PAGES_RETRY 10
1418+
14171419
struct migrate_pages_stats {
14181420
int nr_succeeded; /* Normal and large folios migrated successfully, in
14191421
units of base pages */
@@ -1424,6 +1426,95 @@ struct migrate_pages_stats {
14241426
int nr_thp_split; /* THP split before migrating */
14251427
};
14261428

1429+
/*
1430+
* Returns the number of hugetlb folios that were not migrated, or an error code
1431+
* after NR_MAX_MIGRATE_PAGES_RETRY attempts or if no hugetlb folios are movable
1432+
* any more because the list has become empty or no retryable hugetlb folios
1433+
* exist any more. It is caller's responsibility to call putback_movable_pages()
1434+
* only if ret != 0.
1435+
*/
1436+
static int migrate_hugetlbs(struct list_head *from, new_page_t get_new_page,
1437+
free_page_t put_new_page, unsigned long private,
1438+
enum migrate_mode mode, int reason,
1439+
struct migrate_pages_stats *stats,
1440+
struct list_head *ret_folios)
1441+
{
1442+
int retry = 1;
1443+
int nr_failed = 0;
1444+
int nr_retry_pages = 0;
1445+
int pass = 0;
1446+
struct folio *folio, *folio2;
1447+
int rc, nr_pages;
1448+
1449+
for (pass = 0; pass < NR_MAX_MIGRATE_PAGES_RETRY && retry; pass++) {
1450+
retry = 0;
1451+
nr_retry_pages = 0;
1452+
1453+
list_for_each_entry_safe(folio, folio2, from, lru) {
1454+
if (!folio_test_hugetlb(folio))
1455+
continue;
1456+
1457+
nr_pages = folio_nr_pages(folio);
1458+
1459+
cond_resched();
1460+
1461+
rc = unmap_and_move_huge_page(get_new_page,
1462+
put_new_page, private,
1463+
&folio->page, pass > 2, mode,
1464+
reason, ret_folios);
1465+
/*
1466+
* The rules are:
1467+
* Success: hugetlb folio will be put back
1468+
* -EAGAIN: stay on the from list
1469+
* -ENOMEM: stay on the from list
1470+
* -ENOSYS: stay on the from list
1471+
* Other errno: put on ret_folios list
1472+
*/
1473+
switch(rc) {
1474+
case -ENOSYS:
1475+
/* Hugetlb migration is unsupported */
1476+
nr_failed++;
1477+
stats->nr_failed_pages += nr_pages;
1478+
list_move_tail(&folio->lru, ret_folios);
1479+
break;
1480+
case -ENOMEM:
1481+
/*
1482+
* When memory is low, don't bother to try to migrate
1483+
* other folios, just exit.
1484+
*/
1485+
stats->nr_failed_pages += nr_pages + nr_retry_pages;
1486+
return -ENOMEM;
1487+
case -EAGAIN:
1488+
retry++;
1489+
nr_retry_pages += nr_pages;
1490+
break;
1491+
case MIGRATEPAGE_SUCCESS:
1492+
stats->nr_succeeded += nr_pages;
1493+
break;
1494+
default:
1495+
/*
1496+
* Permanent failure (-EBUSY, etc.):
1497+
* unlike -EAGAIN case, the failed folio is
1498+
* removed from migration folio list and not
1499+
* retried in the next outer loop.
1500+
*/
1501+
nr_failed++;
1502+
stats->nr_failed_pages += nr_pages;
1503+
break;
1504+
}
1505+
}
1506+
}
1507+
/*
1508+
* nr_failed is number of hugetlb folios failed to be migrated. After
1509+
* NR_MAX_MIGRATE_PAGES_RETRY attempts, give up and count retried hugetlb
1510+
* folios as failed.
1511+
*/
1512+
nr_failed += retry;
1513+
stats->nr_failed_pages += nr_retry_pages;
1514+
1515+
return nr_failed;
1516+
}
1517+
14271518
/*
14281519
* migrate_pages - migrate the folios specified in a list, to the free folios
14291520
* supplied as the target for the page migration
@@ -1440,10 +1531,10 @@ struct migrate_pages_stats {
14401531
* @ret_succeeded: Set to the number of folios migrated successfully if
14411532
* the caller passes a non-NULL pointer.
14421533
*
1443-
* The function returns after 10 attempts or if no folios are movable any more
1444-
* because the list has become empty or no retryable folios exist any more.
1445-
* It is caller's responsibility to call putback_movable_pages() to return folios
1446-
* to the LRU or free list only if ret != 0.
1534+
* The function returns after NR_MAX_MIGRATE_PAGES_RETRY attempts or if no folios
1535+
* are movable any more because the list has become empty or no retryable folios
1536+
* exist any more. It is caller's responsibility to call putback_movable_pages()
1537+
* only if ret != 0.
14471538
*
14481539
* Returns the number of {normal folio, large folio, hugetlb} that were not
14491540
* migrated, or an error code. The number of large folio splits will be
@@ -1457,7 +1548,7 @@ int migrate_pages(struct list_head *from, new_page_t get_new_page,
14571548
int retry = 1;
14581549
int large_retry = 1;
14591550
int thp_retry = 1;
1460-
int nr_failed = 0;
1551+
int nr_failed;
14611552
int nr_retry_pages = 0;
14621553
int nr_large_failed = 0;
14631554
int pass = 0;
@@ -1474,38 +1565,45 @@ int migrate_pages(struct list_head *from, new_page_t get_new_page,
14741565
trace_mm_migrate_pages_start(mode, reason);
14751566

14761567
memset(&stats, 0, sizeof(stats));
1568+
rc = migrate_hugetlbs(from, get_new_page, put_new_page, private, mode, reason,
1569+
&stats, &ret_folios);
1570+
if (rc < 0)
1571+
goto out;
1572+
nr_failed = rc;
1573+
14771574
split_folio_migration:
1478-
for (pass = 0; pass < 10 && (retry || large_retry); pass++) {
1575+
for (pass = 0;
1576+
pass < NR_MAX_MIGRATE_PAGES_RETRY && (retry || large_retry);
1577+
pass++) {
14791578
retry = 0;
14801579
large_retry = 0;
14811580
thp_retry = 0;
14821581
nr_retry_pages = 0;
14831582

14841583
list_for_each_entry_safe(folio, folio2, from, lru) {
1584+
/* Retried hugetlb folios will be kept in list */
1585+
if (folio_test_hugetlb(folio)) {
1586+
list_move_tail(&folio->lru, &ret_folios);
1587+
continue;
1588+
}
1589+
14851590
/*
14861591
* Large folio statistics is based on the source large
14871592
* folio. Capture required information that might get
14881593
* lost during migration.
14891594
*/
1490-
is_large = folio_test_large(folio) && !folio_test_hugetlb(folio);
1595+
is_large = folio_test_large(folio);
14911596
is_thp = is_large && folio_test_pmd_mappable(folio);
14921597
nr_pages = folio_nr_pages(folio);
1598+
14931599
cond_resched();
14941600

1495-
if (folio_test_hugetlb(folio))
1496-
rc = unmap_and_move_huge_page(get_new_page,
1497-
put_new_page, private,
1498-
&folio->page, pass > 2, mode,
1499-
reason,
1500-
&ret_folios);
1501-
else
1502-
rc = unmap_and_move(get_new_page, put_new_page,
1503-
private, folio, pass > 2, mode,
1504-
reason, &ret_folios);
1601+
rc = unmap_and_move(get_new_page, put_new_page,
1602+
private, folio, pass > 2, mode,
1603+
reason, &ret_folios);
15051604
/*
15061605
* The rules are:
1507-
* Success: non hugetlb folio will be freed, hugetlb
1508-
* folio will be put back
1606+
* Success: folio will be freed
15091607
* -EAGAIN: stay on the from list
15101608
* -ENOMEM: stay on the from list
15111609
* -ENOSYS: stay on the from list
@@ -1532,7 +1630,6 @@ int migrate_pages(struct list_head *from, new_page_t get_new_page,
15321630
stats.nr_thp_split += is_thp;
15331631
break;
15341632
}
1535-
/* Hugetlb migration is unsupported */
15361633
} else if (!no_split_folio_counting) {
15371634
nr_failed++;
15381635
}
@@ -1626,8 +1723,8 @@ int migrate_pages(struct list_head *from, new_page_t get_new_page,
16261723
*/
16271724
if (!list_empty(&split_folios)) {
16281725
/*
1629-
* Move non-migrated folios (after 10 retries) to ret_folios
1630-
* to avoid migrating them again.
1726+
* Move non-migrated folios (after NR_MAX_MIGRATE_PAGES_RETRY
1727+
* retries) to ret_folios to avoid migrating them again.
16311728
*/
16321729
list_splice_init(from, &ret_folios);
16331730
list_splice_init(&split_folios, from);

0 commit comments

Comments
 (0)