move_pages() migration is best effort and may temporarily leave a page
unmigrated when another task faults on the folio during unmapping.  The
migration test currently tolerates 100 consecutive partial failures,
but a busy machine can exhaust those retries in a fraction of a second
and fail long before the intended 20-second runtime expires.

This is especially visible in the shared-anon cases, where every worker
process continuously accesses the same mapping.  The retry count then
measures syscall rate rather than whether the test can exercise a
successful migration entry.

Retry positive move_pages() results for the full runtime and record the
per-page status.  Pass if at least one migration succeeds, and report the
last status before failing if no migration makes progress.  Continue to
fail immediately for syscall-level errors.

Signed-off-by: Muhammad Usama Anjum <[email protected]>
---
 tools/testing/selftests/mm/migration.c | 34 +++++++++++++++++---------
 1 file changed, 22 insertions(+), 12 deletions(-)

diff --git a/tools/testing/selftests/mm/migration.c 
b/tools/testing/selftests/mm/migration.c
index 29f7492453d43..19b4cef65f345 100644
--- a/tools/testing/selftests/mm/migration.c
+++ b/tools/testing/selftests/mm/migration.c
@@ -7,7 +7,7 @@
 #include "kselftest_harness.h"
 #include "hugepage_settings.h"
 
-#include <strings.h>
+#include <string.h>
 #include <pthread.h>
 #include <numa.h>
 #include <numaif.h>
@@ -20,7 +20,6 @@
 
 #define TWOMEG         (2<<20)
 #define RUNTIME                (20)
-#define MAX_RETRIES    100
 #define ALIGN(x, a)    (((x) + (a - 1)) & (~((a) - 1)))
 
 HUGETLB_SETUP_DEFAULT_PAGES(1)
@@ -110,7 +109,8 @@ int migrate(uint64_t *ptr, int n1, int n2)
        int ret, tmp;
        int status = 0;
        struct timespec ts1, ts2;
-       int failures = 0;
+       int last_status = 0;
+       unsigned long successes = 0;
 
        if (clock_gettime(CLOCK_MONOTONIC, &ts1))
                return -1;
@@ -119,23 +119,33 @@ int migrate(uint64_t *ptr, int n1, int n2)
                if (clock_gettime(CLOCK_MONOTONIC, &ts2))
                        return -1;
 
-               if (ts2.tv_sec - ts1.tv_sec >= RUNTIME)
-                       return 0;
+               if (ts2.tv_sec - ts1.tv_sec >= RUNTIME) {
+                       if (successes)
+                               return 0;
 
+                       if (last_status < 0)
+                               printf("No page migration succeeded: %s (%d)\n",
+                                      strerror(-last_status), last_status);
+                       else
+                               printf("No page migration succeeded: status 
%d\n",
+                                      last_status);
+                       return -2;
+               }
+
+               status = 0;
                ret = move_pages(0, 1, (void **) &ptr, &n2, &status,
                                MPOL_MF_MOVE_ALL);
                if (ret) {
                        if (ret > 0) {
-                               /* Migration is best effort; try again */
-                               if (++failures < MAX_RETRIES)
-                                       continue;
-                               printf("Didn't migrate %d pages\n", ret);
-                       }
-                       else
+                               /* Migration is best effort; try again. */
+                               last_status = status;
+                               continue;
+                       } else {
                                perror("Couldn't migrate pages");
+                       }
                        return -2;
                }
-               failures = 0;
+               successes++;
                tmp = n2;
                n2 = n1;
                n1 = tmp;
-- 
2.47.3


Reply via email to