1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 3 * Copyright (c) 2018 Linaro Limited. All rights reserved. 4 * Author: Rafael David Tinoco <rafael.tinoco@linaro.org> 5 */ 6/* 7 * Basic tests for membarrier(2) syscall. Tests below are responsible for 8 * testing the membarrier(2) interface only, without checking if the barrier 9 * was successful or not. Check test_case structure for each test description. 10 */ 11 12#include "config.h" 13#include <sys/types.h> 14#include <sys/stat.h> 15#include <sys/wait.h> 16#include <syscall.h> 17#include <errno.h> 18#include <fcntl.h> 19#include <unistd.h> 20#include <signal.h> 21#include <stdio.h> 22#include <stdlib.h> 23#include <string.h> 24#include "tst_test.h" 25#include "lapi/syscalls.h" 26#include "lapi/membarrier.h" 27 28struct test_case { 29 char testname[80]; 30 int command; /* membarrier cmd */ 31 int needregister; /* membarrier cmd needs register cmd */ 32 int flags; /* flags for given membarrier cmd */ 33 long exp_ret; /* expected return code for given cmd */ 34 int exp_errno; /* expected errno for given cmd failure */ 35 int enabled; /* enabled, despite results from CMD_QUERY */ 36 int always; /* CMD_QUERY should always enable this test */ 37 int force; /* force if CMD_QUERY reports not enabled */ 38 int force_exp_errno; /* expected errno after forced cmd */ 39 int change_exp_errno; /* previous kernels forced errno result */ 40 int change_kernver[3]; /* kernel version having diff expected errno */ 41}; 42 43struct test_case tc[] = { 44 { 45 /* 46 * case 00) invalid cmd 47 * - enabled by default 48 * - should always fail with EINVAL 49 */ 50 .testname = "cmd_fail", 51 .command = -1, 52 .exp_ret = -1, 53 .exp_errno = EINVAL, 54 .enabled = 1, 55 }, 56 { 57 /* 58 * case 01) invalid flags 59 * - enabled by default 60 * - should always fail with EINVAL 61 */ 62 .testname = "cmd_flags_fail", 63 .command = MEMBARRIER_CMD_QUERY, 64 .flags = 1, 65 .exp_ret = -1, 66 .exp_errno = EINVAL, 67 .enabled = 1, 68 }, 69 { 70 /* 71 * case 02) global barrier 72 * - should ALWAYS be enabled by CMD_QUERY 73 * - should always succeed 74 */ 75 .testname = "cmd_global_success", 76 .command = MEMBARRIER_CMD_GLOBAL, 77 .flags = 0, 78 .exp_ret = 0, 79 .always = 1, 80 }, 81 /* 82 * commit 22e4ebb975 (v4.14-rc1) added cases 03, 04 and 05 features: 83 */ 84 { 85 /* 86 * case 03) private expedited barrier with no registrations 87 * - should fail with errno=EPERM due to no registrations 88 * - or be skipped if unsupported by running kernel 89 */ 90 .testname = "cmd_private_expedited_fail", 91 .command = MEMBARRIER_CMD_PRIVATE_EXPEDITED, 92 .flags = 0, 93 .exp_ret = -1, 94 .exp_errno = EPERM, 95 }, 96 { 97 /* 98 * case 04) register private expedited 99 * - should succeed when supported by running kernel 100 * - or fail with errno=EINVAL if unsupported and forced 101 */ 102 .testname = "cmd_private_expedited_register_success", 103 .command = MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED, 104 .flags = 0, 105 .exp_ret = 0, 106 .force = 1, 107 .force_exp_errno = EINVAL, 108 }, 109 { 110 /* 111 * case 05) private expedited barrier with registration 112 * - should succeed due to existing registration 113 * - or fail with errno=EINVAL if unsupported and forced 114 * - NOTE: commit 70216e18e5 (v4.16-rc1) changed behavior: 115 * - (a) if unsupported, and forced, < 4.16 , errno is EINVAL 116 * - (b) if unsupported, and forced, >= 4.16, errno is EPERM 117 */ 118 .testname = "cmd_private_expedited_success", 119 .needregister = MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED, 120 .command = MEMBARRIER_CMD_PRIVATE_EXPEDITED, 121 .flags = 0, 122 .exp_ret = 0, 123 .force = 1, 124 .force_exp_errno = EPERM, 125 .change_exp_errno = EINVAL, 126 .change_kernver = { 4, 16, 0 }, 127 }, 128 /* 129 * commit 70216e18e5 (v4.16-rc1) added cases 06, 07 and 08 features: 130 */ 131 { 132 /* 133 * case 06) private expedited sync core barrier with no registrations 134 * - should fail with errno=EPERM due to no registrations 135 * - or be skipped if unsupported by running kernel 136 */ 137 .testname = "cmd_private_expedited_sync_core_fail", 138 .command = MEMBARRIER_CMD_PRIVATE_EXPEDITED_SYNC_CORE, 139 .flags = 0, 140 .exp_ret = -1, 141 .exp_errno = EPERM, 142 }, 143 { 144 /* 145 * case 07) register private expedited sync core 146 * - should succeed when supported by running kernel 147 * - or fail with errno=EINVAL if unsupported and forced 148 */ 149 .testname = "cmd_private_expedited_sync_core_register_success", 150 .command = MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_SYNC_CORE, 151 .flags = 0, 152 .exp_ret = 0, 153 .force = 1, 154 .force_exp_errno = EINVAL, 155 }, 156 { 157 /* 158 * case 08) private expedited sync core barrier with registration 159 * - should succeed due to existing registration 160 * - or fail with errno=EINVAL if unsupported and forced 161 */ 162 .testname = "cmd_private_expedited_sync_core_success", 163 .needregister = MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_SYNC_CORE, 164 .command = MEMBARRIER_CMD_PRIVATE_EXPEDITED_SYNC_CORE, 165 .flags = 0, 166 .exp_ret = 0, 167 .force = 1, 168 .force_exp_errno = EINVAL, 169 }, 170 /* 171 * commit c5f58bd58f4 (v4.16-rc1) added cases 09, 10 and 11 features: 172 */ 173 { 174 /* 175 * case 09) global expedited barrier with no registrations 176 * - should never fail due to no registrations 177 * - or be skipped if unsupported by running kernel 178 */ 179 .testname = "cmd_global_expedited_success", 180 .command = MEMBARRIER_CMD_GLOBAL_EXPEDITED, 181 .flags = 0, 182 .exp_ret = 0, 183 }, 184 { 185 /* 186 * case 10) register global expedited 187 * - should succeed when supported by running kernel 188 * - or fail with errno=EINVAL if unsupported and forced 189 */ 190 .testname = "cmd_global_expedited_register_success", 191 .command = MEMBARRIER_CMD_REGISTER_GLOBAL_EXPEDITED, 192 .flags = 0, 193 .exp_ret = 0, 194 .force = 1, 195 .force_exp_errno = EINVAL, 196 }, 197 { 198 /* 199 * case 11) global expedited barrier with registration 200 * - should also succeed with registrations 201 * - or fail with errno=EINVAL if unsupported and forced 202 */ 203 .testname = "cmd_global_expedited_success", 204 .needregister = MEMBARRIER_CMD_REGISTER_GLOBAL_EXPEDITED, 205 .command = MEMBARRIER_CMD_GLOBAL_EXPEDITED, 206 .flags = 0, 207 .exp_ret = 0, 208 .force = 1, 209 .force_exp_errno = EINVAL, 210 }, 211}; 212 213#define passed_ok(_test) \ 214 do { \ 215 tst_res(TPASS, "membarrier(2): %s passed", _test.testname); \ 216 return; \ 217 } while (0) 218 219#define passed_unexpec(_test) \ 220 do { \ 221 tst_res(TFAIL, "membarrier(2): %s passed unexpectedly. " \ 222 "ret = %ld with errno %d were expected. (force: %d)", \ 223 _test.testname, _test.exp_ret, _test.exp_errno, \ 224 _test.force); \ 225 return; \ 226 } while (0) 227 228#define failed_ok(_test) \ 229 do { \ 230 tst_res(TPASS, "membarrier(2): %s failed as expected", \ 231 _test.testname); \ 232 return; \ 233 } while (0) 234 235#define failed_ok_unsupported(_test) \ 236 do { \ 237 tst_res(TPASS, "membarrier(2): %s failed as expected " \ 238 "(unsupported)", _test.testname); \ 239 return; \ 240 } while (0) 241 242#define failed_not_ok(_test, _gotret, _goterr) \ 243 do { \ 244 tst_res(TFAIL, "membarrier(2): %s failed. " \ 245 "ret = %ld when expected was %ld. " \ 246 "errno = %d when expected was %d. (force: %d)", \ 247 _test.testname, _gotret, _test.exp_ret, _goterr, \ 248 _test.exp_errno, _test.force); \ 249 return; \ 250 } while (0) 251 252#define failed_unexpec(_test, _gotret, _goterr) \ 253 do { \ 254 tst_res(TFAIL, "membarrier(2): %s failed unexpectedly. " \ 255 "Got ret = %ld with errno %d. (force: %d)", \ 256 _test.testname, _gotret, _goterr, _test.force); \ 257 return; \ 258 } while (0) 259 260#define skipped(_test) \ 261 do { \ 262 tst_res(TPASS, "membarrier(2): %s skipped (unsupported)", \ 263 _test.testname); \ 264 return; \ 265 } while (0) 266 267#define skipped_fail(_test) \ 268 do { \ 269 tst_res(TFAIL, "membarrier(2): %s reported as not supported", \ 270 _test.testname); \ 271 return; \ 272 } while (0) 273 274static int sys_membarrier(int cmd, int flags) 275{ 276 return tst_syscall(__NR_membarrier, cmd, flags); 277} 278 279static void verify_membarrier(unsigned int i) 280{ 281 int ret; 282 283 /* not enabled and not enforced: test is skipped */ 284 285 if (!tc[i].enabled && !tc[i].force) { 286 287 if (tc[i].always == 0) 288 skipped(tc[i]); 289 290 skipped_fail(tc[i]); 291 } 292 293 /* iterations: registration needed for some cases */ 294 295 if (tc[i].needregister && tc[i].enabled) { 296 ret = sys_membarrier(tc[i].needregister, 0); 297 if (ret < 0) { 298 tst_brk(TBROK, "membarrier(2): %s could not register", 299 tc[i].testname); 300 } 301 } 302 303 TEST(sys_membarrier(tc[i].command, tc[i].flags)); 304 305 /* enabled and not enforced: regular expected results only */ 306 307 if (tc[i].enabled && !tc[i].force) { 308 309 if (TST_RET >= 0 && tc[i].exp_ret == TST_RET) 310 passed_ok(tc[i]); 311 312 if (TST_RET < 0) { 313 if (tc[i].exp_ret == TST_RET) 314 failed_ok(tc[i]); 315 else 316 failed_not_ok(tc[i], TST_RET, TST_ERR); 317 } 318 } 319 320 /* not enabled and enforced: failure and expected errors */ 321 322 if (!tc[i].enabled && tc[i].force) { 323 324 if (TST_RET >= 0) 325 passed_unexpec(tc[i]); 326 327 if (TST_RET < 0) { 328 if (tc[i].force_exp_errno == TST_ERR) 329 failed_ok_unsupported(tc[i]); 330 else 331 failed_unexpec(tc[i], TST_RET, TST_ERR); 332 } 333 } 334 335 /* enabled and enforced: tricky */ 336 337 if (tc[i].enabled && tc[i].force) { 338 339 if (TST_RET >= 0) { 340 if (tc[i].exp_ret == TST_RET) 341 passed_ok(tc[i]); 342 else 343 passed_unexpec(tc[i]); 344 } 345 346 if (TST_RET < 0) { 347 348 if (tc[i].exp_ret == TST_RET) { 349 350 if (tc[i].exp_errno == TST_ERR) 351 failed_ok(tc[i]); 352 else 353 failed_unexpec(tc[i], TST_RET, TST_ERR); 354 } 355 356 /* unknown on force failure if enabled and forced */ 357 failed_unexpec(tc[i], TST_RET, TST_ERR); 358 } 359 } 360} 361 362static void wrap_verify_membarrier(unsigned int i) 363{ 364 pid_t pid; 365 366 /* 367 * The Linux kernel does not provide a way to unregister the process 368 * (mm->membarrier_state) intent of being affected by the membarrier(2) 369 * system call, thus the need of having a wrapper to fork() a child. 370 */ 371 372 pid = SAFE_FORK(); 373 374 if (pid) 375 SAFE_WAITPID(pid, NULL, 0); 376 else 377 verify_membarrier(i); 378} 379 380static void setup(void) 381{ 382 size_t i; 383 int ret; 384 385 ret = sys_membarrier(MEMBARRIER_CMD_QUERY, 0); 386 if (ret < 0) { 387 if (errno == ENOSYS) 388 tst_brk(TBROK, "membarrier(2): not supported"); 389 } 390 391 for (i = 0; i < ARRAY_SIZE(tc); i++) { 392 if ((tc[i].command > 0) && (ret & tc[i].command)) 393 tc[i].enabled = 1; 394 395 /* forcing unsupported command might have different errno */ 396 397 if (tc[i].change_exp_errno && tc[i].enabled == 0) { 398 if (tst_kvercmp(tc[i].change_kernver[0], 399 tc[i].change_kernver[1], 400 tc[i].change_kernver[2]) < 0) 401 tc[i].force_exp_errno = tc[i].change_exp_errno; 402 } 403 } 404} 405 406static struct tst_test test = { 407 .setup = setup, 408 .test = wrap_verify_membarrier, 409 .tcnt = ARRAY_SIZE(tc), 410 .min_kver = "4.3.0", /* commit: 5b25b13ab0 (sys_membarrier(): ...) */ 411 .forks_child = 1, 412}; 413