1 /* 2 * Copyright (c) Crackerjack Project., 2007-2008, Hitachi, Ltd 3 * Copyright (c) 2017 Petr Vorel <pvorel (at) suse.cz> 4 * 5 * Authors: 6 * Takahiro Yasui <takahiro.yasui.mp (at) hitachi.com>, 7 * Yumiko Sugita <yumiko.sugita.yf (at) hitachi.com>, 8 * Satoshi Fujiwara <sa-fuji (at) 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 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 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 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 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 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 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