1 /******************************************************************************/ 2 /* Copyright (c) Crackerjack Project., 2007-2008 */ 3 /* Author(s): Takahiro Yasui <takahiro.yasui.mp (at) hitachi.com>, */ 4 /* Yumiko Sugita <yumiko.sugita.yf (at) hitachi.com>, */ 5 /* Satoshi Fujiwara <sa-fuji (at) 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 (at) 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 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 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 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 308 static void cleanup(void) 309 { 310 tst_rmdir(); 311 } 312 #else /* no NUMA */ 313 int main(void) 314 { 315 tst_brkm(TCONF, NULL, "System doesn't have required numa support"); 316 } 317 #endif 318