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). - able to consider different return codes for diff kernel versions. - checks false positive/negative by checking ret code and errno. - can be extended easily: to expand an array with commands. Link: https://bugs.linaro.org/show_bug.cgi?id=3771 Signed-off-by: Rafael David Tinoco <[email protected]> --- .../selftests/membarrier/membarrier_test.c | 482 +++++++++--------- 1 file changed, 241 insertions(+), 241 deletions(-) diff --git a/tools/testing/selftests/membarrier/membarrier_test.c b/tools/testing/selftests/membarrier/membarrier_test.c index 6793f8ecc8e7..151bc8a944a3 100644 --- a/tools/testing/selftests/membarrier/membarrier_test.c +++ b/tools/testing/selftests/membarrier/membarrier_test.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 #define _GNU_SOURCE #include <linux/membarrier.h> +#include <sys/utsname.h> #include <syscall.h> #include <stdio.h> #include <errno.h> @@ -8,305 +9,304 @@ #include "../kselftest.h" -static int sys_membarrier(int cmd, int flags) +#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) +#define KERNEL_VERSION(a, b, c) (((a) << 16) + ((b) << 8) + (c)) + +struct memb_tests { + char testname[80]; + int command; + int flags; + int exp_ret; + int exp_errno; + int enabled; + int force; + int force_exp_errno; + int above; + int bellow; +}; + +struct memb_tests mbt[] = { + { + .testname = "cmd_fail\0", + .command = -1, + .exp_ret = -1, + .exp_errno = EINVAL, + .enabled = 1, + }, + { + .testname = "cmd_flags_fail\0", + .command = MEMBARRIER_CMD_QUERY, + .flags = 1, + .exp_ret = -1, + .exp_errno = EINVAL, + .enabled = 1, + }, + { + .testname = "cmd_global_success\0", + .command = MEMBARRIER_CMD_GLOBAL, + .flags = 0, + .exp_ret = 0, + }, + /* + * PRIVATE EXPEDITED (forced) + */ + { + .testname = "cmd_private_expedited_fail\0", + .command = MEMBARRIER_CMD_PRIVATE_EXPEDITED, + .flags = 0, + .exp_ret = -1, + .exp_errno = EPERM, + .force = 1, + .force_exp_errno = EINVAL, + .bellow = KERNEL_VERSION(4, 10, 0), + }, + { + .testname = "cmd_private_expedited_fail\0", + .command = MEMBARRIER_CMD_PRIVATE_EXPEDITED, + .flags = 0, + .exp_ret = -1, + .exp_errno = EPERM, + .force = 1, + .force_exp_errno = EPERM, + .above = KERNEL_VERSION(4, 10, 0), + }, + { + .testname = "cmd_register_private_expedited_success\0", + .command = MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED, + .flags = 0, + .exp_ret = 0, + .force = 1, + .force_exp_errno = EINVAL, + }, + { + .testname = "cmd_private_expedited_success\0", + .command = MEMBARRIER_CMD_PRIVATE_EXPEDITED, + .flags = 0, + .exp_ret = 0, + .force = 1, + .force_exp_errno = EINVAL, + }, + /* + * PRIVATE EXPEDITED SYNC CORE + */ + { + .testname = "cmd_private_expedited_sync_core_fail\0", + .command = MEMBARRIER_CMD_PRIVATE_EXPEDITED_SYNC_CORE, + .flags = 0, + .exp_ret = -1, + .exp_errno = EPERM, + }, + { + .testname = "cmd_register_private_expedited_sync_core_success\0", + .command = MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_SYNC_CORE, + .flags = 0, + .exp_ret = 0, + }, + { + .testname = "cmd_private_expedited_sync_core_success\0", + .command = MEMBARRIER_CMD_PRIVATE_EXPEDITED, + .flags = 0, + .exp_ret = 0, + }, + /* + * GLOBAL EXPEDITED + * global membarrier from a non-registered process is valid + */ + { + .testname = "cmd_global_expedited_success\0", + .command = MEMBARRIER_CMD_GLOBAL_EXPEDITED, + .flags = 0, + .exp_ret = 0, + }, + { + .testname = "cmd_register_global_expedited_success\0", + .command = MEMBARRIER_CMD_REGISTER_GLOBAL_EXPEDITED, + .flags = 0, + .exp_ret = 0, + }, + { + .testname = "cmd_global_expedited_success\0", + .command = MEMBARRIER_CMD_GLOBAL_EXPEDITED, + .flags = 0, + .exp_ret = 0, + }, +}; + +static void +info_passed_ok(struct memb_tests test) { - return syscall(__NR_membarrier, cmd, flags); + ksft_test_result_pass("sys_membarrier(): %s succeeded.\n", + test.testname); } -static int test_membarrier_cmd_fail(void) +static void +info_passed_unexpectedly(struct memb_tests test) { - int cmd = -1, flags = 0; - const char *test_name = "sys membarrier invalid command"; - - 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)); - } - - ksft_test_result_pass( - "%s test: command = %d, flags = %d, errno = %d. Failed as expected\n", - test_name, cmd, flags, errno); - return 0; + ksft_test_result_fail("sys_membarrier(): %s passed unexpectedly. " + "ret = %d with errno %d were expected. (force: %d)\n", + test.testname, test.exp_ret, test.exp_errno, + test.force); } -static int test_membarrier_flags_fail(void) +static void +info_failed_ok(struct memb_tests test) { - 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); - } - 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; + ksft_test_result_pass("sys_membarrier(): %s failed as expected.\n", + test.testname); } -static int test_membarrier_global_success(void) +static void +info_failed_not_ok(struct memb_tests test, int gotret, int goterr) { - int cmd = MEMBARRIER_CMD_GLOBAL, flags = 0; - const char *test_name = "sys membarrier MEMBARRIER_CMD_GLOBAL"; - - if (sys_membarrier(cmd, flags) != 0) { - ksft_exit_fail_msg( - "%s test: flags = %d, errno = %d\n", - test_name, flags, errno); - } - - ksft_test_result_pass( - "%s test: flags = %d\n", test_name, flags); - return 0; + ksft_test_result_fail("sys_membarrier(): %s failed as expected. " + "ret = %d when expected was %d. " + "errno = %d when expected was %d. (force: %d)\n", + test.testname, gotret, test.exp_ret, goterr, + test.exp_errno, test.force); } -static int test_membarrier_private_expedited_fail(void) +static void +info_failed_unexpectedly(struct memb_tests test, int gotret, int goterr) { - int cmd = MEMBARRIER_CMD_PRIVATE_EXPEDITED, flags = 0; - const char *test_name = "sys membarrier MEMBARRIER_CMD_PRIVATE_EXPEDITED 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; + ksft_test_result_fail("sys_membarrier(): %s failed unexpectedly. " + "Got ret = %d with errno %d. (force: %d)\n", + test.testname, gotret, goterr, test.force); } -static int test_membarrier_register_private_expedited_success(void) +static void +info_skipped(struct memb_tests test) { - 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); - } - - ksft_test_result_pass( - "%s test: flags = %d\n", - test_name, flags); - return 0; + ksft_test_result_skip("sys_membarrier(): %s unsupported, " + "test skipped.\n", test.testname); } -static int test_membarrier_private_expedited_success(void) +static int test_get_kversion(void) { - int cmd = MEMBARRIER_CMD_PRIVATE_EXPEDITED, flags = 0; - const char *test_name = "sys membarrier MEMBARRIER_CMD_PRIVATE_EXPEDITED"; + char *temp; + int major, minor, rev; + struct utsname uts; - if (sys_membarrier(cmd, flags) != 0) { - ksft_exit_fail_msg( - "%s test: flags = %d, errno = %d\n", - test_name, flags, errno); - } + memset(&uts, 0, sizeof(struct utsname)); + if (uname(&uts) < 0) + ksft_exit_fail_msg("sys_membarrier(): uname() failed\n"); - ksft_test_result_pass( - "%s test: flags = %d\n", - test_name, flags); - return 0; -} + temp = strtok((char *) &uts.release, "."); + if (temp == NULL) + ksft_exit_fail_msg("sys_membarrier(): kver parsing failed\n"); -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"; + major = atoi(temp); - 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)); - } + temp = strtok(NULL, "."); + if (temp == NULL) + ksft_exit_fail_msg("sys_membarrier(): kver parsing failed\n"); - ksft_test_result_pass( - "%s test: flags = %d, errno = %d\n", - test_name, flags, errno); - return 0; -} + minor = atoi(temp); -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"; + temp = strtok(NULL, "."); + if (temp == NULL) + ksft_exit_fail_msg("sys_membarrier(): kver parsing failed\n"); - if (sys_membarrier(cmd, flags) != 0) { - ksft_exit_fail_msg( - "%s test: flags = %d, errno = %d\n", - test_name, flags, errno); - } + rev = atoi(temp); - ksft_test_result_pass( - "%s test: flags = %d\n", - test_name, flags); - return 0; + return KERNEL_VERSION(major, minor, rev); } -static int test_membarrier_private_expedited_sync_core_success(void) +static int sys_membarrier(int cmd, int flags) { - int cmd = MEMBARRIER_CMD_PRIVATE_EXPEDITED, flags = 0; - const char *test_name = "sys membarrier MEMBARRIER_CMD_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); - } - - ksft_test_result_pass( - "%s test: flags = %d\n", - test_name, flags); - return 0; + return syscall(__NR_membarrier, cmd, flags); } -static int test_membarrier_register_global_expedited_success(void) +static void test_membarrier_tests(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); - } + int i, ret; + int kver = test_get_kversion(); - ksft_test_result_pass( - "%s test: flags = %d\n", - test_name, flags); - return 0; -} + for (i = 0; i < ARRAY_SIZE(mbt); i++) { -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 (mbt[i].bellow && kver > mbt[i].bellow) + continue; - if (sys_membarrier(cmd, flags) != 0) { - ksft_exit_fail_msg( - "%s test: flags = %d, errno = %d\n", - test_name, flags, errno); - } + if (mbt[i].above && kver < mbt[i].above) + continue; - ksft_test_result_pass( - "%s test: flags = %d\n", - test_name, flags); - return 0; -} + if (mbt[i].enabled != 1 && mbt[i].force != 1) { + info_skipped(mbt[i]); + continue; + } -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; + /* membarrier command should be evaluated */ + ret = sys_membarrier(mbt[i].command, mbt[i].flags); + + if (ret == mbt[i].exp_ret) { + + if (ret >= 0) + info_passed_ok(mbt[i]); + else { + if (mbt[i].enabled == 1 && mbt[i].force != 1) { + if (errno != mbt[i].exp_errno) { + info_failed_not_ok(mbt[i], ret, + errno); + } else + info_failed_ok(mbt[i]); + } else { + if (errno != mbt[i].force_exp_errno) { + info_failed_not_ok(mbt[i], ret, + errno); + } else + info_failed_ok(mbt[i]); + } + } + + } else { + if (mbt[i].enabled == 1 && mbt[i].force != 1) { + if (ret >= 0) + info_passed_unexpectedly(mbt[i]); + else { + info_failed_unexpectedly(mbt[i], ret, + errno); + } + } else { + if (errno == mbt[i].force_exp_errno) + info_failed_ok(mbt[i]); + else + info_failed_not_ok(mbt[i], ret, errno); + } + } } - /* - * 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; } -static int test_membarrier_query(void) +static int test_membarrier_prepare(void) { - int flags = 0, ret; + int i, ret; - ret = sys_membarrier(MEMBARRIER_CMD_QUERY, flags); + ret = sys_membarrier(MEMBARRIER_CMD_QUERY, 0); 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"); + ksft_exit_skip("sys_membarrier(): CONFIG_MEMBARRIER " + "is disabled.\n"); } - ksft_exit_fail_msg("sys_membarrier() failed\n"); + + ksft_exit_fail_msg("sys_membarrier(): cmd_query failed.\n"); + } + + for (i = 0; i < ARRAY_SIZE(mbt); i++) { + if ((mbt[i].command > 0) && (ret & mbt[i].command)) + mbt[i].enabled = 1; } - 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; + ksft_test_result_pass("sys_membarrier(): cmd_query succeeded.\n"); } int main(int argc, char **argv) { ksft_print_header(); - test_membarrier_query(); - test_membarrier(); + test_membarrier_prepare(); + test_membarrier_tests(); return ksft_exit_pass(); } -- 2.19.0.rc1

