1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Userfaultfd unit tests. 4 * 5 * Copyright (C) 2015-2023 Red Hat, Inc. 6 */ 7 8 #include "uffd-common.h" 9 10 #include <linux/fs.h> 11 #include <sys/uio.h> 12 #include "../../../../mm/gup_test.h" 13 14 #ifdef __NR_userfaultfd 15 16 /* The unit test doesn't need a large or random size, make it 32MB for now */ 17 #define UFFD_TEST_MEM_SIZE (32UL << 20) 18 19 #define MEM_ANON BIT_ULL(0) 20 #define MEM_SHMEM BIT_ULL(1) 21 #define MEM_SHMEM_PRIVATE BIT_ULL(2) 22 #define MEM_HUGETLB BIT_ULL(3) 23 #define MEM_HUGETLB_PRIVATE BIT_ULL(4) 24 25 #define MEM_ALL (MEM_ANON | MEM_SHMEM | MEM_SHMEM_PRIVATE | \ 26 MEM_HUGETLB | MEM_HUGETLB_PRIVATE) 27 28 #define ALIGN_UP(x, align_to) \ 29 ((__typeof__(x))((((unsigned long)(x)) + ((align_to)-1)) & ~((align_to)-1))) 30 31 #define MAX(a, b) (((a) > (b)) ? (a) : (b)) 32 33 struct mem_type { 34 const char *name; 35 unsigned int mem_flag; 36 uffd_test_ops_t *mem_ops; 37 bool shared; 38 }; 39 typedef struct mem_type mem_type_t; 40 41 mem_type_t mem_types[] = { 42 { 43 .name = "anon", 44 .mem_flag = MEM_ANON, 45 .mem_ops = &anon_uffd_test_ops, 46 .shared = false, 47 }, 48 { 49 .name = "shmem", 50 .mem_flag = MEM_SHMEM, 51 .mem_ops = &shmem_uffd_test_ops, 52 .shared = true, 53 }, 54 { 55 .name = "shmem-private", 56 .mem_flag = MEM_SHMEM_PRIVATE, 57 .mem_ops = &shmem_uffd_test_ops, 58 .shared = false, 59 }, 60 { 61 .name = "hugetlb", 62 .mem_flag = MEM_HUGETLB, 63 .mem_ops = &hugetlb_uffd_test_ops, 64 .shared = true, 65 }, 66 { 67 .name = "hugetlb-private", 68 .mem_flag = MEM_HUGETLB_PRIVATE, 69 .mem_ops = &hugetlb_uffd_test_ops, 70 .shared = false, 71 }, 72 }; 73 74 /* Arguments to be passed over to each uffd unit test */ 75 struct uffd_test_args { 76 mem_type_t *mem_type; 77 }; 78 typedef struct uffd_test_args uffd_test_args_t; 79 80 /* Returns: UFFD_TEST_* */ 81 typedef void (*uffd_test_fn)(uffd_global_test_opts_t *, uffd_test_args_t *); 82 83 typedef struct { 84 const char *name; 85 uffd_test_fn uffd_fn; 86 unsigned int mem_targets; 87 uint64_t uffd_feature_required; 88 uffd_test_case_ops_t *test_case_ops; 89 } uffd_test_case_t; 90 91 static char current_test[256]; 92 93 static void uffd_test_pass(void) 94 { 95 ksft_test_result_pass("%s\n", current_test); 96 } 97 98 #define uffd_test_start(...) do { \ 99 snprintf(current_test, sizeof(current_test), __VA_ARGS__); \ 100 } while (0) 101 102 #define uffd_test_fail(fmt, ...) do { \ 103 ksft_print_msg("failed reason: [" fmt "]\n", ##__VA_ARGS__); \ 104 ksft_test_result_fail("%s\n", current_test); \ 105 } while (0) 106 107 static void uffd_test_skip(const char *message) 108 { 109 ksft_test_result_skip("%s (%s)\n", current_test, message); 110 } 111 112 static void test_uffd_api(bool use_dev) 113 { 114 const uint64_t expected_ioctls = 115 BIT_ULL(_UFFDIO_REGISTER) | 116 BIT_ULL(_UFFDIO_UNREGISTER) | 117 BIT_ULL(_UFFDIO_API); 118 struct uffdio_api uffdio_api; 119 int uffd; 120 121 uffd_test_start("UFFDIO_API (with %s)", 122 use_dev ? "/dev/userfaultfd" : "syscall"); 123 124 if (use_dev) 125 uffd = uffd_open_dev(UFFD_FLAGS); 126 else 127 uffd = uffd_open_sys(UFFD_FLAGS); 128 if (uffd < 0) { 129 uffd_test_skip("cannot open userfaultfd handle"); 130 return; 131 } 132 133 /* Test wrong UFFD_API */ 134 uffdio_api.api = 0xab; 135 uffdio_api.features = 0; 136 if (ioctl(uffd, UFFDIO_API, &uffdio_api) == 0) { 137 uffd_test_fail("UFFDIO_API should fail with wrong api but didn't"); 138 goto out; 139 } 140 141 /* Test wrong feature bit */ 142 uffdio_api.api = UFFD_API; 143 uffdio_api.features = BIT_ULL(63); 144 if (ioctl(uffd, UFFDIO_API, &uffdio_api) == 0) { 145 uffd_test_fail("UFFDIO_API should fail with wrong feature but didn't"); 146 goto out; 147 } 148 149 /* Test normal UFFDIO_API */ 150 uffdio_api.api = UFFD_API; 151 uffdio_api.features = 0; 152 if (ioctl(uffd, UFFDIO_API, &uffdio_api)) { 153 uffd_test_fail("UFFDIO_API should succeed but failed"); 154 goto out; 155 } 156 157 /* Verify returned fd-level ioctls bitmask */ 158 if ((uffdio_api.ioctls & expected_ioctls) != expected_ioctls) { 159 uffd_test_fail("UFFDIO_API missing expected ioctls: " 160 "got=0x%"PRIx64", expected=0x%"PRIx64, 161 (uint64_t)uffdio_api.ioctls, 162 expected_ioctls); 163 goto out; 164 } 165 166 /* Test double requests of UFFDIO_API with a random feature set */ 167 uffdio_api.features = BIT_ULL(0); 168 if (ioctl(uffd, UFFDIO_API, &uffdio_api) == 0) { 169 uffd_test_fail("UFFDIO_API should reject initialized uffd"); 170 goto out; 171 } 172 173 uffd_test_pass(); 174 out: 175 close(uffd); 176 } 177 178 179 static bool uffd_feature_supported(uffd_test_case_t *test) 180 { 181 uint64_t features; 182 183 if (uffd_get_features(&features)) 184 return false; 185 186 return (features & test->uffd_feature_required) == 187 test->uffd_feature_required; 188 } 189 190 static int pagemap_open(void) 191 { 192 int fd = open("/proc/self/pagemap", O_RDONLY); 193 194 if (fd < 0) 195 err("open pagemap"); 196 197 return fd; 198 } 199 200 /* This macro let __LINE__ works in err() */ 201 #define pagemap_check_wp(value, wp) do { \ 202 if (!!(value & PM_UFFD_WP) != wp) \ 203 err("pagemap uffd-wp bit error: 0x%"PRIx64, value); \ 204 } while (0) 205 206 typedef struct { 207 uffd_global_test_opts_t *gopts; 208 int child_uffd; 209 } fork_event_args; 210 211 static void *fork_event_consumer(void *data) 212 { 213 fork_event_args *args = data; 214 struct uffd_msg msg = { 0 }; 215 216 args->gopts->ready_for_fork = true; 217 218 /* Read until a full msg received */ 219 while (uffd_read_msg(args->gopts, &msg)); 220 221 if (msg.event != UFFD_EVENT_FORK) 222 err("wrong message: %u\n", msg.event); 223 224 /* Just to be properly freed later */ 225 args->child_uffd = msg.arg.fork.ufd; 226 return NULL; 227 } 228 229 typedef struct { 230 int gup_fd; 231 bool pinned; 232 } pin_args; 233 234 /* 235 * Returns 0 if succeed, <0 for errors. pin_pages() needs to be paired 236 * with unpin_pages(). Currently it needs to be RO longterm pin to satisfy 237 * all needs of the test cases (e.g., trigger unshare, trigger fork() early 238 * CoW, etc.). 239 */ 240 static int pin_pages(pin_args *args, void *buffer, size_t size) 241 { 242 struct pin_longterm_test test = { 243 .addr = (uintptr_t)buffer, 244 .size = size, 245 /* Read-only pins */ 246 .flags = 0, 247 }; 248 249 if (args->pinned) 250 err("already pinned"); 251 252 args->gup_fd = open("/sys/kernel/debug/gup_test", O_RDWR); 253 if (args->gup_fd < 0) 254 return -errno; 255 256 if (ioctl(args->gup_fd, PIN_LONGTERM_TEST_START, &test)) { 257 /* Even if gup_test existed, can be an old gup_test / kernel */ 258 close(args->gup_fd); 259 return -errno; 260 } 261 args->pinned = true; 262 return 0; 263 } 264 265 static void unpin_pages(pin_args *args) 266 { 267 if (!args->pinned) 268 err("unpin without pin first"); 269 if (ioctl(args->gup_fd, PIN_LONGTERM_TEST_STOP)) 270 err("PIN_LONGTERM_TEST_STOP"); 271 close(args->gup_fd); 272 args->pinned = false; 273 } 274 275 static int pagemap_test_fork(uffd_global_test_opts_t *gopts, bool with_event, bool test_pin) 276 { 277 fork_event_args args = { .gopts = gopts, .child_uffd = -1 }; 278 pthread_t thread; 279 pid_t child; 280 uint64_t value; 281 int fd, result; 282 283 /* Prepare a thread to resolve EVENT_FORK */ 284 if (with_event) { 285 gopts->ready_for_fork = false; 286 if (pthread_create(&thread, NULL, fork_event_consumer, &args)) 287 err("pthread_create()"); 288 while (!gopts->ready_for_fork) 289 ; /* Wait for the poll_thread to start executing before forking */ 290 } 291 292 child = fork(); 293 if (!child) { 294 /* Open the pagemap fd of the child itself */ 295 pin_args args = {}; 296 297 fd = pagemap_open(); 298 299 if (test_pin && pin_pages(&args, gopts->area_dst, gopts->page_size)) 300 /* 301 * Normally when reach here we have pinned in 302 * previous tests, so shouldn't fail anymore 303 */ 304 err("pin page failed in child"); 305 306 value = pagemap_get_entry(fd, gopts->area_dst); 307 /* 308 * After fork(), we should handle uffd-wp bit differently: 309 * 310 * (1) when with EVENT_FORK, it should persist 311 * (2) when without EVENT_FORK, it should be dropped 312 */ 313 pagemap_check_wp(value, with_event); 314 if (test_pin) 315 unpin_pages(&args); 316 /* Succeed */ 317 _exit(0); 318 } 319 waitpid(child, &result, 0); 320 321 if (with_event) { 322 if (pthread_join(thread, NULL)) 323 err("pthread_join()"); 324 if (args.child_uffd < 0) 325 err("Didn't receive child uffd"); 326 close(args.child_uffd); 327 } 328 329 return result; 330 } 331 332 static void uffd_wp_unpopulated_test(uffd_global_test_opts_t *gopts, uffd_test_args_t *args) 333 { 334 uint64_t value; 335 int pagemap_fd; 336 337 if (uffd_register(gopts->uffd, gopts->area_dst, gopts->nr_pages * gopts->page_size, 338 false, true, false)) 339 err("register failed"); 340 341 pagemap_fd = pagemap_open(); 342 343 /* Test applying pte marker to anon unpopulated */ 344 wp_range(gopts->uffd, (uint64_t)gopts->area_dst, gopts->page_size, true); 345 value = pagemap_get_entry(pagemap_fd, gopts->area_dst); 346 pagemap_check_wp(value, true); 347 348 /* Test unprotect on anon pte marker */ 349 wp_range(gopts->uffd, (uint64_t)gopts->area_dst, gopts->page_size, false); 350 value = pagemap_get_entry(pagemap_fd, gopts->area_dst); 351 pagemap_check_wp(value, false); 352 353 /* Test zap on anon marker */ 354 wp_range(gopts->uffd, (uint64_t)gopts->area_dst, gopts->page_size, true); 355 if (madvise(gopts->area_dst, gopts->page_size, MADV_DONTNEED)) 356 err("madvise(MADV_DONTNEED) failed"); 357 value = pagemap_get_entry(pagemap_fd, gopts->area_dst); 358 pagemap_check_wp(value, false); 359 360 /* Test fault in after marker removed */ 361 *gopts->area_dst = 1; 362 value = pagemap_get_entry(pagemap_fd, gopts->area_dst); 363 pagemap_check_wp(value, false); 364 /* Drop it to make pte none again */ 365 if (madvise(gopts->area_dst, gopts->page_size, MADV_DONTNEED)) 366 err("madvise(MADV_DONTNEED) failed"); 367 368 /* Test read-zero-page upon pte marker */ 369 wp_range(gopts->uffd, (uint64_t)gopts->area_dst, gopts->page_size, true); 370 *(volatile char *)gopts->area_dst; 371 /* Drop it to make pte none again */ 372 if (madvise(gopts->area_dst, gopts->page_size, MADV_DONTNEED)) 373 err("madvise(MADV_DONTNEED) failed"); 374 375 uffd_test_pass(); 376 } 377 378 static void uffd_wp_fork_test_common(uffd_global_test_opts_t *gopts, uffd_test_args_t *args, 379 bool with_event) 380 { 381 int pagemap_fd; 382 uint64_t value; 383 384 if (uffd_register(gopts->uffd, gopts->area_dst, gopts->nr_pages * gopts->page_size, 385 false, true, false)) 386 err("register failed"); 387 388 pagemap_fd = pagemap_open(); 389 390 /* Touch the page */ 391 *gopts->area_dst = 1; 392 wp_range(gopts->uffd, (uint64_t)gopts->area_dst, gopts->page_size, true); 393 value = pagemap_get_entry(pagemap_fd, gopts->area_dst); 394 pagemap_check_wp(value, true); 395 if (pagemap_test_fork(gopts, with_event, false)) { 396 uffd_test_fail("Detected %s uffd-wp bit in child in present pte", 397 with_event ? "missing" : "stall"); 398 goto out; 399 } 400 401 /* 402 * This is an attempt for zapping the pgtable so as to test the 403 * markers. 404 * 405 * For private mappings, PAGEOUT will only work on exclusive ptes 406 * (PM_MMAP_EXCLUSIVE) which we should satisfy. 407 * 408 * For shared, PAGEOUT may not work. Use DONTNEED instead which 409 * plays a similar role of zapping (rather than freeing the page) 410 * to expose pte markers. 411 */ 412 if (args->mem_type->shared) { 413 if (madvise(gopts->area_dst, gopts->page_size, MADV_DONTNEED)) 414 err("MADV_DONTNEED"); 415 } else { 416 /* 417 * NOTE: ignore retval because private-hugetlb doesn't yet 418 * support swapping, so it could fail. 419 */ 420 madvise(gopts->area_dst, gopts->page_size, MADV_PAGEOUT); 421 } 422 423 /* Uffd-wp should persist even swapped out */ 424 value = pagemap_get_entry(pagemap_fd, gopts->area_dst); 425 pagemap_check_wp(value, true); 426 if (pagemap_test_fork(gopts, with_event, false)) { 427 uffd_test_fail("Detected %s uffd-wp bit in child in zapped pte", 428 with_event ? "missing" : "stall"); 429 goto out; 430 } 431 432 /* Unprotect; this tests swap pte modifications */ 433 wp_range(gopts->uffd, (uint64_t)gopts->area_dst, gopts->page_size, false); 434 value = pagemap_get_entry(pagemap_fd, gopts->area_dst); 435 pagemap_check_wp(value, false); 436 437 /* Fault in the page from disk */ 438 *gopts->area_dst = 2; 439 value = pagemap_get_entry(pagemap_fd, gopts->area_dst); 440 pagemap_check_wp(value, false); 441 uffd_test_pass(); 442 out: 443 if (uffd_unregister(gopts->uffd, gopts->area_dst, gopts->nr_pages * gopts->page_size)) 444 err("unregister failed"); 445 close(pagemap_fd); 446 } 447 448 static void uffd_wp_fork_test(uffd_global_test_opts_t *gopts, uffd_test_args_t *args) 449 { 450 uffd_wp_fork_test_common(gopts, args, false); 451 } 452 453 static void uffd_wp_fork_with_event_test(uffd_global_test_opts_t *gopts, uffd_test_args_t *args) 454 { 455 uffd_wp_fork_test_common(gopts, args, true); 456 } 457 458 static void uffd_wp_fork_pin_test_common(uffd_global_test_opts_t *gopts, 459 uffd_test_args_t *args, 460 bool with_event) 461 { 462 int pagemap_fd; 463 pin_args pin_args = {}; 464 465 if (uffd_register(gopts->uffd, gopts->area_dst, gopts->page_size, false, true, false)) 466 err("register failed"); 467 468 pagemap_fd = pagemap_open(); 469 470 /* Touch the page */ 471 *gopts->area_dst = 1; 472 wp_range(gopts->uffd, (uint64_t)gopts->area_dst, gopts->page_size, true); 473 474 /* 475 * 1. First pin, then fork(). This tests fork() special path when 476 * doing early CoW if the page is private. 477 */ 478 if (pin_pages(&pin_args, gopts->area_dst, gopts->page_size)) { 479 uffd_test_skip("Possibly CONFIG_GUP_TEST missing " 480 "or unprivileged"); 481 close(pagemap_fd); 482 uffd_unregister(gopts->uffd, gopts->area_dst, gopts->page_size); 483 return; 484 } 485 486 if (pagemap_test_fork(gopts, with_event, false)) { 487 uffd_test_fail("Detected %s uffd-wp bit in early CoW of fork()", 488 with_event ? "missing" : "stall"); 489 unpin_pages(&pin_args); 490 goto out; 491 } 492 493 unpin_pages(&pin_args); 494 495 /* 496 * 2. First fork(), then pin (in the child, where test_pin==true). 497 * This tests COR, aka, page unsharing on private memories. 498 */ 499 if (pagemap_test_fork(gopts, with_event, true)) { 500 uffd_test_fail("Detected %s uffd-wp bit when RO pin", 501 with_event ? "missing" : "stall"); 502 goto out; 503 } 504 uffd_test_pass(); 505 out: 506 if (uffd_unregister(gopts->uffd, gopts->area_dst, gopts->page_size)) 507 err("register failed"); 508 close(pagemap_fd); 509 } 510 511 static void uffd_wp_fork_pin_test(uffd_global_test_opts_t *gopts, uffd_test_args_t *args) 512 { 513 uffd_wp_fork_pin_test_common(gopts, args, false); 514 } 515 516 static void uffd_wp_fork_pin_with_event_test(uffd_global_test_opts_t *gopts, uffd_test_args_t *args) 517 { 518 uffd_wp_fork_pin_test_common(gopts, args, true); 519 } 520 521 static void check_memory_contents(uffd_global_test_opts_t *gopts, char *p) 522 { 523 unsigned long i, j; 524 uint8_t expected_byte; 525 526 for (i = 0; i < gopts->nr_pages; ++i) { 527 expected_byte = ~((uint8_t)(i % ((uint8_t)-1))); 528 for (j = 0; j < gopts->page_size; j++) { 529 uint8_t v = *(uint8_t *)(p + (i * gopts->page_size) + j); 530 if (v != expected_byte) 531 err("unexpected page contents"); 532 } 533 } 534 } 535 536 static void uffd_minor_test_common(uffd_global_test_opts_t *gopts, bool test_collapse, bool test_wp) 537 { 538 unsigned long p; 539 pthread_t uffd_mon; 540 char c = '\0'; 541 struct uffd_args args = { 0 }; 542 args.gopts = gopts; 543 544 /* 545 * NOTE: MADV_COLLAPSE is not yet compatible with WP, so testing 546 * both do not make much sense. 547 */ 548 assert(!(test_collapse && test_wp)); 549 550 if (uffd_register(gopts->uffd, gopts->area_dst_alias, gopts->nr_pages * gopts->page_size, 551 /* NOTE! MADV_COLLAPSE may not work with uffd-wp */ 552 false, test_wp, true)) 553 err("register failure"); 554 555 /* 556 * After registering with UFFD, populate the non-UFFD-registered side of 557 * the shared mapping. This should *not* trigger any UFFD minor faults. 558 */ 559 for (p = 0; p < gopts->nr_pages; ++p) 560 memset(gopts->area_dst + (p * gopts->page_size), p % ((uint8_t)-1), 561 gopts->page_size); 562 563 args.apply_wp = test_wp; 564 if (pthread_create(&uffd_mon, NULL, uffd_poll_thread, &args)) 565 err("uffd_poll_thread create"); 566 567 /* 568 * Read each of the pages back using the UFFD-registered mapping. We 569 * expect that the first time we touch a page, it will result in a minor 570 * fault. uffd_poll_thread will resolve the fault by bit-flipping the 571 * page's contents, and then issuing a CONTINUE ioctl. 572 */ 573 check_memory_contents(gopts, gopts->area_dst_alias); 574 575 if (write(gopts->pipefd[1], &c, sizeof(c)) != sizeof(c)) 576 err("pipe write"); 577 if (pthread_join(uffd_mon, NULL)) 578 err("join() failed"); 579 580 if (test_collapse) { 581 if (madvise(gopts->area_dst_alias, gopts->nr_pages * gopts->page_size, 582 MADV_COLLAPSE)) { 583 /* It's fine to fail for this one... */ 584 uffd_test_skip("MADV_COLLAPSE failed"); 585 return; 586 } 587 588 uffd_test_ops->check_pmd_mapping(gopts, 589 gopts->area_dst, 590 gopts->nr_pages * gopts->page_size / 591 read_pmd_pagesize()); 592 /* 593 * This won't cause uffd-fault - it purely just makes sure there 594 * was no corruption. 595 */ 596 check_memory_contents(gopts, gopts->area_dst_alias); 597 } 598 599 if (args.missing_faults != 0 || args.minor_faults != gopts->nr_pages) 600 uffd_test_fail("stats check error"); 601 else 602 uffd_test_pass(); 603 } 604 605 void uffd_minor_test(uffd_global_test_opts_t *gopts, uffd_test_args_t *args) 606 { 607 uffd_minor_test_common(gopts, false, false); 608 } 609 610 void uffd_minor_wp_test(uffd_global_test_opts_t *gopts, uffd_test_args_t *args) 611 { 612 uffd_minor_test_common(gopts, false, true); 613 } 614 615 void uffd_minor_collapse_test(uffd_global_test_opts_t *gopts, uffd_test_args_t *args) 616 { 617 uffd_minor_test_common(gopts, true, false); 618 } 619 620 static int uffd_register_rwp(int uffd, void *addr, uint64_t len) 621 { 622 struct uffdio_register reg = { 623 .range = { .start = (unsigned long)addr, .len = len }, 624 .mode = UFFDIO_REGISTER_MODE_RWP, 625 }; 626 627 if (ioctl(uffd, UFFDIO_REGISTER, ®) == -1) 628 return -errno; 629 return 0; 630 } 631 632 static void rwprotect_range(int uffd, __u64 start, __u64 len, bool protect) 633 { 634 struct uffdio_rwprotect rwp = { 635 .range = { .start = start, .len = len }, 636 .mode = protect ? UFFDIO_RWPROTECT_MODE_RWP : 0, 637 }; 638 639 if (ioctl(uffd, UFFDIO_RWPROTECT, &rwp)) 640 err("UFFDIO_RWPROTECT failed"); 641 } 642 643 static void set_async_mode(int uffd, bool enable) 644 { 645 struct uffdio_set_mode mode = { }; 646 647 if (enable) 648 mode.enable = UFFD_FEATURE_RWP_ASYNC; 649 else 650 mode.disable = UFFD_FEATURE_RWP_ASYNC; 651 652 if (ioctl(uffd, UFFDIO_SET_MODE, &mode)) 653 err("UFFDIO_SET_MODE failed"); 654 } 655 656 /* 657 * Test async RWP faults on anonymous memory. 658 * Populate pages, register MODE_RWP with RWP_ASYNC, 659 * RW-protect, re-access, verify content preserved and no faults delivered. 660 */ 661 static void uffd_rwp_async_test(uffd_global_test_opts_t *gopts, 662 uffd_test_args_t *args) 663 { 664 unsigned long nr_pages = gopts->nr_pages; 665 unsigned long page_size = gopts->page_size; 666 unsigned long p; 667 668 /* Populate all pages with known content */ 669 for (p = 0; p < nr_pages; p++) 670 memset(gopts->area_dst + p * page_size, p % 255 + 1, page_size); 671 672 /* Register MODE_RWP */ 673 if (uffd_register_rwp(gopts->uffd, gopts->area_dst, 674 nr_pages * page_size)) 675 err("register failure"); 676 677 /* RW-protect all pages (sets protnone) */ 678 rwprotect_range(gopts->uffd, (uint64_t)gopts->area_dst, 679 nr_pages * page_size, true); 680 681 /* Access all pages — should auto-resolve, no faults */ 682 for (p = 0; p < nr_pages; p++) { 683 unsigned char *page = (unsigned char *)gopts->area_dst + 684 p * page_size; 685 unsigned char expected = p % 255 + 1; 686 687 if (page[0] != expected) { 688 uffd_test_fail("page %lu content mismatch: %u != %u", 689 p, page[0], expected); 690 return; 691 } 692 } 693 694 uffd_test_pass(); 695 } 696 697 /* 698 * Fault handler for RWP — unprotect the page via UFFDIO_RWPROTECT. 699 */ 700 static void uffd_handle_rwp_fault(uffd_global_test_opts_t *gopts, 701 struct uffd_msg *msg, 702 struct uffd_args *uargs) 703 { 704 if (!(msg->arg.pagefault.flags & UFFD_PAGEFAULT_FLAG_RWP)) 705 err("expected RWP fault, got 0x%llx", 706 msg->arg.pagefault.flags); 707 708 rwprotect_range(gopts->uffd, msg->arg.pagefault.address, 709 gopts->page_size, false); 710 uargs->minor_faults++; 711 } 712 713 /* 714 * Test sync RWP faults on anonymous memory. 715 * Populate pages, register MODE_RWP (sync), RW-protect, 716 * access from worker thread, verify fault delivered, UFFDIO_RWPROTECT resolves. 717 */ 718 static void uffd_rwp_sync_test(uffd_global_test_opts_t *gopts, 719 uffd_test_args_t *args) 720 { 721 unsigned long nr_pages = gopts->nr_pages; 722 unsigned long page_size = gopts->page_size; 723 pthread_t uffd_mon; 724 struct uffd_args uargs = { }; 725 bool failed = false; 726 char c = '\0'; 727 unsigned long p; 728 729 uargs.gopts = gopts; 730 uargs.handle_fault = uffd_handle_rwp_fault; 731 732 /* Populate all pages */ 733 for (p = 0; p < nr_pages; p++) 734 memset(gopts->area_dst + p * page_size, p % 255 + 1, page_size); 735 736 /* Register MODE_RWP */ 737 if (uffd_register_rwp(gopts->uffd, gopts->area_dst, 738 nr_pages * page_size)) 739 err("register failure"); 740 741 /* RW-protect all pages */ 742 rwprotect_range(gopts->uffd, (uint64_t)gopts->area_dst, 743 nr_pages * page_size, true); 744 745 /* Start fault handler thread */ 746 if (pthread_create(&uffd_mon, NULL, uffd_poll_thread, &uargs)) 747 err("uffd_poll_thread create"); 748 749 /* Access all pages — triggers sync RWP faults, handler unprotects */ 750 for (p = 0; p < nr_pages; p++) { 751 unsigned char *page = (unsigned char *)gopts->area_dst + 752 p * page_size; 753 754 if (page[0] != (p % 255 + 1)) { 755 uffd_test_fail("page %lu content mismatch", p); 756 failed = true; 757 goto out; 758 } 759 } 760 761 out: 762 /* 763 * Stop the handler before reading minor_faults: the last fault 764 * resolution rwprotect_range()s before incrementing the counter, 765 * so the main thread can race ahead of the increment. 766 */ 767 if (write(gopts->pipefd[1], &c, sizeof(c)) != sizeof(c)) 768 err("pipe write"); 769 if (pthread_join(uffd_mon, NULL)) 770 err("join() failed"); 771 772 if (failed) 773 return; 774 if (uargs.minor_faults == 0) 775 uffd_test_fail("expected RWP faults, got 0"); 776 else 777 uffd_test_pass(); 778 } 779 780 /* 781 * Test PAGEMAP_SCAN working-set discovery via the "hot" (accessed) scan. 782 * 783 * The working-set primitive is to find pages that were accessed: scan for 784 * PAGE_IS_ACCESSED, which is set once an access clears the protnone+uffd 785 * marker. A VMM treats every access fault as "hot" (RWP here; MINOR/MISSING 786 * for non-resident pages) and reclaims the rest from the backing file. 787 * 788 * We deliberately do NOT use an inverted "cold" scan: that only sees 789 * VMA-resident ptes, so for a file mapping it misses cached-but-unmapped (and 790 * never-faulted, pre-populated) pages, which are pte_none and thus invisible. 791 * Hot tracking + file-level reclaim covers them; a cold pte scan cannot. 792 */ 793 static void uffd_rwp_pagemap_test(uffd_global_test_opts_t *gopts, 794 uffd_test_args_t *args) 795 { 796 unsigned long nr_pages = gopts->nr_pages; 797 unsigned long page_size = gopts->page_size; 798 unsigned long p; 799 struct page_region regions[16]; 800 struct pm_scan_arg pm_arg; 801 int pagemap_fd; 802 long ret; 803 804 /* Need at least 4 pages */ 805 if (nr_pages < 4) { 806 uffd_test_skip("need at least 4 pages"); 807 return; 808 } 809 810 /* Populate all pages */ 811 for (p = 0; p < nr_pages; p++) 812 memset(gopts->area_dst + p * page_size, 0xab, page_size); 813 814 /* Register and RW-protect */ 815 if (uffd_register_rwp(gopts->uffd, gopts->area_dst, 816 nr_pages * page_size)) 817 err("register failure"); 818 819 rwprotect_range(gopts->uffd, (uint64_t)gopts->area_dst, 820 nr_pages * page_size, true); 821 822 /* Touch first half of pages to re-activate them (async auto-resolve) */ 823 for (p = 0; p < nr_pages / 2; p++) { 824 volatile char *page = gopts->area_dst + p * page_size; 825 (void)*page; 826 } 827 828 uint64_t start = (uint64_t)gopts->area_dst; 829 uint64_t boundary = start + (nr_pages / 2) * page_size; 830 uint64_t end = start + nr_pages * page_size; 831 832 pagemap_fd = open("/proc/self/pagemap", O_RDONLY); 833 if (pagemap_fd < 0) 834 err("open pagemap"); 835 836 /* 837 * Hot scan: report the pages that were accessed. PAGE_IS_ACCESSED is 838 * set once the protnone+uffd marker is cleared (by the access, async 839 * auto-resolve here). The touched first half must come back as exactly 840 * one hot region [start, boundary); the untouched second half must not 841 * appear. 842 */ 843 memset(&pm_arg, 0, sizeof(pm_arg)); 844 pm_arg.size = sizeof(pm_arg); 845 pm_arg.start = start; 846 pm_arg.end = end; 847 pm_arg.vec = (uint64_t)regions; 848 pm_arg.vec_len = ARRAY_SIZE(regions); 849 pm_arg.category_mask = PAGE_IS_ACCESSED; 850 pm_arg.return_mask = PAGE_IS_ACCESSED; 851 852 ret = ioctl(pagemap_fd, PAGEMAP_SCAN, &pm_arg); 853 close(pagemap_fd); 854 855 if (ret < 0) { 856 uffd_test_fail("PAGEMAP_SCAN failed: %s", strerror(errno)); 857 return; 858 } 859 860 if (ret != 1 || regions[0].start != start || 861 regions[0].end != boundary) { 862 uffd_test_fail("hot set wrong: got %ld regions [0x%lx,0x%lx), expected 1 [0x%lx,0x%lx)", 863 ret, (unsigned long)regions[0].start, 864 (unsigned long)regions[0].end, 865 (unsigned long)start, (unsigned long)boundary); 866 return; 867 } 868 869 uffd_test_pass(); 870 } 871 872 /* 873 * Test that RWP protection survives a mprotect(PROT_NONE) -> 874 * mprotect(PROT_READ|PROT_WRITE) round-trip. The uffd-wp bit on a 875 * VM_UFFD_RWP VMA must continue to carry PROT_NONE semantics after 876 * mprotect() changes the base protection; otherwise accesses would 877 * silently succeed and the pagemap bit would stick without a fault 878 * ever clearing it. 879 */ 880 static void uffd_rwp_mprotect_test(uffd_global_test_opts_t *gopts, 881 uffd_test_args_t *args) 882 { 883 unsigned long nr_pages = gopts->nr_pages; 884 unsigned long page_size = gopts->page_size; 885 unsigned long p; 886 struct page_region regions[16]; 887 struct pm_scan_arg pm_arg; 888 int pagemap_fd; 889 uint64_t value; 890 long ret; 891 892 /* Populate all pages */ 893 for (p = 0; p < nr_pages; p++) 894 memset(gopts->area_dst + p * page_size, 0xab, page_size); 895 896 /* Register and RW-protect the whole range */ 897 if (uffd_register_rwp(gopts->uffd, gopts->area_dst, 898 nr_pages * page_size)) 899 err("register failure"); 900 rwprotect_range(gopts->uffd, (uint64_t)gopts->area_dst, 901 nr_pages * page_size, true); 902 903 /* Round-trip mprotect(): PROT_NONE -> PROT_READ|PROT_WRITE */ 904 if (mprotect(gopts->area_dst, nr_pages * page_size, PROT_NONE)) 905 err("mprotect() PROT_NONE"); 906 if (mprotect(gopts->area_dst, nr_pages * page_size, 907 PROT_READ | PROT_WRITE)) 908 err("mprotect() PROT_READ|PROT_WRITE"); 909 910 /* 911 * The marker must survive the round-trip; if mprotect() dropped it, 912 * the touches below would not fault and the scan would pass 913 * vacuously. 914 */ 915 pagemap_fd = pagemap_open(); 916 value = pagemap_get_entry(pagemap_fd, gopts->area_dst); 917 close(pagemap_fd); 918 if (!(value & PM_UFFD_WP)) { 919 uffd_test_fail("RWP marker lost across mprotect()"); 920 return; 921 } 922 923 /* Touch every page. Async RWP must auto-resolve each fault. */ 924 for (p = 0; p < nr_pages; p++) { 925 volatile char *page = gopts->area_dst + p * page_size; 926 (void)*page; 927 } 928 929 /* 930 * After touching, no page should remain RW-protected. A stuck 931 * uffd-wp bit would mean mprotect() silently dropped PROT_NONE and 932 * the access never faulted. 933 */ 934 pagemap_fd = open("/proc/self/pagemap", O_RDONLY); 935 if (pagemap_fd < 0) 936 err("open pagemap"); 937 938 memset(&pm_arg, 0, sizeof(pm_arg)); 939 pm_arg.size = sizeof(pm_arg); 940 pm_arg.start = (uint64_t)gopts->area_dst; 941 pm_arg.end = (uint64_t)gopts->area_dst + nr_pages * page_size; 942 pm_arg.vec = (uint64_t)regions; 943 pm_arg.vec_len = ARRAY_SIZE(regions); 944 pm_arg.category_mask = PAGE_IS_ACCESSED; 945 pm_arg.category_inverted = PAGE_IS_ACCESSED; 946 pm_arg.return_mask = PAGE_IS_ACCESSED; 947 948 ret = ioctl(pagemap_fd, PAGEMAP_SCAN, &pm_arg); 949 close(pagemap_fd); 950 951 if (ret < 0) { 952 uffd_test_fail("PAGEMAP_SCAN failed: %s", strerror(errno)); 953 return; 954 } 955 if (ret != 0) { 956 uffd_test_fail("expected no cold pages after mprotect()+touch, got %ld regions", 957 ret); 958 return; 959 } 960 961 uffd_test_pass(); 962 } 963 964 /* 965 * Test that GUP resolves through protnone PTEs (async mode). 966 * vmsplice() into a pipe pins user pages via get_user_pages_fast() -- 967 * unlike write(), which goes through copy_from_user() and ordinary 968 * hardware page faults -- so it exercises gup_can_follow_protnone() on 969 * the RW-protected PTE. In async mode the kernel auto-restores 970 * permissions and GUP returns the page. 971 */ 972 static void uffd_rwp_gup_test(uffd_global_test_opts_t *gopts, 973 uffd_test_args_t *args) 974 { 975 struct iovec iov; 976 char buf; 977 int pipefd[2]; 978 979 /* Populate first page with known content */ 980 memset(gopts->area_dst, 0xCD, gopts->page_size); 981 982 if (uffd_register_rwp(gopts->uffd, gopts->area_dst, gopts->page_size)) 983 err("register failure"); 984 985 rwprotect_range(gopts->uffd, (uint64_t)gopts->area_dst, 986 gopts->page_size, true); 987 988 if (pipe(pipefd)) 989 err("pipe"); 990 991 /* 992 * One byte's worth of iov is enough to GUP the containing page and 993 * keeps the pipe transfer well under any pipe-capacity limit even on 994 * hugetlb-backed runs. 995 */ 996 iov.iov_base = gopts->area_dst; 997 iov.iov_len = 1; 998 if (vmsplice(pipefd[1], &iov, 1, 0) != 1) { 999 uffd_test_fail("vmsplice from RW-protected page failed: %s", 1000 strerror(errno)); 1001 goto out; 1002 } 1003 1004 if (read(pipefd[0], &buf, 1) != 1) { 1005 uffd_test_fail("read from pipe failed"); 1006 goto out; 1007 } 1008 1009 if (buf != (char)0xCD) { 1010 uffd_test_fail("content mismatch: got 0x%02x, expected 0xCD", 1011 (unsigned char)buf); 1012 goto out; 1013 } 1014 1015 uffd_test_pass(); 1016 out: 1017 close(pipefd[0]); 1018 close(pipefd[1]); 1019 } 1020 1021 /* 1022 * Test runtime toggle between async and sync modes. 1023 * Start in async mode (detection), flip to sync (eviction), verify faults 1024 * block, resolve them, flip back to async. 1025 */ 1026 static void uffd_rwp_async_toggle_test(uffd_global_test_opts_t *gopts, 1027 uffd_test_args_t *args) 1028 { 1029 unsigned long nr_pages = gopts->nr_pages; 1030 unsigned long page_size = gopts->page_size; 1031 struct uffd_args uargs = { }; 1032 pthread_t uffd_mon; 1033 char c = '\0'; 1034 unsigned long p; 1035 1036 uargs.gopts = gopts; 1037 uargs.handle_fault = uffd_handle_rwp_fault; 1038 1039 /* Populate */ 1040 for (p = 0; p < nr_pages; p++) 1041 memset(gopts->area_dst + p * page_size, p % 255 + 1, page_size); 1042 1043 if (uffd_register_rwp(gopts->uffd, gopts->area_dst, 1044 nr_pages * page_size)) 1045 err("register failure"); 1046 1047 /* Phase 1: async detection — RW-protect, access first half */ 1048 rwprotect_range(gopts->uffd, (uint64_t)gopts->area_dst, 1049 nr_pages * page_size, true); 1050 1051 for (p = 0; p < nr_pages / 2; p++) { 1052 volatile char *page = gopts->area_dst + p * page_size; 1053 (void)*page; /* auto-resolves in async mode */ 1054 } 1055 1056 /* Phase 2: flip to sync for eviction */ 1057 set_async_mode(gopts->uffd, false); 1058 1059 /* Start handler — will receive faults for cold pages */ 1060 if (pthread_create(&uffd_mon, NULL, uffd_poll_thread, &uargs)) 1061 err("uffd_poll_thread create"); 1062 1063 /* Access second half (cold pages) — should trigger sync faults */ 1064 for (p = nr_pages / 2; p < nr_pages; p++) { 1065 unsigned char *page = (unsigned char *)gopts->area_dst + 1066 p * page_size; 1067 if (page[0] != (p % 255 + 1)) { 1068 uffd_test_fail("page %lu content mismatch", p); 1069 goto out; 1070 } 1071 } 1072 1073 /* 1074 * Stop the handler before reading minor_faults: the last fault 1075 * resolution rwprotect_range()s before incrementing the counter, 1076 * so the main thread can race ahead of the increment. Stopping 1077 * here also makes Phase 3 a clean async-only test -- with the 1078 * handler still running it would silently resolve any sync fault 1079 * the kernel erroneously delivers, masking a regression. 1080 */ 1081 if (write(gopts->pipefd[1], &c, sizeof(c)) != sizeof(c)) 1082 err("pipe write"); 1083 if (pthread_join(uffd_mon, NULL)) 1084 err("join() failed"); 1085 1086 if (uargs.minor_faults == 0) { 1087 uffd_test_fail("expected sync faults, got 0"); 1088 return; 1089 } 1090 1091 /* Phase 3: flip back to async */ 1092 set_async_mode(gopts->uffd, true); 1093 1094 /* RW-protect and access again — should auto-resolve */ 1095 rwprotect_range(gopts->uffd, (uint64_t)gopts->area_dst, 1096 nr_pages * page_size, true); 1097 1098 for (p = 0; p < nr_pages; p++) { 1099 volatile char *page = gopts->area_dst + p * page_size; 1100 (void)*page; 1101 } 1102 1103 uffd_test_pass(); 1104 return; 1105 out: 1106 if (write(gopts->pipefd[1], &c, sizeof(c)) != sizeof(c)) 1107 err("pipe write"); 1108 if (pthread_join(uffd_mon, NULL)) 1109 err("join() failed"); 1110 } 1111 1112 /* 1113 * Test that RW-protected pages become accessible after closing uffd. 1114 */ 1115 static void uffd_rwp_close_test(uffd_global_test_opts_t *gopts, 1116 uffd_test_args_t *args) 1117 { 1118 unsigned long nr_pages = gopts->nr_pages; 1119 unsigned long page_size = gopts->page_size; 1120 unsigned long p; 1121 1122 /* Populate */ 1123 for (p = 0; p < nr_pages; p++) 1124 memset(gopts->area_dst + p * page_size, p % 255 + 1, page_size); 1125 1126 if (uffd_register_rwp(gopts->uffd, gopts->area_dst, 1127 nr_pages * page_size)) 1128 err("register failure"); 1129 1130 rwprotect_range(gopts->uffd, (uint64_t)gopts->area_dst, 1131 nr_pages * page_size, true); 1132 1133 /* Close uffd — should restore protnone PTEs */ 1134 close(gopts->uffd); 1135 gopts->uffd = -1; 1136 1137 /* All pages should be accessible with original content */ 1138 for (p = 0; p < nr_pages; p++) { 1139 unsigned char *page = (unsigned char *)gopts->area_dst + 1140 p * page_size; 1141 unsigned char expected = p % 255 + 1; 1142 1143 if (page[0] != expected) { 1144 uffd_test_fail("page %lu not accessible after close", p); 1145 return; 1146 } 1147 } 1148 1149 uffd_test_pass(); 1150 } 1151 1152 /* 1153 * Test that RWP protection is preserved across fork() when 1154 * UFFD_FEATURE_EVENT_FORK is enabled. Without preservation, the child's 1155 * PTEs would lose the uffd-wp marker and RWP-protected accesses would 1156 * silently fall through to do_numa_page(). 1157 */ 1158 static void uffd_rwp_fork_test(uffd_global_test_opts_t *gopts, 1159 uffd_test_args_t *args) 1160 { 1161 unsigned long nr_pages = gopts->nr_pages; 1162 unsigned long page_size = gopts->page_size; 1163 int pagemap_fd; 1164 uint64_t value; 1165 1166 if (uffd_register_rwp(gopts->uffd, gopts->area_dst, 1167 nr_pages * page_size)) 1168 err("register failed"); 1169 1170 /* Populate + RWP-protect */ 1171 *gopts->area_dst = 1; 1172 rwprotect_range(gopts->uffd, (uint64_t)gopts->area_dst, 1173 page_size, true); 1174 1175 /* Parent: verify uffd-wp bit is set before fork */ 1176 pagemap_fd = pagemap_open(); 1177 value = pagemap_get_entry(pagemap_fd, gopts->area_dst); 1178 pagemap_check_wp(value, true); 1179 1180 /* 1181 * Fork with EVENT_FORK: child inherits VM_UFFD_RWP. Child reads 1182 * its own pagemap and must still see the uffd-wp bit set. 1183 */ 1184 if (pagemap_test_fork(gopts, true, false)) { 1185 uffd_test_fail("RWP marker lost in child after fork"); 1186 goto out; 1187 } 1188 1189 uffd_test_pass(); 1190 out: 1191 close(pagemap_fd); 1192 } 1193 1194 /* 1195 * Test that RWP protection on a pinned anon page is preserved across fork(). 1196 * Pinning forces copy_present_page() in the child path, which must restore 1197 * PAGE_NONE on top of the uffd bit. Using async mode, a read in the child 1198 * auto-resolves if — and only if — the PTE was actually protnone+uffd; the 1199 * cleared uffd bit afterward proves the fault path ran. 1200 */ 1201 static void uffd_rwp_fork_pin_test(uffd_global_test_opts_t *gopts, 1202 uffd_test_args_t *args) 1203 { 1204 unsigned long page_size = gopts->page_size; 1205 fork_event_args fevent_args = { .gopts = gopts, .child_uffd = -1 }; 1206 pin_args pin_args = {}; 1207 int pagemap_fd, status; 1208 pthread_t fevent_thread; 1209 uint64_t value; 1210 pid_t child; 1211 1212 if (uffd_register_rwp(gopts->uffd, gopts->area_dst, page_size)) 1213 err("register failed"); 1214 1215 /* Populate. */ 1216 *gopts->area_dst = 1; 1217 1218 /* RO-longterm pin so fork() takes copy_present_page() for this PTE. */ 1219 if (pin_pages(&pin_args, gopts->area_dst, page_size)) { 1220 uffd_test_skip("Possibly CONFIG_GUP_TEST missing or unprivileged"); 1221 uffd_unregister(gopts->uffd, gopts->area_dst, page_size); 1222 return; 1223 } 1224 1225 /* RWP-protect: PTE is now PAGE_NONE + uffd bit. */ 1226 rwprotect_range(gopts->uffd, (uint64_t)gopts->area_dst, page_size, true); 1227 1228 pagemap_fd = pagemap_open(); 1229 value = pagemap_get_entry(pagemap_fd, gopts->area_dst); 1230 pagemap_check_wp(value, true); 1231 1232 /* 1233 * UFFD_FEATURE_EVENT_FORK is required so the child inherits 1234 * VM_UFFD_RWP and the marker; without it dup_userfaultfd() resets 1235 * the child VMA and the test would pass for the wrong reason. 1236 * dup_userfaultfd() blocks until the EVENT_FORK message is consumed, 1237 * so spawn a reader before the fork(). 1238 */ 1239 gopts->ready_for_fork = false; 1240 if (pthread_create(&fevent_thread, NULL, fork_event_consumer, 1241 &fevent_args)) 1242 err("pthread_create() for fork event consumer"); 1243 while (!gopts->ready_for_fork) 1244 ; /* Wait for consumer to start polling. */ 1245 1246 child = fork(); 1247 if (child < 0) 1248 err("fork"); 1249 if (child == 0) { 1250 volatile char c; 1251 int cfd; 1252 1253 /* 1254 * Precondition: the child must have inherited the marker. 1255 * If copy_present_page() dropped it together with PAGE_NONE, 1256 * the read below would succeed without the fault path and 1257 * the after-read check would pass for the wrong reason. 1258 */ 1259 cfd = pagemap_open(); 1260 value = pagemap_get_entry(cfd, gopts->area_dst); 1261 if (!(value & PM_UFFD_WP)) { 1262 close(cfd); 1263 _exit(2); 1264 } 1265 1266 /* 1267 * Read the pinned page. Only reaches the fault path if the 1268 * child PTE is protnone + uffd; async mode auto-resolves and 1269 * clears the uffd bit. If copy_present_page() dropped 1270 * PAGE_NONE, the read would silently succeed and the bit 1271 * would still be set. 1272 */ 1273 c = *(volatile char *)gopts->area_dst; 1274 (void)c; 1275 1276 value = pagemap_get_entry(cfd, gopts->area_dst); 1277 close(cfd); 1278 _exit((value & PM_UFFD_WP) ? 1 : 0); 1279 } 1280 if (waitpid(child, &status, 0) < 0) 1281 err("waitpid"); 1282 if (pthread_join(fevent_thread, NULL)) 1283 err("pthread_join() for fork event consumer"); 1284 if (fevent_args.child_uffd >= 0) 1285 close(fevent_args.child_uffd); 1286 1287 unpin_pages(&pin_args); 1288 close(pagemap_fd); 1289 if (uffd_unregister(gopts->uffd, gopts->area_dst, page_size)) 1290 err("unregister failed"); 1291 1292 if (WIFEXITED(status) && WEXITSTATUS(status) == 2) { 1293 uffd_test_fail("RWP marker not inherited by child"); 1294 return; 1295 } 1296 if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) { 1297 uffd_test_fail("RWP not enforced in child after pinned fork"); 1298 return; 1299 } 1300 1301 uffd_test_pass(); 1302 } 1303 1304 /* 1305 * A non-exclusive (forked, COW-shared) anon page that is RWP-protected and 1306 * then swapped out must keep tracking across swap-in. On the write that 1307 * swaps it back in, do_swap_page() restores PAGE_NONE and the access retries 1308 * through the RWP fault path, instead of being COWed straight to a fresh 1309 * accessible page -- which would silently drop the marker for a non-exclusive 1310 * folio. Sync mode lets us observe the fault directly: with the bug, the 1311 * write COWs without delivering any RWP fault. 1312 * 1313 * Needs a swap device; skipped if MADV_PAGEOUT cannot evict the page. 1314 */ 1315 static void uffd_rwp_swap_cow_test(uffd_global_test_opts_t *gopts, 1316 uffd_test_args_t *args) 1317 { 1318 unsigned long page_size = gopts->page_size; 1319 struct uffd_args uargs = { }; 1320 int pagemap_fd, go[2], i; 1321 pthread_t uffd_mon; 1322 char c = '\0'; 1323 pid_t child; 1324 1325 uargs.gopts = gopts; 1326 uargs.handle_fault = uffd_handle_rwp_fault; 1327 1328 if (uffd_register_rwp(gopts->uffd, gopts->area_dst, page_size)) 1329 err("register failed"); 1330 1331 /* Populate one page (exclusive at this point). */ 1332 *gopts->area_dst = 0x11; 1333 1334 /* RWP-protect: PTE becomes PAGE_NONE + uffd bit (still exclusive). */ 1335 rwprotect_range(gopts->uffd, (uint64_t)gopts->area_dst, page_size, true); 1336 1337 /* 1338 * Swap the page out while it is still exclusive: a shared (forked) 1339 * folio does not get reclaimed by MADV_PAGEOUT. Retry, since a hot 1340 * page may just be rotated on the first reclaim pass. 1341 */ 1342 pagemap_fd = pagemap_open(); 1343 for (i = 0; i < 100; i++) { 1344 if (madvise(gopts->area_dst, page_size, MADV_PAGEOUT)) 1345 err("MADV_PAGEOUT"); 1346 if (pagemap_is_swapped(pagemap_fd, gopts->area_dst)) 1347 break; 1348 usleep(10000); 1349 } 1350 if (!pagemap_is_swapped(pagemap_fd, gopts->area_dst)) { 1351 uffd_test_skip("MADV_PAGEOUT did not swap the page; is swap enabled?"); 1352 close(pagemap_fd); 1353 uffd_unregister(gopts->uffd, gopts->area_dst, page_size); 1354 return; 1355 } 1356 1357 /* 1358 * fork() now: the child duplicates the swap entry, so the slot becomes 1359 * non-exclusive. The child parks (keeping the reference) until the 1360 * parent has faulted the page back in. 1361 */ 1362 if (pipe(go)) 1363 err("pipe"); 1364 child = fork(); 1365 if (child < 0) 1366 err("fork"); 1367 if (child == 0) { 1368 close(go[1]); 1369 read(go[0], &c, 1); 1370 _exit(0); 1371 } 1372 close(go[0]); 1373 1374 if (pthread_create(&uffd_mon, NULL, uffd_poll_thread, &uargs)) 1375 err("uffd_poll_thread create"); 1376 1377 /* 1378 * Write the page: swaps it back in (do_swap_page) on a non-exclusive 1379 * folio with FAULT_FLAG_WRITE. The marker must survive and deliver an 1380 * RWP fault rather than COW silently. 1381 */ 1382 *gopts->area_dst = 0x22; 1383 1384 if (write(gopts->pipefd[1], &c, sizeof(c)) != sizeof(c)) 1385 err("pipe write"); 1386 if (pthread_join(uffd_mon, NULL)) 1387 err("join failed"); 1388 1389 if (uargs.minor_faults == 0) 1390 uffd_test_fail("no RWP fault on swapped-in non-exclusive page"); 1391 else 1392 uffd_test_pass(); 1393 1394 close(pagemap_fd); 1395 if (write(go[1], &c, 1) != 1) 1396 err("child release"); 1397 close(go[1]); 1398 waitpid(child, NULL, 0); 1399 } 1400 1401 /* 1402 * WP and RWP share the uffd-wp PTE bit and cannot coexist in the same VMA. 1403 * Registration requesting both modes must be rejected. 1404 */ 1405 static void uffd_rwp_wp_exclusive_test(uffd_global_test_opts_t *gopts, 1406 uffd_test_args_t *args) 1407 { 1408 unsigned long nr_pages = gopts->nr_pages; 1409 unsigned long page_size = gopts->page_size; 1410 struct uffdio_register reg = { }; 1411 1412 reg.range.start = (unsigned long)gopts->area_dst; 1413 reg.range.len = nr_pages * page_size; 1414 reg.mode = UFFDIO_REGISTER_MODE_WP | UFFDIO_REGISTER_MODE_RWP; 1415 1416 if (ioctl(gopts->uffd, UFFDIO_REGISTER, ®) == 0) { 1417 uffd_test_fail("register with WP|RWP unexpectedly succeeded"); 1418 return; 1419 } 1420 if (errno != EINVAL) { 1421 uffd_test_fail("register with WP|RWP: expected EINVAL, got %d", 1422 errno); 1423 return; 1424 } 1425 uffd_test_pass(); 1426 } 1427 1428 static sigjmp_buf jbuf, *sigbuf; 1429 1430 static void sighndl(int sig, siginfo_t *siginfo, void *ptr) 1431 { 1432 if (sig == SIGBUS) { 1433 if (sigbuf) 1434 siglongjmp(*sigbuf, 1); 1435 abort(); 1436 } 1437 } 1438 1439 /* 1440 * For non-cooperative userfaultfd test we fork() a process that will 1441 * generate pagefaults, will mremap the area monitored by the 1442 * userfaultfd and at last this process will release the monitored 1443 * area. 1444 * For the anonymous and shared memory the area is divided into two 1445 * parts, the first part is accessed before mremap, and the second 1446 * part is accessed after mremap. Since hugetlbfs does not support 1447 * mremap, the entire monitored area is accessed in a single pass for 1448 * HUGETLB_TEST. 1449 * The release of the pages currently generates event for shmem and 1450 * anonymous memory (UFFD_EVENT_REMOVE), hence it is not checked 1451 * for hugetlb. 1452 * For signal test(UFFD_FEATURE_SIGBUS), signal_test = 1, we register 1453 * monitored area, generate pagefaults and test that signal is delivered. 1454 * Use UFFDIO_COPY to allocate missing page and retry. For signal_test = 2 1455 * test robustness use case - we release monitored area, fork a process 1456 * that will generate pagefaults and verify signal is generated. 1457 * This also tests UFFD_FEATURE_EVENT_FORK event along with the signal 1458 * feature. Using monitor thread, verify no userfault events are generated. 1459 */ 1460 static int faulting_process(uffd_global_test_opts_t *gopts, int signal_test, bool wp) 1461 { 1462 unsigned long nr, i; 1463 unsigned long long count; 1464 unsigned long split_nr_pages; 1465 unsigned long lastnr; 1466 struct sigaction act; 1467 volatile unsigned long signalled = 0; 1468 1469 split_nr_pages = (gopts->nr_pages + 1) / 2; 1470 1471 if (signal_test) { 1472 sigbuf = &jbuf; 1473 memset(&act, 0, sizeof(act)); 1474 act.sa_sigaction = sighndl; 1475 act.sa_flags = SA_SIGINFO; 1476 if (sigaction(SIGBUS, &act, 0)) 1477 err("sigaction"); 1478 lastnr = (unsigned long)-1; 1479 } 1480 1481 for (nr = 0; nr < split_nr_pages; nr++) { 1482 volatile int steps = 1; 1483 unsigned long offset = nr * gopts->page_size; 1484 1485 if (signal_test) { 1486 if (sigsetjmp(*sigbuf, 1) != 0) { 1487 if (steps == 1 && nr == lastnr) 1488 err("Signal repeated"); 1489 1490 lastnr = nr; 1491 if (signal_test == 1) { 1492 if (steps == 1) { 1493 /* This is a MISSING request */ 1494 steps++; 1495 if (copy_page(gopts, offset, wp)) 1496 signalled++; 1497 } else { 1498 /* This is a WP request */ 1499 assert(steps == 2); 1500 wp_range(gopts->uffd, 1501 (__u64)gopts->area_dst + 1502 offset, 1503 gopts->page_size, false); 1504 } 1505 } else { 1506 signalled++; 1507 continue; 1508 } 1509 } 1510 } 1511 1512 count = *area_count(gopts->area_dst, nr, gopts); 1513 if (count != gopts->count_verify[nr]) 1514 err("nr %lu memory corruption %llu %llu\n", 1515 nr, count, gopts->count_verify[nr]); 1516 /* 1517 * Trigger write protection if there is by writing 1518 * the same value back. 1519 */ 1520 *area_count(gopts->area_dst, nr, gopts) = count; 1521 } 1522 1523 if (signal_test) 1524 return signalled != split_nr_pages; 1525 1526 gopts->area_dst = mremap(gopts->area_dst, gopts->nr_pages * gopts->page_size, 1527 gopts->nr_pages * gopts->page_size, 1528 MREMAP_MAYMOVE | MREMAP_FIXED, 1529 gopts->area_src); 1530 if (gopts->area_dst == MAP_FAILED) 1531 err("mremap"); 1532 /* Reset area_src since we just clobbered it */ 1533 gopts->area_src = NULL; 1534 1535 for (; nr < gopts->nr_pages; nr++) { 1536 count = *area_count(gopts->area_dst, nr, gopts); 1537 if (count != gopts->count_verify[nr]) { 1538 err("nr %lu memory corruption %llu %llu\n", 1539 nr, count, gopts->count_verify[nr]); 1540 } 1541 /* 1542 * Trigger write protection if there is by writing 1543 * the same value back. 1544 */ 1545 *area_count(gopts->area_dst, nr, gopts) = count; 1546 } 1547 1548 uffd_test_ops->release_pages(gopts, gopts->area_dst); 1549 1550 for (nr = 0; nr < gopts->nr_pages; nr++) 1551 for (i = 0; i < gopts->page_size; i++) 1552 if (*(gopts->area_dst + nr * gopts->page_size + i) != 0) 1553 err("page %lu offset %lu is not zero", nr, i); 1554 1555 return 0; 1556 } 1557 1558 static void uffd_sigbus_test_common(uffd_global_test_opts_t *gopts, bool wp) 1559 { 1560 unsigned long userfaults; 1561 pthread_t uffd_mon; 1562 pid_t pid; 1563 int err; 1564 char c = '\0'; 1565 struct uffd_args args = { 0 }; 1566 args.gopts = gopts; 1567 1568 gopts->ready_for_fork = false; 1569 1570 fcntl(gopts->uffd, F_SETFL, gopts->uffd_flags | O_NONBLOCK); 1571 1572 if (uffd_register(gopts->uffd, gopts->area_dst, gopts->nr_pages * gopts->page_size, 1573 true, wp, false)) 1574 err("register failure"); 1575 1576 if (faulting_process(gopts, 1, wp)) 1577 err("faulting process failed"); 1578 1579 uffd_test_ops->release_pages(gopts, gopts->area_dst); 1580 1581 args.apply_wp = wp; 1582 if (pthread_create(&uffd_mon, NULL, uffd_poll_thread, &args)) 1583 err("uffd_poll_thread create"); 1584 1585 while (!gopts->ready_for_fork) 1586 ; /* Wait for the poll_thread to start executing before forking */ 1587 1588 pid = fork(); 1589 if (pid < 0) 1590 err("fork"); 1591 1592 if (!pid) 1593 _exit(faulting_process(gopts, 2, wp)); 1594 1595 waitpid(pid, &err, 0); 1596 if (err) 1597 err("faulting process failed"); 1598 if (write(gopts->pipefd[1], &c, sizeof(c)) != sizeof(c)) 1599 err("pipe write"); 1600 if (pthread_join(uffd_mon, (void **)&userfaults)) 1601 err("pthread_join()"); 1602 1603 if (userfaults) 1604 uffd_test_fail("Signal test failed, userfaults: %ld", userfaults); 1605 else 1606 uffd_test_pass(); 1607 } 1608 1609 static void uffd_sigbus_test(uffd_global_test_opts_t *gopts, uffd_test_args_t *args) 1610 { 1611 uffd_sigbus_test_common(gopts, false); 1612 } 1613 1614 static void uffd_sigbus_wp_test(uffd_global_test_opts_t *gopts, uffd_test_args_t *args) 1615 { 1616 uffd_sigbus_test_common(gopts, true); 1617 } 1618 1619 static void uffd_events_test_common(uffd_global_test_opts_t *gopts, bool wp) 1620 { 1621 pthread_t uffd_mon; 1622 pid_t pid; 1623 int err; 1624 char c = '\0'; 1625 struct uffd_args args = { 0 }; 1626 args.gopts = gopts; 1627 1628 gopts->ready_for_fork = false; 1629 1630 fcntl(gopts->uffd, F_SETFL, gopts->uffd_flags | O_NONBLOCK); 1631 if (uffd_register(gopts->uffd, gopts->area_dst, gopts->nr_pages * gopts->page_size, 1632 true, wp, false)) 1633 err("register failure"); 1634 1635 args.apply_wp = wp; 1636 if (pthread_create(&uffd_mon, NULL, uffd_poll_thread, &args)) 1637 err("uffd_poll_thread create"); 1638 1639 while (!gopts->ready_for_fork) 1640 ; /* Wait for the poll_thread to start executing before forking */ 1641 1642 pid = fork(); 1643 if (pid < 0) 1644 err("fork"); 1645 1646 if (!pid) 1647 _exit(faulting_process(gopts, 0, wp)); 1648 1649 waitpid(pid, &err, 0); 1650 if (err) 1651 err("faulting process failed"); 1652 if (write(gopts->pipefd[1], &c, sizeof(c)) != sizeof(c)) 1653 err("pipe write"); 1654 if (pthread_join(uffd_mon, NULL)) 1655 err("pthread_join()"); 1656 1657 if (args.missing_faults != gopts->nr_pages) 1658 uffd_test_fail("Fault counts wrong"); 1659 else 1660 uffd_test_pass(); 1661 } 1662 1663 static void uffd_events_test(uffd_global_test_opts_t *gopts, uffd_test_args_t *args) 1664 { 1665 uffd_events_test_common(gopts, false); 1666 } 1667 1668 static void uffd_events_wp_test(uffd_global_test_opts_t *gopts, uffd_test_args_t *args) 1669 { 1670 uffd_events_test_common(gopts, true); 1671 } 1672 1673 static void retry_uffdio_zeropage(uffd_global_test_opts_t *gopts, 1674 struct uffdio_zeropage *uffdio_zeropage) 1675 { 1676 uffd_test_ops->alias_mapping(gopts, &uffdio_zeropage->range.start, 1677 uffdio_zeropage->range.len, 1678 0); 1679 if (ioctl(gopts->uffd, UFFDIO_ZEROPAGE, uffdio_zeropage)) { 1680 if (uffdio_zeropage->zeropage != -EEXIST) 1681 err("UFFDIO_ZEROPAGE error: %"PRId64, 1682 (int64_t)uffdio_zeropage->zeropage); 1683 } else { 1684 err("UFFDIO_ZEROPAGE error: %"PRId64, 1685 (int64_t)uffdio_zeropage->zeropage); 1686 } 1687 } 1688 1689 static bool do_uffdio_zeropage(uffd_global_test_opts_t *gopts, bool has_zeropage) 1690 { 1691 struct uffdio_zeropage uffdio_zeropage = { 0 }; 1692 int ret; 1693 __s64 res; 1694 1695 uffdio_zeropage.range.start = (unsigned long) gopts->area_dst; 1696 uffdio_zeropage.range.len = gopts->page_size; 1697 uffdio_zeropage.mode = 0; 1698 ret = ioctl(gopts->uffd, UFFDIO_ZEROPAGE, &uffdio_zeropage); 1699 res = uffdio_zeropage.zeropage; 1700 if (ret) { 1701 /* real retval in ufdio_zeropage.zeropage */ 1702 if (has_zeropage) 1703 err("UFFDIO_ZEROPAGE error: %"PRId64, (int64_t)res); 1704 else if (res != -EINVAL) 1705 err("UFFDIO_ZEROPAGE not -EINVAL"); 1706 } else if (has_zeropage) { 1707 if (res != gopts->page_size) 1708 err("UFFDIO_ZEROPAGE unexpected size"); 1709 else 1710 retry_uffdio_zeropage(gopts, &uffdio_zeropage); 1711 return true; 1712 } else 1713 err("UFFDIO_ZEROPAGE succeeded"); 1714 1715 return false; 1716 } 1717 1718 /* 1719 * Registers a range with MISSING mode only for zeropage test. Return true 1720 * if UFFDIO_ZEROPAGE supported, false otherwise. Can't use uffd_register() 1721 * because we want to detect .ioctls along the way. 1722 */ 1723 static bool 1724 uffd_register_detect_zeropage(int uffd, void *addr, uint64_t len) 1725 { 1726 uint64_t ioctls = 0; 1727 1728 if (uffd_register_with_ioctls(uffd, addr, len, true, 1729 false, false, &ioctls)) 1730 err("zeropage register fail"); 1731 1732 return ioctls & (1 << _UFFDIO_ZEROPAGE); 1733 } 1734 1735 /* exercise UFFDIO_ZEROPAGE */ 1736 static void uffd_zeropage_test(uffd_global_test_opts_t *gopts, uffd_test_args_t *args) 1737 { 1738 bool has_zeropage; 1739 int i; 1740 1741 has_zeropage = uffd_register_detect_zeropage(gopts->uffd, 1742 gopts->area_dst, 1743 gopts->page_size); 1744 if (gopts->area_dst_alias) 1745 /* Ignore the retval; we already have it */ 1746 uffd_register_detect_zeropage(gopts->uffd, gopts->area_dst_alias, gopts->page_size); 1747 1748 if (do_uffdio_zeropage(gopts, has_zeropage)) 1749 for (i = 0; i < gopts->page_size; i++) 1750 if (gopts->area_dst[i] != 0) 1751 err("data non-zero at offset %d\n", i); 1752 1753 if (uffd_unregister(gopts->uffd, gopts->area_dst, gopts->page_size)) 1754 err("unregister"); 1755 1756 if (gopts->area_dst_alias && uffd_unregister(gopts->uffd, 1757 gopts->area_dst_alias, 1758 gopts->page_size)) 1759 err("unregister"); 1760 1761 uffd_test_pass(); 1762 } 1763 1764 static void uffd_register_poison(int uffd, void *addr, uint64_t len) 1765 { 1766 uint64_t ioctls = 0; 1767 uint64_t expected = (1 << _UFFDIO_COPY) | (1 << _UFFDIO_POISON); 1768 1769 if (uffd_register_with_ioctls(uffd, addr, len, true, 1770 false, false, &ioctls)) 1771 err("poison register fail"); 1772 1773 if ((ioctls & expected) != expected) 1774 err("registered area doesn't support COPY and POISON ioctls"); 1775 } 1776 1777 static void do_uffdio_poison(uffd_global_test_opts_t *gopts, unsigned long offset) 1778 { 1779 struct uffdio_poison uffdio_poison = { 0 }; 1780 int ret; 1781 __s64 res; 1782 1783 uffdio_poison.range.start = (unsigned long) gopts->area_dst + offset; 1784 uffdio_poison.range.len = gopts->page_size; 1785 uffdio_poison.mode = 0; 1786 ret = ioctl(gopts->uffd, UFFDIO_POISON, &uffdio_poison); 1787 res = uffdio_poison.updated; 1788 1789 if (ret) 1790 err("UFFDIO_POISON error: %"PRId64, (int64_t)res); 1791 else if (res != gopts->page_size) 1792 err("UFFDIO_POISON unexpected size: %"PRId64, (int64_t)res); 1793 } 1794 1795 static void uffd_poison_handle_fault(uffd_global_test_opts_t *gopts, 1796 struct uffd_msg *msg, 1797 struct uffd_args *args) 1798 { 1799 unsigned long offset; 1800 1801 if (msg->event != UFFD_EVENT_PAGEFAULT) 1802 err("unexpected msg event %u", msg->event); 1803 1804 if (msg->arg.pagefault.flags & 1805 (UFFD_PAGEFAULT_FLAG_WP | UFFD_PAGEFAULT_FLAG_MINOR)) 1806 err("unexpected fault type %llu", msg->arg.pagefault.flags); 1807 1808 offset = (char *)(unsigned long)msg->arg.pagefault.address - gopts->area_dst; 1809 offset &= ~(gopts->page_size-1); 1810 1811 /* Odd pages -> copy zeroed page; even pages -> poison. */ 1812 if (offset & gopts->page_size) 1813 copy_page(gopts, offset, false); 1814 else 1815 do_uffdio_poison(gopts, offset); 1816 } 1817 1818 /* Make sure to cover odd/even, and minimum duplications */ 1819 #define UFFD_POISON_TEST_NPAGES 4 1820 1821 static void uffd_poison_test(uffd_global_test_opts_t *gopts, uffd_test_args_t *targs) 1822 { 1823 pthread_t uffd_mon; 1824 char c; 1825 struct uffd_args args = { 0 }; 1826 struct sigaction act = { 0 }; 1827 unsigned long nr_sigbus = 0; 1828 unsigned long nr, poison_pages = UFFD_POISON_TEST_NPAGES; 1829 1830 if (gopts->nr_pages < poison_pages) { 1831 uffd_test_skip("Too less pages for POISON test"); 1832 return; 1833 } 1834 1835 args.gopts = gopts; 1836 1837 fcntl(gopts->uffd, F_SETFL, gopts->uffd_flags | O_NONBLOCK); 1838 1839 uffd_register_poison(gopts->uffd, gopts->area_dst, poison_pages * gopts->page_size); 1840 memset(gopts->area_src, 0, poison_pages * gopts->page_size); 1841 1842 args.handle_fault = uffd_poison_handle_fault; 1843 if (pthread_create(&uffd_mon, NULL, uffd_poll_thread, &args)) 1844 err("uffd_poll_thread create"); 1845 1846 sigbuf = &jbuf; 1847 act.sa_sigaction = sighndl; 1848 act.sa_flags = SA_SIGINFO; 1849 if (sigaction(SIGBUS, &act, 0)) 1850 err("sigaction"); 1851 1852 for (nr = 0; nr < poison_pages; ++nr) { 1853 unsigned long offset = nr * gopts->page_size; 1854 const char *bytes = (const char *) gopts->area_dst + offset; 1855 const char *i; 1856 1857 if (sigsetjmp(*sigbuf, 1)) { 1858 /* 1859 * Access below triggered a SIGBUS, which was caught by 1860 * sighndl, which then jumped here. Count this SIGBUS, 1861 * and move on to next page. 1862 */ 1863 ++nr_sigbus; 1864 continue; 1865 } 1866 1867 for (i = bytes; i < bytes + gopts->page_size; ++i) { 1868 if (*i) 1869 err("nonzero byte in area_dst (%p) at %p: %u", 1870 gopts->area_dst, i, *i); 1871 } 1872 } 1873 1874 if (write(gopts->pipefd[1], &c, sizeof(c)) != sizeof(c)) 1875 err("pipe write"); 1876 if (pthread_join(uffd_mon, NULL)) 1877 err("pthread_join()"); 1878 1879 if (nr_sigbus != poison_pages / 2) 1880 err("expected to receive %lu SIGBUS, actually received %lu", 1881 poison_pages / 2, nr_sigbus); 1882 1883 uffd_test_pass(); 1884 } 1885 1886 static void 1887 uffd_move_handle_fault_common(uffd_global_test_opts_t *gopts, 1888 struct uffd_msg *msg, 1889 struct uffd_args *args, 1890 unsigned long len) 1891 { 1892 unsigned long offset; 1893 1894 if (msg->event != UFFD_EVENT_PAGEFAULT) 1895 err("unexpected msg event %u", msg->event); 1896 1897 if (msg->arg.pagefault.flags & 1898 (UFFD_PAGEFAULT_FLAG_WP | UFFD_PAGEFAULT_FLAG_MINOR | UFFD_PAGEFAULT_FLAG_WRITE)) 1899 err("unexpected fault type %llu", msg->arg.pagefault.flags); 1900 1901 offset = (char *)(unsigned long)msg->arg.pagefault.address - gopts->area_dst; 1902 offset &= ~(len-1); 1903 1904 if (move_page(gopts, offset, len)) 1905 args->missing_faults++; 1906 } 1907 1908 static void uffd_move_handle_fault(uffd_global_test_opts_t *gopts, struct uffd_msg *msg, 1909 struct uffd_args *args) 1910 { 1911 uffd_move_handle_fault_common(gopts, msg, args, gopts->page_size); 1912 } 1913 1914 static void uffd_move_pmd_handle_fault(uffd_global_test_opts_t *gopts, struct uffd_msg *msg, 1915 struct uffd_args *args) 1916 { 1917 uffd_move_handle_fault_common(gopts, msg, args, read_pmd_pagesize()); 1918 } 1919 1920 static void 1921 uffd_move_test_common(uffd_global_test_opts_t *gopts, 1922 uffd_test_args_t *targs, 1923 unsigned long chunk_size, 1924 void (*handle_fault)(struct uffd_global_test_opts *gopts, 1925 struct uffd_msg *msg, struct uffd_args *args) 1926 ) 1927 { 1928 unsigned long nr; 1929 pthread_t uffd_mon; 1930 char c = '\0'; 1931 unsigned long long count; 1932 struct uffd_args args = { 0 }; 1933 char *orig_area_src = NULL, *orig_area_dst = NULL; 1934 unsigned long step_size, step_count; 1935 unsigned long src_offs = 0; 1936 unsigned long dst_offs = 0; 1937 1938 args.gopts = gopts; 1939 1940 /* Prevent source pages from being mapped more than once */ 1941 if (madvise(gopts->area_src, gopts->nr_pages * gopts->page_size, MADV_DONTFORK)) 1942 err("madvise(MADV_DONTFORK) failure"); 1943 1944 if (uffd_register(gopts->uffd, gopts->area_dst, gopts->nr_pages * gopts->page_size, 1945 true, false, false)) 1946 err("register failure"); 1947 1948 args.handle_fault = handle_fault; 1949 if (pthread_create(&uffd_mon, NULL, uffd_poll_thread, &args)) 1950 err("uffd_poll_thread create"); 1951 1952 step_size = chunk_size / gopts->page_size; 1953 step_count = gopts->nr_pages / step_size; 1954 1955 if (chunk_size > gopts->page_size) { 1956 char *aligned_src = ALIGN_UP(gopts->area_src, chunk_size); 1957 char *aligned_dst = ALIGN_UP(gopts->area_dst, chunk_size); 1958 1959 if (aligned_src != gopts->area_src || aligned_dst != gopts->area_dst) { 1960 src_offs = (aligned_src - gopts->area_src) / gopts->page_size; 1961 dst_offs = (aligned_dst - gopts->area_dst) / gopts->page_size; 1962 step_count--; 1963 } 1964 orig_area_src = gopts->area_src; 1965 orig_area_dst = gopts->area_dst; 1966 gopts->area_src = aligned_src; 1967 gopts->area_dst = aligned_dst; 1968 } 1969 1970 /* 1971 * Read each of the pages back using the UFFD-registered mapping. We 1972 * expect that the first time we touch a page, it will result in a missing 1973 * fault. uffd_poll_thread will resolve the fault by moving source 1974 * page to destination. 1975 */ 1976 for (nr = 0; nr < step_count * step_size; nr += step_size) { 1977 unsigned long i; 1978 1979 /* Check area_src content */ 1980 for (i = 0; i < step_size; i++) { 1981 count = *area_count(gopts->area_src, nr + i, gopts); 1982 if (count != gopts->count_verify[src_offs + nr + i]) 1983 err("nr %lu source memory invalid %llu %llu\n", 1984 nr + i, count, gopts->count_verify[src_offs + nr + i]); 1985 } 1986 1987 /* Faulting into area_dst should move the page or the huge page */ 1988 for (i = 0; i < step_size; i++) { 1989 count = *area_count(gopts->area_dst, nr + i, gopts); 1990 if (count != gopts->count_verify[dst_offs + nr + i]) 1991 err("nr %lu memory corruption %llu %llu\n", 1992 nr, count, gopts->count_verify[dst_offs + nr + i]); 1993 } 1994 1995 /* Re-check area_src content which should be empty */ 1996 for (i = 0; i < step_size; i++) { 1997 count = *area_count(gopts->area_src, nr + i, gopts); 1998 if (count != 0) 1999 err("nr %lu move failed %llu %llu\n", 2000 nr, count, gopts->count_verify[src_offs + nr + i]); 2001 } 2002 } 2003 if (chunk_size > gopts->page_size) { 2004 gopts->area_src = orig_area_src; 2005 gopts->area_dst = orig_area_dst; 2006 } 2007 2008 if (write(gopts->pipefd[1], &c, sizeof(c)) != sizeof(c)) 2009 err("pipe write"); 2010 if (pthread_join(uffd_mon, NULL)) 2011 err("join() failed"); 2012 2013 if (args.missing_faults != step_count || args.minor_faults != 0) 2014 uffd_test_fail("stats check error"); 2015 else 2016 uffd_test_pass(); 2017 } 2018 2019 static void uffd_move_test(uffd_global_test_opts_t *gopts, uffd_test_args_t *targs) 2020 { 2021 uffd_move_test_common(gopts, targs, gopts->page_size, uffd_move_handle_fault); 2022 } 2023 2024 static void uffd_move_pmd_test(uffd_global_test_opts_t *gopts, uffd_test_args_t *targs) 2025 { 2026 if (madvise(gopts->area_dst, gopts->nr_pages * gopts->page_size, MADV_HUGEPAGE)) 2027 err("madvise(MADV_HUGEPAGE) failure"); 2028 uffd_move_test_common(gopts, targs, read_pmd_pagesize(), 2029 uffd_move_pmd_handle_fault); 2030 } 2031 2032 static void uffd_move_pmd_split_test(uffd_global_test_opts_t *gopts, uffd_test_args_t *targs) 2033 { 2034 if (madvise(gopts->area_dst, gopts->nr_pages * gopts->page_size, MADV_NOHUGEPAGE)) 2035 err("madvise(MADV_NOHUGEPAGE) failure"); 2036 uffd_move_test_common(gopts, targs, read_pmd_pagesize(), 2037 uffd_move_pmd_handle_fault); 2038 } 2039 2040 static bool 2041 uffdio_verify_results(const char *name, int ret, int error, long result) 2042 { 2043 /* 2044 * Should always return -1 with errno=EAGAIN, with corresponding 2045 * result field updated in ioctl() args to be -EAGAIN too 2046 * (e.g. copy.copy field for UFFDIO_COPY). 2047 */ 2048 if (ret != -1) { 2049 uffd_test_fail("%s should have returned -1", name); 2050 return false; 2051 } 2052 2053 if (error != EAGAIN) { 2054 uffd_test_fail("%s should have errno==EAGAIN", name); 2055 return false; 2056 } 2057 2058 if (result != -EAGAIN) { 2059 uffd_test_fail("%s should have been updated for -EAGAIN", 2060 name); 2061 return false; 2062 } 2063 2064 return true; 2065 } 2066 2067 /* 2068 * This defines a function to test one ioctl. Note that here "field" can 2069 * be 1 or anything not -EAGAIN. With that initial value set, we can 2070 * verify later that it should be updated by kernel (when -EAGAIN 2071 * returned), by checking whether it is also updated to -EAGAIN. 2072 */ 2073 #define DEFINE_MMAP_CHANGING_TEST(name, ioctl_name, field) \ 2074 static bool uffdio_mmap_changing_test_##name(int fd) \ 2075 { \ 2076 int ret; \ 2077 struct uffdio_##name args = { \ 2078 .field = 1, \ 2079 }; \ 2080 ret = ioctl(fd, ioctl_name, &args); \ 2081 return uffdio_verify_results(#ioctl_name, ret, errno, args.field); \ 2082 } 2083 2084 DEFINE_MMAP_CHANGING_TEST(zeropage, UFFDIO_ZEROPAGE, zeropage) 2085 DEFINE_MMAP_CHANGING_TEST(copy, UFFDIO_COPY, copy) 2086 DEFINE_MMAP_CHANGING_TEST(move, UFFDIO_MOVE, move) 2087 DEFINE_MMAP_CHANGING_TEST(poison, UFFDIO_POISON, updated) 2088 DEFINE_MMAP_CHANGING_TEST(continue, UFFDIO_CONTINUE, mapped) 2089 2090 typedef enum { 2091 /* We actually do not care about any state except UNINTERRUPTIBLE.. */ 2092 THR_STATE_UNKNOWN = 0, 2093 THR_STATE_UNINTERRUPTIBLE, 2094 } thread_state; 2095 2096 typedef struct { 2097 uffd_global_test_opts_t *gopts; 2098 volatile pid_t *pid; 2099 } mmap_changing_thread_args; 2100 2101 static void sleep_short(void) 2102 { 2103 usleep(1000); 2104 } 2105 2106 static thread_state thread_state_get(pid_t tid) 2107 { 2108 const char *header = "State:\t"; 2109 char tmp[256], *p, c; 2110 FILE *fp; 2111 2112 snprintf(tmp, sizeof(tmp), "/proc/%d/status", tid); 2113 fp = fopen(tmp, "r"); 2114 2115 if (!fp) 2116 return THR_STATE_UNKNOWN; 2117 2118 while (fgets(tmp, sizeof(tmp), fp)) { 2119 p = strstr(tmp, header); 2120 if (p) { 2121 /* For example, "State:\tD (disk sleep)" */ 2122 c = *(p + strlen(header)); 2123 return c == 'D' ? 2124 THR_STATE_UNINTERRUPTIBLE : THR_STATE_UNKNOWN; 2125 } 2126 } 2127 2128 return THR_STATE_UNKNOWN; 2129 } 2130 2131 static void thread_state_until(pid_t tid, thread_state state) 2132 { 2133 thread_state s; 2134 2135 do { 2136 s = thread_state_get(tid); 2137 sleep_short(); 2138 } while (s != state); 2139 } 2140 2141 static void *uffd_mmap_changing_thread(void *opaque) 2142 { 2143 mmap_changing_thread_args *args = opaque; 2144 uffd_global_test_opts_t *gopts = args->gopts; 2145 volatile pid_t *pid = args->pid; 2146 int ret; 2147 2148 /* Unfortunately, it's only fetch-able from the thread itself.. */ 2149 assert(*pid == 0); 2150 *pid = syscall(SYS_gettid); 2151 2152 /* Inject an event, this will hang solid until the event read */ 2153 ret = madvise(gopts->area_dst, gopts->page_size, MADV_REMOVE); 2154 if (ret) 2155 err("madvise(MADV_REMOVE) failed"); 2156 2157 return NULL; 2158 } 2159 2160 static void uffd_consume_message(uffd_global_test_opts_t *gopts) 2161 { 2162 struct uffd_msg msg = { 0 }; 2163 2164 while (uffd_read_msg(gopts, &msg)); 2165 } 2166 2167 static void uffd_mmap_changing_test(uffd_global_test_opts_t *gopts, uffd_test_args_t *targs) 2168 { 2169 /* 2170 * This stores the real PID (which can be different from how tid is 2171 * defined..) for the child thread, 0 means not initialized. 2172 */ 2173 pid_t pid = 0; 2174 pthread_t tid; 2175 int ret; 2176 mmap_changing_thread_args args = { gopts, &pid }; 2177 2178 if (uffd_register(gopts->uffd, gopts->area_dst, gopts->nr_pages * gopts->page_size, 2179 true, false, false)) 2180 err("uffd_register() failed"); 2181 2182 /* Create a thread to generate the racy event */ 2183 ret = pthread_create(&tid, NULL, uffd_mmap_changing_thread, &args); 2184 if (ret) 2185 err("pthread_create() failed"); 2186 2187 /* 2188 * Wait until the thread setup the pid. Use volatile to make sure 2189 * it reads from RAM not regs. 2190 */ 2191 while (!(volatile pid_t)pid) 2192 sleep_short(); 2193 2194 /* Wait until the thread hangs at REMOVE event */ 2195 thread_state_until(pid, THR_STATE_UNINTERRUPTIBLE); 2196 2197 if (!uffdio_mmap_changing_test_copy(gopts->uffd)) 2198 return; 2199 2200 if (!uffdio_mmap_changing_test_zeropage(gopts->uffd)) 2201 return; 2202 2203 if (!uffdio_mmap_changing_test_move(gopts->uffd)) 2204 return; 2205 2206 if (!uffdio_mmap_changing_test_poison(gopts->uffd)) 2207 return; 2208 2209 if (!uffdio_mmap_changing_test_continue(gopts->uffd)) 2210 return; 2211 2212 /* 2213 * All succeeded above! Recycle everything. Start by reading the 2214 * event so as to kick the thread roll again.. 2215 */ 2216 uffd_consume_message(gopts); 2217 2218 ret = pthread_join(tid, NULL); 2219 assert(ret == 0); 2220 2221 uffd_test_pass(); 2222 } 2223 2224 static int prevent_hugepages(uffd_global_test_opts_t *gopts, const char **errmsg) 2225 { 2226 /* This should be done before source area is populated */ 2227 if (madvise(gopts->area_src, gopts->nr_pages * gopts->page_size, MADV_NOHUGEPAGE)) { 2228 /* Ignore only if CONFIG_TRANSPARENT_HUGEPAGE=n */ 2229 if (errno != EINVAL) { 2230 if (errmsg) 2231 *errmsg = "madvise(MADV_NOHUGEPAGE) failed"; 2232 return -errno; 2233 } 2234 } 2235 return 0; 2236 } 2237 2238 static int request_hugepages(uffd_global_test_opts_t *gopts, const char **errmsg) 2239 { 2240 /* This should be done before source area is populated */ 2241 if (madvise(gopts->area_src, gopts->nr_pages * gopts->page_size, MADV_HUGEPAGE)) { 2242 if (errmsg) { 2243 *errmsg = (errno == EINVAL) ? 2244 "CONFIG_TRANSPARENT_HUGEPAGE is not set" : 2245 "madvise(MADV_HUGEPAGE) failed"; 2246 } 2247 return -errno; 2248 } 2249 return 0; 2250 } 2251 2252 struct uffd_test_case_ops uffd_move_test_case_ops = { 2253 .post_alloc = prevent_hugepages, 2254 }; 2255 2256 struct uffd_test_case_ops uffd_move_test_pmd_case_ops = { 2257 .post_alloc = request_hugepages, 2258 }; 2259 2260 /* 2261 * Test the returned uffdio_register.ioctls with different register modes. 2262 * Note that _UFFDIO_ZEROPAGE is tested separately in the zeropage test. 2263 */ 2264 static void 2265 do_register_ioctls_test(uffd_global_test_opts_t *gopts, 2266 uffd_test_args_t *args, 2267 bool miss, 2268 bool wp, 2269 bool minor) 2270 { 2271 uint64_t ioctls = 0, expected = BIT_ULL(_UFFDIO_WAKE); 2272 mem_type_t *mem_type = args->mem_type; 2273 int ret; 2274 2275 ret = uffd_register_with_ioctls(gopts->uffd, gopts->area_dst, gopts->page_size, 2276 miss, wp, minor, &ioctls); 2277 2278 /* 2279 * Handle special cases of UFFDIO_REGISTER here where it should 2280 * just fail with -EINVAL first.. 2281 * 2282 * Case 1: register MINOR on anon 2283 * Case 2: register with no mode selected 2284 */ 2285 if ((minor && (mem_type->mem_flag == MEM_ANON)) || 2286 (!miss && !wp && !minor)) { 2287 if (ret != -EINVAL) 2288 err("register (miss=%d, wp=%d, minor=%d) failed " 2289 "with wrong errno=%d", miss, wp, minor, ret); 2290 return; 2291 } 2292 2293 /* UFFDIO_REGISTER should succeed, then check ioctls returned */ 2294 if (miss) 2295 expected |= BIT_ULL(_UFFDIO_COPY); 2296 if (wp) 2297 expected |= BIT_ULL(_UFFDIO_WRITEPROTECT); 2298 if (minor) 2299 expected |= BIT_ULL(_UFFDIO_CONTINUE); 2300 2301 if ((ioctls & expected) != expected) 2302 err("unexpected uffdio_register.ioctls " 2303 "(miss=%d, wp=%d, minor=%d): expected=0x%"PRIx64", " 2304 "returned=0x%"PRIx64, miss, wp, minor, expected, ioctls); 2305 2306 if (uffd_unregister(gopts->uffd, gopts->area_dst, gopts->page_size)) 2307 err("unregister"); 2308 } 2309 2310 static void uffd_register_ioctls_test(uffd_global_test_opts_t *gopts, uffd_test_args_t *args) 2311 { 2312 int miss, wp, minor; 2313 2314 for (miss = 0; miss <= 1; miss++) 2315 for (wp = 0; wp <= 1; wp++) 2316 for (minor = 0; minor <= 1; minor++) 2317 do_register_ioctls_test(gopts, args, miss, wp, minor); 2318 2319 uffd_test_pass(); 2320 } 2321 2322 uffd_test_case_t uffd_tests[] = { 2323 { 2324 /* Test returned uffdio_register.ioctls. */ 2325 .name = "register-ioctls", 2326 .uffd_fn = uffd_register_ioctls_test, 2327 .mem_targets = MEM_ALL, 2328 .uffd_feature_required = UFFD_FEATURE_MISSING_HUGETLBFS | 2329 UFFD_FEATURE_MISSING_SHMEM | 2330 UFFD_FEATURE_PAGEFAULT_FLAG_WP | 2331 UFFD_FEATURE_WP_HUGETLBFS_SHMEM | 2332 UFFD_FEATURE_MINOR_HUGETLBFS | 2333 UFFD_FEATURE_MINOR_SHMEM, 2334 }, 2335 { 2336 .name = "zeropage", 2337 .uffd_fn = uffd_zeropage_test, 2338 .mem_targets = MEM_ALL, 2339 .uffd_feature_required = 0, 2340 }, 2341 { 2342 .name = "move", 2343 .uffd_fn = uffd_move_test, 2344 .mem_targets = MEM_ANON, 2345 .uffd_feature_required = UFFD_FEATURE_MOVE, 2346 .test_case_ops = &uffd_move_test_case_ops, 2347 }, 2348 { 2349 .name = "move-pmd", 2350 .uffd_fn = uffd_move_pmd_test, 2351 .mem_targets = MEM_ANON, 2352 .uffd_feature_required = UFFD_FEATURE_MOVE, 2353 .test_case_ops = &uffd_move_test_pmd_case_ops, 2354 }, 2355 { 2356 .name = "move-pmd-split", 2357 .uffd_fn = uffd_move_pmd_split_test, 2358 .mem_targets = MEM_ANON, 2359 .uffd_feature_required = UFFD_FEATURE_MOVE, 2360 .test_case_ops = &uffd_move_test_pmd_case_ops, 2361 }, 2362 { 2363 .name = "wp-fork", 2364 .uffd_fn = uffd_wp_fork_test, 2365 .mem_targets = MEM_ALL, 2366 .uffd_feature_required = UFFD_FEATURE_PAGEFAULT_FLAG_WP | 2367 UFFD_FEATURE_WP_HUGETLBFS_SHMEM, 2368 }, 2369 { 2370 .name = "wp-fork-with-event", 2371 .uffd_fn = uffd_wp_fork_with_event_test, 2372 .mem_targets = MEM_ALL, 2373 .uffd_feature_required = UFFD_FEATURE_PAGEFAULT_FLAG_WP | 2374 UFFD_FEATURE_WP_HUGETLBFS_SHMEM | 2375 /* when set, child process should inherit uffd-wp bits */ 2376 UFFD_FEATURE_EVENT_FORK, 2377 }, 2378 { 2379 .name = "wp-fork-pin", 2380 .uffd_fn = uffd_wp_fork_pin_test, 2381 .mem_targets = MEM_ALL, 2382 .uffd_feature_required = UFFD_FEATURE_PAGEFAULT_FLAG_WP | 2383 UFFD_FEATURE_WP_HUGETLBFS_SHMEM, 2384 }, 2385 { 2386 .name = "wp-fork-pin-with-event", 2387 .uffd_fn = uffd_wp_fork_pin_with_event_test, 2388 .mem_targets = MEM_ALL, 2389 .uffd_feature_required = UFFD_FEATURE_PAGEFAULT_FLAG_WP | 2390 UFFD_FEATURE_WP_HUGETLBFS_SHMEM | 2391 /* when set, child process should inherit uffd-wp bits */ 2392 UFFD_FEATURE_EVENT_FORK, 2393 }, 2394 { 2395 .name = "wp-unpopulated", 2396 .uffd_fn = uffd_wp_unpopulated_test, 2397 .mem_targets = MEM_ANON, 2398 .uffd_feature_required = 2399 UFFD_FEATURE_PAGEFAULT_FLAG_WP | UFFD_FEATURE_WP_UNPOPULATED, 2400 }, 2401 { 2402 .name = "minor", 2403 .uffd_fn = uffd_minor_test, 2404 .mem_targets = MEM_SHMEM | MEM_HUGETLB, 2405 .uffd_feature_required = 2406 UFFD_FEATURE_MINOR_HUGETLBFS | UFFD_FEATURE_MINOR_SHMEM, 2407 }, 2408 { 2409 .name = "minor-wp", 2410 .uffd_fn = uffd_minor_wp_test, 2411 .mem_targets = MEM_SHMEM | MEM_HUGETLB, 2412 .uffd_feature_required = 2413 UFFD_FEATURE_MINOR_HUGETLBFS | UFFD_FEATURE_MINOR_SHMEM | 2414 UFFD_FEATURE_PAGEFAULT_FLAG_WP | 2415 /* 2416 * HACK: here we leveraged WP_UNPOPULATED to detect whether 2417 * minor mode supports wr-protect. There's no feature flag 2418 * for it so this is the best we can test against. 2419 */ 2420 UFFD_FEATURE_WP_UNPOPULATED, 2421 }, 2422 { 2423 .name = "minor-collapse", 2424 .uffd_fn = uffd_minor_collapse_test, 2425 /* MADV_COLLAPSE only works with shmem */ 2426 .mem_targets = MEM_SHMEM, 2427 /* We can't test MADV_COLLAPSE, so try our luck */ 2428 .uffd_feature_required = UFFD_FEATURE_MINOR_SHMEM, 2429 }, 2430 { 2431 .name = "rwp-async", 2432 .uffd_fn = uffd_rwp_async_test, 2433 .mem_targets = MEM_ALL, 2434 .uffd_feature_required = 2435 UFFD_FEATURE_RWP | UFFD_FEATURE_RWP_ASYNC, 2436 }, 2437 { 2438 .name = "rwp-sync", 2439 .uffd_fn = uffd_rwp_sync_test, 2440 .mem_targets = MEM_ALL, 2441 .uffd_feature_required = UFFD_FEATURE_RWP, 2442 }, 2443 { 2444 .name = "rwp-pagemap", 2445 .uffd_fn = uffd_rwp_pagemap_test, 2446 .mem_targets = MEM_ALL, 2447 .uffd_feature_required = 2448 UFFD_FEATURE_RWP | UFFD_FEATURE_RWP_ASYNC, 2449 }, 2450 { 2451 .name = "rwp-mprotect", 2452 .uffd_fn = uffd_rwp_mprotect_test, 2453 .mem_targets = MEM_ALL, 2454 .uffd_feature_required = 2455 UFFD_FEATURE_RWP | UFFD_FEATURE_RWP_ASYNC, 2456 }, 2457 { 2458 .name = "rwp-gup", 2459 .uffd_fn = uffd_rwp_gup_test, 2460 .mem_targets = MEM_ALL, 2461 .uffd_feature_required = 2462 UFFD_FEATURE_RWP | UFFD_FEATURE_RWP_ASYNC, 2463 }, 2464 { 2465 .name = "rwp-async-toggle", 2466 .uffd_fn = uffd_rwp_async_toggle_test, 2467 .mem_targets = MEM_ALL, 2468 .uffd_feature_required = 2469 UFFD_FEATURE_RWP | UFFD_FEATURE_RWP_ASYNC, 2470 }, 2471 { 2472 .name = "rwp-close", 2473 .uffd_fn = uffd_rwp_close_test, 2474 .mem_targets = MEM_ALL, 2475 .uffd_feature_required = UFFD_FEATURE_RWP, 2476 }, 2477 { 2478 .name = "rwp-fork", 2479 .uffd_fn = uffd_rwp_fork_test, 2480 .mem_targets = MEM_ALL, 2481 .uffd_feature_required = 2482 UFFD_FEATURE_RWP | UFFD_FEATURE_EVENT_FORK, 2483 }, 2484 { 2485 .name = "rwp-fork-pin", 2486 .uffd_fn = uffd_rwp_fork_pin_test, 2487 .mem_targets = MEM_ANON, 2488 .uffd_feature_required = 2489 UFFD_FEATURE_RWP | UFFD_FEATURE_RWP_ASYNC | 2490 UFFD_FEATURE_EVENT_FORK, 2491 }, 2492 { 2493 .name = "rwp-swap-cow", 2494 .uffd_fn = uffd_rwp_swap_cow_test, 2495 .mem_targets = MEM_ANON, 2496 .uffd_feature_required = UFFD_FEATURE_RWP, 2497 }, 2498 { 2499 .name = "rwp-wp-exclusive", 2500 .uffd_fn = uffd_rwp_wp_exclusive_test, 2501 .mem_targets = MEM_ALL, 2502 .uffd_feature_required = 2503 UFFD_FEATURE_RWP | 2504 UFFD_FEATURE_PAGEFAULT_FLAG_WP | 2505 UFFD_FEATURE_WP_HUGETLBFS_SHMEM, 2506 }, 2507 { 2508 .name = "sigbus", 2509 .uffd_fn = uffd_sigbus_test, 2510 .mem_targets = MEM_ALL, 2511 .uffd_feature_required = UFFD_FEATURE_SIGBUS | 2512 UFFD_FEATURE_EVENT_FORK, 2513 }, 2514 { 2515 .name = "sigbus-wp", 2516 .uffd_fn = uffd_sigbus_wp_test, 2517 .mem_targets = MEM_ALL, 2518 .uffd_feature_required = UFFD_FEATURE_SIGBUS | 2519 UFFD_FEATURE_EVENT_FORK | UFFD_FEATURE_PAGEFAULT_FLAG_WP | 2520 UFFD_FEATURE_WP_HUGETLBFS_SHMEM, 2521 }, 2522 { 2523 .name = "events", 2524 .uffd_fn = uffd_events_test, 2525 .mem_targets = MEM_ALL, 2526 .uffd_feature_required = UFFD_FEATURE_EVENT_FORK | 2527 UFFD_FEATURE_EVENT_REMAP | UFFD_FEATURE_EVENT_REMOVE, 2528 }, 2529 { 2530 .name = "events-wp", 2531 .uffd_fn = uffd_events_wp_test, 2532 .mem_targets = MEM_ALL, 2533 .uffd_feature_required = UFFD_FEATURE_EVENT_FORK | 2534 UFFD_FEATURE_EVENT_REMAP | UFFD_FEATURE_EVENT_REMOVE | 2535 UFFD_FEATURE_PAGEFAULT_FLAG_WP | 2536 UFFD_FEATURE_WP_HUGETLBFS_SHMEM, 2537 }, 2538 { 2539 .name = "poison", 2540 .uffd_fn = uffd_poison_test, 2541 .mem_targets = MEM_ALL, 2542 .uffd_feature_required = UFFD_FEATURE_POISON, 2543 }, 2544 { 2545 .name = "mmap-changing", 2546 .uffd_fn = uffd_mmap_changing_test, 2547 /* 2548 * There's no point running this test over all mem types as 2549 * they share the same code paths. 2550 * 2551 * Choose shmem for simplicity, because (1) shmem supports 2552 * MINOR mode to cover UFFDIO_CONTINUE, and (2) shmem is 2553 * almost always available (unlike hugetlb). Here we 2554 * abused SHMEM for UFFDIO_MOVE, but the test we want to 2555 * cover doesn't yet need the correct memory type.. 2556 */ 2557 .mem_targets = MEM_SHMEM, 2558 /* 2559 * Any UFFD_FEATURE_EVENT_* should work to trigger the 2560 * race logically, but choose the simplest (REMOVE). 2561 * 2562 * Meanwhile, since we'll cover quite a few new ioctl()s 2563 * (CONTINUE, POISON, MOVE), skip this test for old kernels 2564 * by choosing all of them. 2565 */ 2566 .uffd_feature_required = UFFD_FEATURE_EVENT_REMOVE | 2567 UFFD_FEATURE_MOVE | UFFD_FEATURE_POISON | 2568 UFFD_FEATURE_MINOR_SHMEM, 2569 }, 2570 }; 2571 2572 static void usage(const char *prog) 2573 { 2574 printf("usage: %s [-f TESTNAME]\n", prog); 2575 puts(""); 2576 puts(" -f: test name to filter (e.g., event)"); 2577 puts(" -h: show the help msg"); 2578 puts(" -l: list tests only"); 2579 puts(""); 2580 exit(KSFT_FAIL); 2581 } 2582 2583 static int uffd_count_tests(int n_tests, int n_mems, const char *test_filter) 2584 { 2585 uffd_test_case_t *test; 2586 int i, j, count = 0; 2587 2588 if (!test_filter) 2589 count += 2; /* test_uffd_api(false) + test_uffd_api(true) */ 2590 2591 for (i = 0; i < n_tests; i++) { 2592 test = &uffd_tests[i]; 2593 if (test_filter && !strstr(test->name, test_filter)) 2594 continue; 2595 for (j = 0; j < n_mems; j++) 2596 if (test->mem_targets & mem_types[j].mem_flag) 2597 count++; 2598 } 2599 2600 return count; 2601 } 2602 2603 static unsigned long uffd_setup_hugetlb(void) 2604 { 2605 unsigned long nr_hugepages, hp_size; 2606 2607 hugetlb_save_settings(); 2608 hp_size = default_huge_page_size(); 2609 2610 if (!hp_size) 2611 return 0; 2612 2613 /* need twice UFFD_TEST_MEM_SIZE, one for src area and one for dst */ 2614 nr_hugepages = 2 * MAX(UFFD_TEST_MEM_SIZE, hp_size * 2) / hp_size; 2615 hugetlb_set_nr_default_pages(nr_hugepages); 2616 2617 if (hugetlb_free_default_pages() < nr_hugepages) 2618 return 0; 2619 2620 return hp_size; 2621 } 2622 2623 int main(int argc, char *argv[]) 2624 { 2625 int n_tests = sizeof(uffd_tests) / sizeof(uffd_test_case_t); 2626 int n_mems = sizeof(mem_types) / sizeof(mem_type_t); 2627 const char *test_filter = NULL; 2628 unsigned long hugepage_size; 2629 bool list_only = false; 2630 uffd_test_case_t *test; 2631 mem_type_t *mem_type; 2632 uffd_test_args_t args; 2633 const char *errmsg; 2634 int i, j, opt; 2635 2636 while ((opt = getopt(argc, argv, "f:hl")) != -1) { 2637 switch (opt) { 2638 case 'f': 2639 test_filter = optarg; 2640 break; 2641 case 'l': 2642 list_only = true; 2643 break; 2644 case 'h': 2645 default: 2646 /* Unknown */ 2647 usage(argv[0]); 2648 break; 2649 } 2650 } 2651 2652 if (list_only) { 2653 for (i = 0; i < n_tests; i++) { 2654 test = &uffd_tests[i]; 2655 if (test_filter && !strstr(test->name, test_filter)) 2656 continue; 2657 printf("%s\n", test->name); 2658 } 2659 return KSFT_PASS; 2660 } 2661 2662 hugepage_size = uffd_setup_hugetlb(); 2663 2664 ksft_print_header(); 2665 ksft_set_plan(uffd_count_tests(n_tests, n_mems, test_filter)); 2666 2667 if (!test_filter) { 2668 test_uffd_api(false); 2669 test_uffd_api(true); 2670 } 2671 2672 for (i = 0; i < n_tests; i++) { 2673 test = &uffd_tests[i]; 2674 if (test_filter && !strstr(test->name, test_filter)) 2675 continue; 2676 for (j = 0; j < n_mems; j++) { 2677 mem_type = &mem_types[j]; 2678 2679 /* Initialize global test options */ 2680 uffd_global_test_opts_t gopts = { 0 }; 2681 2682 gopts.map_shared = mem_type->shared; 2683 uffd_test_ops = mem_type->mem_ops; 2684 uffd_test_case_ops = test->test_case_ops; 2685 2686 if (!(test->mem_targets & mem_type->mem_flag)) 2687 continue; 2688 2689 uffd_test_start("%s on %s", test->name, mem_type->name); 2690 if (mem_type->mem_flag & (MEM_HUGETLB_PRIVATE | MEM_HUGETLB)) { 2691 gopts.page_size = hugepage_size; 2692 if (gopts.page_size == 0) { 2693 uffd_test_skip("not enough HugeTLB pages"); 2694 continue; 2695 } 2696 } else { 2697 gopts.page_size = psize(); 2698 } 2699 2700 /* Ensure we have at least 2 pages */ 2701 gopts.nr_pages = MAX(UFFD_TEST_MEM_SIZE, gopts.page_size * 2) 2702 / gopts.page_size; 2703 2704 gopts.nr_parallel = 1; 2705 2706 /* Initialize test arguments */ 2707 args.mem_type = mem_type; 2708 2709 if (!uffd_feature_supported(test)) { 2710 uffd_test_skip("feature missing"); 2711 continue; 2712 } 2713 if (uffd_test_ctx_init(&gopts, test->uffd_feature_required, &errmsg)) { 2714 uffd_test_skip(errmsg); 2715 continue; 2716 } 2717 /* 2718 * RWP tracks protection on ptes; a THP-backed shmem/anon 2719 * range (e.g. shmem_enabled=always) would split on 2720 * rwprotect and change behaviour under the test. Keep 2721 * such ranges off THP. hugetlb is huge by definition and 2722 * rejects MADV_NOHUGEPAGE, so skip it. 2723 */ 2724 if ((test->uffd_feature_required & UFFD_FEATURE_RWP) && 2725 !(mem_type->mem_flag & (MEM_HUGETLB | MEM_HUGETLB_PRIVATE))) { 2726 unsigned long len = gopts.nr_pages * gopts.page_size; 2727 2728 /* 2729 * EINVAL means CONFIG_TRANSPARENT_HUGEPAGE=n: 2730 * nothing to opt out of. 2731 */ 2732 if (madvise(gopts.area_dst, len, MADV_NOHUGEPAGE) && 2733 errno != EINVAL) 2734 err("madvise(MADV_NOHUGEPAGE)"); 2735 } 2736 test->uffd_fn(&gopts, &args); 2737 uffd_test_ctx_clear(&gopts); 2738 } 2739 } 2740 2741 ksft_finished(); 2742 } 2743 2744 #else /* __NR_userfaultfd */ 2745 2746 #warning "missing __NR_userfaultfd definition" 2747 2748 int main(void) 2749 { 2750 ksft_print_header(); 2751 ksft_exit_skip("missing __NR_userfaultfd definition\n"); 2752 } 2753 2754 #endif /* __NR_userfaultfd */ 2755