1 /* 2 * Copyright (C) 2013-2017 Red Hat, Inc. 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation; either version 2 of the License, or 7 * (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See 12 * the GNU General Public License for more details. 13 */ 14 15 /* 16 * The case is designed to test new sysfs boolean knob 17 * /sys/kernel/mm/ksm/merge_across_nodes, which was introduced by 18 * commit 90bd6fd31c8097ee (ksm: allow trees per NUMA node). 19 * when merge_across_nodes is set to zero only pages from the same 20 * node are merged, otherwise pages from all nodes can be merged 21 * together. 22 */ 23 24 #include "config.h" 25 #include <sys/types.h> 26 #include <sys/stat.h> 27 #include <sys/mman.h> 28 #include <limits.h> 29 #include <errno.h> 30 #include <fcntl.h> 31 #include <signal.h> 32 #include <stdio.h> 33 #include <unistd.h> 34 #include <limits.h> 35 36 #include "mem.h" 37 #include "numa_helper.h" 38 39 #ifdef HAVE_NUMA_V2 40 #include <numaif.h> 41 42 static int run = -1; 43 static int sleep_millisecs = -1; 44 static int merge_across_nodes = -1; 45 static unsigned long nr_pages; 46 47 static char *n_opt; 48 static struct tst_option ksm_options[] = { 49 {"n:", &n_opt, "-n x Allocate x pages memory per node"}, 50 {NULL, NULL, NULL} 51 }; 52 53 static const char * const save_restore[] = { 54 "?/sys/kernel/mm/ksm/max_page_sharing", 55 NULL, 56 }; 57 58 static void test_ksm(void) 59 { 60 if (n_opt) 61 nr_pages = SAFE_STRTOUL(n_opt, 0, ULONG_MAX); 62 else 63 nr_pages = 100; 64 65 test_ksm_merge_across_nodes(nr_pages); 66 } 67 68 static void setup(void) 69 { 70 if (access(PATH_KSM "merge_across_nodes", F_OK) == -1) 71 tst_brk(TCONF, "no merge_across_nodes sysfs knob"); 72 73 if (!is_numa(NULL, NH_MEMS, 2)) 74 tst_brk(TCONF, "The case needs a NUMA system."); 75 76 /* save the current value */ 77 SAFE_FILE_SCANF(PATH_KSM "run", "%d", &run); 78 SAFE_FILE_SCANF(PATH_KSM "merge_across_nodes", 79 "%d", &merge_across_nodes); 80 SAFE_FILE_SCANF(PATH_KSM "sleep_millisecs", 81 "%d", &sleep_millisecs); 82 } 83 84 static void cleanup(void) 85 { 86 if (merge_across_nodes != -1) { 87 FILE_PRINTF(PATH_KSM "merge_across_nodes", 88 "%d", merge_across_nodes); 89 } 90 91 if (sleep_millisecs != -1) 92 FILE_PRINTF(PATH_KSM "sleep_millisecs", "%d", sleep_millisecs); 93 94 if (run != -1) 95 FILE_PRINTF(PATH_KSM "run", "%d", run); 96 } 97 98 static struct tst_test test = { 99 .needs_root = 1, 100 .options = ksm_options, 101 .setup = setup, 102 .cleanup = cleanup, 103 .save_restore = save_restore, 104 .test_all = test_ksm, 105 }; 106 107 #else 108 TST_TEST_TCONF(NUMA_ERROR_MSG); 109 #endif 110