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