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