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 = 0; 397 if (ioctl(uffd, UFFDIO_API, &uffdio_api) < 0) { 398 if (errno == EINVAL) 399 ksft_test_result_skip("The API version requested is not supported\n"); 400 else 401 ksft_test_result_fail("UFFDIO_API failed: %s\n", strerror(errno)); 402 403 goto close_uffd; 404 } 405 if (!(uffdio_api.features & UFFD_FEATURE_PAGEFAULT_FLAG_WP)) { 406 ksft_test_result_skip("UFFD_FEATURE_PAGEFAULT_FLAG_WP not available\n"); 407 goto close_uffd; 408 } 409 410 /* 411 * UFFDIO_API must only be called once to enable features. 412 * So we close the old userfaultfd and create a new one to 413 * actually enable UFFD_FEATURE_PAGEFAULT_FLAG_WP. 414 */ 415 close(uffd); 416 uffd = syscall(__NR_userfaultfd, O_CLOEXEC | O_NONBLOCK); 417 if (uffd < 0) { 418 ksft_test_result_fail("__NR_userfaultfd failed\n"); 419 goto unmap; 420 } 421 422 /* Now, enable it ("two-step handshake") */ 423 uffdio_api.api = UFFD_API; 424 uffdio_api.features = UFFD_FEATURE_PAGEFAULT_FLAG_WP; 425 if (ioctl(uffd, UFFDIO_API, &uffdio_api) < 0) { 426 ksft_test_result_fail("UFFDIO_API failed: %s\n", strerror(errno)); 427 goto close_uffd; 428 } 429 430 /* Register UFFD-WP, no need for an actual handler. */ 431 if (uffd_register(uffd, map, size, false, true, false)) { 432 ksft_test_result_fail("UFFDIO_REGISTER_MODE_WP failed\n"); 433 goto close_uffd; 434 } 435 436 /* Write-protect the range using UFFD-WP. */ 437 uffd_writeprotect.range.start = (unsigned long) map; 438 uffd_writeprotect.range.len = size; 439 uffd_writeprotect.mode = UFFDIO_WRITEPROTECT_MODE_WP; 440 if (ioctl(uffd, UFFDIO_WRITEPROTECT, &uffd_writeprotect)) { 441 ksft_test_result_fail("UFFDIO_WRITEPROTECT failed\n"); 442 goto close_uffd; 443 } 444 445 if (madvise(map, size, MADV_UNMERGEABLE)) { 446 ksft_test_result_fail("MADV_UNMERGEABLE failed\n"); 447 goto close_uffd; 448 } 449 450 ksft_test_result(!range_maps_duplicates(map, size), 451 "Pages were unmerged\n"); 452 close_uffd: 453 close(uffd); 454 unmap: 455 munmap(map, size); 456 } 457 #endif 458 459 /* Verify that KSM can be enabled / queried with prctl. */ 460 static void test_prctl(void) 461 { 462 int ret; 463 464 ksft_print_msg("[RUN] %s\n", __func__); 465 466 ret = prctl(PR_SET_MEMORY_MERGE, 1, 0, 0, 0); 467 if (ret < 0 && errno == EINVAL) { 468 ksft_test_result_skip("PR_SET_MEMORY_MERGE not supported\n"); 469 return; 470 } else if (ret) { 471 ksft_test_result_fail("PR_SET_MEMORY_MERGE=1 failed\n"); 472 return; 473 } 474 475 ret = prctl(PR_GET_MEMORY_MERGE, 0, 0, 0, 0); 476 if (ret < 0) { 477 ksft_test_result_fail("PR_GET_MEMORY_MERGE failed\n"); 478 return; 479 } else if (ret != 1) { 480 ksft_test_result_fail("PR_SET_MEMORY_MERGE=1 not effective\n"); 481 return; 482 } 483 484 ret = prctl(PR_SET_MEMORY_MERGE, 0, 0, 0, 0); 485 if (ret) { 486 ksft_test_result_fail("PR_SET_MEMORY_MERGE=0 failed\n"); 487 return; 488 } 489 490 ret = prctl(PR_GET_MEMORY_MERGE, 0, 0, 0, 0); 491 if (ret < 0) { 492 ksft_test_result_fail("PR_GET_MEMORY_MERGE failed\n"); 493 return; 494 } else if (ret != 0) { 495 ksft_test_result_fail("PR_SET_MEMORY_MERGE=0 not effective\n"); 496 return; 497 } 498 499 ksft_test_result_pass("Setting/clearing PR_SET_MEMORY_MERGE works\n"); 500 } 501 502 static int test_child_ksm(void) 503 { 504 const unsigned int size = 2 * MiB; 505 char *map; 506 507 /* Test if KSM is enabled for the process. */ 508 if (prctl(PR_GET_MEMORY_MERGE, 0, 0, 0, 0) != 1) 509 return -1; 510 511 /* Test if merge could really happen. */ 512 map = __mmap_and_merge_range(0xcf, size, PROT_READ | PROT_WRITE, KSM_MERGE_NONE); 513 if (map == MAP_MERGE_FAIL) 514 return -2; 515 else if (map == MAP_MERGE_SKIP) 516 return -3; 517 518 munmap(map, size); 519 return 0; 520 } 521 522 static void test_child_ksm_err(int status) 523 { 524 if (status == -1) 525 ksft_test_result_fail("unexpected PR_GET_MEMORY_MERGE result in child\n"); 526 else if (status == -2) 527 ksft_test_result_fail("Merge in child failed\n"); 528 else if (status == -3) 529 ksft_test_result_skip("Merge in child skipped\n"); 530 } 531 532 /* Verify that prctl ksm flag is inherited. */ 533 static void test_prctl_fork(void) 534 { 535 int ret, status; 536 pid_t child_pid; 537 538 ksft_print_msg("[RUN] %s\n", __func__); 539 540 ret = prctl(PR_SET_MEMORY_MERGE, 1, 0, 0, 0); 541 if (ret < 0 && errno == EINVAL) { 542 ksft_test_result_skip("PR_SET_MEMORY_MERGE not supported\n"); 543 return; 544 } else if (ret) { 545 ksft_test_result_fail("PR_SET_MEMORY_MERGE=1 failed\n"); 546 return; 547 } 548 549 child_pid = fork(); 550 if (!child_pid) { 551 exit(test_child_ksm()); 552 } else if (child_pid < 0) { 553 ksft_test_result_fail("fork() failed\n"); 554 return; 555 } 556 557 if (waitpid(child_pid, &status, 0) < 0) { 558 ksft_test_result_fail("waitpid() failed\n"); 559 return; 560 } 561 562 status = WEXITSTATUS(status); 563 if (status) { 564 test_child_ksm_err(status); 565 return; 566 } 567 568 if (prctl(PR_SET_MEMORY_MERGE, 0, 0, 0, 0)) { 569 ksft_test_result_fail("PR_SET_MEMORY_MERGE=0 failed\n"); 570 return; 571 } 572 573 ksft_test_result_pass("PR_SET_MEMORY_MERGE value is inherited\n"); 574 } 575 576 static void test_prctl_fork_exec(void) 577 { 578 int ret, status; 579 pid_t child_pid; 580 581 ksft_print_msg("[RUN] %s\n", __func__); 582 583 ret = prctl(PR_SET_MEMORY_MERGE, 1, 0, 0, 0); 584 if (ret < 0 && errno == EINVAL) { 585 ksft_test_result_skip("PR_SET_MEMORY_MERGE not supported\n"); 586 return; 587 } else if (ret) { 588 ksft_test_result_fail("PR_SET_MEMORY_MERGE=1 failed\n"); 589 return; 590 } 591 592 child_pid = fork(); 593 if (child_pid == -1) { 594 ksft_test_result_skip("fork() failed\n"); 595 return; 596 } else if (child_pid == 0) { 597 char *prg_name = "./ksm_functional_tests"; 598 char *argv_for_program[] = { prg_name, FORK_EXEC_CHILD_PRG_NAME }; 599 600 execv(prg_name, argv_for_program); 601 return; 602 } 603 604 if (waitpid(child_pid, &status, 0) > 0) { 605 if (WIFEXITED(status)) { 606 status = WEXITSTATUS(status); 607 if (status) { 608 test_child_ksm_err(status); 609 return; 610 } 611 } else { 612 ksft_test_result_fail("program didn't terminate normally\n"); 613 return; 614 } 615 } else { 616 ksft_test_result_fail("waitpid() failed\n"); 617 return; 618 } 619 620 if (prctl(PR_SET_MEMORY_MERGE, 0, 0, 0, 0)) { 621 ksft_test_result_fail("PR_SET_MEMORY_MERGE=0 failed\n"); 622 return; 623 } 624 625 ksft_test_result_pass("PR_SET_MEMORY_MERGE value is inherited\n"); 626 } 627 628 static void test_prctl_unmerge(void) 629 { 630 const unsigned int size = 2 * MiB; 631 char *map; 632 633 ksft_print_msg("[RUN] %s\n", __func__); 634 635 map = mmap_and_merge_range(0xcf, size, PROT_READ | PROT_WRITE, KSM_MERGE_PRCTL); 636 if (map == MAP_FAILED) 637 return; 638 639 if (prctl(PR_SET_MEMORY_MERGE, 0, 0, 0, 0)) { 640 ksft_test_result_fail("PR_SET_MEMORY_MERGE=0 failed\n"); 641 goto unmap; 642 } 643 644 ksft_test_result(!range_maps_duplicates(map, size), 645 "Pages were unmerged\n"); 646 unmap: 647 munmap(map, size); 648 } 649 650 static void test_prot_none(void) 651 { 652 const unsigned int size = 2 * MiB; 653 char *map; 654 int i; 655 656 ksft_print_msg("[RUN] %s\n", __func__); 657 658 map = mmap_and_merge_range(0x11, size, PROT_NONE, KSM_MERGE_MADVISE); 659 if (map == MAP_FAILED) 660 goto unmap; 661 662 /* Store a unique value in each page on one half using ptrace */ 663 for (i = 0; i < size / 2; i += pagesize) { 664 lseek(mem_fd, (uintptr_t) map + i, SEEK_SET); 665 if (write(mem_fd, &i, sizeof(i)) != sizeof(i)) { 666 ksft_test_result_fail("ptrace write failed\n"); 667 goto unmap; 668 } 669 } 670 671 /* Trigger unsharing on the other half. */ 672 if (madvise(map + size / 2, size / 2, MADV_UNMERGEABLE)) { 673 ksft_test_result_fail("MADV_UNMERGEABLE failed\n"); 674 goto unmap; 675 } 676 677 ksft_test_result(!range_maps_duplicates(map, size), 678 "Pages were unmerged\n"); 679 unmap: 680 munmap(map, size); 681 } 682 683 static void init_global_file_handles(void) 684 { 685 mem_fd = open("/proc/self/mem", O_RDWR); 686 if (mem_fd < 0) 687 ksft_exit_fail_msg("opening /proc/self/mem failed\n"); 688 ksm_fd = open("/sys/kernel/mm/ksm/run", O_RDWR); 689 if (ksm_fd < 0) 690 ksft_exit_skip("open(\"/sys/kernel/mm/ksm/run\") failed\n"); 691 ksm_full_scans_fd = open("/sys/kernel/mm/ksm/full_scans", O_RDONLY); 692 if (ksm_full_scans_fd < 0) 693 ksft_exit_skip("open(\"/sys/kernel/mm/ksm/full_scans\") failed\n"); 694 pagemap_fd = open("/proc/self/pagemap", O_RDONLY); 695 if (pagemap_fd < 0) 696 ksft_exit_skip("open(\"/proc/self/pagemap\") failed\n"); 697 proc_self_ksm_stat_fd = open("/proc/self/ksm_stat", O_RDONLY); 698 proc_self_ksm_merging_pages_fd = open("/proc/self/ksm_merging_pages", 699 O_RDONLY); 700 ksm_use_zero_pages_fd = open("/sys/kernel/mm/ksm/use_zero_pages", O_RDWR); 701 } 702 703 int main(int argc, char **argv) 704 { 705 unsigned int tests = 8; 706 int err; 707 708 if (argc > 1 && !strcmp(argv[1], FORK_EXEC_CHILD_PRG_NAME)) { 709 init_global_file_handles(); 710 exit(test_child_ksm()); 711 } 712 713 #ifdef __NR_userfaultfd 714 tests++; 715 #endif 716 717 ksft_print_header(); 718 ksft_set_plan(tests); 719 720 pagesize = getpagesize(); 721 722 init_global_file_handles(); 723 724 test_unmerge(); 725 test_unmerge_zero_pages(); 726 test_unmerge_discarded(); 727 #ifdef __NR_userfaultfd 728 test_unmerge_uffd_wp(); 729 #endif 730 731 test_prot_none(); 732 733 test_prctl(); 734 test_prctl_fork(); 735 test_prctl_fork_exec(); 736 test_prctl_unmerge(); 737 738 err = ksft_get_fail_cnt(); 739 if (err) 740 ksft_exit_fail_msg("%d out of %d tests failed\n", 741 err, ksft_test_num()); 742 ksft_exit_pass(); 743 } 744