1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * The main purpose of the tests here is to exercise the migration entry code 4 * paths in the kernel. 5 */ 6 7 #include "kselftest_harness.h" 8 #include "hugepage_settings.h" 9 10 #include <strings.h> 11 #include <pthread.h> 12 #include <numa.h> 13 #include <numaif.h> 14 #include <sys/mman.h> 15 #include <sys/prctl.h> 16 #include <sys/types.h> 17 #include <signal.h> 18 #include <time.h> 19 #include "vm_util.h" 20 21 #define TWOMEG (2<<20) 22 #define RUNTIME (20) 23 #define MAX_RETRIES 100 24 #define ALIGN(x, a) (((x) + (a - 1)) & (~((a) - 1))) 25 26 HUGETLB_SETUP_DEFAULT_PAGES(1) 27 28 FIXTURE(migration) 29 { 30 pthread_t *threads; 31 pid_t *pids; 32 int nthreads; 33 int n1; 34 int n2; 35 }; 36 37 static void reset_signals(void) 38 { 39 struct sigaction sa = { .sa_handler = SIG_DFL }; 40 41 sigemptyset(&sa.sa_mask); 42 sigaction(SIGTERM, &sa, NULL); 43 sigaction(SIGHUP, &sa, NULL); 44 sigaction(SIGINT, &sa, NULL); 45 sigaction(SIGQUIT, &sa, NULL); 46 } 47 48 FIXTURE_SETUP(migration) 49 { 50 int n; 51 52 reset_signals(); 53 54 if (numa_available() < 0) 55 SKIP(return, "NUMA not available"); 56 self->nthreads = numa_num_task_cpus() - 2; 57 self->n1 = -1; 58 self->n2 = -1; 59 60 for (n = 0; n < numa_max_possible_node(); n++) 61 if (numa_bitmask_isbitset(numa_all_nodes_ptr, n)) { 62 if (self->n1 == -1) { 63 self->n1 = n; 64 } else { 65 self->n2 = n; 66 break; 67 } 68 } 69 70 if (self->nthreads < 1 || self->n1 < 0 || self->n2 < 0) 71 SKIP(return, "Not enough threads or NUMA nodes available"); 72 73 self->threads = malloc(self->nthreads * sizeof(*self->threads)); 74 ASSERT_NE(self->threads, NULL); 75 self->pids = malloc(self->nthreads * sizeof(*self->pids)); 76 ASSERT_NE(self->pids, NULL); 77 }; 78 79 FIXTURE_TEARDOWN(migration) 80 { 81 free(self->threads); 82 free(self->pids); 83 } 84 85 static bool kill_children(FIXTURE_DATA(migration) * self) 86 { 87 bool err = false; 88 pid_t pid; 89 int i; 90 91 for (i = 0; i < self->nthreads; i++) { 92 int status = 0; 93 94 pid = self->pids[i]; 95 if (pid < 0) 96 continue; 97 if (kill(pid, SIGTERM)) 98 err = true; 99 if (pid != waitpid(pid, &status, 0)) 100 err = true; 101 if (!WIFSIGNALED(status) || WTERMSIG(status) != SIGTERM) 102 err = true; 103 } 104 105 return !err; 106 } 107 108 int migrate(uint64_t *ptr, int n1, int n2) 109 { 110 int ret, tmp; 111 int status = 0; 112 struct timespec ts1, ts2; 113 int failures = 0; 114 115 if (clock_gettime(CLOCK_MONOTONIC, &ts1)) 116 return -1; 117 118 while (1) { 119 if (clock_gettime(CLOCK_MONOTONIC, &ts2)) 120 return -1; 121 122 if (ts2.tv_sec - ts1.tv_sec >= RUNTIME) 123 return 0; 124 125 ret = move_pages(0, 1, (void **) &ptr, &n2, &status, 126 MPOL_MF_MOVE_ALL); 127 if (ret) { 128 if (ret > 0) { 129 /* Migration is best effort; try again */ 130 if (++failures < MAX_RETRIES) 131 continue; 132 printf("Didn't migrate %d pages\n", ret); 133 } 134 else 135 perror("Couldn't migrate pages"); 136 return -2; 137 } 138 failures = 0; 139 tmp = n2; 140 n2 = n1; 141 n1 = tmp; 142 } 143 144 return 0; 145 } 146 147 void *access_mem(void *ptr) 148 { 149 while (1) { 150 pthread_testcancel(); 151 /* Force a read from the memory pointed to by ptr. This ensures 152 * the memory access actually happens and prevents the compiler 153 * from optimizing away this entire loop. 154 */ 155 FORCE_READ(*(uint64_t *)ptr); 156 } 157 158 return NULL; 159 } 160 161 /* 162 * Basic migration entry testing. One thread will move pages back and forth 163 * between nodes whilst other threads try and access them triggering the 164 * migration entry wait paths in the kernel. 165 */ 166 TEST_F_TIMEOUT(migration, private_anon, 2*RUNTIME) 167 { 168 uint64_t *ptr; 169 int i; 170 171 ptr = mmap(NULL, TWOMEG, PROT_READ | PROT_WRITE, 172 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); 173 ASSERT_NE(ptr, MAP_FAILED); 174 175 memset(ptr, 0xde, TWOMEG); 176 for (i = 0; i < self->nthreads; i++) 177 if (pthread_create(&self->threads[i], NULL, access_mem, ptr)) 178 perror("Couldn't create thread"); 179 180 ASSERT_EQ(migrate(ptr, self->n1, self->n2), 0); 181 for (i = 0; i < self->nthreads; i++) 182 ASSERT_EQ(pthread_cancel(self->threads[i]), 0); 183 } 184 185 /* 186 * Same as the previous test but with shared memory. 187 */ 188 TEST_F_TIMEOUT(migration, shared_anon, 2*RUNTIME) 189 { 190 pid_t pid; 191 uint64_t *ptr; 192 int i, err; 193 194 ptr = mmap(NULL, TWOMEG, PROT_READ | PROT_WRITE, 195 MAP_SHARED | MAP_ANONYMOUS, -1, 0); 196 ASSERT_NE(ptr, MAP_FAILED); 197 198 memset(ptr, 0xde, TWOMEG); 199 for (i = 0; i < self->nthreads; i++) { 200 pid = fork(); 201 if (!pid) { 202 prctl(PR_SET_PDEATHSIG, SIGHUP); 203 /* Parent may have died before prctl so check now. */ 204 if (getppid() == 1) 205 kill(getpid(), SIGHUP); 206 access_mem(ptr); 207 } else { 208 self->pids[i] = pid; 209 } 210 } 211 212 err = migrate(ptr, self->n1, self->n2); 213 ASSERT_EQ(kill_children(self), true); 214 ASSERT_EQ(err, 0); 215 } 216 217 /* 218 * Tests the pmd migration entry paths. 219 */ 220 TEST_F_TIMEOUT(migration, private_anon_thp, 2*RUNTIME) 221 { 222 uint64_t pmdsize; 223 uint64_t *ptr; 224 int i; 225 226 if (!thp_is_enabled()) 227 SKIP(return, "Transparent Hugepages not available"); 228 229 pmdsize = read_pmd_pagesize(); 230 if (!pmdsize) 231 SKIP(return, "Reading PMD pagesize failed"); 232 233 ptr = mmap(NULL, 2 * pmdsize, PROT_READ | PROT_WRITE, 234 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); 235 ASSERT_NE(ptr, MAP_FAILED); 236 237 ptr = (uint64_t *) ALIGN((uintptr_t) ptr, pmdsize); 238 ASSERT_EQ(madvise(ptr, pmdsize, MADV_HUGEPAGE), 0); 239 memset(ptr, 0xde, pmdsize); 240 for (i = 0; i < self->nthreads; i++) 241 if (pthread_create(&self->threads[i], NULL, access_mem, ptr)) 242 perror("Couldn't create thread"); 243 244 ASSERT_EQ(migrate(ptr, self->n1, self->n2), 0); 245 for (i = 0; i < self->nthreads; i++) 246 ASSERT_EQ(pthread_cancel(self->threads[i]), 0); 247 } 248 249 /* 250 * migration test with shared anon THP page 251 */ 252 253 TEST_F_TIMEOUT(migration, shared_anon_thp, 2*RUNTIME) 254 { 255 uint64_t pmdsize; 256 pid_t pid; 257 uint64_t *ptr; 258 int i, err; 259 260 if (!thp_is_enabled()) 261 SKIP(return, "Transparent Hugepages not available"); 262 263 pmdsize = read_pmd_pagesize(); 264 if (!pmdsize) 265 SKIP(return, "Reading PMD pagesize failed"); 266 267 ptr = mmap(NULL, 2 * pmdsize, PROT_READ | PROT_WRITE, 268 MAP_SHARED | MAP_ANONYMOUS, -1, 0); 269 ASSERT_NE(ptr, MAP_FAILED); 270 271 ptr = (uint64_t *) ALIGN((uintptr_t) ptr, pmdsize); 272 ASSERT_EQ(madvise(ptr, pmdsize, MADV_HUGEPAGE), 0); 273 274 memset(ptr, 0xde, pmdsize); 275 for (i = 0; i < self->nthreads; i++) { 276 pid = fork(); 277 if (!pid) { 278 prctl(PR_SET_PDEATHSIG, SIGHUP); 279 /* Parent may have died before prctl so check now. */ 280 if (getppid() == 1) 281 kill(getpid(), SIGHUP); 282 access_mem(ptr); 283 } else { 284 self->pids[i] = pid; 285 } 286 } 287 288 err = migrate(ptr, self->n1, self->n2); 289 ASSERT_EQ(kill_children(self), true); 290 ASSERT_EQ(err, 0); 291 } 292 293 /* 294 * migration test with private anon hugetlb page 295 */ 296 TEST_F_TIMEOUT(migration, private_anon_htlb, 2*RUNTIME) 297 { 298 unsigned long hugepage_size; 299 uint64_t *ptr; 300 int i; 301 302 hugepage_size = default_huge_page_size(); 303 if (!hugepage_size) 304 SKIP(return, "Reading HugeTLB pagesize failed"); 305 306 if (hugetlb_free_default_pages() < 1) 307 SKIP(return, "Not enough huge pages"); 308 309 ptr = mmap(NULL, hugepage_size, PROT_READ | PROT_WRITE, 310 MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGETLB, -1, 0); 311 ASSERT_NE(ptr, MAP_FAILED); 312 313 memset(ptr, 0xde, hugepage_size); 314 for (i = 0; i < self->nthreads; i++) 315 if (pthread_create(&self->threads[i], NULL, access_mem, ptr)) 316 perror("Couldn't create thread"); 317 318 ASSERT_EQ(migrate(ptr, self->n1, self->n2), 0); 319 for (i = 0; i < self->nthreads; i++) 320 ASSERT_EQ(pthread_cancel(self->threads[i]), 0); 321 } 322 323 /* 324 * migration test with shared anon hugetlb page 325 */ 326 TEST_F_TIMEOUT(migration, shared_anon_htlb, 2*RUNTIME) 327 { 328 unsigned long hugepage_size; 329 pid_t pid; 330 uint64_t *ptr; 331 int i, err; 332 333 hugepage_size = default_huge_page_size(); 334 if (!hugepage_size) 335 SKIP(return, "Reading HugeTLB pagesize failed"); 336 337 if (hugetlb_free_default_pages() < 1) 338 SKIP(return, "Not enough huge pages"); 339 340 ptr = mmap(NULL, hugepage_size, PROT_READ | PROT_WRITE, 341 MAP_SHARED | MAP_ANONYMOUS | MAP_HUGETLB, -1, 0); 342 ASSERT_NE(ptr, MAP_FAILED); 343 344 memset(ptr, 0xde, hugepage_size); 345 for (i = 0; i < self->nthreads; i++) { 346 pid = fork(); 347 if (!pid) { 348 prctl(PR_SET_PDEATHSIG, SIGHUP); 349 /* Parent may have died before prctl so check now. */ 350 if (getppid() == 1) 351 kill(getpid(), SIGHUP); 352 access_mem(ptr); 353 } else { 354 self->pids[i] = pid; 355 } 356 } 357 358 err = migrate(ptr, self->n1, self->n2); 359 ASSERT_EQ(kill_children(self), true); 360 ASSERT_EQ(err, 0); 361 } 362 363 TEST_HARNESS_MAIN 364