This commit re-organizes membarrier test, solving issues when testing LTS kernels. Now, the code: - always run the same amount of tests (even on older kernels). - allows each test to succeed, fail or be skipped independently. - allows testing features even when explicitly unsupported (force=1). - checks false positive/negative by checking ret code and errno. - can be extended easily: to expand an array with commands. Note: like this, the test is pretty close to the LTP membarrier basic tests, and both can be maintained together. Link: https://bugs.linaro.org/show_bug.cgi?id=3771 Link: http://lists.linux.it/pipermail/ltp/2018-October/009578.html Signed-off-by: Rafael David Tinoco <rafael.tinoco@xxxxxxxxxx> --- .../selftests/membarrier/membarrier_test.c | 566 ++++++++++-------- 1 file changed, 314 insertions(+), 252 deletions(-) diff --git a/tools/testing/selftests/membarrier/membarrier_test.c b/tools/testing/selftests/membarrier/membarrier_test.c index 6793f8ecc8e7..7eb0e2395cbd 100644 --- a/tools/testing/selftests/membarrier/membarrier_test.c +++ b/tools/testing/selftests/membarrier/membarrier_test.c @@ -8,305 +8,367 @@ #include "../kselftest.h" +#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) + +struct test_case { + char testname[80]; + int command; /* membarrier cmd */ + int needregister; /* membarrier cmd needs register cmd */ + int flags; /* flags for given membarrier cmd */ + long exp_ret; /* expected return code for given cmd */ + int exp_errno; /* expected errno for given cmd failure */ + int enabled; /* enabled, despite results from CMD_QUERY */ + int always; /* CMD_QUERY should always enable this test */ + int force; /* force if CMD_QUERY reports not enabled */ + int force_exp_errno; /* expected errno after forced cmd */ +}; + +struct test_case tc[] = { + { + /* + * case 00) invalid cmd + * - enabled by default + * - should always fail with EINVAL + */ + .testname = "cmd_fail", + .command = -1, + .exp_ret = -1, + .exp_errno = EINVAL, + .enabled = 1, + }, + { + /* + * case 01) invalid flags + * - enabled by default + * - should always fail with EINVAL + */ + .testname = "cmd_flags_fail", + .command = MEMBARRIER_CMD_QUERY, + .flags = 1, + .exp_ret = -1, + .exp_errno = EINVAL, + .enabled = 1, + }, + { + /* + * case 02) global barrier + * - should ALWAYS be enabled by CMD_QUERY + * - should always succeed + */ + .testname = "cmd_global_success", + .command = MEMBARRIER_CMD_GLOBAL, + .flags = 0, + .exp_ret = 0, + .always = 1, + }, + /* + * commit 22e4ebb975 (v4.14-rc1) added cases 03, 04 and 05 features: + */ + { + /* + * case 03) private expedited barrier with no registrations + * - should fail with errno=EPERM due to no registrations + * - or be skipped if unsupported by running kernel + */ + .testname = "cmd_private_expedited_fail", + .command = MEMBARRIER_CMD_PRIVATE_EXPEDITED, + .flags = 0, + .exp_ret = -1, + .exp_errno = EPERM, + }, + { + /* + * case 04) register private expedited + * - should succeed when supported by running kernel + * - or fail with errno=EINVAL if unsupported and forced + */ + .testname = "cmd_private_expedited_register_success", + .command = MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED, + .flags = 0, + .exp_ret = 0, + .force = 1, + .force_exp_errno = EINVAL, + }, + { + /* + * case 05) private expedited barrier with registration + * - should succeed due to existing registration + * - or fail with errno=EINVAL if unsupported and forced + * - NOTE: commit 70216e18e5 (v4.16-rc1) changed behavior: + * - (a) if unsupported, and forced, < 4.16 , errno is EINVAL + * - (b) if unsupported, and forced, >= 4.16, errno is EPERM + */ + .testname = "cmd_private_expedited_success", + .needregister = MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED, + .command = MEMBARRIER_CMD_PRIVATE_EXPEDITED, + .flags = 0, + .exp_ret = 0, + .force = 1, + .force_exp_errno = EPERM, + }, + /* + * commit 70216e18e5 (v4.16-rc1) added cases 06, 07 and 08 features: + */ + { + /* + * case 06) private expedited sync core barrier with no registrations + * - should fail with errno=EPERM due to no registrations + * - or be skipped if unsupported by running kernel + */ + .testname = "cmd_private_expedited_sync_core_fail", + .command = MEMBARRIER_CMD_PRIVATE_EXPEDITED_SYNC_CORE, + .flags = 0, + .exp_ret = -1, + .exp_errno = EPERM, + }, + { + /* + * case 07) register private expedited sync core + * - should succeed when supported by running kernel + * - or fail with errno=EINVAL if unsupported and forced + */ + .testname = "cmd_private_expedited_sync_core_register_success", + .command = MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_SYNC_CORE, + .flags = 0, + .exp_ret = 0, + .force = 1, + .force_exp_errno = EINVAL, + }, + { + /* + * case 08) private expedited sync core barrier with registration + * - should succeed due to existing registration + * - or fail with errno=EINVAL if unsupported and forced + */ + .testname = "cmd_private_expedited_sync_core_success", + .needregister = MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_SYNC_CORE, + .command = MEMBARRIER_CMD_PRIVATE_EXPEDITED_SYNC_CORE, + .flags = 0, + .exp_ret = 0, + .force = 1, + .force_exp_errno = EINVAL, + }, + /* + * commit c5f58bd58f4 (v4.16-rc1) added cases 09, 10 and 11 features: + */ + { + /* + * case 09) global expedited barrier with no registrations + * - should never fail due to no registrations + * - or be skipped if unsupported by running kernel + */ + .testname = "cmd_global_expedited_success", + .command = MEMBARRIER_CMD_GLOBAL_EXPEDITED, + .flags = 0, + .exp_ret = 0, + }, + { + /* + * case 10) register global expedited + * - should succeed when supported by running kernel + * - or fail with errno=EINVAL if unsupported and forced + */ + .testname = "cmd_global_expedited_register_success", + .command = MEMBARRIER_CMD_REGISTER_GLOBAL_EXPEDITED, + .flags = 0, + .exp_ret = 0, + .force = 1, + .force_exp_errno = EINVAL, + }, + { + /* + * case 11) global expedited barrier with registration + * - should also succeed with registrations + * - or fail with errno=EINVAL if unsupported and forced + */ + .testname = "cmd_global_expedited_success", + .needregister = MEMBARRIER_CMD_REGISTER_GLOBAL_EXPEDITED, + .command = MEMBARRIER_CMD_GLOBAL_EXPEDITED, + .flags = 0, + .exp_ret = 0, + .force = 1, + .force_exp_errno = EINVAL, + }, +}; + +#define passed_ok(_test) \ + do { \ + ksft_test_result_pass("membarrier(2): %s passed.\n", \ + _test.testname); \ + return; \ + } while (0) + +#define passed_unexpec(_test) \ + do { \ + ksft_exit_fail_msg("membarrier(2): %s passed unexpectedly. " \ + "ret = %ld with errno %d were expected. (force: %d)\n",\ + _test.testname, _test.exp_ret, _test.exp_errno, \ + _test.force); \ + return; \ + } while (0) + +#define failed_ok(_test) \ + do { \ + ksft_test_result_pass("membarrier(2): %s failed as " \ + "expected.\n", _test.testname); \ + return; \ + } while (0) + +#define failed_ok_unsupported(_test) \ + do { \ + ksft_test_result_pass("membarrier(2): %s failed as expected.\n"\ + "(unsupported)", _test.testname); \ + return; \ + } while (0) + +#define failed_not_ok(_test, _gotret, _goterr) \ + do { \ + ksft_exit_fail_msg("membarrier(2): %s failed. " \ + "ret = %ld when expected was %ld. " \ + "errno = %d when expected was %d. (force: %d)\n", \ + _test.testname, _gotret, _test.exp_ret, _goterr, \ + _test.exp_errno, _test.force); \ + return; \ + } while (0) + +#define failed_unexpec(_test, _gotret, _goterr) \ + do { \ + ksft_exit_fail_msg("membarrier(2): %s failed unexpectedly. " \ + "Got ret = %ld with errno %d. (force: %d)\n", \ + _test.testname, _gotret, _goterr, _test.force); \ + return; \ + } while (0) + +#define skipped(_test) \ + do { \ + ksft_test_result_pass("membarrier(2): %s skipped (unsupp)\n", \ + _test.testname); \ + return; \ + } while (0) + +#define skipped_fail(_test) \ + do { \ + ksft_exit_fail_msg("membarrier(2): %s reported as " \ + "unsupported\n", _test.testname); \ + return; \ + } while (0) + static int sys_membarrier(int cmd, int flags) { return syscall(__NR_membarrier, cmd, flags); } -static int test_membarrier_cmd_fail(void) +static void test_membarrier_setup(void) { - int cmd = -1, flags = 0; - const char *test_name = "sys membarrier invalid command"; + size_t i; + int ret; - if (sys_membarrier(cmd, flags) != -1) { - ksft_exit_fail_msg( - "%s test: command = %d, flags = %d. Should fail, but passed\n", - test_name, cmd, flags); - } - if (errno != EINVAL) { - ksft_exit_fail_msg( - "%s test: flags = %d. Should return (%d: \"%s\"), but returned (%d: \"%s\").\n", - test_name, flags, EINVAL, strerror(EINVAL), - errno, strerror(errno)); + ret = sys_membarrier(MEMBARRIER_CMD_QUERY, 0); + if (ret < 0) { + if (errno == ENOSYS) + ksft_test_result_skip("membarrier(2): not supported\n"); } - ksft_test_result_pass( - "%s test: command = %d, flags = %d, errno = %d. Failed as expected\n", - test_name, cmd, flags, errno); - return 0; -} - -static int test_membarrier_flags_fail(void) -{ - int cmd = MEMBARRIER_CMD_QUERY, flags = 1; - const char *test_name = "sys membarrier MEMBARRIER_CMD_QUERY invalid flags"; - - if (sys_membarrier(cmd, flags) != -1) { - ksft_exit_fail_msg( - "%s test: flags = %d. Should fail, but passed\n", - test_name, flags); + for (i = 0; i < ARRAY_SIZE(tc); i++) { + if ((tc[i].command > 0) && (ret & tc[i].command)) + tc[i].enabled = 1; } - if (errno != EINVAL) { - ksft_exit_fail_msg( - "%s test: flags = %d. Should return (%d: \"%s\"), but returned (%d: \"%s\").\n", - test_name, flags, EINVAL, strerror(EINVAL), - errno, strerror(errno)); - } - - ksft_test_result_pass( - "%s test: flags = %d, errno = %d. Failed as expected\n", - test_name, flags, errno); - return 0; } -static int test_membarrier_global_success(void) +static void test_membarrier_run(unsigned int i) { - int cmd = MEMBARRIER_CMD_GLOBAL, flags = 0; - const char *test_name = "sys membarrier MEMBARRIER_CMD_GLOBAL"; + int ret, err = 0; - if (sys_membarrier(cmd, flags) != 0) { - ksft_exit_fail_msg( - "%s test: flags = %d, errno = %d\n", - test_name, flags, errno); - } + /* not enabled and not enforced: test is skipped */ - ksft_test_result_pass( - "%s test: flags = %d\n", test_name, flags); - return 0; -} + if (!tc[i].enabled && !tc[i].force) { -static int test_membarrier_private_expedited_fail(void) -{ - int cmd = MEMBARRIER_CMD_PRIVATE_EXPEDITED, flags = 0; - const char *test_name = "sys membarrier MEMBARRIER_CMD_PRIVATE_EXPEDITED not registered failure"; + if (tc[i].always == 0) + skipped(tc[i]); - if (sys_membarrier(cmd, flags) != -1) { - ksft_exit_fail_msg( - "%s test: flags = %d. Should fail, but passed\n", - test_name, flags); - } - if (errno != EPERM) { - ksft_exit_fail_msg( - "%s test: flags = %d. Should return (%d: \"%s\"), but returned (%d: \"%s\").\n", - test_name, flags, EPERM, strerror(EPERM), - errno, strerror(errno)); + skipped_fail(tc[i]); } - ksft_test_result_pass( - "%s test: flags = %d, errno = %d\n", - test_name, flags, errno); - return 0; -} + /* iterations: registration needed for some cases */ -static int test_membarrier_register_private_expedited_success(void) -{ - int cmd = MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED, flags = 0; - const char *test_name = "sys membarrier MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED"; - - if (sys_membarrier(cmd, flags) != 0) { - ksft_exit_fail_msg( - "%s test: flags = %d, errno = %d\n", - test_name, flags, errno); + if (tc[i].needregister && tc[i].enabled) { + ret = sys_membarrier(tc[i].needregister, 0); + if (ret < 0) { + ksft_test_result_fail("membarrier(2): %s could not" + "register\n", tc[i].testname); + } } - ksft_test_result_pass( - "%s test: flags = %d\n", - test_name, flags); - return 0; -} + ret = sys_membarrier(tc[i].command, tc[i].flags); + err = errno; -static int test_membarrier_private_expedited_success(void) -{ - int cmd = MEMBARRIER_CMD_PRIVATE_EXPEDITED, flags = 0; - const char *test_name = "sys membarrier MEMBARRIER_CMD_PRIVATE_EXPEDITED"; + /* enabled and not enforced: regular expected results only */ - if (sys_membarrier(cmd, flags) != 0) { - ksft_exit_fail_msg( - "%s test: flags = %d, errno = %d\n", - test_name, flags, errno); - } + if (tc[i].enabled && !tc[i].force) { - ksft_test_result_pass( - "%s test: flags = %d\n", - test_name, flags); - return 0; -} + if (ret >= 0 && tc[i].exp_ret == ret) + passed_ok(tc[i]); -static int test_membarrier_private_expedited_sync_core_fail(void) -{ - int cmd = MEMBARRIER_CMD_PRIVATE_EXPEDITED_SYNC_CORE, flags = 0; - const char *test_name = "sys membarrier MEMBARRIER_CMD_PRIVATE_EXPEDITED_SYNC_CORE not registered failure"; - - if (sys_membarrier(cmd, flags) != -1) { - ksft_exit_fail_msg( - "%s test: flags = %d. Should fail, but passed\n", - test_name, flags); - } - if (errno != EPERM) { - ksft_exit_fail_msg( - "%s test: flags = %d. Should return (%d: \"%s\"), but returned (%d: \"%s\").\n", - test_name, flags, EPERM, strerror(EPERM), - errno, strerror(errno)); - } - - ksft_test_result_pass( - "%s test: flags = %d, errno = %d\n", - test_name, flags, errno); - return 0; -} - -static int test_membarrier_register_private_expedited_sync_core_success(void) -{ - int cmd = MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_SYNC_CORE, flags = 0; - const char *test_name = "sys membarrier MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_SYNC_CORE"; - - if (sys_membarrier(cmd, flags) != 0) { - ksft_exit_fail_msg( - "%s test: flags = %d, errno = %d\n", - test_name, flags, errno); + if (ret < 0) { + if (tc[i].exp_ret == ret) + failed_ok(tc[i]); + else + failed_not_ok(tc[i], ret, err); + } } - ksft_test_result_pass( - "%s test: flags = %d\n", - test_name, flags); - return 0; -} + /* not enabled and enforced: failure and expected errors */ -static int test_membarrier_private_expedited_sync_core_success(void) -{ - int cmd = MEMBARRIER_CMD_PRIVATE_EXPEDITED, flags = 0; - const char *test_name = "sys membarrier MEMBARRIER_CMD_PRIVATE_EXPEDITED_SYNC_CORE"; + if (!tc[i].enabled && tc[i].force) { - if (sys_membarrier(cmd, flags) != 0) { - ksft_exit_fail_msg( - "%s test: flags = %d, errno = %d\n", - test_name, flags, errno); - } + if (ret >= 0) + passed_unexpec(tc[i]); - ksft_test_result_pass( - "%s test: flags = %d\n", - test_name, flags); - return 0; -} - -static int test_membarrier_register_global_expedited_success(void) -{ - int cmd = MEMBARRIER_CMD_REGISTER_GLOBAL_EXPEDITED, flags = 0; - const char *test_name = "sys membarrier MEMBARRIER_CMD_REGISTER_GLOBAL_EXPEDITED"; - - if (sys_membarrier(cmd, flags) != 0) { - ksft_exit_fail_msg( - "%s test: flags = %d, errno = %d\n", - test_name, flags, errno); + if (ret < 0) { + if (tc[i].force_exp_errno == err) + failed_ok_unsupported(tc[i]); + else + failed_unexpec(tc[i], ret, err); + } } - ksft_test_result_pass( - "%s test: flags = %d\n", - test_name, flags); - return 0; -} + /* enabled and enforced: tricky */ -static int test_membarrier_global_expedited_success(void) -{ - int cmd = MEMBARRIER_CMD_GLOBAL_EXPEDITED, flags = 0; - const char *test_name = "sys membarrier MEMBARRIER_CMD_GLOBAL_EXPEDITED"; + if (tc[i].enabled && tc[i].force) { - if (sys_membarrier(cmd, flags) != 0) { - ksft_exit_fail_msg( - "%s test: flags = %d, errno = %d\n", - test_name, flags, errno); - } + if (ret >= 0) { + if (tc[i].exp_ret == ret) + passed_ok(tc[i]); + else + passed_unexpec(tc[i]); + } - ksft_test_result_pass( - "%s test: flags = %d\n", - test_name, flags); - return 0; -} + if (ret < 0) { -static int test_membarrier(void) -{ - int status; - - status = test_membarrier_cmd_fail(); - if (status) - return status; - status = test_membarrier_flags_fail(); - if (status) - return status; - status = test_membarrier_global_success(); - if (status) - return status; - status = test_membarrier_private_expedited_fail(); - if (status) - return status; - status = test_membarrier_register_private_expedited_success(); - if (status) - return status; - status = test_membarrier_private_expedited_success(); - if (status) - return status; - status = sys_membarrier(MEMBARRIER_CMD_QUERY, 0); - if (status < 0) { - ksft_test_result_fail("sys_membarrier() failed\n"); - return status; - } - if (status & MEMBARRIER_CMD_PRIVATE_EXPEDITED_SYNC_CORE) { - status = test_membarrier_private_expedited_sync_core_fail(); - if (status) - return status; - status = test_membarrier_register_private_expedited_sync_core_success(); - if (status) - return status; - status = test_membarrier_private_expedited_sync_core_success(); - if (status) - return status; - } - /* - * It is valid to send a global membarrier from a non-registered - * process. - */ - status = test_membarrier_global_expedited_success(); - if (status) - return status; - status = test_membarrier_register_global_expedited_success(); - if (status) - return status; - status = test_membarrier_global_expedited_success(); - if (status) - return status; - return 0; -} + if (tc[i].exp_ret == ret) { -static int test_membarrier_query(void) -{ - int flags = 0, ret; + if (tc[i].exp_errno == err) + failed_ok(tc[i]); + else + failed_unexpec(tc[i], ret, err); + } - ret = sys_membarrier(MEMBARRIER_CMD_QUERY, flags); - if (ret < 0) { - if (errno == ENOSYS) { - /* - * It is valid to build a kernel with - * CONFIG_MEMBARRIER=n. However, this skips the tests. - */ - ksft_exit_skip( - "sys membarrier (CONFIG_MEMBARRIER) is disabled.\n"); + /* unknown on force failure if enabled and forced */ + failed_unexpec(tc[i], ret, err); } - ksft_exit_fail_msg("sys_membarrier() failed\n"); } - if (!(ret & MEMBARRIER_CMD_GLOBAL)) - ksft_exit_skip( - "sys_membarrier unsupported: CMD_GLOBAL not found.\n"); - - ksft_test_result_pass("sys_membarrier available\n"); - return 0; } int main(int argc, char **argv) { + size_t i; + ksft_print_header(); - test_membarrier_query(); - test_membarrier(); + test_membarrier_setup(); + + for (i = 0; i < ARRAY_SIZE(tc); i++) + test_membarrier_run(i); return ksft_exit_pass(); } -- 2.19.1