1 #define _GNU_SOURCE 2 #include <ctype.h> 3 #include <errno.h> 4 #include <fcntl.h> 5 #include <limits.h> 6 #include <dirent.h> 7 #include <signal.h> 8 #include <stdio.h> 9 #include <stdlib.h> 10 #include <stdbool.h> 11 #include <string.h> 12 #include <unistd.h> 13 14 #include <linux/mman.h> 15 #include <sys/mman.h> 16 #include <sys/wait.h> 17 #include <sys/types.h> 18 #include <sys/stat.h> 19 #include <sys/sysmacros.h> 20 #include <sys/vfs.h> 21 22 #include "linux/magic.h" 23 24 #include "vm_util.h" 25 #include "hugepage_settings.h" 26 27 #define BASE_ADDR ((void *)(1UL << 30)) 28 static unsigned long hpage_pmd_size; 29 static unsigned long page_size; 30 static int hpage_pmd_nr; 31 static int anon_order; 32 33 #define PID_SMAPS "/proc/self/smaps" 34 #define TEST_FILE "collapse_test_file" 35 36 #define MAX_LINE_LENGTH 500 37 38 enum vma_type { 39 VMA_ANON, 40 VMA_FILE, 41 VMA_SHMEM, 42 }; 43 44 enum file_setup_ops { 45 FILE_SETUP_READ_ONLY_FS, 46 FILE_SETUP_READ_WRITE_FS_READ_DATA, 47 FILE_SETUP_READ_WRITE_FS_WRITE_DATA, 48 }; 49 50 struct mem_ops { 51 void *(*setup_area)(int nr_hpages); 52 void (*cleanup_area)(void *p, unsigned long size); 53 void (*fault)(void *p, unsigned long start, unsigned long end); 54 bool (*check_huge)(void *addr, int nr_hpages); 55 const char *name; 56 }; 57 58 static struct mem_ops *read_only_file_ops; 59 static struct mem_ops *read_write_file_read_ops; 60 static struct mem_ops *read_write_file_write_ops; 61 static struct mem_ops *anon_ops; 62 static struct mem_ops *shmem_ops; 63 64 struct collapse_context { 65 void (*collapse)(const char *msg, char *p, int nr_hpages, 66 struct mem_ops *ops, bool expect); 67 bool enforce_pte_scan_limits; 68 const char *name; 69 }; 70 71 static struct collapse_context *khugepaged_context; 72 static struct collapse_context *madvise_context; 73 74 struct file_info { 75 const char *dir; 76 char path[PATH_MAX]; 77 enum vma_type type; 78 int fd; 79 char dev_queue_read_ahead_path[PATH_MAX]; 80 }; 81 82 static struct file_info finfo; 83 static int exit_status; 84 85 static void success(const char *msg) 86 { 87 printf(" \e[32m%s\e[0m\n", msg); 88 exit_status = KSFT_PASS; 89 } 90 91 static void fail(const char *msg) 92 { 93 printf(" \e[31m%s\e[0m\n", msg); 94 exit_status = KSFT_FAIL; 95 } 96 97 static void skip(const char *msg) 98 { 99 printf(" \e[33m%s\e[0m\n", msg); 100 exit_status = KSFT_SKIP; 101 } 102 103 static void save_settings(void) 104 { 105 ksft_print_msg("Save THP and khugepaged settings..."); 106 if ((read_only_file_ops || read_write_file_read_ops || 107 read_write_file_write_ops) && 108 finfo.type == VMA_FILE) 109 thp_set_read_ahead_path(finfo.dev_queue_read_ahead_path); 110 thp_save_settings(); 111 112 success("OK"); 113 } 114 115 static void get_finfo(const char *dir) 116 { 117 struct stat path_stat; 118 struct statfs fs; 119 char buf[1 << 10]; 120 char path[PATH_MAX]; 121 char *str, *end; 122 123 finfo.dir = dir; 124 stat(finfo.dir, &path_stat); 125 if (!S_ISDIR(path_stat.st_mode)) 126 ksft_exit_fail_msg("%s: Not a directory (%s)\n", __func__, finfo.dir); 127 if (snprintf(finfo.path, sizeof(finfo.path), "%s/" TEST_FILE, 128 finfo.dir) >= sizeof(finfo.path)) 129 ksft_exit_fail_msg("%s: Pathname is too long\n", __func__); 130 if (statfs(finfo.dir, &fs)) 131 ksft_exit_fail_perror("statfs()"); 132 finfo.type = fs.f_type == TMPFS_MAGIC ? VMA_SHMEM : VMA_FILE; 133 if (finfo.type == VMA_SHMEM) 134 return; 135 136 /* Find owning device's queue/read_ahead_kb control */ 137 if (snprintf(path, sizeof(path), "/sys/dev/block/%d:%d/uevent", 138 major(path_stat.st_dev), minor(path_stat.st_dev)) 139 >= sizeof(path)) 140 ksft_exit_fail_msg("%s: Pathname is too long\n", __func__); 141 if (read_file(path, buf, sizeof(buf)) < 0) 142 ksft_exit_fail_perror("read_file(read_num)"); 143 if (strstr(buf, "DEVTYPE=disk")) { 144 /* Found it */ 145 if (snprintf(finfo.dev_queue_read_ahead_path, 146 sizeof(finfo.dev_queue_read_ahead_path), 147 "/sys/dev/block/%d:%d/queue/read_ahead_kb", 148 major(path_stat.st_dev), minor(path_stat.st_dev)) 149 >= sizeof(finfo.dev_queue_read_ahead_path)) 150 ksft_exit_fail_msg("%s: Pathname is too long\n", __func__); 151 return; 152 } 153 if (!strstr(buf, "DEVTYPE=partition")) 154 ksft_exit_fail_msg("%s: Unknown device type: %s\n", __func__, path); 155 /* 156 * Partition of block device - need to find actual device. 157 * Using naming convention that devnameN is partition of 158 * device devname. 159 */ 160 str = strstr(buf, "DEVNAME="); 161 if (!str) 162 ksft_exit_fail_msg("%s: Could not read: %s", __func__, path); 163 str += 8; 164 end = str; 165 while (*end) { 166 if (isdigit(*end)) { 167 *end = '\0'; 168 if (snprintf(finfo.dev_queue_read_ahead_path, 169 sizeof(finfo.dev_queue_read_ahead_path), 170 "/sys/block/%s/queue/read_ahead_kb", 171 str) >= sizeof(finfo.dev_queue_read_ahead_path)) 172 ksft_exit_fail_msg("%s: Pathname is too long\n", __func__); 173 return; 174 } 175 ++end; 176 } 177 ksft_exit_fail_msg("%s: Could not read: %s\n", __func__, path); 178 } 179 180 static bool check_swap(void *addr, unsigned long size) 181 { 182 bool swap = false; 183 int ret; 184 FILE *fp; 185 char buffer[MAX_LINE_LENGTH]; 186 char addr_pattern[MAX_LINE_LENGTH]; 187 188 ret = snprintf(addr_pattern, MAX_LINE_LENGTH, "%08lx-", 189 (unsigned long) addr); 190 if (ret >= MAX_LINE_LENGTH) 191 ksft_exit_fail_msg("%s: Pattern is too long\n", __func__); 192 193 fp = fopen(PID_SMAPS, "r"); 194 if (!fp) 195 ksft_exit_fail_msg("%s: Failed to open file %s\n", __func__, PID_SMAPS); 196 if (!check_for_pattern(fp, addr_pattern, buffer, sizeof(buffer))) 197 goto err_out; 198 199 ret = snprintf(addr_pattern, MAX_LINE_LENGTH, "Swap:%19ld kB", 200 size >> 10); 201 if (ret >= MAX_LINE_LENGTH) 202 ksft_exit_fail_msg("%s: Pattern is too long\n", __func__); 203 /* 204 * Fetch the Swap: in the same block and check whether it got 205 * the expected number of hugeepages next. 206 */ 207 if (!check_for_pattern(fp, "Swap:", buffer, sizeof(buffer))) 208 goto err_out; 209 210 if (strncmp(buffer, addr_pattern, strlen(addr_pattern))) 211 goto err_out; 212 213 swap = true; 214 err_out: 215 fclose(fp); 216 return swap; 217 } 218 219 static void *alloc_mapping(int nr) 220 { 221 void *p; 222 223 p = mmap(BASE_ADDR, nr * hpage_pmd_size, PROT_READ | PROT_WRITE, 224 MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); 225 if (p != BASE_ADDR) 226 ksft_exit_fail_msg("Failed to allocate VMA at %p\n", BASE_ADDR); 227 228 return p; 229 } 230 231 static void fill_memory(int *p, unsigned long start, unsigned long end) 232 { 233 int i; 234 235 for (i = start / page_size; i < end / page_size; i++) 236 p[i * page_size / sizeof(*p)] = i + 0xdead0000; 237 } 238 239 /* 240 * MADV_COLLAPSE is a best-effort request and may fail if an internal 241 * resource is temporarily unavailable, in which case it will set errno to 242 * EAGAIN. In such a case, immediately reattempt the operation one more 243 * time. 244 */ 245 static int madvise_collapse_retry(void *p, unsigned long size) 246 { 247 bool retry = true; 248 int ret; 249 250 retry: 251 ret = madvise(p, size, MADV_COLLAPSE); 252 if (ret && errno == EAGAIN && retry) { 253 retry = false; 254 goto retry; 255 } 256 return ret; 257 } 258 259 /* 260 * Returns pmd-mapped hugepage in VMA marked VM_HUGEPAGE, filled with 261 * validate_memory()'able contents. 262 */ 263 static void *alloc_hpage(struct mem_ops *ops) 264 { 265 void *p = ops->setup_area(1); 266 267 ops->fault(p, 0, hpage_pmd_size); 268 269 /* 270 * VMA should be neither VM_HUGEPAGE nor VM_NOHUGEPAGE. 271 * The latter is ineligible for collapse by MADV_COLLAPSE 272 * while the former might cause MADV_COLLAPSE to race with 273 * khugepaged on low-load system (like a test machine), which 274 * would cause MADV_COLLAPSE to fail with EAGAIN. 275 */ 276 ksft_print_msg("Allocate huge page..."); 277 if (madvise_collapse_retry(p, hpage_pmd_size)) 278 ksft_exit_fail_perror("madvise(MADV_COLLAPSE)"); 279 if (!ops->check_huge(p, 1)) 280 ksft_exit_fail_perror("madvise(MADV_COLLAPSE)"); 281 if (madvise(p, hpage_pmd_size, MADV_HUGEPAGE)) 282 ksft_exit_fail_perror("madvise(MADV_HUGEPAGE)"); 283 success("OK"); 284 return p; 285 } 286 287 static void validate_memory(int *p, unsigned long start, unsigned long end) 288 { 289 int i; 290 291 for (i = start / page_size; i < end / page_size; i++) { 292 if (p[i * page_size / sizeof(*p)] != i + 0xdead0000) 293 ksft_exit_fail_msg("Page %d is corrupted: %#x\n", 294 i, p[i * page_size / sizeof(*p)]); 295 } 296 } 297 298 static void *anon_setup_area(int nr_hpages) 299 { 300 return alloc_mapping(nr_hpages); 301 } 302 303 static void anon_cleanup_area(void *p, unsigned long size) 304 { 305 munmap(p, size); 306 } 307 308 static void anon_fault(void *p, unsigned long start, unsigned long end) 309 { 310 fill_memory(p, start, end); 311 } 312 313 static bool anon_check_huge(void *addr, int nr_hpages) 314 { 315 return check_huge_anon(addr, nr_hpages, hpage_pmd_size); 316 } 317 318 static void *file_setup_area_common(int nr_hpages, enum file_setup_ops setup) 319 { 320 const int open_opt = setup == FILE_SETUP_READ_ONLY_FS ? O_RDONLY : O_RDWR; 321 const int mmap_prot = setup == FILE_SETUP_READ_ONLY_FS ? PROT_READ : (PROT_READ | PROT_WRITE); 322 int fd; 323 void *p; 324 unsigned long size; 325 326 unlink(finfo.path); /* Cleanup from previous failed tests */ 327 ksft_print_msg("Creating %s for collapse%s...", finfo.path, 328 finfo.type == VMA_SHMEM ? " (tmpfs)" : ""); 329 fd = open(finfo.path, O_CREAT | O_RDWR | O_TRUNC | O_EXCL, 330 777); 331 if (fd < 0) 332 ksft_exit_fail_perror("open()"); 333 334 size = nr_hpages * hpage_pmd_size; 335 if (ftruncate(fd, size)) { 336 perror("ftruncate()"); 337 exit(EXIT_FAILURE); 338 } 339 p = mmap(BASE_ADDR, size, PROT_READ | PROT_WRITE, 340 MAP_SHARED, fd, 0); 341 if (p != BASE_ADDR) { 342 perror("mmap()"); 343 exit(EXIT_FAILURE); 344 } 345 fill_memory(p, 0, size); 346 if (msync(p, size, MS_SYNC)) { 347 perror("msync()"); 348 exit(EXIT_FAILURE); 349 } 350 close(fd); 351 munmap(p, size); 352 success("OK"); 353 ksft_print_msg("Opening %s %s for collapse...", finfo.path, 354 setup == FILE_SETUP_READ_ONLY_FS ? "read-only" : 355 setup == FILE_SETUP_READ_WRITE_FS_READ_DATA ? 356 "read-write (read)" : 357 "read-write (write)"); 358 finfo.fd = open(finfo.path, open_opt, 777); 359 if (finfo.fd < 0) 360 ksft_exit_fail_perror("open()"); 361 p = mmap(BASE_ADDR, size, mmap_prot, MAP_SHARED, finfo.fd, 0); 362 if (p == MAP_FAILED || p != BASE_ADDR) 363 ksft_exit_fail_perror("mmap()"); 364 365 /* Drop page cache */ 366 write_file("/proc/sys/vm/drop_caches", "3", 2); 367 success("OK"); 368 return p; 369 } 370 371 static void *file_setup_read_only_area(int nr_hpages) 372 { 373 return file_setup_area_common(nr_hpages, FILE_SETUP_READ_ONLY_FS); 374 } 375 376 static void *file_setup_read_write_fs_read_area(int nr_hpages) 377 { 378 return file_setup_area_common(nr_hpages, FILE_SETUP_READ_WRITE_FS_READ_DATA); 379 } 380 381 static void *file_setup_read_write_fs_write_area(int nr_hpages) 382 { 383 return file_setup_area_common(nr_hpages, FILE_SETUP_READ_WRITE_FS_WRITE_DATA); 384 } 385 386 static void file_cleanup_area(void *p, unsigned long size) 387 { 388 munmap(p, size); 389 close(finfo.fd); 390 unlink(finfo.path); 391 } 392 393 static void file_fault_read(void *p, unsigned long start, unsigned long end) 394 { 395 if (madvise(((char *)p) + start, end - start, MADV_POPULATE_READ)) 396 ksft_exit_fail_perror("madvise(MADV_POPULATE_READ)"); 397 } 398 399 static void file_fault_read_and_flush(void *p, unsigned long start, unsigned long end) 400 { 401 file_fault_read(p, start, end); 402 /* 403 * make folio clean, since dirty folios from read&write file are 404 * rejected and not flushed 405 */ 406 msync((char *)p + start, end - start, MS_SYNC); 407 } 408 409 static void file_fault_write(void *p, unsigned long start, unsigned long end) 410 { 411 if (madvise(((char *)p) + start, end - start, MADV_POPULATE_WRITE)) 412 ksft_exit_fail_perror("madvise(MADV_POPULATE_WRITE)"); 413 } 414 415 static bool file_check_huge(void *addr, int nr_hpages) 416 { 417 switch (finfo.type) { 418 case VMA_FILE: 419 return check_huge_file(addr, nr_hpages, hpage_pmd_size); 420 case VMA_SHMEM: 421 return check_huge_shmem(addr, nr_hpages, hpage_pmd_size); 422 default: 423 exit(EXIT_FAILURE); 424 return false; 425 } 426 } 427 428 static void *shmem_setup_area(int nr_hpages) 429 { 430 void *p; 431 unsigned long size = nr_hpages * hpage_pmd_size; 432 433 finfo.fd = memfd_create("khugepaged-selftest-collapse-shmem", 0); 434 if (finfo.fd < 0) 435 ksft_exit_fail_perror("memfd_create()"); 436 if (ftruncate(finfo.fd, size)) 437 ksft_exit_fail_perror("ftruncate()"); 438 p = mmap(BASE_ADDR, size, PROT_READ | PROT_WRITE, MAP_SHARED, finfo.fd, 439 0); 440 if (p != BASE_ADDR) 441 ksft_exit_fail_perror("mmap()"); 442 return p; 443 } 444 445 static void shmem_cleanup_area(void *p, unsigned long size) 446 { 447 munmap(p, size); 448 close(finfo.fd); 449 } 450 451 static bool shmem_check_huge(void *addr, int nr_hpages) 452 { 453 return check_huge_shmem(addr, nr_hpages, hpage_pmd_size); 454 } 455 456 static struct mem_ops __anon_ops = { 457 .setup_area = &anon_setup_area, 458 .cleanup_area = &anon_cleanup_area, 459 .fault = &anon_fault, 460 .check_huge = &anon_check_huge, 461 .name = "anon", 462 }; 463 464 static struct mem_ops __read_only_file_ops = { 465 .setup_area = &file_setup_read_only_area, 466 .cleanup_area = &file_cleanup_area, 467 .fault = &file_fault_read, 468 .check_huge = &file_check_huge, 469 .name = "file", 470 }; 471 472 static struct mem_ops __read_write_file_read_ops = { 473 .setup_area = &file_setup_read_write_fs_read_area, 474 .cleanup_area = &file_cleanup_area, 475 .fault = &file_fault_read_and_flush, 476 .check_huge = &file_check_huge, 477 .name = "file", 478 }; 479 480 static struct mem_ops __read_write_file_write_ops = { 481 .setup_area = &file_setup_read_write_fs_write_area, 482 .cleanup_area = &file_cleanup_area, 483 .fault = &file_fault_write, 484 .check_huge = &file_check_huge, 485 .name = "file", 486 }; 487 488 static struct mem_ops __shmem_ops = { 489 .setup_area = &shmem_setup_area, 490 .cleanup_area = &shmem_cleanup_area, 491 .fault = &anon_fault, 492 .check_huge = &shmem_check_huge, 493 .name = "shmem", 494 }; 495 496 static bool is_tmpfs(struct mem_ops *ops) 497 { 498 return (ops == &__read_only_file_ops || 499 ops == &__read_write_file_read_ops || 500 ops == &__read_write_file_write_ops) && 501 finfo.type == VMA_SHMEM; 502 } 503 504 static bool is_anon(struct mem_ops *ops) 505 { 506 return ops == &__anon_ops; 507 } 508 509 static void __madvise_collapse(const char *msg, char *p, int nr_hpages, 510 struct mem_ops *ops, bool expect) 511 { 512 int ret; 513 struct thp_settings settings = *thp_current_settings(); 514 515 ksft_print_msg("%s...", msg); 516 517 /* 518 * read&write file collapse succeeds for MADV_COLLAPSE because dirty 519 * folios are written back after collapse fails for dirty folios and 520 * another collapse is attempted. 521 */ 522 523 /* 524 * Prevent khugepaged interference and tests that MADV_COLLAPSE 525 * ignores /sys/kernel/mm/transparent_hugepage/enabled 526 */ 527 settings.thp_enabled = THP_NEVER; 528 settings.shmem_enabled = SHMEM_NEVER; 529 thp_push_settings(&settings); 530 531 /* Clear VM_NOHUGEPAGE */ 532 madvise(p, nr_hpages * hpage_pmd_size, MADV_HUGEPAGE); 533 ret = madvise_collapse_retry(p, nr_hpages * hpage_pmd_size); 534 if (((bool)ret) == expect) 535 fail("Fail: Bad return value"); 536 else if (!ops->check_huge(p, expect ? nr_hpages : 0)) 537 fail("Fail: check_huge()"); 538 else 539 success("OK"); 540 541 thp_pop_settings(); 542 } 543 544 static void madvise_collapse(const char *msg, char *p, int nr_hpages, 545 struct mem_ops *ops, bool expect) 546 { 547 /* Sanity check */ 548 if (!ops->check_huge(p, 0)) 549 ksft_exit_fail_msg("Unexpected huge page\n"); 550 __madvise_collapse(msg, p, nr_hpages, ops, expect); 551 } 552 553 #define TICK 500000 554 static bool wait_for_scan(const char *msg, char *p, int nr_hpages, 555 struct mem_ops *ops) 556 { 557 int full_scans; 558 int timeout = 6; /* 3 seconds */ 559 560 /* Sanity check */ 561 if (!ops->check_huge(p, 0)) 562 ksft_exit_fail_msg("Unexpected huge page\n"); 563 564 madvise(p, nr_hpages * hpage_pmd_size, MADV_HUGEPAGE); 565 566 /* Wait until the second full_scan completed */ 567 full_scans = thp_read_num("khugepaged/full_scans") + 2; 568 569 ksft_print_msg("%s...", msg); 570 while (timeout--) { 571 if (ops->check_huge(p, nr_hpages)) 572 break; 573 if (thp_read_num("khugepaged/full_scans") >= full_scans) 574 break; 575 printf("."); 576 usleep(TICK); 577 } 578 579 return timeout == -1; 580 } 581 582 static void khugepaged_collapse(const char *msg, char *p, int nr_hpages, 583 struct mem_ops *ops, bool expect) 584 { 585 /* 586 * read&write file collapse fails since khugepaged does not flush 587 * the target dirty folios 588 */ 589 if (!is_tmpfs(ops) && ops == &__read_write_file_write_ops) 590 expect = false; 591 592 if (wait_for_scan(msg, p, nr_hpages, ops)) { 593 if (expect) 594 fail("Timeout"); 595 else 596 success("OK"); 597 return; 598 } 599 600 /* 601 * For file and shmem memory, khugepaged only retracts pte entries after 602 * putting the new hugepage in the page cache. The hugepage must be 603 * subsequently refaulted to install the pmd mapping for the mm. 604 */ 605 if (ops != &__anon_ops) 606 ops->fault(p, 0, nr_hpages * hpage_pmd_size); 607 608 if (ops->check_huge(p, expect ? nr_hpages : 0)) 609 success("OK"); 610 else 611 fail("Fail"); 612 } 613 614 static struct collapse_context __khugepaged_context = { 615 .collapse = &khugepaged_collapse, 616 .enforce_pte_scan_limits = true, 617 .name = "khugepaged", 618 }; 619 620 static struct collapse_context __madvise_context = { 621 .collapse = &madvise_collapse, 622 .enforce_pte_scan_limits = false, 623 .name = "madvise", 624 }; 625 626 static void alloc_at_fault(void) 627 { 628 struct thp_settings settings = *thp_current_settings(); 629 char *p; 630 631 settings.thp_enabled = THP_ALWAYS; 632 thp_push_settings(&settings); 633 634 p = alloc_mapping(1); 635 *p = 1; 636 ksft_print_msg("Allocate huge page on fault..."); 637 if (check_huge_anon(p, 1, hpage_pmd_size)) 638 success("OK"); 639 else 640 fail("Fail"); 641 642 thp_pop_settings(); 643 644 madvise(p, page_size, MADV_DONTNEED); 645 ksft_print_msg("Split huge PMD on MADV_DONTNEED..."); 646 if (check_huge_anon(p, 0, hpage_pmd_size)) 647 success("OK"); 648 else 649 fail("Fail"); 650 munmap(p, hpage_pmd_size); 651 652 ksft_test_result_report(exit_status, "allocate on fault and split\n"); 653 } 654 655 static void collapse_full(struct collapse_context *c, struct mem_ops *ops) 656 { 657 void *p; 658 int nr_hpages = 4; 659 unsigned long size = nr_hpages * hpage_pmd_size; 660 661 p = ops->setup_area(nr_hpages); 662 ops->fault(p, 0, size); 663 c->collapse("Collapse multiple fully populated PTE table", p, nr_hpages, 664 ops, true); 665 validate_memory(p, 0, size); 666 ops->cleanup_area(p, size); 667 668 ksft_test_result_report(exit_status, "%s\n", __func__); 669 } 670 671 static void collapse_empty(struct collapse_context *c, struct mem_ops *ops) 672 { 673 void *p; 674 675 p = ops->setup_area(1); 676 c->collapse("Do not collapse empty PTE table", p, 1, ops, false); 677 ops->cleanup_area(p, hpage_pmd_size); 678 ksft_test_result_report(exit_status, "%s\n", __func__); 679 } 680 681 static void collapse_single_pte_entry(struct collapse_context *c, struct mem_ops *ops) 682 { 683 void *p; 684 685 p = ops->setup_area(1); 686 ops->fault(p, 0, page_size); 687 c->collapse("Collapse PTE table with single PTE entry present", p, 688 1, ops, true); 689 ops->cleanup_area(p, hpage_pmd_size); 690 ksft_test_result_report(exit_status, "%s\n", __func__); 691 } 692 693 static void collapse_max_ptes_none(struct collapse_context *c, struct mem_ops *ops) 694 { 695 int max_ptes_none = hpage_pmd_nr / 2; 696 struct thp_settings settings = *thp_current_settings(); 697 void *p; 698 int fault_nr_pages = is_anon(ops) ? 1 << anon_order : 1; 699 700 settings.khugepaged.max_ptes_none = max_ptes_none; 701 thp_push_settings(&settings); 702 703 p = ops->setup_area(1); 704 705 if (is_tmpfs(ops)) { 706 /* shmem pages always in the page cache */ 707 printf("tmpfs..."); 708 skip("Skip"); 709 goto skip; 710 } 711 712 ops->fault(p, 0, (hpage_pmd_nr - max_ptes_none - fault_nr_pages) * page_size); 713 c->collapse("Maybe collapse with max_ptes_none exceeded", p, 1, 714 ops, !c->enforce_pte_scan_limits); 715 validate_memory(p, 0, (hpage_pmd_nr - max_ptes_none - fault_nr_pages) * page_size); 716 717 if (c->enforce_pte_scan_limits) { 718 ops->cleanup_area(p, hpage_pmd_size); 719 p = ops->setup_area(1); 720 721 ops->fault(p, 0, (hpage_pmd_nr - max_ptes_none) * page_size); 722 c->collapse("Collapse with max_ptes_none PTEs empty", p, 1, ops, 723 true); 724 validate_memory(p, 0, 725 (hpage_pmd_nr - max_ptes_none) * page_size); 726 } 727 skip: 728 ops->cleanup_area(p, hpage_pmd_size); 729 thp_pop_settings(); 730 ksft_test_result_report(exit_status, "%s\n", __func__); 731 } 732 733 static void collapse_swapin_single_pte(struct collapse_context *c, struct mem_ops *ops) 734 { 735 void *p; 736 737 p = ops->setup_area(1); 738 ops->fault(p, 0, hpage_pmd_size); 739 740 ksft_print_msg("Swapout one page..."); 741 if (madvise(p, page_size, MADV_PAGEOUT)) 742 ksft_exit_fail_perror("madvise(MADV_PAGEOUT)"); 743 if (check_swap(p, page_size)) { 744 success("OK"); 745 } else { 746 fail("Fail"); 747 goto out; 748 } 749 750 c->collapse("Collapse with swapping in single PTE entry", p, 1, ops, 751 true); 752 validate_memory(p, 0, hpage_pmd_size); 753 out: 754 ops->cleanup_area(p, hpage_pmd_size); 755 ksft_test_result_report(exit_status, "%s\n", __func__); 756 } 757 758 static void collapse_max_ptes_swap(struct collapse_context *c, struct mem_ops *ops) 759 { 760 int max_ptes_swap = thp_read_num("khugepaged/max_ptes_swap"); 761 void *p; 762 763 p = ops->setup_area(1); 764 ops->fault(p, 0, hpage_pmd_size); 765 766 ksft_print_msg("Swapout %d of %d pages...", max_ptes_swap + 1, hpage_pmd_nr); 767 if (madvise(p, (max_ptes_swap + 1) * page_size, MADV_PAGEOUT)) 768 ksft_exit_fail_perror("madvise(MADV_PAGEOUT)"); 769 if (check_swap(p, (max_ptes_swap + 1) * page_size)) { 770 success("OK"); 771 } else { 772 fail("Fail"); 773 goto out; 774 } 775 776 c->collapse("Maybe collapse with max_ptes_swap exceeded", p, 1, ops, 777 !c->enforce_pte_scan_limits); 778 validate_memory(p, 0, hpage_pmd_size); 779 780 if (c->enforce_pte_scan_limits) { 781 ops->fault(p, 0, hpage_pmd_size); 782 ksft_print_msg("Swapout %d of %d pages...", max_ptes_swap, 783 hpage_pmd_nr); 784 if (madvise(p, max_ptes_swap * page_size, MADV_PAGEOUT)) 785 ksft_exit_fail_perror("madvise(MADV_PAGEOUT)"); 786 if (check_swap(p, max_ptes_swap * page_size)) { 787 success("OK"); 788 } else { 789 fail("Fail"); 790 goto out; 791 } 792 793 c->collapse("Collapse with max_ptes_swap pages swapped out", p, 794 1, ops, true); 795 validate_memory(p, 0, hpage_pmd_size); 796 } 797 out: 798 ops->cleanup_area(p, hpage_pmd_size); 799 ksft_test_result_report(exit_status, "%s\n", __func__); 800 } 801 802 static void collapse_single_pte_entry_compound(struct collapse_context *c, struct mem_ops *ops) 803 { 804 void *p; 805 806 p = alloc_hpage(ops); 807 808 if (is_tmpfs(ops)) { 809 /* MADV_DONTNEED won't evict tmpfs pages */ 810 printf("tmpfs..."); 811 skip("Skip"); 812 goto skip; 813 } 814 815 madvise(p, hpage_pmd_size, MADV_NOHUGEPAGE); 816 ksft_print_msg("Split huge page leaving single PTE mapping compound page..."); 817 madvise(p + page_size, hpage_pmd_size - page_size, MADV_DONTNEED); 818 if (ops->check_huge(p, 0)) 819 success("OK"); 820 else 821 fail("Fail"); 822 823 c->collapse("Collapse PTE table with single PTE mapping compound page", 824 p, 1, ops, true); 825 validate_memory(p, 0, page_size); 826 skip: 827 ops->cleanup_area(p, hpage_pmd_size); 828 ksft_test_result_report(exit_status, "%s\n", __func__); 829 } 830 831 static void collapse_full_of_compound(struct collapse_context *c, struct mem_ops *ops) 832 { 833 void *p; 834 835 p = alloc_hpage(ops); 836 ksft_print_msg("Split huge page leaving single PTE page table full of compound pages..."); 837 madvise(p, page_size, MADV_NOHUGEPAGE); 838 madvise(p, hpage_pmd_size, MADV_NOHUGEPAGE); 839 if (ops->check_huge(p, 0)) 840 success("OK"); 841 else 842 fail("Fail"); 843 844 c->collapse("Collapse PTE table full of compound pages", p, 1, ops, 845 true); 846 validate_memory(p, 0, hpage_pmd_size); 847 ops->cleanup_area(p, hpage_pmd_size); 848 ksft_test_result_report(exit_status, "%s\n", __func__); 849 } 850 851 static void collapse_compound_extreme(struct collapse_context *c, struct mem_ops *ops) 852 { 853 void *p; 854 int i; 855 856 p = ops->setup_area(1); 857 ksft_print_msg("Construct PTE page table full of different PTE-mapped compound pages\n"); 858 for (i = 0; i < hpage_pmd_nr; i++) { 859 madvise(BASE_ADDR, hpage_pmd_size, MADV_HUGEPAGE); 860 ops->fault(BASE_ADDR, 0, hpage_pmd_size); 861 if (!ops->check_huge(BASE_ADDR, 1)) 862 ksft_exit_fail_msg("Failed to allocate huge page\n"); 863 madvise(BASE_ADDR, hpage_pmd_size, MADV_NOHUGEPAGE); 864 865 p = mremap(BASE_ADDR - i * page_size, 866 i * page_size + hpage_pmd_size, 867 (i + 1) * page_size, 868 MREMAP_MAYMOVE | MREMAP_FIXED, 869 BASE_ADDR + 2 * hpage_pmd_size); 870 if (p == MAP_FAILED) 871 ksft_exit_fail_perror("mremap+unmap"); 872 873 p = mremap(BASE_ADDR + 2 * hpage_pmd_size, 874 (i + 1) * page_size, 875 (i + 1) * page_size + hpage_pmd_size, 876 MREMAP_MAYMOVE | MREMAP_FIXED, 877 BASE_ADDR - (i + 1) * page_size); 878 if (p == MAP_FAILED) 879 ksft_exit_fail_perror("mremap+alloc"); 880 } 881 882 ops->cleanup_area(BASE_ADDR, hpage_pmd_size); 883 ops->fault(p, 0, hpage_pmd_size); 884 if (!ops->check_huge(p, 1)) 885 success("OK"); 886 else 887 fail("Fail"); 888 889 c->collapse("Collapse PTE table full of different compound pages", p, 1, 890 ops, true); 891 892 validate_memory(p, 0, hpage_pmd_size); 893 ops->cleanup_area(p, hpage_pmd_size); 894 ksft_test_result_report(exit_status, "%s\n", __func__); 895 } 896 897 static void collapse_fork(struct collapse_context *c, struct mem_ops *ops) 898 { 899 int wstatus; 900 void *p; 901 902 p = ops->setup_area(1); 903 904 ksft_print_msg("Allocate small page..."); 905 ops->fault(p, 0, page_size); 906 if (ops->check_huge(p, 0)) 907 success("OK"); 908 else 909 fail("Fail"); 910 911 ksft_print_msg("Share small page over fork()..."); 912 if (!fork()) { 913 /* Do not touch settings on child exit */ 914 if (ops->check_huge(p, 0)) 915 success("OK"); 916 else 917 fail("Fail"); 918 919 ops->fault(p, page_size, 2 * page_size); 920 c->collapse("Collapse PTE table with single page shared with parent process", 921 p, 1, ops, true); 922 923 validate_memory(p, 0, page_size); 924 ops->cleanup_area(p, hpage_pmd_size); 925 _exit(exit_status); 926 } 927 928 wait(&wstatus); 929 exit_status = WEXITSTATUS(wstatus); 930 931 ksft_print_msg("Check if parent still has small page..."); 932 if (ops->check_huge(p, 0)) 933 success("OK"); 934 else 935 fail("Fail"); 936 validate_memory(p, 0, page_size); 937 ops->cleanup_area(p, hpage_pmd_size); 938 ksft_test_result_report(exit_status, "%s\n", __func__); 939 } 940 941 static void collapse_fork_compound(struct collapse_context *c, struct mem_ops *ops) 942 { 943 int wstatus; 944 void *p; 945 946 p = alloc_hpage(ops); 947 ksft_print_msg("Share huge page over fork()..."); 948 if (!fork()) { 949 /* Do not touch settings on child exit */ 950 if (ops->check_huge(p, 1)) 951 success("OK"); 952 else 953 fail("Fail"); 954 955 ksft_print_msg("Split huge page PMD in child process..."); 956 madvise(p, page_size, MADV_NOHUGEPAGE); 957 madvise(p, hpage_pmd_size, MADV_NOHUGEPAGE); 958 if (ops->check_huge(p, 0)) 959 success("OK"); 960 else 961 fail("Fail"); 962 ops->fault(p, 0, page_size); 963 964 thp_write_num("khugepaged/max_ptes_shared", hpage_pmd_nr - 1); 965 c->collapse("Collapse PTE table full of compound pages in child", 966 p, 1, ops, true); 967 thp_write_num("khugepaged/max_ptes_shared", 968 thp_current_settings()->khugepaged.max_ptes_shared); 969 970 validate_memory(p, 0, hpage_pmd_size); 971 ops->cleanup_area(p, hpage_pmd_size); 972 _exit(exit_status); 973 } 974 975 wait(&wstatus); 976 exit_status = WEXITSTATUS(wstatus); 977 978 ksft_print_msg("Check if parent still has huge page..."); 979 if (ops->check_huge(p, 1)) 980 success("OK"); 981 else 982 fail("Fail"); 983 validate_memory(p, 0, hpage_pmd_size); 984 ops->cleanup_area(p, hpage_pmd_size); 985 ksft_test_result_report(exit_status, "%s\n", __func__); 986 } 987 988 static void collapse_max_ptes_shared(struct collapse_context *c, struct mem_ops *ops) 989 { 990 int max_ptes_shared = thp_read_num("khugepaged/max_ptes_shared"); 991 int wstatus; 992 void *p; 993 994 p = alloc_hpage(ops); 995 ksft_print_msg("Share huge page over fork()..."); 996 if (!fork()) { 997 /* Do not touch settings on child exit */ 998 if (ops->check_huge(p, 1)) 999 success("OK"); 1000 else 1001 fail("Fail"); 1002 1003 ksft_print_msg("Trigger CoW on page %d of %d...", 1004 hpage_pmd_nr - max_ptes_shared - 1, hpage_pmd_nr); 1005 ops->fault(p, 0, (hpage_pmd_nr - max_ptes_shared - 1) * page_size); 1006 if (ops->check_huge(p, 0)) 1007 success("OK"); 1008 else 1009 fail("Fail"); 1010 1011 c->collapse("Maybe collapse with max_ptes_shared exceeded", p, 1012 1, ops, !c->enforce_pte_scan_limits); 1013 1014 if (c->enforce_pte_scan_limits) { 1015 ksft_print_msg("Trigger CoW on page %d of %d...", 1016 hpage_pmd_nr - max_ptes_shared, hpage_pmd_nr); 1017 ops->fault(p, 0, (hpage_pmd_nr - max_ptes_shared) * 1018 page_size); 1019 if (ops->check_huge(p, 0)) 1020 success("OK"); 1021 else 1022 fail("Fail"); 1023 1024 c->collapse("Collapse with max_ptes_shared PTEs shared", 1025 p, 1, ops, true); 1026 } 1027 1028 validate_memory(p, 0, hpage_pmd_size); 1029 ops->cleanup_area(p, hpage_pmd_size); 1030 _exit(exit_status); 1031 } 1032 1033 wait(&wstatus); 1034 exit_status = WEXITSTATUS(wstatus); 1035 1036 ksft_print_msg("Check if parent still has huge page..."); 1037 if (ops->check_huge(p, 1)) 1038 success("OK"); 1039 else 1040 fail("Fail"); 1041 validate_memory(p, 0, hpage_pmd_size); 1042 ops->cleanup_area(p, hpage_pmd_size); 1043 ksft_test_result_report(exit_status, "%s\n", __func__); 1044 } 1045 1046 static void madvise_collapse_existing_thps(struct collapse_context *c, 1047 struct mem_ops *ops) 1048 { 1049 void *p; 1050 1051 p = ops->setup_area(1); 1052 ops->fault(p, 0, hpage_pmd_size); 1053 c->collapse("Collapse fully populated PTE table...", p, 1, ops, true); 1054 validate_memory(p, 0, hpage_pmd_size); 1055 1056 /* c->collapse() will find a hugepage and complain - call directly. */ 1057 __madvise_collapse("Re-collapse PMD-mapped hugepage", p, 1, ops, true); 1058 validate_memory(p, 0, hpage_pmd_size); 1059 ops->cleanup_area(p, hpage_pmd_size); 1060 ksft_test_result_report(exit_status, "%s\n", __func__); 1061 } 1062 1063 /* 1064 * Test race with khugepaged where page tables have been retracted and 1065 * pmd cleared. 1066 */ 1067 static void madvise_retracted_page_tables(struct collapse_context *c, 1068 struct mem_ops *ops) 1069 { 1070 void *p; 1071 int nr_hpages = 1; 1072 unsigned long size = nr_hpages * hpage_pmd_size; 1073 1074 p = ops->setup_area(nr_hpages); 1075 ops->fault(p, 0, size); 1076 1077 /* Let khugepaged collapse and leave pmd cleared */ 1078 if (wait_for_scan("Collapse and leave PMD cleared", p, nr_hpages, 1079 ops)) { 1080 fail("Timeout"); 1081 return; 1082 } 1083 success("OK"); 1084 c->collapse("Install huge PMD from page cache", p, nr_hpages, ops, 1085 true); 1086 validate_memory(p, 0, size); 1087 ops->cleanup_area(p, size); 1088 ksft_test_result_report(exit_status, "%s\n", __func__); 1089 } 1090 1091 static void usage(void) 1092 { 1093 fprintf(stderr, "\nUsage: ./khugepaged [OPTIONS] <test type> [dir]\n\n"); 1094 fprintf(stderr, "\t<test type>\t: <context>:<mem_type>\n"); 1095 fprintf(stderr, "\t<context>\t: [all|khugepaged|madvise]\n"); 1096 fprintf(stderr, "\t<mem_type>\t: [all|anon|file|shmem]\n"); 1097 fprintf(stderr, "\n\t\"file,all\" mem_type requires [dir] argument\n"); 1098 fprintf(stderr, "\n\t\"file,all\" mem_type requires a file system\n"); 1099 fprintf(stderr, "\twith PMD-sized large folio support\n"); 1100 fprintf(stderr, "\n\tif [dir] is a (sub)directory of a tmpfs mount, tmpfs must be\n"); 1101 fprintf(stderr, "\tmounted with huge=advise option for khugepaged tests to work\n"); 1102 fprintf(stderr, "\n\tSupported Options:\n"); 1103 fprintf(stderr, "\t\t-h: This help message.\n"); 1104 fprintf(stderr, "\t\t-s: mTHP size, expressed as page order.\n"); 1105 fprintf(stderr, "\t\t Defaults to 0. Use this size for anon or shmem allocations.\n"); 1106 exit(1); 1107 } 1108 1109 static void parse_test_type(int argc, char **argv) 1110 { 1111 int opt; 1112 char *buf; 1113 const char *token; 1114 1115 while ((opt = getopt(argc, argv, "s:h")) != -1) { 1116 switch (opt) { 1117 case 's': 1118 anon_order = atoi(optarg); 1119 break; 1120 case 'h': 1121 default: 1122 usage(); 1123 } 1124 } 1125 1126 argv += optind; 1127 argc -= optind; 1128 1129 if (argc == 0) { 1130 /* Backwards compatibility */ 1131 khugepaged_context = &__khugepaged_context; 1132 madvise_context = &__madvise_context; 1133 anon_ops = &__anon_ops; 1134 return; 1135 } 1136 1137 buf = strdup(argv[0]); 1138 token = strsep(&buf, ":"); 1139 1140 if (!strcmp(token, "all")) { 1141 khugepaged_context = &__khugepaged_context; 1142 madvise_context = &__madvise_context; 1143 } else if (!strcmp(token, "khugepaged")) { 1144 khugepaged_context = &__khugepaged_context; 1145 } else if (!strcmp(token, "madvise")) { 1146 madvise_context = &__madvise_context; 1147 } else { 1148 usage(); 1149 } 1150 1151 if (!buf) 1152 usage(); 1153 1154 if (!strcmp(buf, "all")) { 1155 read_only_file_ops = &__read_only_file_ops; 1156 read_write_file_read_ops = &__read_write_file_read_ops; 1157 read_write_file_write_ops = &__read_write_file_write_ops; 1158 anon_ops = &__anon_ops; 1159 shmem_ops = &__shmem_ops; 1160 } else if (!strcmp(buf, "anon")) { 1161 anon_ops = &__anon_ops; 1162 } else if (!strcmp(buf, "file")) { 1163 read_only_file_ops = &__read_only_file_ops; 1164 read_write_file_read_ops = &__read_write_file_read_ops; 1165 read_write_file_write_ops = &__read_write_file_write_ops; 1166 } else if (!strcmp(buf, "shmem")) { 1167 shmem_ops = &__shmem_ops; 1168 } else { 1169 usage(); 1170 } 1171 1172 if (!read_only_file_ops && !read_write_file_read_ops && 1173 !read_write_file_write_ops) 1174 return; 1175 1176 if (argc != 2) 1177 usage(); 1178 1179 get_finfo(argv[1]); 1180 } 1181 1182 typedef void (*test_fn)(struct collapse_context *c, struct mem_ops *ops); 1183 1184 struct test_case { 1185 struct collapse_context *ctx; 1186 struct mem_ops *ops; 1187 const char *desc; 1188 test_fn fn; 1189 }; 1190 1191 #define MAX_TEST_CASES 64 1192 static struct test_case test_cases[MAX_TEST_CASES]; 1193 static int nr_test_cases; 1194 1195 #define TEST(t, c, o) do { \ 1196 if (c && o) { \ 1197 if (nr_test_cases >= MAX_TEST_CASES) \ 1198 ksft_exit_fail_msg("MAX_TEST_CASES is too small\n"); \ 1199 test_cases[nr_test_cases++] = (struct test_case){ \ 1200 .ctx = c, \ 1201 .ops = o, \ 1202 .desc = #t, \ 1203 .fn = t, \ 1204 }; \ 1205 } \ 1206 } while (0) 1207 1208 int main(int argc, char **argv) 1209 { 1210 int hpage_pmd_order; 1211 struct thp_settings default_settings = { 1212 .thp_enabled = THP_MADVISE, 1213 .thp_defrag = THP_DEFRAG_ALWAYS, 1214 .shmem_enabled = SHMEM_ADVISE, 1215 .use_zero_page = 0, 1216 .khugepaged = { 1217 .defrag = 1, 1218 .alloc_sleep_millisecs = 10, 1219 .scan_sleep_millisecs = 10, 1220 }, 1221 /* 1222 * When testing file-backed memory, the collapse path 1223 * looks at how many pages are found in the page cache, not 1224 * what pages are mapped. Disable read ahead optimization so 1225 * pages don't find their way into the page cache unless 1226 * we mem_ops->fault() them in. 1227 */ 1228 .read_ahead_kb = 0, 1229 }; 1230 1231 ksft_print_header(); 1232 1233 if (!thp_is_enabled()) 1234 ksft_exit_skip("Transparent Hugepages not available\n"); 1235 1236 parse_test_type(argc, argv); 1237 1238 setbuf(stdout, NULL); 1239 1240 page_size = getpagesize(); 1241 hpage_pmd_size = read_pmd_pagesize(); 1242 if (!hpage_pmd_size) 1243 ksft_exit_fail_msg("Reading PMD pagesize failed\n"); 1244 hpage_pmd_nr = hpage_pmd_size / page_size; 1245 hpage_pmd_order = __builtin_ctz(hpage_pmd_nr); 1246 1247 default_settings.khugepaged.max_ptes_none = hpage_pmd_nr - 1; 1248 default_settings.khugepaged.max_ptes_swap = hpage_pmd_nr / 8; 1249 default_settings.khugepaged.max_ptes_shared = hpage_pmd_nr / 2; 1250 default_settings.khugepaged.pages_to_scan = hpage_pmd_nr * 8; 1251 default_settings.hugepages[hpage_pmd_order].enabled = THP_INHERIT; 1252 default_settings.hugepages[anon_order].enabled = THP_ALWAYS; 1253 default_settings.shmem_hugepages[hpage_pmd_order].enabled = SHMEM_INHERIT; 1254 default_settings.shmem_hugepages[anon_order].enabled = SHMEM_ALWAYS; 1255 1256 save_settings(); 1257 thp_push_settings(&default_settings); 1258 1259 TEST(collapse_full, khugepaged_context, anon_ops); 1260 TEST(collapse_full, khugepaged_context, read_only_file_ops); 1261 TEST(collapse_full, khugepaged_context, read_write_file_read_ops); 1262 TEST(collapse_full, khugepaged_context, read_write_file_write_ops); 1263 TEST(collapse_full, khugepaged_context, shmem_ops); 1264 TEST(collapse_full, madvise_context, anon_ops); 1265 TEST(collapse_full, madvise_context, read_only_file_ops); 1266 TEST(collapse_full, madvise_context, read_write_file_read_ops); 1267 TEST(collapse_full, madvise_context, read_write_file_write_ops); 1268 TEST(collapse_full, madvise_context, shmem_ops); 1269 1270 TEST(collapse_empty, khugepaged_context, anon_ops); 1271 TEST(collapse_empty, madvise_context, anon_ops); 1272 1273 TEST(collapse_single_pte_entry, khugepaged_context, anon_ops); 1274 TEST(collapse_single_pte_entry, khugepaged_context, read_only_file_ops); 1275 TEST(collapse_single_pte_entry, khugepaged_context, read_write_file_read_ops); 1276 TEST(collapse_single_pte_entry, khugepaged_context, read_write_file_write_ops); 1277 TEST(collapse_single_pte_entry, khugepaged_context, shmem_ops); 1278 TEST(collapse_single_pte_entry, madvise_context, anon_ops); 1279 TEST(collapse_single_pte_entry, madvise_context, read_only_file_ops); 1280 TEST(collapse_single_pte_entry, madvise_context, read_write_file_read_ops); 1281 TEST(collapse_single_pte_entry, madvise_context, read_write_file_write_ops); 1282 TEST(collapse_single_pte_entry, madvise_context, shmem_ops); 1283 1284 TEST(collapse_max_ptes_none, khugepaged_context, anon_ops); 1285 TEST(collapse_max_ptes_none, khugepaged_context, read_only_file_ops); 1286 TEST(collapse_max_ptes_none, khugepaged_context, read_write_file_read_ops); 1287 TEST(collapse_max_ptes_none, khugepaged_context, read_write_file_write_ops); 1288 TEST(collapse_max_ptes_none, madvise_context, anon_ops); 1289 TEST(collapse_max_ptes_none, madvise_context, read_only_file_ops); 1290 TEST(collapse_max_ptes_none, madvise_context, read_write_file_read_ops); 1291 TEST(collapse_max_ptes_none, madvise_context, read_write_file_write_ops); 1292 1293 TEST(collapse_single_pte_entry_compound, khugepaged_context, anon_ops); 1294 TEST(collapse_single_pte_entry_compound, khugepaged_context, read_only_file_ops); 1295 TEST(collapse_single_pte_entry_compound, khugepaged_context, read_write_file_read_ops); 1296 TEST(collapse_single_pte_entry_compound, madvise_context, anon_ops); 1297 TEST(collapse_single_pte_entry_compound, madvise_context, read_only_file_ops); 1298 TEST(collapse_single_pte_entry_compound, madvise_context, read_write_file_read_ops); 1299 1300 TEST(collapse_full_of_compound, khugepaged_context, anon_ops); 1301 TEST(collapse_full_of_compound, khugepaged_context, read_only_file_ops); 1302 TEST(collapse_full_of_compound, khugepaged_context, read_write_file_read_ops); 1303 TEST(collapse_full_of_compound, khugepaged_context, shmem_ops); 1304 TEST(collapse_full_of_compound, madvise_context, anon_ops); 1305 TEST(collapse_full_of_compound, madvise_context, read_only_file_ops); 1306 TEST(collapse_full_of_compound, madvise_context, read_write_file_read_ops); 1307 TEST(collapse_full_of_compound, madvise_context, shmem_ops); 1308 1309 TEST(collapse_compound_extreme, khugepaged_context, anon_ops); 1310 TEST(collapse_compound_extreme, madvise_context, anon_ops); 1311 1312 TEST(collapse_swapin_single_pte, khugepaged_context, anon_ops); 1313 TEST(collapse_swapin_single_pte, madvise_context, anon_ops); 1314 1315 TEST(collapse_max_ptes_swap, khugepaged_context, anon_ops); 1316 TEST(collapse_max_ptes_swap, madvise_context, anon_ops); 1317 1318 TEST(collapse_fork, khugepaged_context, anon_ops); 1319 TEST(collapse_fork, madvise_context, anon_ops); 1320 1321 TEST(collapse_fork_compound, khugepaged_context, anon_ops); 1322 TEST(collapse_fork_compound, madvise_context, anon_ops); 1323 1324 TEST(collapse_max_ptes_shared, khugepaged_context, anon_ops); 1325 TEST(collapse_max_ptes_shared, madvise_context, anon_ops); 1326 1327 TEST(madvise_collapse_existing_thps, madvise_context, anon_ops); 1328 TEST(madvise_collapse_existing_thps, madvise_context, read_only_file_ops); 1329 TEST(madvise_collapse_existing_thps, madvise_context, read_write_file_read_ops); 1330 TEST(madvise_collapse_existing_thps, madvise_context, shmem_ops); 1331 1332 TEST(madvise_retracted_page_tables, madvise_context, read_only_file_ops); 1333 TEST(madvise_retracted_page_tables, madvise_context, read_write_file_read_ops); 1334 TEST(madvise_retracted_page_tables, madvise_context, shmem_ops); 1335 1336 ksft_set_plan(nr_test_cases + 1); 1337 1338 alloc_at_fault(); 1339 for (int i = 0; i < nr_test_cases; i++) { 1340 struct test_case *t = &test_cases[i]; 1341 1342 ksft_print_msg("\n# Run test: %s (%s:%s)\n", t->desc, t->ctx->name, t->ops->name); 1343 t->fn(t->ctx, t->ops); 1344 } 1345 1346 ksft_finished(); 1347 } 1348