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