1 /******************************************************************************/
2 /* Copyright (c) Crackerjack Project., 2007-2008 */
3 /* Author(s): Takahiro Yasui <takahiro.yasui.mp@hitachi.com>, */
4 /* Yumiko Sugita <yumiko.sugita.yf@hitachi.com>, */
5 /* Satoshi Fujiwara <sa-fuji@sdl.hitachi.co.jp> */
6 /* */
7 /* This program is free software; you can redistribute it and/or modify */
8 /* it under the terms of the GNU General Public License as published by */
9 /* the Free Software Foundation; either version 2 of the License, or */
10 /* (at your option) any later version. */
11 /* */
12 /* This program is distributed in the hope that it will be useful, */
13 /* but WITHOUT ANY WARRANTY; without even the implied warranty of */
14 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See */
15 /* the GNU General Public License for more details. */
16 /* */
17 /* You should have received a copy of the GNU General Public License */
18 /* along with this program; if not, write to the Free Software */
19 /* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
20 /* */
21 /******************************************************************************/
22 /******************************************************************************/
23 /* */
24 /* File: mbind01.c */
25 /* */
26 /* Description: This tests the mbind() syscall */
27 /* */
28 /* Usage: <for command-line> */
29 /* mbind01 [-c n] [-e][-i n] [-I x] [-p x] [-t] */
30 /* where, -c n : Run n copies concurrently. */
31 /* -e : Turn on errno logging. */
32 /* -i n : Execute test n times. */
33 /* -I x : Execute test for x seconds. */
34 /* -P x : Pause for x seconds between iterations. */
35 /* -t : Turn on syscall timing. */
36 /* */
37 /* Total Tests: 1 */
38 /* */
39 /* Test Name: mbind01 */
40 /* History: Porting from Crackerjack to LTP is done by */
41 /* Manas Kumar Nayak maknayak@in.ibm.com> */
42 /******************************************************************************/
43
44 #include "config.h"
45 #include <sys/types.h>
46 #include <sys/mman.h>
47 #include <sys/syscall.h>
48 #include <errno.h>
49 #include <getopt.h>
50 #include <libgen.h>
51 #if HAVE_NUMA_H
52 #include <numa.h>
53 #endif
54 #if HAVE_NUMAIF_H
55 #include <numaif.h>
56 #endif
57 #include <stdio.h>
58 #include <stdlib.h>
59 #include <string.h>
60 #include <unistd.h>
61
62 #include "test.h"
63 #include "linux_syscall_numbers.h"
64 #include "include_j_h.h"
65 #include "numa_helper.h"
66
67 char *TCID = "mbind01";
68 int TST_TOTAL = 2;
69
70 #if HAVE_NUMA_H && HAVE_LINUX_MEMPOLICY_H && HAVE_NUMAIF_H && \
71 HAVE_MPOL_CONSTANTS
72
73 #define MEM_LENGTH (4 * 1024 * 1024)
74
75 static int testno;
76
77 enum test_type {
78 NORMAL,
79 INVALID_POINTER,
80 };
81
82 enum from_node {
83 NONE,
84 SELF,
85 };
86
87 struct test_case {
88 int ttype;
89 int policy;
90 int from_node;
91 unsigned flags;
92 int ret;
93 int err;
94 };
95
96 /* Test cases
97 *
98 * test status of errors on man page
99 *
100 * EFAULT v (detect unmapped hole or invalid pointer)
101 * EINVAL v (invalid arguments)
102 * ENOMEM can't check because it's difficult to create no-memory
103 * EIO can't check because we don't have N-node NUMA system
104 * (only we can do is simulate 1-node NUMA)
105 */
106 static struct test_case tcase[] = {
107 { /* case00 */
108 .policy = MPOL_DEFAULT,
109 .from_node = NONE,
110 .ret = 0,
111 .err = 0,
112 },
113 { /* case01 */
114 .policy = MPOL_DEFAULT,
115 .from_node = SELF, /* target exists */
116 .ret = -1,
117 .err = EINVAL,
118 },
119 { /* case02 */
120 .policy = MPOL_BIND,
121 .from_node = NONE, /* no target */
122 .ret = -1,
123 .err = EINVAL,
124 },
125 { /* case03 */
126 .policy = MPOL_BIND,
127 .from_node = SELF,
128 .ret = 0,
129 .err = 0,
130 },
131 { /* case04 */
132 .policy = MPOL_INTERLEAVE,
133 .from_node = NONE, /* no target */
134 .ret = -1,
135 .err = EINVAL,
136 },
137 { /* case05 */
138 .policy = MPOL_INTERLEAVE,
139 .from_node = SELF,
140 .ret = 0,
141 .err = 0,
142 },
143 { /* case06 */
144 .policy = MPOL_PREFERRED,
145 .from_node = NONE,
146 .ret = 0,
147 .err = 0,
148 },
149 { /* case07 */
150 .policy = MPOL_PREFERRED,
151 .from_node = SELF,
152 .ret = 0,
153 .err = 0,
154 },
155 { /* case08 */
156 .policy = -1, /* unknown policy */
157 .from_node = NONE,
158 .ret = -1,
159 .err = EINVAL,
160 },
161 { /* case09 */
162 .policy = MPOL_DEFAULT,
163 .from_node = NONE,
164 .flags = -1, /* invalid flags */
165 .ret = -1,
166 .err = EINVAL,
167 },
168 { /* case10 */
169 .ttype = INVALID_POINTER,
170 .policy = MPOL_PREFERRED,
171 .from_node = SELF,
172 .ret = -1,
173 .err = EFAULT,
174 },
175 };
176
177 static int do_test(struct test_case *tc);
178 static void setup(void);
179 static void cleanup(void);
180
main(int argc,char ** argv)181 int main(int argc, char **argv)
182 {
183 int lc, i, ret;
184
185 tst_parse_opts(argc, argv, NULL, NULL);
186
187 setup();
188 testno = (int)(sizeof(tcase) / sizeof(tcase[0]));
189
190 for (lc = 0; TEST_LOOPING(lc); ++lc) {
191 tst_count = 0;
192 for (i = 0; i < testno; i++) {
193 tst_resm(TINFO, "(case%02d) START", i);
194 ret = do_test(&tcase[i]);
195 tst_resm((ret == 0 ? TPASS : TFAIL | TERRNO),
196 "(case%02d) END", i);
197 }
198 }
199 cleanup();
200 tst_exit();
201 }
202
do_test(struct test_case * tc)203 static int do_test(struct test_case *tc)
204 {
205 int ret, err, result, cmp_ok = 1;
206 int policy;
207 char *p = NULL;
208 #if !defined(LIBNUMA_API_VERSION) || LIBNUMA_API_VERSION < 2
209 nodemask_t *nodemask, *getnodemask;
210 #else
211 struct bitmask *nodemask = numa_allocate_nodemask();
212 struct bitmask *getnodemask = numa_allocate_nodemask();
213 #endif
214 unsigned long maxnode = NUMA_NUM_NODES;
215 unsigned long len = MEM_LENGTH;
216 unsigned long *invalid_nodemask;
217 int test_node = -1;
218
219 ret = get_allowed_nodes(NH_MEMS, 1, &test_node);
220 if (ret < 0)
221 tst_brkm(TBROK | TERRNO, cleanup, "get_allowed_nodes: %d", ret);
222
223 #if !defined(LIBNUMA_API_VERSION) || LIBNUMA_API_VERSION < 2
224 nodemask = malloc(sizeof(nodemask_t));
225 nodemask_zero(nodemask);
226 nodemask_set(nodemask, test_node);
227 getnodemask = malloc(sizeof(nodemask_t));
228 nodemask_zero(getnodemask);
229 #else
230 numa_bitmask_setbit(nodemask, test_node);
231 #endif
232 p = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS,
233 0, 0);
234 if (p == MAP_FAILED)
235 tst_brkm(TBROK | TERRNO, cleanup, "mmap");
236
237 if (tc->ttype == INVALID_POINTER)
238 invalid_nodemask = (unsigned long *)0xc0000000;
239
240 errno = 0;
241 if (tc->from_node == NONE)
242 TEST(ret = ltp_syscall(__NR_mbind, p, len, tc->policy,
243 NULL, 0, tc->flags));
244 else if (tc->ttype == INVALID_POINTER)
245 TEST(ret = ltp_syscall(__NR_mbind, p, len, tc->policy,
246 invalid_nodemask, maxnode, tc->flags));
247 else
248 #if !defined(LIBNUMA_API_VERSION) || LIBNUMA_API_VERSION < 2
249 TEST(ret = ltp_syscall(__NR_mbind, p, len, tc->policy,
250 nodemask, maxnode, tc->flags));
251 #else
252 TEST(ret = ltp_syscall(__NR_mbind, p, len, tc->policy,
253 nodemask->maskp, nodemask->size, tc->flags));
254 #endif
255
256 err = TEST_ERRNO;
257 if (ret < 0)
258 goto TEST_END;
259
260 /* Check policy of the allocated memory */
261 #if !defined(LIBNUMA_API_VERSION) || LIBNUMA_API_VERSION < 2
262 TEST(ltp_syscall(__NR_get_mempolicy, &policy, getnodemask,
263 maxnode, p, MPOL_F_ADDR));
264 #else
265 TEST(ltp_syscall(__NR_get_mempolicy, &policy, getnodemask->maskp,
266 getnodemask->size, p, MPOL_F_ADDR));
267 #endif
268 if (TEST_RETURN < 0) {
269 tst_resm(TFAIL | TERRNO, "get_mempolicy failed");
270 return -1;
271 }
272
273 /* If policy == MPOL_DEFAULT, get_mempolicy doesn't return nodemask */
274 if (tc->policy == MPOL_DEFAULT)
275 #if !defined(LIBNUMA_API_VERSION) || LIBNUMA_API_VERSION < 2
276 nodemask_zero(nodemask);
277 #else
278 numa_bitmask_clearall(nodemask);
279 #endif
280
281 if ((tc->policy == MPOL_PREFERRED) && (tc->from_node == NONE))
282 cmp_ok = (tc->policy == policy);
283 else
284 cmp_ok = ((tc->policy == policy) &&
285 #if !defined(LIBNUMA_API_VERSION) || LIBNUMA_API_VERSION < 2
286 nodemask_equal(nodemask, getnodemask));
287 #else
288 numa_bitmask_equal(nodemask, getnodemask));
289 #endif
290 TEST_END:
291 result = ((err != tc->err) || (!cmp_ok));
292 PRINT_RESULT_CMP(0, tc->ret, tc->err, ret, err, cmp_ok);
293 return result;
294 }
295
setup(void)296 static void setup(void)
297 {
298 /* check syscall availability */
299 ltp_syscall(__NR_mbind, NULL, 0, 0, NULL, 0, 0);
300
301 if (!is_numa(NULL, NH_MEMS, 1))
302 tst_brkm(TCONF, NULL, "requires NUMA with at least 1 node");
303
304 TEST_PAUSE;
305 tst_tmpdir();
306 }
307
cleanup(void)308 static void cleanup(void)
309 {
310 tst_rmdir();
311 }
312 #else /* no NUMA */
main(void)313 int main(void)
314 {
315 tst_brkm(TCONF, NULL, "System doesn't have required numa support");
316 }
317 #endif
318