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
test_ksm(void)49 static void test_ksm(void)
50 {
51 if (n_opt)
52 nr_pages = SAFE_STRTOUL(n_opt, 0, ULONG_MAX);
53 else
54 nr_pages = 100;
55
56 test_ksm_merge_across_nodes(nr_pages);
57 }
58
setup(void)59 static void setup(void)
60 {
61 if (access(PATH_KSM "merge_across_nodes", F_OK) == -1)
62 tst_brk(TCONF, "no merge_across_nodes sysfs knob");
63
64 if (!is_numa(NULL, NH_MEMS, 2))
65 tst_brk(TCONF, "The case needs a NUMA system.");
66
67 /* save the current value */
68 SAFE_FILE_SCANF(PATH_KSM "run", "%d", &run);
69 SAFE_FILE_SCANF(PATH_KSM "merge_across_nodes",
70 "%d", &merge_across_nodes);
71 SAFE_FILE_SCANF(PATH_KSM "sleep_millisecs",
72 "%d", &sleep_millisecs);
73 }
74
cleanup(void)75 static void cleanup(void)
76 {
77 if (merge_across_nodes != -1) {
78 FILE_PRINTF(PATH_KSM "merge_across_nodes",
79 "%d", merge_across_nodes);
80 }
81
82 if (sleep_millisecs != -1)
83 FILE_PRINTF(PATH_KSM "sleep_millisecs", "%d", sleep_millisecs);
84
85 if (run != -1)
86 FILE_PRINTF(PATH_KSM "run", "%d", run);
87 }
88
89 static struct tst_test test = {
90 .needs_root = 1,
91 .options = (struct tst_option[]) {
92 {"n:", &n_opt, "Allocate x pages memory per node"},
93 {}
94 },
95 .setup = setup,
96 .cleanup = cleanup,
97 .save_restore = (const char * const[]) {
98 "?/sys/kernel/mm/ksm/max_page_sharing",
99 NULL,
100 },
101 .test_all = test_ksm,
102 };
103
104 #else
105 TST_TEST_TCONF(NUMA_ERROR_MSG);
106 #endif
107