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 size_t len; 502 503 ksm_fd = open("/sys/kernel/mm/ksm/run", O_RDWR); 504 if (ksm_fd < 0) 505 return -errno; 506 507 if (write(ksm_fd, "1", 1) != 1) 508 return -errno; 509 510 len = strlen(pages_to_scan); 511 if (write(pages_to_scan_fd, pages_to_scan, len) != len) 512 return -1; 513 514 len = strlen(sleep_ms); 515 if (write(sleep_millisecs_fd, sleep_ms, len) != len) 516 return -1; 517 518 return 0; 519 } 520 521 static int stop_ksmd_and_restore_frequency(void) 522 { 523 int ksm_fd; 524 525 ksm_fd = open("/sys/kernel/mm/ksm/run", O_RDWR); 526 if (ksm_fd < 0) 527 return -errno; 528 529 if (write(ksm_fd, "2", 1) != 1) 530 return -errno; 531 532 if (write(pages_to_scan_fd, "100", 3) != 3) 533 return -1; 534 535 if (write(sleep_millisecs_fd, "20", 2) != 2) 536 return -1; 537 538 return 0; 539 } 540 541 static void test_prctl_fork_exec(void) 542 { 543 int ret, status; 544 pid_t child_pid; 545 546 ksft_print_msg("[RUN] %s\n", __func__); 547 548 if (start_ksmd_and_set_frequency("2000", "0")) 549 ksft_test_result_fail("set ksmd's scanning frequency failed\n"); 550 551 ret = prctl(PR_SET_MEMORY_MERGE, 1, 0, 0, 0); 552 if (ret < 0 && errno == EINVAL) { 553 ksft_test_result_skip("PR_SET_MEMORY_MERGE not supported\n"); 554 return; 555 } else if (ret) { 556 ksft_test_result_fail("PR_SET_MEMORY_MERGE=1 failed\n"); 557 return; 558 } 559 560 child_pid = fork(); 561 if (child_pid == -1) { 562 ksft_test_result_skip("fork() failed\n"); 563 return; 564 } else if (child_pid == 0) { 565 char *prg_name = "./ksm_functional_tests"; 566 char *argv_for_program[] = { prg_name, FORK_EXEC_CHILD_PRG_NAME, NULL }; 567 568 execv(prg_name, argv_for_program); 569 exit(4); 570 } 571 572 if (waitpid(child_pid, &status, 0) > 0) { 573 if (WIFEXITED(status)) { 574 status = WEXITSTATUS(status); 575 if (status) { 576 test_child_ksm_err(status); 577 return; 578 } 579 } else { 580 ksft_test_result_fail("program didn't terminate normally\n"); 581 return; 582 } 583 } else { 584 ksft_test_result_fail("waitpid() failed\n"); 585 return; 586 } 587 588 if (prctl(PR_SET_MEMORY_MERGE, 0, 0, 0, 0)) { 589 ksft_test_result_fail("PR_SET_MEMORY_MERGE=0 failed\n"); 590 return; 591 } 592 593 if (stop_ksmd_and_restore_frequency()) { 594 ksft_test_result_fail("restore ksmd frequency failed\n"); 595 return; 596 } 597 598 ksft_test_result_pass("PR_SET_MEMORY_MERGE value is inherited\n"); 599 } 600 601 static void test_prctl_unmerge(void) 602 { 603 const unsigned int size = 2 * MiB; 604 char *map; 605 606 ksft_print_msg("[RUN] %s\n", __func__); 607 608 map = mmap_and_merge_range(0xcf, size, PROT_READ | PROT_WRITE, KSM_MERGE_PRCTL); 609 if (map == MAP_FAILED) 610 return; 611 612 if (prctl(PR_SET_MEMORY_MERGE, 0, 0, 0, 0)) { 613 ksft_test_result_fail("PR_SET_MEMORY_MERGE=0 failed\n"); 614 goto unmap; 615 } 616 617 ksft_test_result(!range_maps_duplicates(map, size), 618 "Pages were unmerged\n"); 619 unmap: 620 ksm_stop(); 621 munmap(map, size); 622 } 623 624 static void test_prot_none(void) 625 { 626 const unsigned int size = 2 * MiB; 627 char *map; 628 int i; 629 630 ksft_print_msg("[RUN] %s\n", __func__); 631 632 map = mmap_and_merge_range(0x11, size, PROT_NONE, KSM_MERGE_MADVISE); 633 if (map == MAP_FAILED) 634 goto unmap; 635 636 /* Store a unique value in each page on one half using ptrace */ 637 for (i = 0; i < size / 2; i += pagesize) { 638 lseek(mem_fd, (uintptr_t) map + i, SEEK_SET); 639 if (write(mem_fd, &i, sizeof(i)) != sizeof(i)) { 640 ksft_test_result_fail("ptrace write failed\n"); 641 goto unmap; 642 } 643 } 644 645 /* Trigger unsharing on the other half. */ 646 if (madvise(map + size / 2, size / 2, MADV_UNMERGEABLE)) { 647 ksft_test_result_fail("MADV_UNMERGEABLE failed\n"); 648 goto unmap; 649 } 650 651 ksft_test_result(!range_maps_duplicates(map, size), 652 "Pages were unmerged\n"); 653 unmap: 654 ksm_stop(); 655 munmap(map, size); 656 } 657 658 static void test_fork_ksm_merging_page_count(void) 659 { 660 const unsigned int size = 2 * MiB; 661 char *map; 662 pid_t child_pid; 663 int status; 664 665 ksft_print_msg("[RUN] %s\n", __func__); 666 667 map = mmap_and_merge_range(0xcf, size, PROT_READ | PROT_WRITE, KSM_MERGE_MADVISE); 668 if (map == MAP_FAILED) 669 return; 670 671 child_pid = fork(); 672 if (!child_pid) { 673 init_global_file_handles(); 674 exit(ksm_get_self_merging_pages()); 675 } else if (child_pid < 0) { 676 ksft_test_result_fail("fork() failed\n"); 677 goto unmap; 678 } 679 680 if (waitpid(child_pid, &status, 0) < 0) { 681 ksft_test_result_fail("waitpid() failed\n"); 682 goto unmap; 683 } 684 685 status = WEXITSTATUS(status); 686 if (status) { 687 ksft_test_result_fail("ksm_merging_page in child: %d\n", status); 688 goto unmap; 689 } 690 691 ksft_test_result_pass("ksm_merging_pages is not inherited after fork\n"); 692 693 unmap: 694 ksm_stop(); 695 munmap(map, size); 696 } 697 698 static void init_global_file_handles(void) 699 { 700 mem_fd = open("/proc/self/mem", O_RDWR); 701 if (mem_fd < 0) 702 ksft_exit_fail_msg("opening /proc/self/mem failed\n"); 703 if (ksm_stop() < 0) 704 ksft_exit_skip("accessing \"/sys/kernel/mm/ksm/run\") failed\n"); 705 if (ksm_get_full_scans() < 0) 706 ksft_exit_skip("accessing \"/sys/kernel/mm/ksm/full_scans\") failed\n"); 707 pagemap_fd = open("/proc/self/pagemap", O_RDONLY); 708 if (pagemap_fd < 0) 709 ksft_exit_skip("open(\"/proc/self/pagemap\") failed\n"); 710 if (ksm_get_self_merging_pages() < 0) 711 ksft_exit_skip("accessing \"/proc/self/ksm_merging_pages\") failed\n"); 712 713 pages_to_scan_fd = open("/sys/kernel/mm/ksm/pages_to_scan", O_RDWR); 714 if (pages_to_scan_fd < 0) 715 ksft_exit_fail_msg("opening /sys/kernel/mm/ksm/pages_to_scan failed\n"); 716 sleep_millisecs_fd = open("/sys/kernel/mm/ksm/sleep_millisecs", O_RDWR); 717 if (sleep_millisecs_fd < 0) 718 ksft_exit_fail_msg("opening /sys/kernel/mm/ksm/sleep_millisecs failed\n"); 719 } 720 721 int main(int argc, char **argv) 722 { 723 unsigned int tests = 9; 724 int err; 725 726 if (argc > 1 && !strcmp(argv[1], FORK_EXEC_CHILD_PRG_NAME)) { 727 init_global_file_handles(); 728 exit(test_child_ksm()); 729 } 730 731 #ifdef __NR_userfaultfd 732 tests++; 733 #endif 734 735 ksft_print_header(); 736 ksft_set_plan(tests); 737 738 pagesize = getpagesize(); 739 740 init_global_file_handles(); 741 742 test_unmerge(); 743 test_unmerge_zero_pages(); 744 test_unmerge_discarded(); 745 #ifdef __NR_userfaultfd 746 test_unmerge_uffd_wp(); 747 #endif 748 749 test_prot_none(); 750 751 test_prctl(); 752 test_prctl_fork(); 753 test_prctl_fork_exec(); 754 test_prctl_unmerge(); 755 test_fork_ksm_merging_page_count(); 756 757 err = ksft_get_fail_cnt(); 758 if (err) 759 ksft_exit_fail_msg("%d out of %d tests failed\n", 760 err, ksft_test_num()); 761 ksft_exit_pass(); 762 } 763