Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

selftests/mm: add new selftests for KSM

This adds three new tests to the selftests for KSM. These tests use the
new prctl API's to enable and disable KSM.

1) add new prctl flags to prctl header file in tools dir

This adds the new prctl flags to the include file prct.h in the
tools directory. This makes sure they are available for testing.

2) add KSM prctl merge test to ksm_tests

This adds the -t option to the ksm_tests program. The -t flag
allows to specify if it should use madvise or prctl ksm merging.

3) add two functions for debugging merge outcome for ksm_tests

This adds two functions to report the metrics in /proc/self/ksm_stat
and /sys/kernel/debug/mm/ksm. The debug output is enabled with the
-d option.

4) add KSM prctl test to ksm_functional_tests

This adds a test to the ksm_functional_test that verifies that the
prctl system call to enable / disable KSM works.

5) add KSM fork test to ksm_functional_test

Add fork test to verify that the MMF_VM_MERGE_ANY flag is inherited
by the child process.

Link: https://lkml.kernel.org/r/20230418051342.1919757-4-shr@devkernel.io
Signed-off-by: Stefan Roesch <shr@devkernel.io>
Acked-by: David Hildenbrand <david@redhat.com>
Cc: Bagas Sanjaya <bagasdotme@gmail.com>
Cc: David Hildenbrand <david@redhat.com>
Cc: Johannes Weiner <hannes@cmpxchg.org>
Cc: Michal Hocko <mhocko@suse.com>
Cc: Rik van Riel <riel@surriel.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>

authored by

Stefan Roesch and committed by
Andrew Morton
07115fcc d21077fb

+228 -39
+2
tools/include/uapi/linux/prctl.h
··· 290 290 #define PR_SET_VMA 0x53564d41 291 291 # define PR_SET_VMA_ANON_NAME 0 292 292 293 + #define PR_SET_MEMORY_MERGE 67 294 + #define PR_GET_MEMORY_MERGE 68 293 295 #endif /* _LINUX_PRCTL_H */
+1 -1
tools/testing/selftests/mm/Makefile
··· 29 29 # LDLIBS. 30 30 MAKEFLAGS += --no-builtin-rules 31 31 32 - CFLAGS = -Wall -I $(top_srcdir) $(EXTRA_CFLAGS) $(KHDR_INCLUDES) 32 + CFLAGS = -Wall -I $(top_srcdir) -I $(top_srcdir)/tools/include/uapi $(EXTRA_CFLAGS) $(KHDR_INCLUDES) 33 33 LDLIBS = -lrt -lpthread 34 34 35 35 TEST_GEN_PROGS = cow
+90 -1
tools/testing/selftests/mm/ksm_functional_tests.c
··· 15 15 #include <errno.h> 16 16 #include <fcntl.h> 17 17 #include <sys/mman.h> 18 + #include <sys/prctl.h> 18 19 #include <sys/syscall.h> 19 20 #include <sys/ioctl.h> 21 + #include <sys/wait.h> 20 22 #include <linux/userfaultfd.h> 21 23 22 24 #include "../kselftest.h" ··· 239 237 } 240 238 #endif 241 239 240 + /* Verify that KSM can be enabled / queried with prctl. */ 241 + static void test_prctl(void) 242 + { 243 + int ret; 244 + 245 + ksft_print_msg("[RUN] %s\n", __func__); 246 + 247 + ret = prctl(PR_SET_MEMORY_MERGE, 1, 0, 0, 0); 248 + if (ret < 0 && errno == EINVAL) { 249 + ksft_test_result_skip("PR_SET_MEMORY_MERGE not supported\n"); 250 + return; 251 + } else if (ret) { 252 + ksft_test_result_fail("PR_SET_MEMORY_MERGE=1 failed\n"); 253 + return; 254 + } 255 + 256 + ret = prctl(PR_GET_MEMORY_MERGE, 0, 0, 0, 0); 257 + if (ret < 0) { 258 + ksft_test_result_fail("PR_GET_MEMORY_MERGE failed\n"); 259 + return; 260 + } else if (ret != 1) { 261 + ksft_test_result_fail("PR_SET_MEMORY_MERGE=1 not effective\n"); 262 + return; 263 + } 264 + 265 + ret = prctl(PR_SET_MEMORY_MERGE, 0, 0, 0, 0); 266 + if (ret) { 267 + ksft_test_result_fail("PR_SET_MEMORY_MERGE=0 failed\n"); 268 + return; 269 + } 270 + 271 + ret = prctl(PR_GET_MEMORY_MERGE, 0, 0, 0, 0); 272 + if (ret < 0) { 273 + ksft_test_result_fail("PR_GET_MEMORY_MERGE failed\n"); 274 + return; 275 + } else if (ret != 0) { 276 + ksft_test_result_fail("PR_SET_MEMORY_MERGE=0 not effective\n"); 277 + return; 278 + } 279 + 280 + ksft_test_result_pass("Setting/clearing PR_SET_MEMORY_MERGE works\n"); 281 + } 282 + 283 + /* Verify that prctl ksm flag is inherited. */ 284 + static void test_prctl_fork(void) 285 + { 286 + int ret, status; 287 + pid_t child_pid; 288 + 289 + ksft_print_msg("[RUN] %s\n", __func__); 290 + 291 + ret = prctl(PR_SET_MEMORY_MERGE, 1, 0, 0, 0); 292 + if (ret < 0 && errno == EINVAL) { 293 + ksft_test_result_skip("PR_SET_MEMORY_MERGE not supported\n"); 294 + return; 295 + } else if (ret) { 296 + ksft_test_result_fail("PR_SET_MEMORY_MERGE=1 failed\n"); 297 + return; 298 + } 299 + 300 + child_pid = fork(); 301 + if (!child_pid) { 302 + exit(prctl(PR_GET_MEMORY_MERGE, 0, 0, 0, 0)); 303 + } else if (child_pid < 0) { 304 + ksft_test_result_fail("fork() failed\n"); 305 + return; 306 + } 307 + 308 + if (waitpid(child_pid, &status, 0) < 0) { 309 + ksft_test_result_fail("waitpid() failed\n"); 310 + return; 311 + } else if (WEXITSTATUS(status) != 1) { 312 + ksft_test_result_fail("unexpected PR_GET_MEMORY_MERGE result in child\n"); 313 + return; 314 + } 315 + 316 + if (prctl(PR_SET_MEMORY_MERGE, 0, 0, 0, 0)) { 317 + ksft_test_result_fail("PR_SET_MEMORY_MERGE=0 failed\n"); 318 + return; 319 + } 320 + 321 + ksft_test_result_pass("PR_SET_MEMORY_MERGE value is inherited\n"); 322 + } 323 + 242 324 int main(int argc, char **argv) 243 325 { 244 - unsigned int tests = 2; 326 + unsigned int tests = 4; 245 327 int err; 246 328 247 329 #ifdef __NR_userfaultfd ··· 352 266 #ifdef __NR_userfaultfd 353 267 test_unmerge_uffd_wp(); 354 268 #endif 269 + 270 + test_prctl(); 271 + test_prctl_fork(); 355 272 356 273 err = ksft_get_fail_cnt(); 357 274 if (err)
+135 -37
tools/testing/selftests/mm/ksm_tests.c
··· 1 1 // SPDX-License-Identifier: GPL-2.0 2 2 3 3 #include <sys/mman.h> 4 + #include <sys/prctl.h> 5 + #include <sys/wait.h> 4 6 #include <stdbool.h> 5 7 #include <time.h> 6 8 #include <string.h> ··· 23 21 #define KSM_PROT_STR_DEFAULT "rw" 24 22 #define KSM_USE_ZERO_PAGES_DEFAULT false 25 23 #define KSM_MERGE_ACROSS_NODES_DEFAULT true 24 + #define KSM_MERGE_TYPE_DEFAULT 0 26 25 #define MB (1ul << 20) 27 26 28 27 struct ksm_sysfs { ··· 36 33 unsigned long use_zero_pages; 37 34 }; 38 35 36 + enum ksm_merge_type { 37 + KSM_MERGE_MADVISE, 38 + KSM_MERGE_PRCTL, 39 + KSM_MERGE_LAST = KSM_MERGE_PRCTL 40 + }; 41 + 39 42 enum ksm_test_name { 40 43 CHECK_KSM_MERGE, 41 44 CHECK_KSM_UNMERGE, 45 + CHECK_KSM_GET_MERGE_TYPE, 42 46 CHECK_KSM_ZERO_PAGE_MERGE, 43 47 CHECK_KSM_NUMA_MERGE, 44 48 KSM_MERGE_TIME, ··· 53 43 KSM_UNMERGE_TIME, 54 44 KSM_COW_TIME 55 45 }; 46 + 47 + int debug; 56 48 57 49 static int ksm_write_sysfs(const char *file_path, unsigned long val) 58 50 { ··· 92 80 fclose(f); 93 81 94 82 return 0; 83 + } 84 + 85 + static void ksm_print_sysfs(void) 86 + { 87 + unsigned long max_page_sharing, pages_sharing, pages_shared; 88 + unsigned long full_scans, pages_unshared, pages_volatile; 89 + unsigned long stable_node_chains, stable_node_dups; 90 + long general_profit; 91 + 92 + if (ksm_read_sysfs(KSM_FP("pages_shared"), &pages_shared) || 93 + ksm_read_sysfs(KSM_FP("pages_sharing"), &pages_sharing) || 94 + ksm_read_sysfs(KSM_FP("max_page_sharing"), &max_page_sharing) || 95 + ksm_read_sysfs(KSM_FP("full_scans"), &full_scans) || 96 + ksm_read_sysfs(KSM_FP("pages_unshared"), &pages_unshared) || 97 + ksm_read_sysfs(KSM_FP("pages_volatile"), &pages_volatile) || 98 + ksm_read_sysfs(KSM_FP("stable_node_chains"), &stable_node_chains) || 99 + ksm_read_sysfs(KSM_FP("stable_node_dups"), &stable_node_dups) || 100 + ksm_read_sysfs(KSM_FP("general_profit"), (unsigned long *)&general_profit)) 101 + return; 102 + 103 + printf("pages_shared : %lu\n", pages_shared); 104 + printf("pages_sharing : %lu\n", pages_sharing); 105 + printf("max_page_sharing : %lu\n", max_page_sharing); 106 + printf("full_scans : %lu\n", full_scans); 107 + printf("pages_unshared : %lu\n", pages_unshared); 108 + printf("pages_volatile : %lu\n", pages_volatile); 109 + printf("stable_node_chains: %lu\n", stable_node_chains); 110 + printf("stable_node_dups : %lu\n", stable_node_dups); 111 + printf("general_profit : %ld\n", general_profit); 112 + } 113 + 114 + static void ksm_print_procfs(void) 115 + { 116 + const char *file_name = "/proc/self/ksm_stat"; 117 + char buffer[512]; 118 + FILE *f = fopen(file_name, "r"); 119 + 120 + if (!f) { 121 + fprintf(stderr, "f %s\n", file_name); 122 + perror("fopen"); 123 + return; 124 + } 125 + 126 + while (fgets(buffer, sizeof(buffer), f)) 127 + printf("%s", buffer); 128 + 129 + fclose(f); 95 130 } 96 131 97 132 static int str_to_prot(char *prot_str) ··· 187 128 " Default: %d\n", KSM_USE_ZERO_PAGES_DEFAULT); 188 129 printf(" -m: change merge_across_nodes tunable\n" 189 130 " Default: %d\n", KSM_MERGE_ACROSS_NODES_DEFAULT); 131 + printf(" -d: turn debugging output on\n"); 190 132 printf(" -s: the size of duplicated memory area (in MiB)\n"); 133 + printf(" -t: KSM merge type\n" 134 + " Default: 0\n" 135 + " 0: madvise merging\n" 136 + " 1: prctl merging\n"); 191 137 192 138 exit(0); 193 139 } ··· 240 176 return 0; 241 177 } 242 178 243 - static int ksm_merge_pages(void *addr, size_t size, struct timespec start_time, int timeout) 179 + static int ksm_merge_pages(int merge_type, void *addr, size_t size, 180 + struct timespec start_time, int timeout) 244 181 { 245 - if (madvise(addr, size, MADV_MERGEABLE)) { 246 - perror("madvise"); 247 - return 1; 182 + if (merge_type == KSM_MERGE_MADVISE) { 183 + if (madvise(addr, size, MADV_MERGEABLE)) { 184 + perror("madvise"); 185 + return 1; 186 + } 187 + } else if (merge_type == KSM_MERGE_PRCTL) { 188 + if (prctl(PR_SET_MEMORY_MERGE, 1, 0, 0, 0)) { 189 + perror("prctl"); 190 + return 1; 191 + } 248 192 } 193 + 249 194 if (ksm_write_sysfs(KSM_FP("run"), 1)) 250 195 return 1; 251 196 ··· 283 210 ksm_read_sysfs(KSM_FP("pages_sharing"), &pages_sharing) || 284 211 ksm_read_sysfs(KSM_FP("max_page_sharing"), &max_page_sharing)) 285 212 return false; 213 + 214 + if (debug) { 215 + ksm_print_sysfs(); 216 + ksm_print_procfs(); 217 + } 286 218 287 219 /* 288 220 * Since there must be at least 2 pages for merging and 1 page can be ··· 344 266 return 0; 345 267 } 346 268 347 - static int check_ksm_merge(int mapping, int prot, long page_count, int timeout, size_t page_size) 269 + static int check_ksm_merge(int merge_type, int mapping, int prot, 270 + long page_count, int timeout, size_t page_size) 348 271 { 349 272 void *map_ptr; 350 273 struct timespec start_time; ··· 360 281 if (!map_ptr) 361 282 return KSFT_FAIL; 362 283 363 - if (ksm_merge_pages(map_ptr, page_size * page_count, start_time, timeout)) 284 + if (ksm_merge_pages(merge_type, map_ptr, page_size * page_count, start_time, timeout)) 364 285 goto err_out; 365 286 366 287 /* verify that the right number of pages are merged */ 367 288 if (assert_ksm_pages_count(page_count)) { 368 289 printf("OK\n"); 369 290 munmap(map_ptr, page_size * page_count); 291 + if (merge_type == KSM_MERGE_PRCTL) 292 + prctl(PR_SET_MEMORY_MERGE, 0, 0, 0, 0); 370 293 return KSFT_PASS; 371 294 } 372 295 ··· 378 297 return KSFT_FAIL; 379 298 } 380 299 381 - static int check_ksm_unmerge(int mapping, int prot, int timeout, size_t page_size) 300 + static int check_ksm_unmerge(int merge_type, int mapping, int prot, int timeout, size_t page_size) 382 301 { 383 302 void *map_ptr; 384 303 struct timespec start_time; ··· 394 313 if (!map_ptr) 395 314 return KSFT_FAIL; 396 315 397 - if (ksm_merge_pages(map_ptr, page_size * page_count, start_time, timeout)) 316 + if (ksm_merge_pages(merge_type, map_ptr, page_size * page_count, start_time, timeout)) 398 317 goto err_out; 399 318 400 319 /* change 1 byte in each of the 2 pages -- KSM must automatically unmerge them */ ··· 418 337 return KSFT_FAIL; 419 338 } 420 339 421 - static int check_ksm_zero_page_merge(int mapping, int prot, long page_count, int timeout, 422 - bool use_zero_pages, size_t page_size) 340 + static int check_ksm_zero_page_merge(int merge_type, int mapping, int prot, long page_count, 341 + int timeout, bool use_zero_pages, size_t page_size) 423 342 { 424 343 void *map_ptr; 425 344 struct timespec start_time; ··· 437 356 if (!map_ptr) 438 357 return KSFT_FAIL; 439 358 440 - if (ksm_merge_pages(map_ptr, page_size * page_count, start_time, timeout)) 359 + if (ksm_merge_pages(merge_type, map_ptr, page_size * page_count, start_time, timeout)) 441 360 goto err_out; 442 361 443 362 /* ··· 483 402 return get_next_mem_node(numa_max_node()); 484 403 } 485 404 486 - static int check_ksm_numa_merge(int mapping, int prot, int timeout, bool merge_across_nodes, 487 - size_t page_size) 405 + static int check_ksm_numa_merge(int merge_type, int mapping, int prot, int timeout, 406 + bool merge_across_nodes, size_t page_size) 488 407 { 489 408 void *numa1_map_ptr, *numa2_map_ptr; 490 409 struct timespec start_time; ··· 520 439 memset(numa2_map_ptr, '*', page_size); 521 440 522 441 /* try to merge the pages */ 523 - if (ksm_merge_pages(numa1_map_ptr, page_size, start_time, timeout) || 524 - ksm_merge_pages(numa2_map_ptr, page_size, start_time, timeout)) 442 + if (ksm_merge_pages(merge_type, numa1_map_ptr, page_size, start_time, timeout) || 443 + ksm_merge_pages(merge_type, numa2_map_ptr, page_size, start_time, timeout)) 525 444 goto err_out; 526 445 527 446 /* ··· 547 466 return KSFT_FAIL; 548 467 } 549 468 550 - static int ksm_merge_hugepages_time(int mapping, int prot, int timeout, size_t map_size) 469 + static int ksm_merge_hugepages_time(int merge_type, int mapping, int prot, 470 + int timeout, size_t map_size) 551 471 { 552 472 void *map_ptr, *map_ptr_orig; 553 473 struct timespec start_time, end_time; ··· 590 508 perror("clock_gettime"); 591 509 goto err_out; 592 510 } 593 - if (ksm_merge_pages(map_ptr, map_size, start_time, timeout)) 511 + if (ksm_merge_pages(merge_type, map_ptr, map_size, start_time, timeout)) 594 512 goto err_out; 595 513 if (clock_gettime(CLOCK_MONOTONIC_RAW, &end_time)) { 596 514 perror("clock_gettime"); ··· 615 533 return KSFT_FAIL; 616 534 } 617 535 618 - static int ksm_merge_time(int mapping, int prot, int timeout, size_t map_size) 536 + static int ksm_merge_time(int merge_type, int mapping, int prot, int timeout, size_t map_size) 619 537 { 620 538 void *map_ptr; 621 539 struct timespec start_time, end_time; ··· 631 549 perror("clock_gettime"); 632 550 goto err_out; 633 551 } 634 - if (ksm_merge_pages(map_ptr, map_size, start_time, timeout)) 552 + if (ksm_merge_pages(merge_type, map_ptr, map_size, start_time, timeout)) 635 553 goto err_out; 636 554 if (clock_gettime(CLOCK_MONOTONIC_RAW, &end_time)) { 637 555 perror("clock_gettime"); ··· 656 574 return KSFT_FAIL; 657 575 } 658 576 659 - static int ksm_unmerge_time(int mapping, int prot, int timeout, size_t map_size) 577 + static int ksm_unmerge_time(int merge_type, int mapping, int prot, int timeout, size_t map_size) 660 578 { 661 579 void *map_ptr; 662 580 struct timespec start_time, end_time; ··· 671 589 perror("clock_gettime"); 672 590 goto err_out; 673 591 } 674 - if (ksm_merge_pages(map_ptr, map_size, start_time, timeout)) 592 + if (ksm_merge_pages(merge_type, map_ptr, map_size, start_time, timeout)) 675 593 goto err_out; 676 594 677 595 if (clock_gettime(CLOCK_MONOTONIC_RAW, &start_time)) { ··· 703 621 return KSFT_FAIL; 704 622 } 705 623 706 - static int ksm_cow_time(int mapping, int prot, int timeout, size_t page_size) 624 + static int ksm_cow_time(int merge_type, int mapping, int prot, int timeout, size_t page_size) 707 625 { 708 626 void *map_ptr; 709 627 struct timespec start_time, end_time; ··· 742 660 memset(map_ptr + page_size * i, '+', i / 2 + 1); 743 661 memset(map_ptr + page_size * (i + 1), '+', i / 2 + 1); 744 662 } 745 - if (ksm_merge_pages(map_ptr, page_size * page_count, start_time, timeout)) 663 + if (ksm_merge_pages(merge_type, map_ptr, page_size * page_count, start_time, timeout)) 746 664 goto err_out; 747 665 748 666 if (clock_gettime(CLOCK_MONOTONIC_RAW, &start_time)) { ··· 779 697 int ret, opt; 780 698 int prot = 0; 781 699 int ksm_scan_limit_sec = KSM_SCAN_LIMIT_SEC_DEFAULT; 700 + int merge_type = KSM_MERGE_TYPE_DEFAULT; 782 701 long page_count = KSM_PAGE_COUNT_DEFAULT; 783 702 size_t page_size = sysconf(_SC_PAGESIZE); 784 703 struct ksm_sysfs ksm_sysfs_old; ··· 788 705 bool merge_across_nodes = KSM_MERGE_ACROSS_NODES_DEFAULT; 789 706 long size_MB = 0; 790 707 791 - while ((opt = getopt(argc, argv, "ha:p:l:z:m:s:MUZNPCHD")) != -1) { 708 + while ((opt = getopt(argc, argv, "dha:p:l:z:m:s:t:MUZNPCHD")) != -1) { 792 709 switch (opt) { 793 710 case 'a': 794 711 prot = str_to_prot(optarg); ··· 822 739 else 823 740 merge_across_nodes = 1; 824 741 break; 742 + case 'd': 743 + debug = 1; 744 + break; 825 745 case 's': 826 746 size_MB = atoi(optarg); 827 747 if (size_MB <= 0) { 828 748 printf("Size must be greater than 0\n"); 829 749 return KSFT_FAIL; 830 750 } 751 + case 't': 752 + { 753 + int tmp = atoi(optarg); 754 + 755 + if (tmp < 0 || tmp > KSM_MERGE_LAST) { 756 + printf("Invalid merge type\n"); 757 + return KSFT_FAIL; 758 + } 759 + merge_type = tmp; 760 + } 761 + break; 831 762 case 'M': 832 763 break; 833 764 case 'U': ··· 892 795 893 796 switch (test_name) { 894 797 case CHECK_KSM_MERGE: 895 - ret = check_ksm_merge(MAP_PRIVATE | MAP_ANONYMOUS, prot, page_count, 798 + ret = check_ksm_merge(merge_type, MAP_PRIVATE | MAP_ANONYMOUS, prot, page_count, 896 799 ksm_scan_limit_sec, page_size); 897 800 break; 898 801 case CHECK_KSM_UNMERGE: 899 - ret = check_ksm_unmerge(MAP_PRIVATE | MAP_ANONYMOUS, prot, ksm_scan_limit_sec, 900 - page_size); 802 + ret = check_ksm_unmerge(merge_type, MAP_PRIVATE | MAP_ANONYMOUS, prot, 803 + ksm_scan_limit_sec, page_size); 901 804 break; 902 805 case CHECK_KSM_ZERO_PAGE_MERGE: 903 - ret = check_ksm_zero_page_merge(MAP_PRIVATE | MAP_ANONYMOUS, prot, page_count, 904 - ksm_scan_limit_sec, use_zero_pages, page_size); 806 + ret = check_ksm_zero_page_merge(merge_type, MAP_PRIVATE | MAP_ANONYMOUS, prot, 807 + page_count, ksm_scan_limit_sec, use_zero_pages, 808 + page_size); 905 809 break; 906 810 case CHECK_KSM_NUMA_MERGE: 907 - ret = check_ksm_numa_merge(MAP_PRIVATE | MAP_ANONYMOUS, prot, ksm_scan_limit_sec, 908 - merge_across_nodes, page_size); 811 + ret = check_ksm_numa_merge(merge_type, MAP_PRIVATE | MAP_ANONYMOUS, prot, 812 + ksm_scan_limit_sec, merge_across_nodes, page_size); 909 813 break; 910 814 case KSM_MERGE_TIME: 911 815 if (size_MB == 0) { 912 816 printf("Option '-s' is required.\n"); 913 817 return KSFT_FAIL; 914 818 } 915 - ret = ksm_merge_time(MAP_PRIVATE | MAP_ANONYMOUS, prot, ksm_scan_limit_sec, 916 - size_MB); 819 + ret = ksm_merge_time(merge_type, MAP_PRIVATE | MAP_ANONYMOUS, prot, 820 + ksm_scan_limit_sec, size_MB); 917 821 break; 918 822 case KSM_MERGE_TIME_HUGE_PAGES: 919 823 if (size_MB == 0) { 920 824 printf("Option '-s' is required.\n"); 921 825 return KSFT_FAIL; 922 826 } 923 - ret = ksm_merge_hugepages_time(MAP_PRIVATE | MAP_ANONYMOUS, prot, 827 + ret = ksm_merge_hugepages_time(merge_type, MAP_PRIVATE | MAP_ANONYMOUS, prot, 924 828 ksm_scan_limit_sec, size_MB); 925 829 break; 926 830 case KSM_UNMERGE_TIME: ··· 929 831 printf("Option '-s' is required.\n"); 930 832 return KSFT_FAIL; 931 833 } 932 - ret = ksm_unmerge_time(MAP_PRIVATE | MAP_ANONYMOUS, prot, 834 + ret = ksm_unmerge_time(merge_type, MAP_PRIVATE | MAP_ANONYMOUS, prot, 933 835 ksm_scan_limit_sec, size_MB); 934 836 break; 935 837 case KSM_COW_TIME: 936 - ret = ksm_cow_time(MAP_PRIVATE | MAP_ANONYMOUS, prot, ksm_scan_limit_sec, 937 - page_size); 838 + ret = ksm_cow_time(merge_type, MAP_PRIVATE | MAP_ANONYMOUS, prot, 839 + ksm_scan_limit_sec, page_size); 938 840 break; 939 841 } 940 842