[PATCH RFC 02/11] mm/migrate: handle retries in migrate_folios_move()

From: Shivank Garg

Date: Wed Sep 02 2026 - 07:10:47 EST


After extracting the unmap phase, migrate_pages_batch() still drives the
retry loop for the move phase and passes its retry bookkeeping to
migrate_folios_move(). This splits the move phase across the two
functions and requires several output parameters.

Move the retry loop and its bookkeeping into migrate_folios_move().
The function now takes the number of passes and reports failures through
@nr_failed, matching migrate_folios_unmap().

No functional change is intended.

Signed-off-by: Shivank Garg <shivankg@xxxxxxx>
---
mm/migrate.c | 104 ++++++++++++++++++++++++++++-------------------------------
1 file changed, 49 insertions(+), 55 deletions(-)

diff --git a/mm/migrate.c b/mm/migrate.c
index 14a0f84009c6..89207bf515b9 100644
--- a/mm/migrate.c
+++ b/mm/migrate.c
@@ -1729,51 +1729,61 @@ static void migrate_folios_move(struct list_head *src_folios,
free_folio_t put_new_folio, unsigned long private,
enum migrate_mode mode, enum migrate_reason reason,
struct list_head *ret_folios,
- struct migrate_pages_stats *stats,
- int *retry, int *thp_retry, int *nr_failed,
- int *nr_retry_pages)
+ struct migrate_pages_stats *stats, int nr_pass,
+ int *nr_failed)
{
struct folio *folio, *folio2, *dst, *dst2;
+ int retry = 1;
+ int thp_retry = 0;
+ int nr_retry_pages = 0;
bool is_thp;
int nr_pages;
- int rc;
+ int pass, rc;

- dst = list_first_entry(dst_folios, struct folio, lru);
- dst2 = list_next_entry(dst, lru);
- list_for_each_entry_safe(folio, folio2, src_folios, lru) {
- is_thp = folio_test_large(folio) && folio_test_pmd_mappable(folio);
- nr_pages = folio_nr_pages(folio);
+ for (pass = 0; pass < nr_pass && retry; pass++) {
+ retry = 0;
+ thp_retry = 0;
+ nr_retry_pages = 0;

- cond_resched();
+ dst = list_first_entry(dst_folios, struct folio, lru);
+ dst2 = list_next_entry(dst, lru);
+ list_for_each_entry_safe(folio, folio2, src_folios, lru) {
+ is_thp = folio_test_large(folio) && folio_test_pmd_mappable(folio);
+ nr_pages = folio_nr_pages(folio);

- rc = migrate_folio_move(put_new_folio, private,
- folio, dst, mode,
- reason, ret_folios);
- /*
- * The rules are:
- * 0: folio will be freed
- * -EAGAIN: stay on the src_folios list
- * Other errno: put on ret_folios list
- */
- switch (rc) {
- case -EAGAIN:
- *retry += 1;
- *thp_retry += is_thp;
- *nr_retry_pages += nr_pages;
- break;
- case 0:
- stats->nr_succeeded += nr_pages;
- stats->nr_thp_succeeded += is_thp;
- break;
- default:
- *nr_failed += 1;
- stats->nr_thp_failed += is_thp;
- stats->nr_failed_pages += nr_pages;
- break;
+ cond_resched();
+
+ rc = migrate_folio_move(put_new_folio, private,
+ folio, dst, mode, reason, ret_folios);
+ /*
+ * The rules are:
+ * 0: folio will be freed
+ * -EAGAIN: stay on the src_folios list
+ * Other errno: put on ret_folios list
+ */
+ switch (rc) {
+ case -EAGAIN:
+ retry++;
+ thp_retry += is_thp;
+ nr_retry_pages += nr_pages;
+ break;
+ case 0:
+ stats->nr_succeeded += nr_pages;
+ stats->nr_thp_succeeded += is_thp;
+ break;
+ default:
+ *nr_failed += 1;
+ stats->nr_thp_failed += is_thp;
+ stats->nr_failed_pages += nr_pages;
+ break;
+ }
+ dst = dst2;
+ dst2 = list_next_entry(dst, lru);
}
- dst = dst2;
- dst2 = list_next_entry(dst, lru);
}
+ *nr_failed += retry;
+ stats->nr_thp_failed += thp_retry;
+ stats->nr_failed_pages += nr_retry_pages;
}

static void migrate_folios_undo(struct list_head *src_folios,
@@ -2000,11 +2010,7 @@ static int migrate_pages_batch(struct list_head *from,
struct list_head *ret_folios, struct list_head *split_folios,
struct migrate_pages_stats *stats, int nr_pass)
{
- int retry = 1;
- int thp_retry = 1;
int nr_failed = 0;
- int nr_retry_pages = 0;
- int pass = 0;
int rc, rc_saved;
LIST_HEAD(unmap_folios);
LIST_HEAD(dst_folios);
@@ -2024,21 +2030,9 @@ static int migrate_pages_batch(struct list_head *from,
/* Flush TLBs for all unmapped folios */
try_to_unmap_flush();

- retry = 1;
- for (pass = 0; pass < nr_pass && retry; pass++) {
- retry = 0;
- thp_retry = 0;
- nr_retry_pages = 0;
-
- /* Move the unmapped folios */
- migrate_folios_move(&unmap_folios, &dst_folios,
- put_new_folio, private, mode, reason,
- ret_folios, stats, &retry, &thp_retry,
- &nr_failed, &nr_retry_pages);
- }
- nr_failed += retry;
- stats->nr_thp_failed += thp_retry;
- stats->nr_failed_pages += nr_retry_pages;
+ /* Move the unmapped folios */
+ migrate_folios_move(&unmap_folios, &dst_folios, put_new_folio, private,
+ mode, reason, ret_folios, stats, nr_pass, &nr_failed);

rc = rc_saved ? : nr_failed;
out:

--
2.43.0