| @@ -13,6 +13,8 @@ · 12 unmodified lines |
| 13 | * Author: Marco Elver <elver@google.com> | 13 | * Author: Marco Elver <elver@google.com> |
| 14 | */ | 14 | */ |
| 15 | | 15 | |
| | 16 | #define pr_fmt(fmt) "kcsan_test: " fmt |
| | 17 | |
| 16 | #include <kunit/test.h> | 18 | #include <kunit/test.h> |
| 17 | #include <linux/jiffies.h> | 19 | #include <linux/jiffies.h> |
| 18 | #include <linux/kcsan-checks.h> | 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 | 956 | * Generate thread counts for all test cases. Values generated are in interval |
| 955 | * passing arguments for each test case, we encode #threads in the test case | 957 | * [2, 5] followed by exponentially increasing thread counts from 8 to 32. |
| 956 | * name (read by get_num_threads()). [The '-' was chosen as a stylistic | | |
| 957 | * preference to separate test name and #threads.] | | |
| 958 | * | 958 | * |
| 959 | * The thread counts are chosen to cover potentially interesting boundaries and | 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) \ | 962 | static const void *nthreads_gen_params(const void *prev, char *desc) |
| 963 | { .run_case = test_name, .name = #test_name "-02" }, \ | 963 | { |
| 964 | { .run_case = test_name, .name = #test_name "-03" }, \ | 964 | long nthreads = (long)prev; |
| 965 | { .run_case = test_name, .name = #test_name "-04" }, \ | 965 | |
| 966 | { .run_case = test_name, .name = #test_name "-05" }, \ | 966 | if (nthreads < 0 || nthreads >= 32) |
| 967 | { .run_case = test_name, .name = #test_name "-08" }, \ | 967 | nthreads = 0; /* stop */ |
| 968 | { .run_case = test_name, .name = #test_name "-16" } | 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 | static struct kunit_case kcsan_test_cases[] = { | 1003 | static struct kunit_case kcsan_test_cases[] = { |
| 971 | KCSAN_KUNIT_CASE(test_basic), | 1004 | KCSAN_KUNIT_CASE(test_basic), |
| 972 | KCSAN_KUNIT_CASE(test_concurrent_races), | 1005 | KCSAN_KUNIT_CASE(test_concurrent_races), |
| @@ -996,24 +1029,6 @@ static struct kunit_case kcsan_test_cases[] = { · 23 unmodified lines |
| 996 | | 1029 | |
| 997 | /* ===== End test cases ===== */ | 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 | /* Concurrent accesses from interrupts. */ | 1032 | /* Concurrent accesses from interrupts. */ |
| 1018 | __no_kcsan | 1033 | __no_kcsan |
| 1019 | static void access_thread_timer(struct timer_list *timer) | 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 | if (!torture_init_begin((char *)test->name, 1)) | 1091 | if (!torture_init_begin((char *)test->name, 1)) |
| 1077 | return -EBUSY; | 1092 | return -EBUSY; |
| 1078 | | 1093 | |
| 1079 | if (!get_num_threads(test->name, &nthreads)) | | |
| 1080 | goto err; | | |
| 1081 | | | |
| 1082 | if (WARN_ON(threads)) | 1094 | if (WARN_ON(threads)) |
| 1083 | goto err; | 1095 | goto err; |
| 1084 | | 1096 | |
| @@ -1087,38 +1099,18 @@ static int test_init(struct kunit *test) · 2 unmodified lines |
| 1087 | goto err; | 1099 | goto err; |
| 1088 | } | 1100 | } |
| 1089 | | 1101 | |
| 1090 | if (!IS_ENABLED(CONFIG_PREEMPT) || !IS_ENABLED(CONFIG_KCSAN_INTERRUPT_WATCHER)) { | 1102 | nthreads = abs((long)test->param_value); |
| 1091 | /* | 1103 | if (WARN_ON(!nthreads)) |
| 1092 | * Without any preemption, keep 2 CPUs free for other tasks, one | 1104 | goto err; |
| 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; | | |
| 1098 | | 1105 | |
| 1099 | if (num_online_cpus() < min_required_cpus) { | 1106 | threads = kcalloc(nthreads + 1, sizeof(struct task_struct *), GFP_KERNEL); |
| 1100 | pr_err("%s: too few online CPUs (%u < %d) for test", | 1107 | if (WARN_ON(!threads)) |
| 1101 | test->name, num_online_cpus(), min_required_cpus); | 1108 | goto err; |
| 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 | } | | |
| 1109 | | 1109 | |
| 1110 | if (nthreads) { | 1110 | threads[nthreads] = NULL; |
| 1111 | threads = kcalloc(nthreads + 1, sizeof(struct task_struct *), | 1111 | for (i = 0; i < nthreads; ++i) { |
| 1112 | GFP_KERNEL); | 1112 | if (torture_create_kthread(access_thread, NULL, threads[i])) |
| 1113 | if (WARN_ON(!threads)) | | |
| 1114 | goto err; | 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 | torture_init_end(); | 1116 | torture_init_end(); |
| @@ -1156,7 +1148,7 @@ static void test_exit(struct kunit *test) · 31 unmodified lines |
| 1156 | } | 1148 | } |
| 1157 | | 1149 | |
| 1158 | static struct kunit_suite kcsan_test_suite = { | 1150 | static struct kunit_suite kcsan_test_suite = { |
| 1159 | .name = "kcsan-test", | 1151 | .name = "kcsan", |
| 1160 | .test_cases = kcsan_test_cases, | 1152 | .test_cases = kcsan_test_cases, |
| 1161 | .init = test_init, | 1153 | .init = test_init, |
| 1162 | .exit = test_exit, | 1154 | .exit = test_exit, |