• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Copyright (c) Crackerjack Project., 2007-2008, Hitachi, Ltd
4  * Copyright (c) 2017 Petr Vorel <pvorel@suse.cz>
5  *
6  * Authors:
7  * Takahiro Yasui <takahiro.yasui.mp@hitachi.com>,
8  * Yumiko Sugita <yumiko.sugita.yf@hitachi.com>,
9  * Satoshi Fujiwara <sa-fuji@sdl.hitachi.co.jp>
10  */
11 
12 #include <errno.h>
13 #if HAVE_NUMA_H
14 #include <numa.h>
15 #endif
16 
17 #include "config.h"
18 #include "numa_helper.h"
19 #include "tst_test.h"
20 #include "tst_numa.h"
21 #include "lapi/numaif.h"
22 
23 #ifdef HAVE_NUMA_V2
24 
25 #define MEM_LENGTH (4 * 1024 * 1024)
26 
27 #define UNKNOWN_POLICY -1
28 
29 #define POLICY_DESC(x) .policy = x, .desc = #x
30 #define POLICY_DESC_TEXT(x, y) .policy = x, .desc = #x" ("y")"
31 
32 static struct bitmask *nodemask, *getnodemask, *empty_nodemask;
33 
34 static void test_default(unsigned int i, char *p);
35 static void test_none(unsigned int i, char *p);
36 static void test_invalid_nodemask(unsigned int i, char *p);
37 static void check_policy_pref_or_local(int);
38 
39 struct test_case {
40 	int policy;
41 	const char *desc;
42 	unsigned flags;
43 	int ret;
44 	int err;
45 	void (*check_policy)(int);
46 	void (*test)(unsigned int, char *);
47 	struct bitmask **exp_nodemask;
48 };
49 
50 static struct test_case tcase[] = {
51 	{
52 		POLICY_DESC(MPOL_DEFAULT),
53 		.ret = 0,
54 		.err = 0,
55 		.test = test_none,
56 		.exp_nodemask = &empty_nodemask,
57 	},
58 	{
59 		POLICY_DESC_TEXT(MPOL_DEFAULT, "target exists"),
60 		.ret = -1,
61 		.err = EINVAL,
62 		.test = test_default,
63 	},
64 	{
65 		POLICY_DESC_TEXT(MPOL_BIND, "no target"),
66 		.ret = -1,
67 		.err = EINVAL,
68 		.test = test_none,
69 	},
70 	{
71 		POLICY_DESC(MPOL_BIND),
72 		.ret = 0,
73 		.err = 0,
74 		.test = test_default,
75 		.exp_nodemask = &nodemask,
76 	},
77 	{
78 		POLICY_DESC_TEXT(MPOL_INTERLEAVE, "no target"),
79 		.ret = -1,
80 		.err = EINVAL,
81 		.test = test_none,
82 	},
83 	{
84 		POLICY_DESC(MPOL_INTERLEAVE),
85 		.ret = 0,
86 		.err = 0,
87 		.test = test_default,
88 		.exp_nodemask = &nodemask,
89 	},
90 	{
91 		POLICY_DESC_TEXT(MPOL_PREFERRED, "no target"),
92 		.ret = 0,
93 		.err = 0,
94 		.test = test_none,
95 		.check_policy = check_policy_pref_or_local,
96 	},
97 	{
98 		POLICY_DESC(MPOL_PREFERRED),
99 		.ret = 0,
100 		.err = 0,
101 		.test = test_default,
102 		.exp_nodemask = &nodemask,
103 	},
104 	{
105 		POLICY_DESC(MPOL_LOCAL),
106 		.ret = 0,
107 		.err = 0,
108 		.test = test_none,
109 		.exp_nodemask = &empty_nodemask,
110 		.check_policy = check_policy_pref_or_local,
111 	},
112 	{
113 		POLICY_DESC_TEXT(MPOL_LOCAL, "target exists"),
114 		.ret = -1,
115 		.err = EINVAL,
116 		.test = test_default,
117 	},
118 	{
119 		POLICY_DESC(UNKNOWN_POLICY),
120 		.ret = -1,
121 		.err = EINVAL,
122 		.test = test_none,
123 	},
124 	{
125 		POLICY_DESC_TEXT(MPOL_DEFAULT, "invalid flags"),
126 		.flags = -1,
127 		.ret = -1,
128 		.err = EINVAL,
129 		.test = test_none,
130 	},
131 	{
132 		POLICY_DESC_TEXT(MPOL_PREFERRED, "invalid nodemask"),
133 		.ret = -1,
134 		.err = EFAULT,
135 		.test = test_invalid_nodemask,
136 	},
137 };
138 
check_policy_pref_or_local(int policy)139 static void check_policy_pref_or_local(int policy)
140 {
141 	if (policy != MPOL_PREFERRED && policy != MPOL_LOCAL) {
142 		tst_res(TFAIL, "Wrong policy: %s(%d), "
143 			"expected MPOL_PREFERRED or MPOL_LOCAL",
144 			tst_mempolicy_mode_name(policy), policy);
145 	}
146 }
147 
test_default(unsigned int i,char * p)148 static void test_default(unsigned int i, char *p)
149 {
150 	struct test_case *tc = &tcase[i];
151 
152 	TEST(mbind(p, MEM_LENGTH, tc->policy, nodemask->maskp,
153 		   nodemask->size, tc->flags));
154 }
155 
test_none(unsigned int i,char * p)156 static void test_none(unsigned int i, char *p)
157 {
158 	struct test_case *tc = &tcase[i];
159 
160 	TEST(mbind(p, MEM_LENGTH, tc->policy, NULL, 0, tc->flags));
161 }
162 
test_invalid_nodemask(unsigned int i,char * p)163 static void test_invalid_nodemask(unsigned int i, char *p)
164 {
165 	struct test_case *tc = &tcase[i];
166 
167 	/* use invalid nodemask (64 MiB after heap) */
168 	TEST(mbind(p, MEM_LENGTH, tc->policy, sbrk(0) + 64*1024*1024,
169 		   NUMA_NUM_NODES, tc->flags));
170 }
171 
setup(void)172 static void setup(void)
173 {
174 	if (!is_numa(NULL, NH_MEMS, 1))
175 		tst_brk(TCONF, "requires NUMA with at least 1 node");
176 	empty_nodemask = numa_allocate_nodemask();
177 }
178 
setup_node(void)179 static void setup_node(void)
180 {
181 	int test_node = -1;
182 
183 	if (get_allowed_nodes(NH_MEMS, 1, &test_node) < 0)
184 		tst_brk(TBROK | TERRNO, "get_allowed_nodes failed");
185 
186 	nodemask = numa_allocate_nodemask();
187 	getnodemask = numa_allocate_nodemask();
188 	numa_bitmask_setbit(nodemask, test_node);
189 }
190 
do_test(unsigned int i)191 static void do_test(unsigned int i)
192 {
193 	struct test_case *tc = &tcase[i];
194 	int policy, fail = 0;
195 	char *p = NULL;
196 
197 	tst_res(TINFO, "case %s", tc->desc);
198 
199 	if (tc->policy == MPOL_LOCAL) {
200 		if ((tst_kvercmp(3, 8, 0)) < 0) {
201 			tst_res(TCONF, "%s is not supported",
202 				tst_mempolicy_mode_name(tc->policy));
203 			return;
204 		}
205 
206 		if ((tst_kvercmp(5, 14, 0)) >= 0)
207 			tc->check_policy = NULL;
208 	}
209 
210 	setup_node();
211 
212 	p = SAFE_MMAP(NULL, MEM_LENGTH, PROT_READ | PROT_WRITE, MAP_PRIVATE |
213 			 MAP_ANONYMOUS, 0, 0);
214 
215 	tc->test(i, p);
216 
217 	if (TST_RET >= 0) {
218 		/* Check policy of the allocated memory */
219 		TEST(get_mempolicy(&policy, getnodemask->maskp,
220 				   getnodemask->size, p, MPOL_F_ADDR));
221 		if (TST_RET < 0) {
222 			tst_res(TFAIL | TTERRNO, "get_mempolicy failed");
223 			return;
224 		}
225 
226 		if (tc->check_policy)
227 			tc->check_policy(policy);
228 		else if (tc->policy != policy) {
229 			tst_res(TFAIL, "Wrong policy: %s(%d), expected: %s(%d)",
230 				tst_mempolicy_mode_name(policy), policy,
231 				tst_mempolicy_mode_name(tc->policy), tc->policy);
232 			fail = 1;
233 		}
234 		if (tc->exp_nodemask) {
235 			struct bitmask *exp_mask = *(tc->exp_nodemask);
236 
237 			if (!numa_bitmask_equal(exp_mask, getnodemask)) {
238 				tst_res(TFAIL, "masks are not equal");
239 				tst_res_hexd(TINFO, exp_mask->maskp,
240 					exp_mask->size / 8, "exp_mask: ");
241 				tst_res_hexd(TINFO, getnodemask->maskp,
242 					getnodemask->size / 8, "returned: ");
243 				fail = 1;
244 			}
245 		}
246 	}
247 
248 	if (TST_RET != tc->ret) {
249 		tst_res(TFAIL, "wrong return code: %ld, expected: %d",
250 			TST_RET, tc->ret);
251 		fail = 1;
252 	}
253 	if (TST_RET == -1 && TST_ERR != tc->err) {
254 		tst_res(TFAIL | TTERRNO, "expected errno: %s, got",
255 			tst_strerrno(tc->err));
256 		fail = 1;
257 	}
258 	if (!fail)
259 		tst_res(TPASS, "Test passed");
260 }
261 
262 static struct tst_test test = {
263 	.tcnt = ARRAY_SIZE(tcase),
264 	.test = do_test,
265 	.setup = setup,
266 };
267 
268 #else
269 	TST_TEST_TCONF(NUMA_ERROR_MSG);
270 #endif
271