• 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 
21 #ifdef HAVE_NUMA_V2
22 
23 #define MEM_LENGTH (4 * 1024 * 1024)
24 
25 #define UNKNOWN_POLICY -1
26 
27 #define POLICY_DESC(x) .policy = x, .desc = #x
28 #define POLICY_DESC_TEXT(x, y) .policy = x, .desc = #x" ("y")"
29 
30 static struct bitmask *nodemask, *getnodemask, *empty_nodemask;
31 
32 static void test_default(unsigned int i, char *p);
33 static void test_none(unsigned int i, char *p);
34 static void test_invalid_nodemask(unsigned int i, char *p);
35 
36 struct test_case {
37 	int policy;
38 	const char *desc;
39 	unsigned flags;
40 	int ret;
41 	int err;
42 	void (*test)(unsigned int, char *);
43 	struct bitmask **exp_nodemask;
44 };
45 
46 static struct test_case tcase[] = {
47 	{
48 		POLICY_DESC(MPOL_DEFAULT),
49 		.ret = 0,
50 		.err = 0,
51 		.test = test_none,
52 		.exp_nodemask = &empty_nodemask,
53 	},
54 	{
55 		POLICY_DESC_TEXT(MPOL_DEFAULT, "target exists"),
56 		.ret = -1,
57 		.err = EINVAL,
58 		.test = test_default,
59 	},
60 	{
61 		POLICY_DESC_TEXT(MPOL_BIND, "no target"),
62 		.ret = -1,
63 		.err = EINVAL,
64 		.test = test_none,
65 	},
66 	{
67 		POLICY_DESC(MPOL_BIND),
68 		.ret = 0,
69 		.err = 0,
70 		.test = test_default,
71 		.exp_nodemask = &nodemask,
72 	},
73 	{
74 		POLICY_DESC_TEXT(MPOL_INTERLEAVE, "no target"),
75 		.ret = -1,
76 		.err = EINVAL,
77 		.test = test_none,
78 	},
79 	{
80 		POLICY_DESC(MPOL_INTERLEAVE),
81 		.ret = 0,
82 		.err = 0,
83 		.test = test_default,
84 		.exp_nodemask = &nodemask,
85 	},
86 	{
87 		POLICY_DESC_TEXT(MPOL_PREFERRED, "no target"),
88 		.ret = 0,
89 		.err = 0,
90 		.test = test_none,
91 	},
92 	{
93 		POLICY_DESC(MPOL_PREFERRED),
94 		.ret = 0,
95 		.err = 0,
96 		.test = test_default,
97 		.exp_nodemask = &nodemask,
98 	},
99 	{
100 		POLICY_DESC(UNKNOWN_POLICY),
101 		.ret = -1,
102 		.err = EINVAL,
103 		.test = test_none,
104 	},
105 	{
106 		POLICY_DESC_TEXT(MPOL_DEFAULT, "invalid flags"),
107 		.flags = -1,
108 		.ret = -1,
109 		.err = EINVAL,
110 		.test = test_none,
111 	},
112 	{
113 		POLICY_DESC_TEXT(MPOL_PREFERRED, "invalid nodemask"),
114 		.ret = -1,
115 		.err = EFAULT,
116 		.test = test_invalid_nodemask,
117 	},
118 };
119 
test_default(unsigned int i,char * p)120 static void test_default(unsigned int i, char *p)
121 {
122 	struct test_case *tc = &tcase[i];
123 
124 	TEST(mbind(p, MEM_LENGTH, tc->policy, nodemask->maskp,
125 		   nodemask->size, tc->flags));
126 }
127 
test_none(unsigned int i,char * p)128 static void test_none(unsigned int i, char *p)
129 {
130 	struct test_case *tc = &tcase[i];
131 
132 	TEST(mbind(p, MEM_LENGTH, tc->policy, NULL, 0, tc->flags));
133 }
134 
test_invalid_nodemask(unsigned int i,char * p)135 static void test_invalid_nodemask(unsigned int i, char *p)
136 {
137 	struct test_case *tc = &tcase[i];
138 
139 	/* use invalid nodemask (64 MiB after heap) */
140 	TEST(mbind(p, MEM_LENGTH, tc->policy, sbrk(0) + 64*1024*1024,
141 		   NUMA_NUM_NODES, tc->flags));
142 }
143 
setup(void)144 static void setup(void)
145 {
146 	if (!is_numa(NULL, NH_MEMS, 1))
147 		tst_brk(TCONF, "requires NUMA with at least 1 node");
148 	empty_nodemask = numa_allocate_nodemask();
149 }
150 
setup_node(void)151 static void setup_node(void)
152 {
153 	int test_node = -1;
154 
155 	if (get_allowed_nodes(NH_MEMS, 1, &test_node) < 0)
156 		tst_brk(TBROK | TERRNO, "get_allowed_nodes failed");
157 
158 	nodemask = numa_allocate_nodemask();
159 	getnodemask = numa_allocate_nodemask();
160 	numa_bitmask_setbit(nodemask, test_node);
161 }
162 
do_test(unsigned int i)163 static void do_test(unsigned int i)
164 {
165 	struct test_case *tc = &tcase[i];
166 	int policy, fail = 0;
167 	char *p = NULL;
168 
169 	tst_res(TINFO, "case %s", tc->desc);
170 
171 	setup_node();
172 
173 	p = mmap(NULL, MEM_LENGTH, PROT_READ | PROT_WRITE, MAP_PRIVATE |
174 			 MAP_ANONYMOUS, 0, 0);
175 	if (p == MAP_FAILED)
176 		tst_brk(TBROK | TERRNO, "mmap");
177 
178 	tc->test(i, p);
179 
180 	if (TST_RET >= 0) {
181 		/* Check policy of the allocated memory */
182 		TEST(get_mempolicy(&policy, getnodemask->maskp,
183 				   getnodemask->size, p, MPOL_F_ADDR));
184 		if (TST_RET < 0) {
185 			tst_res(TFAIL | TTERRNO, "get_mempolicy failed");
186 			return;
187 		}
188 		if (tc->policy != policy) {
189 			tst_res(TFAIL, "Wrong policy: %d, expected: %d",
190 				tc->policy, policy);
191 			fail = 1;
192 		}
193 		if (tc->exp_nodemask) {
194 			struct bitmask *exp_mask = *(tc->exp_nodemask);
195 
196 			if (!numa_bitmask_equal(exp_mask, getnodemask)) {
197 				tst_res(TFAIL, "masks are not equal");
198 				tst_res_hexd(TINFO, exp_mask->maskp,
199 					exp_mask->size / 8, "exp_mask: ");
200 				tst_res_hexd(TINFO, getnodemask->maskp,
201 					getnodemask->size / 8, "returned: ");
202 				fail = 1;
203 			}
204 		}
205 	}
206 
207 	if (TST_RET != tc->ret) {
208 		tst_res(TFAIL, "wrong return code: %ld, expected: %d",
209 			TST_RET, tc->ret);
210 		fail = 1;
211 	}
212 	if (TST_RET == -1 && TST_ERR != tc->err) {
213 		tst_res(TFAIL | TTERRNO, "expected errno: %s, got",
214 			tst_strerrno(tc->err));
215 		fail = 1;
216 	}
217 	if (!fail)
218 		tst_res(TPASS, "Test passed");
219 }
220 
221 static struct tst_test test = {
222 	.tcnt = ARRAY_SIZE(tcase),
223 	.test = do_test,
224 	.setup = setup,
225 };
226 
227 #else
228 	TST_TEST_TCONF(NUMA_ERROR_MSG);
229 #endif
230