| @@ -13,6 +13,8 @@ · 12 unmodified lines |
| 13 | 13 | * Author: Marco Elver <elver@google.com> |
| 14 | 14 | */ |
| 15 | 15 | |
| 16 | +#define pr_fmt(fmt) "kcsan_test: " fmt |
| 17 | + |
| 16 | 18 | #include <kunit/test.h> |
| 17 | 19 | #include <linux/jiffies.h> |
| 18 | 20 | #include <linux/kcsan-checks.h> |
| @@ -951,22 +953,53 @@ static void test_atomic_builtins(struct kunit *test) · 932 unmodified lines |
| 951 | 953 | } |
| 952 | 954 | |
| 953 | 955 | /* |
| 954 | | − * Each test case is run with different numbers of threads. Until KUnit supports |
| 955 | | − * passing arguments for each test case, we encode #threads in the test case |
| 956 | | − * name (read by get_num_threads()). [The '-' was chosen as a stylistic |
| 957 | | − * preference to separate test name and #threads.] |
| 956 | + * Generate thread counts for all test cases. Values generated are in interval |
| 957 | + * [2, 5] followed by exponentially increasing thread counts from 8 to 32. |
| 958 | 958 | * |
| 959 | 959 | * The thread counts are chosen to cover potentially interesting boundaries and |
| 960 | | − * corner cases (range 2-5), and then stress the system with larger counts. |
| 960 | + * corner cases (2 to 5), and then stress the system with larger counts. |
| 961 | 961 | */ |
| 962 | | −#define KCSAN_KUNIT_CASE(test_name) \ |
| 963 | | − { .run_case = test_name, .name = #test_name "-02" }, \ |
| 964 | | − { .run_case = test_name, .name = #test_name "-03" }, \ |
| 965 | | − { .run_case = test_name, .name = #test_name "-04" }, \ |
| 966 | | − { .run_case = test_name, .name = #test_name "-05" }, \ |
| 967 | | − { .run_case = test_name, .name = #test_name "-08" }, \ |
| 968 | | − { .run_case = test_name, .name = #test_name "-16" } |
| 962 | +static const void *nthreads_gen_params(const void *prev, char *desc) |
| 963 | +{ |
| 964 | + long nthreads = (long)prev; |
| 965 | + |
| 966 | + if (nthreads < 0 || nthreads >= 32) |
| 967 | + nthreads = 0; /* stop */ |
| 968 | + else if (!nthreads) |
| 969 | + nthreads = 2; /* initial value */ |
| 970 | + else if (nthreads < 5) |
| 971 | + nthreads++; |
| 972 | + else if (nthreads == 5) |
| 973 | + nthreads = 8; |
| 974 | + else |
| 975 | + nthreads *= 2; |
| 969 | 976 | |
| 977 | + if (!IS_ENABLED(CONFIG_PREEMPT) || !IS_ENABLED(CONFIG_KCSAN_INTERRUPT_WATCHER)) { |
| 978 | + /* |
| 979 | + * Without any preemption, keep 2 CPUs free for other tasks, one |
| 980 | + * of which is the main test case function checking for |
| 981 | + * completion or failure. |
| 982 | + */ |
| 983 | + const long min_unused_cpus = IS_ENABLED(CONFIG_PREEMPT_NONE) ? 2 : 0; |
| 984 | + const long min_required_cpus = 2 + min_unused_cpus; |
| 985 | + |
| 986 | + if (num_online_cpus() < min_required_cpus) { |
| 987 | + pr_err_once("Too few online CPUs (%u < %d) for test\n", |
| 988 | + num_online_cpus(), min_required_cpus); |
| 989 | + nthreads = 0; |
| 990 | + } else if (nthreads >= num_online_cpus() - min_unused_cpus) { |
| 991 | + /* Use negative value to indicate last param. */ |
| 992 | + nthreads = -(num_online_cpus() - min_unused_cpus); |
| 993 | + pr_warn_once("Limiting number of threads to %ld (only %d online CPUs)\n", |
| 994 | + -nthreads, num_online_cpus()); |
| 995 | + } |
| 996 | + } |
| 997 | + |
| 998 | + snprintf(desc, KUNIT_PARAM_DESC_SIZE, "threads=%ld", abs(nthreads)); |
| 999 | + return (void *)nthreads; |
| 1000 | +} |
| 1001 | + |
| 1002 | +#define KCSAN_KUNIT_CASE(test_name) KUNIT_CASE_PARAM(test_name, nthreads_gen_params) |
| 970 | 1003 | static struct kunit_case kcsan_test_cases[] = { |
| 971 | 1004 | KCSAN_KUNIT_CASE(test_basic), |
| 972 | 1005 | KCSAN_KUNIT_CASE(test_concurrent_races), |
| @@ -996,24 +1029,6 @@ static struct kunit_case kcsan_test_cases[] = { · 23 unmodified lines |
| 996 | 1029 | |
| 997 | 1030 | /* ===== End test cases ===== */ |
| 998 | 1031 | |
| 999 | | −/* Get number of threads encoded in test name. */ |
| 1000 | | −static bool __no_kcsan |
| 1001 | | −get_num_threads(const char *test, int *nthreads) |
| 1002 | | −{ |
| 1003 | | − int len = strlen(test); |
| 1004 | | − |
| 1005 | | − if (WARN_ON(len < 3)) |
| 1006 | | − return false; |
| 1007 | | − |
| 1008 | | − *nthreads = test[len - 1] - '0'; |
| 1009 | | − *nthreads += (test[len - 2] - '0') * 10; |
| 1010 | | − |
| 1011 | | − if (WARN_ON(*nthreads < 0)) |
| 1012 | | − return false; |
| 1013 | | − |
| 1014 | | − return true; |
| 1015 | | −} |
| 1016 | | − |
| 1017 | 1032 | /* Concurrent accesses from interrupts. */ |
| 1018 | 1033 | __no_kcsan |
| 1019 | 1034 | static void access_thread_timer(struct timer_list *timer) |
| @@ -1076,9 +1091,6 @@ static int test_init(struct kunit *test) · 56 unmodified lines |
| 1076 | 1091 | if (!torture_init_begin((char *)test->name, 1)) |
| 1077 | 1092 | return -EBUSY; |
| 1078 | 1093 | |
| 1079 | | − if (!get_num_threads(test->name, &nthreads)) |
| 1080 | | − goto err; |
| 1081 | | − |
| 1082 | 1094 | if (WARN_ON(threads)) |
| 1083 | 1095 | goto err; |
| 1084 | 1096 | |
| @@ -1087,38 +1099,18 @@ static int test_init(struct kunit *test) · 2 unmodified lines |
| 1087 | 1099 | goto err; |
| 1088 | 1100 | } |
| 1089 | 1101 | |
| 1090 | | − if (!IS_ENABLED(CONFIG_PREEMPT) || !IS_ENABLED(CONFIG_KCSAN_INTERRUPT_WATCHER)) { |
| 1091 | | − /* |
| 1092 | | − * Without any preemption, keep 2 CPUs free for other tasks, one |
| 1093 | | − * of which is the main test case function checking for |
| 1094 | | − * completion or failure. |
| 1095 | | − */ |
| 1096 | | − const int min_unused_cpus = IS_ENABLED(CONFIG_PREEMPT_NONE) ? 2 : 0; |
| 1097 | | − const int min_required_cpus = 2 + min_unused_cpus; |
| 1102 | + nthreads = abs((long)test->param_value); |
| 1103 | + if (WARN_ON(!nthreads)) |
| 1104 | + goto err; |
| 1098 | 1105 | |
| 1099 | | − if (num_online_cpus() < min_required_cpus) { |
| 1100 | | − pr_err("%s: too few online CPUs (%u < %d) for test", |
| 1101 | | − test->name, num_online_cpus(), min_required_cpus); |
| 1102 | | − goto err; |
| 1103 | | − } else if (nthreads > num_online_cpus() - min_unused_cpus) { |
| 1104 | | − nthreads = num_online_cpus() - min_unused_cpus; |
| 1105 | | − pr_warn("%s: limiting number of threads to %d\n", |
| 1106 | | − test->name, nthreads); |
| 1107 | | − } |
| 1108 | | − } |
| 1106 | + threads = kcalloc(nthreads + 1, sizeof(struct task_struct *), GFP_KERNEL); |
| 1107 | + if (WARN_ON(!threads)) |
| 1108 | + goto err; |
| 1109 | 1109 | |
| 1110 | | − if (nthreads) { |
| 1111 | | − threads = kcalloc(nthreads + 1, sizeof(struct task_struct *), |
| 1112 | | − GFP_KERNEL); |
| 1113 | | − if (WARN_ON(!threads)) |
| 1110 | + threads[nthreads] = NULL; |
| 1111 | + for (i = 0; i < nthreads; ++i) { |
| 1112 | + if (torture_create_kthread(access_thread, NULL, threads[i])) |
| 1114 | 1113 | goto err; |
| 1115 | | − |
| 1116 | | − threads[nthreads] = NULL; |
| 1117 | | − for (i = 0; i < nthreads; ++i) { |
| 1118 | | − if (torture_create_kthread(access_thread, NULL, |
| 1119 | | − threads[i])) |
| 1120 | | − goto err; |
| 1121 | | − } |
| 1122 | 1114 | } |
| 1123 | 1115 | |
| 1124 | 1116 | torture_init_end(); |
| @@ -1156,7 +1148,7 @@ static void test_exit(struct kunit *test) · 31 unmodified lines |
| 1156 | 1148 | } |
| 1157 | 1149 | |
| 1158 | 1150 | static struct kunit_suite kcsan_test_suite = { |
| 1159 | | − .name = "kcsan-test", |
| 1151 | + .name = "kcsan", |
| 1160 | 1152 | .test_cases = kcsan_test_cases, |
| 1161 | 1153 | .init = test_init, |
| 1162 | 1154 | .exit = test_exit, |