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
test_ksm(void)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
setup(void)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
cleanup(void)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