1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * KSM functional tests 4 * 5 * Copyright 2022, Red Hat, Inc. 6 * 7 * Author(s): David Hildenbrand <david@redhat.com> 8 */ 9 #define _GNU_SOURCE 10 #include <stdlib.h> 11 #include <string.h> 12 #include <stdbool.h> 13 #include <stdint.h> 14 #include <unistd.h> 15 #include <errno.h> 16 #include <fcntl.h> 17 #include <sys/mman.h> 18 #include <sys/prctl.h> 19 #include <sys/syscall.h> 20 #include <sys/ioctl.h> 21 #include <sys/wait.h> 22 #include <linux/userfaultfd.h> 23 24 #include "../kselftest.h" 25 #include "vm_util.h" 26 27 #define KiB 1024u 28 #define MiB (1024 * KiB) 29 #define FORK_EXEC_CHILD_PRG_NAME "ksm_fork_exec_child" 30 31 #define MAP_MERGE_FAIL ((void *)-1) 32 #define MAP_MERGE_SKIP ((void *)-2) 33 34 enum ksm_merge_mode { 35 KSM_MERGE_PRCTL, 36 KSM_MERGE_MADVISE, 37 KSM_MERGE_NONE, /* PRCTL already set */ 38 }; 39 40 static int mem_fd; 41 static int ksm_fd; 42 static int ksm_full_scans_fd; 43 static int proc_self_ksm_stat_fd; 44 static int proc_self_ksm_merging_pages_fd; 45 static int ksm_use_zero_pages_fd; 46 static int pagemap_fd; 47 static size_t pagesize; 48 49 static bool range_maps_duplicates(char *addr, unsigned long size) 50 { 51 unsigned long offs_a, offs_b, pfn_a, pfn_b; 52 53 /* 54 * There is no easy way to check if there are KSM pages mapped into 55 * this range. We only check that the range does not map the same PFN 56 * twice by comparing each pair of mapped pages. 57 */ 58 for (offs_a = 0; offs_a < size; offs_a += pagesize) { 59 pfn_a = pagemap_get_pfn(pagemap_fd, addr + offs_a); 60 /* Page not present or PFN not exposed by the kernel. */ 61 if (pfn_a == -1ul || !pfn_a) 62 continue; 63 64 for (offs_b = offs_a + pagesize; offs_b < size; 65 offs_b += pagesize) { 66 pfn_b = pagemap_get_pfn(pagemap_fd, addr + offs_b); 67 if (pfn_b == -1ul || !pfn_b) 68 continue; 69 if (pfn_a == pfn_b) 70 return true; 71 } 72 } 73 return false; 74 } 75 76 static long get_my_ksm_zero_pages(void) 77 { 78 char buf[200]; 79 char *substr_ksm_zero; 80 size_t value_pos; 81 ssize_t read_size; 82 unsigned long my_ksm_zero_pages; 83 84 if (!proc_self_ksm_stat_fd) 85 return 0; 86 87 read_size = pread(proc_self_ksm_stat_fd, buf, sizeof(buf) - 1, 0); 88 if (read_size < 0) 89 return -errno; 90 91 buf[read_size] = 0; 92 93 substr_ksm_zero = strstr(buf, "ksm_zero_pages"); 94 if (!substr_ksm_zero) 95 return 0; 96 97 value_pos = strcspn(substr_ksm_zero, "0123456789"); 98 my_ksm_zero_pages = strtol(substr_ksm_zero + value_pos, NULL, 10); 99 100 return my_ksm_zero_pages; 101 } 102 103 static long get_my_merging_pages(void) 104 { 105 char buf[10]; 106 ssize_t ret; 107 108 if (proc_self_ksm_merging_pages_fd < 0) 109 return proc_self_ksm_merging_pages_fd; 110 111 ret = pread(proc_self_ksm_merging_pages_fd, buf, sizeof(buf) - 1, 0); 112 if (ret <= 0) 113 return -errno; 114 buf[ret] = 0; 115 116 return strtol(buf, NULL, 10); 117 } 118 119 static long ksm_get_full_scans(void) 120 { 121 char buf[10]; 122 ssize_t ret; 123 124 ret = pread(ksm_full_scans_fd, buf, sizeof(buf) - 1, 0); 125 if (ret <= 0) 126 return -errno; 127 buf[ret] = 0; 128 129 return strtol(buf, NULL, 10); 130 } 131 132 static int ksm_merge(void) 133 { 134 long start_scans, end_scans; 135 136 /* Wait for two full scans such that any possible merging happened. */ 137 start_scans = ksm_get_full_scans(); 138 if (start_scans < 0) 139 return start_scans; 140 if (write(ksm_fd, "1", 1) != 1) 141 return -errno; 142 do { 143 end_scans = ksm_get_full_scans(); 144 if (end_scans < 0) 145 return end_scans; 146 } while (end_scans < start_scans + 2); 147 148 return 0; 149 } 150 151 static int ksm_unmerge(void) 152 { 153 if (write(ksm_fd, "2", 1) != 1) 154 return -errno; 155 return 0; 156 } 157 158 static char *__mmap_and_merge_range(char val, unsigned long size, int prot, 159 enum ksm_merge_mode mode) 160 { 161 char *map; 162 char *err_map = MAP_MERGE_FAIL; 163 int ret; 164 165 /* Stabilize accounting by disabling KSM completely. */ 166 if (ksm_unmerge()) { 167 ksft_print_msg("Disabling (unmerging) KSM failed\n"); 168 return err_map; 169 } 170 171 if (get_my_merging_pages() > 0) { 172 ksft_print_msg("Still pages merged\n"); 173 return err_map; 174 } 175 176 map = mmap(NULL, size, PROT_READ|PROT_WRITE, 177 MAP_PRIVATE|MAP_ANON, -1, 0); 178 if (map == MAP_FAILED) { 179 ksft_print_msg("mmap() failed\n"); 180 return err_map; 181 } 182 183 /* Don't use THP. Ignore if THP are not around on a kernel. */ 184 if (madvise(map, size, MADV_NOHUGEPAGE) && errno != EINVAL) { 185 ksft_print_msg("MADV_NOHUGEPAGE failed\n"); 186 goto unmap; 187 } 188 189 /* Make sure each page contains the same values to merge them. */ 190 memset(map, val, size); 191 192 if (mprotect(map, size, prot)) { 193 ksft_print_msg("mprotect() failed\n"); 194 err_map = MAP_MERGE_SKIP; 195 goto unmap; 196 } 197 198 switch (mode) { 199 case KSM_MERGE_PRCTL: 200 ret = prctl(PR_SET_MEMORY_MERGE, 1, 0, 0, 0); 201 if (ret < 0 && errno == EINVAL) { 202 ksft_print_msg("PR_SET_MEMORY_MERGE not supported\n"); 203 err_map = MAP_MERGE_SKIP; 204 goto unmap; 205 } else if (ret) { 206 ksft_print_msg("PR_SET_MEMORY_MERGE=1 failed\n"); 207 goto unmap; 208 } 209 break; 210 case KSM_MERGE_MADVISE: 211 if (madvise(map, size, MADV_MERGEABLE)) { 212 ksft_print_msg("MADV_MERGEABLE failed\n"); 213 goto unmap; 214 } 215 break; 216 case KSM_MERGE_NONE: 217 break; 218 } 219 220 /* Run KSM to trigger merging and wait. */ 221 if (ksm_merge()) { 222 ksft_print_msg("Running KSM failed\n"); 223 goto unmap; 224 } 225 226 /* 227 * Check if anything was merged at all. Ignore the zero page that is 228 * accounted differently (depending on kernel support). 229 */ 230 if (val && !get_my_merging_pages()) { 231 ksft_print_msg("No pages got merged\n"); 232 goto unmap; 233 } 234 235 return map; 236 unmap: 237 munmap(map, size); 238 return err_map; 239 } 240 241 static char *mmap_and_merge_range(char val, unsigned long size, int prot, 242 enum ksm_merge_mode mode) 243 { 244 char *map; 245 char *ret = MAP_FAILED; 246 247 map = __mmap_and_merge_range(val, size, prot, mode); 248 if (map == MAP_MERGE_FAIL) 249 ksft_test_result_fail("Merging memory failed"); 250 else if (map == MAP_MERGE_SKIP) 251 ksft_test_result_skip("Merging memory skipped"); 252 else 253 ret = map; 254 255 return ret; 256 } 257 258 static void test_unmerge(void) 259 { 260 const unsigned int size = 2 * MiB; 261 char *map; 262 263 ksft_print_msg("[RUN] %s\n", __func__); 264 265 map = mmap_and_merge_range(0xcf, size, PROT_READ | PROT_WRITE, KSM_MERGE_MADVISE); 266 if (map == MAP_FAILED) 267 return; 268 269 if (madvise(map, size, MADV_UNMERGEABLE)) { 270 ksft_test_result_fail("MADV_UNMERGEABLE failed\n"); 271 goto unmap; 272 } 273 274 ksft_test_result(!range_maps_duplicates(map, size), 275 "Pages were unmerged\n"); 276 unmap: 277 munmap(map, size); 278 } 279 280 static void test_unmerge_zero_pages(void) 281 { 282 const unsigned int size = 2 * MiB; 283 char *map; 284 unsigned int offs; 285 unsigned long pages_expected; 286 287 ksft_print_msg("[RUN] %s\n", __func__); 288 289 if (proc_self_ksm_stat_fd < 0) { 290 ksft_test_result_skip("open(\"/proc/self/ksm_stat\") failed\n"); 291 return; 292 } 293 if (ksm_use_zero_pages_fd < 0) { 294 ksft_test_result_skip("open \"/sys/kernel/mm/ksm/use_zero_pages\" failed\n"); 295 return; 296 } 297 if (write(ksm_use_zero_pages_fd, "1", 1) != 1) { 298 ksft_test_result_skip("write \"/sys/kernel/mm/ksm/use_zero_pages\" failed\n"); 299 return; 300 } 301 302 /* Let KSM deduplicate zero pages. */ 303 map = mmap_and_merge_range(0x00, size, PROT_READ | PROT_WRITE, KSM_MERGE_MADVISE); 304 if (map == MAP_FAILED) 305 return; 306 307 /* Check if ksm_zero_pages is updated correctly after KSM merging */ 308 pages_expected = size / pagesize; 309 if (pages_expected != get_my_ksm_zero_pages()) { 310 ksft_test_result_fail("'ksm_zero_pages' updated after merging\n"); 311 goto unmap; 312 } 313 314 /* Try to unmerge half of the region */ 315 if (madvise(map, size / 2, MADV_UNMERGEABLE)) { 316 ksft_test_result_fail("MADV_UNMERGEABLE failed\n"); 317 goto unmap; 318 } 319 320 /* Check if ksm_zero_pages is updated correctly after unmerging */ 321 pages_expected /= 2; 322 if (pages_expected != get_my_ksm_zero_pages()) { 323 ksft_test_result_fail("'ksm_zero_pages' updated after unmerging\n"); 324 goto unmap; 325 } 326 327 /* Trigger unmerging of the other half by writing to the pages. */ 328 for (offs = size / 2; offs < size; offs += pagesize) 329 *((unsigned int *)&map[offs]) = offs; 330 331 /* Now we should have no zeropages remaining. */ 332 if (get_my_ksm_zero_pages()) { 333 ksft_test_result_fail("'ksm_zero_pages' updated after write fault\n"); 334 goto unmap; 335 } 336 337 /* Check if ksm zero pages are really unmerged */ 338 ksft_test_result(!range_maps_duplicates(map, size), 339 "KSM zero pages were unmerged\n"); 340 unmap: 341 munmap(map, size); 342 } 343 344 static void test_unmerge_discarded(void) 345 { 346 const unsigned int size = 2 * MiB; 347 char *map; 348 349 ksft_print_msg("[RUN] %s\n", __func__); 350 351 map = mmap_and_merge_range(0xcf, size, PROT_READ | PROT_WRITE, KSM_MERGE_MADVISE); 352 if (map == MAP_FAILED) 353 return; 354 355 /* Discard half of all mapped pages so we have pte_none() entries. */ 356 if (madvise(map, size / 2, MADV_DONTNEED)) { 357 ksft_test_result_fail("MADV_DONTNEED failed\n"); 358 goto unmap; 359 } 360 361 if (madvise(map, size, MADV_UNMERGEABLE)) { 362 ksft_test_result_fail("MADV_UNMERGEABLE failed\n"); 363 goto unmap; 364 } 365 366 ksft_test_result(!range_maps_duplicates(map, size), 367 "Pages were unmerged\n"); 368 unmap: 369 munmap(map, size); 370 } 371 372 #ifdef __NR_userfaultfd 373 static void test_unmerge_uffd_wp(void) 374 { 375 struct uffdio_writeprotect uffd_writeprotect; 376 const unsigned int size = 2 * MiB; 377 struct uffdio_api uffdio_api; 378 char *map; 379 int uffd; 380 381 ksft_print_msg("[RUN] %s\n", __func__); 382 383 map = mmap_and_merge_range(0xcf, size, PROT_READ | PROT_WRITE, KSM_MERGE_MADVISE); 384 if (map == MAP_FAILED) 385 return; 386 387 /* See if UFFD is around. */ 388 uffd = syscall(__NR_userfaultfd, O_CLOEXEC | O_NONBLOCK); 389 if (uffd < 0) { 390 ksft_test_result_skip("__NR_userfaultfd failed\n"); 391 goto unmap; 392 } 393 394 /* See if UFFD-WP is around. */ 395 uffdio_api.api = UFFD_API; 396 uffdio_api.features = UFFD_FEATURE_PAGEFAULT_FLAG_WP; 397 if (ioctl(uffd, UFFDIO_API, &uffdio_api) < 0) { 398 ksft_test_result_fail("UFFDIO_API failed\n"); 399 goto close_uffd; 400 } 401 if (!(uffdio_api.features & UFFD_FEATURE_PAGEFAULT_FLAG_WP)) { 402 ksft_test_result_skip("UFFD_FEATURE_PAGEFAULT_FLAG_WP not available\n"); 403 goto close_uffd; 404 } 405 406 /* Register UFFD-WP, no need for an actual handler. */ 407 if (uffd_register(uffd, map, size, false, true, false)) { 408 ksft_test_result_fail("UFFDIO_REGISTER_MODE_WP failed\n"); 409 goto close_uffd; 410 } 411 412 /* Write-protect the range using UFFD-WP. */ 413 uffd_writeprotect.range.start = (unsigned long) map; 414 uffd_writeprotect.range.len = size; 415 uffd_writeprotect.mode = UFFDIO_WRITEPROTECT_MODE_WP; 416 if (ioctl(uffd, UFFDIO_WRITEPROTECT, &uffd_writeprotect)) { 417 ksft_test_result_fail("UFFDIO_WRITEPROTECT failed\n"); 418 goto close_uffd; 419 } 420 421 if (madvise(map, size, MADV_UNMERGEABLE)) { 422 ksft_test_result_fail("MADV_UNMERGEABLE failed\n"); 423 goto close_uffd; 424 } 425 426 ksft_test_result(!range_maps_duplicates(map, size), 427 "Pages were unmerged\n"); 428 close_uffd: 429 close(uffd); 430 unmap: 431 munmap(map, size); 432 } 433 #endif 434 435 /* Verify that KSM can be enabled / queried with prctl. */ 436 static void test_prctl(void) 437 { 438 int ret; 439 440 ksft_print_msg("[RUN] %s\n", __func__); 441 442 ret = prctl(PR_SET_MEMORY_MERGE, 1, 0, 0, 0); 443 if (ret < 0 && errno == EINVAL) { 444 ksft_test_result_skip("PR_SET_MEMORY_MERGE not supported\n"); 445 return; 446 } else if (ret) { 447 ksft_test_result_fail("PR_SET_MEMORY_MERGE=1 failed\n"); 448 return; 449 } 450 451 ret = prctl(PR_GET_MEMORY_MERGE, 0, 0, 0, 0); 452 if (ret < 0) { 453 ksft_test_result_fail("PR_GET_MEMORY_MERGE failed\n"); 454 return; 455 } else if (ret != 1) { 456 ksft_test_result_fail("PR_SET_MEMORY_MERGE=1 not effective\n"); 457 return; 458 } 459 460 ret = prctl(PR_SET_MEMORY_MERGE, 0, 0, 0, 0); 461 if (ret) { 462 ksft_test_result_fail("PR_SET_MEMORY_MERGE=0 failed\n"); 463 return; 464 } 465 466 ret = prctl(PR_GET_MEMORY_MERGE, 0, 0, 0, 0); 467 if (ret < 0) { 468 ksft_test_result_fail("PR_GET_MEMORY_MERGE failed\n"); 469 return; 470 } else if (ret != 0) { 471 ksft_test_result_fail("PR_SET_MEMORY_MERGE=0 not effective\n"); 472 return; 473 } 474 475 ksft_test_result_pass("Setting/clearing PR_SET_MEMORY_MERGE works\n"); 476 } 477 478 static int test_child_ksm(void) 479 { 480 const unsigned int size = 2 * MiB; 481 char *map; 482 483 /* Test if KSM is enabled for the process. */ 484 if (prctl(PR_GET_MEMORY_MERGE, 0, 0, 0, 0) != 1) 485 return -1; 486 487 /* Test if merge could really happen. */ 488 map = __mmap_and_merge_range(0xcf, size, PROT_READ | PROT_WRITE, KSM_MERGE_NONE); 489 if (map == MAP_MERGE_FAIL) 490 return -2; 491 else if (map == MAP_MERGE_SKIP) 492 return -3; 493 494 munmap(map, size); 495 return 0; 496 } 497 498 static void test_child_ksm_err(int status) 499 { 500 if (status == -1) 501 ksft_test_result_fail("unexpected PR_GET_MEMORY_MERGE result in child\n"); 502 else if (status == -2) 503 ksft_test_result_fail("Merge in child failed\n"); 504 else if (status == -3) 505 ksft_test_result_skip("Merge in child skipped\n"); 506 } 507 508 /* Verify that prctl ksm flag is inherited. */ 509 static void test_prctl_fork(void) 510 { 511 int ret, status; 512 pid_t child_pid; 513 514 ksft_print_msg("[RUN] %s\n", __func__); 515 516 ret = prctl(PR_SET_MEMORY_MERGE, 1, 0, 0, 0); 517 if (ret < 0 && errno == EINVAL) { 518 ksft_test_result_skip("PR_SET_MEMORY_MERGE not supported\n"); 519 return; 520 } else if (ret) { 521 ksft_test_result_fail("PR_SET_MEMORY_MERGE=1 failed\n"); 522 return; 523 } 524 525 child_pid = fork(); 526 if (!child_pid) { 527 exit(test_child_ksm()); 528 } else if (child_pid < 0) { 529 ksft_test_result_fail("fork() failed\n"); 530 return; 531 } 532 533 if (waitpid(child_pid, &status, 0) < 0) { 534 ksft_test_result_fail("waitpid() failed\n"); 535 return; 536 } 537 538 status = WEXITSTATUS(status); 539 if (status) { 540 test_child_ksm_err(status); 541 return; 542 } 543 544 if (prctl(PR_SET_MEMORY_MERGE, 0, 0, 0, 0)) { 545 ksft_test_result_fail("PR_SET_MEMORY_MERGE=0 failed\n"); 546 return; 547 } 548 549 ksft_test_result_pass("PR_SET_MEMORY_MERGE value is inherited\n"); 550 } 551 552 static void test_prctl_fork_exec(void) 553 { 554 int ret, status; 555 pid_t child_pid; 556 557 ksft_print_msg("[RUN] %s\n", __func__); 558 559 ret = prctl(PR_SET_MEMORY_MERGE, 1, 0, 0, 0); 560 if (ret < 0 && errno == EINVAL) { 561 ksft_test_result_skip("PR_SET_MEMORY_MERGE not supported\n"); 562 return; 563 } else if (ret) { 564 ksft_test_result_fail("PR_SET_MEMORY_MERGE=1 failed\n"); 565 return; 566 } 567 568 child_pid = fork(); 569 if (child_pid == -1) { 570 ksft_test_result_skip("fork() failed\n"); 571 return; 572 } else if (child_pid == 0) { 573 char *prg_name = "./ksm_functional_tests"; 574 char *argv_for_program[] = { prg_name, FORK_EXEC_CHILD_PRG_NAME }; 575 576 execv(prg_name, argv_for_program); 577 return; 578 } 579 580 if (waitpid(child_pid, &status, 0) > 0) { 581 if (WIFEXITED(status)) { 582 status = WEXITSTATUS(status); 583 if (status) { 584 test_child_ksm_err(status); 585 return; 586 } 587 } else { 588 ksft_test_result_fail("program didn't terminate normally\n"); 589 return; 590 } 591 } else { 592 ksft_test_result_fail("waitpid() failed\n"); 593 return; 594 } 595 596 if (prctl(PR_SET_MEMORY_MERGE, 0, 0, 0, 0)) { 597 ksft_test_result_fail("PR_SET_MEMORY_MERGE=0 failed\n"); 598 return; 599 } 600 601 ksft_test_result_pass("PR_SET_MEMORY_MERGE value is inherited\n"); 602 } 603 604 static void test_prctl_unmerge(void) 605 { 606 const unsigned int size = 2 * MiB; 607 char *map; 608 609 ksft_print_msg("[RUN] %s\n", __func__); 610 611 map = mmap_and_merge_range(0xcf, size, PROT_READ | PROT_WRITE, KSM_MERGE_PRCTL); 612 if (map == MAP_FAILED) 613 return; 614 615 if (prctl(PR_SET_MEMORY_MERGE, 0, 0, 0, 0)) { 616 ksft_test_result_fail("PR_SET_MEMORY_MERGE=0 failed\n"); 617 goto unmap; 618 } 619 620 ksft_test_result(!range_maps_duplicates(map, size), 621 "Pages were unmerged\n"); 622 unmap: 623 munmap(map, size); 624 } 625 626 static void test_prot_none(void) 627 { 628 const unsigned int size = 2 * MiB; 629 char *map; 630 int i; 631 632 ksft_print_msg("[RUN] %s\n", __func__); 633 634 map = mmap_and_merge_range(0x11, size, PROT_NONE, KSM_MERGE_MADVISE); 635 if (map == MAP_FAILED) 636 goto unmap; 637 638 /* Store a unique value in each page on one half using ptrace */ 639 for (i = 0; i < size / 2; i += pagesize) { 640 lseek(mem_fd, (uintptr_t) map + i, SEEK_SET); 641 if (write(mem_fd, &i, sizeof(i)) != sizeof(i)) { 642 ksft_test_result_fail("ptrace write failed\n"); 643 goto unmap; 644 } 645 } 646 647 /* Trigger unsharing on the other half. */ 648 if (madvise(map + size / 2, size / 2, MADV_UNMERGEABLE)) { 649 ksft_test_result_fail("MADV_UNMERGEABLE failed\n"); 650 goto unmap; 651 } 652 653 ksft_test_result(!range_maps_duplicates(map, size), 654 "Pages were unmerged\n"); 655 unmap: 656 munmap(map, size); 657 } 658 659 int main(int argc, char **argv) 660 { 661 unsigned int tests = 8; 662 int err; 663 664 if (argc > 1 && !strcmp(argv[1], FORK_EXEC_CHILD_PRG_NAME)) { 665 exit(test_child_ksm()); 666 } 667 668 #ifdef __NR_userfaultfd 669 tests++; 670 #endif 671 672 ksft_print_header(); 673 ksft_set_plan(tests); 674 675 pagesize = getpagesize(); 676 677 mem_fd = open("/proc/self/mem", O_RDWR); 678 if (mem_fd < 0) 679 ksft_exit_fail_msg("opening /proc/self/mem failed\n"); 680 ksm_fd = open("/sys/kernel/mm/ksm/run", O_RDWR); 681 if (ksm_fd < 0) 682 ksft_exit_skip("open(\"/sys/kernel/mm/ksm/run\") failed\n"); 683 ksm_full_scans_fd = open("/sys/kernel/mm/ksm/full_scans", O_RDONLY); 684 if (ksm_full_scans_fd < 0) 685 ksft_exit_skip("open(\"/sys/kernel/mm/ksm/full_scans\") failed\n"); 686 pagemap_fd = open("/proc/self/pagemap", O_RDONLY); 687 if (pagemap_fd < 0) 688 ksft_exit_skip("open(\"/proc/self/pagemap\") failed\n"); 689 proc_self_ksm_stat_fd = open("/proc/self/ksm_stat", O_RDONLY); 690 proc_self_ksm_merging_pages_fd = open("/proc/self/ksm_merging_pages", 691 O_RDONLY); 692 ksm_use_zero_pages_fd = open("/sys/kernel/mm/ksm/use_zero_pages", O_RDWR); 693 694 test_unmerge(); 695 test_unmerge_zero_pages(); 696 test_unmerge_discarded(); 697 #ifdef __NR_userfaultfd 698 test_unmerge_uffd_wp(); 699 #endif 700 701 test_prot_none(); 702 703 test_prctl(); 704 test_prctl_fork(); 705 test_prctl_fork_exec(); 706 test_prctl_unmerge(); 707 708 err = ksft_get_fail_cnt(); 709 if (err) 710 ksft_exit_fail_msg("%d out of %d tests failed\n", 711 err, ksft_test_num()); 712 ksft_exit_pass(); 713 } 714