1 // SPDX-License-Identifier: GPL-2.0 2 3 #include <linux/reboot.h> 4 #include <kunit/test.h> 5 #include <linux/glob.h> 6 #include <linux/moduleparam.h> 7 8 /* 9 * These symbols point to the .kunit_test_suites section and are defined in 10 * include/asm-generic/vmlinux.lds.h, and consequently must be extern. 11 */ 12 extern struct kunit_suite * const * const __kunit_suites_start[]; 13 extern struct kunit_suite * const * const __kunit_suites_end[]; 14 15 #if IS_BUILTIN(CONFIG_KUNIT) 16 17 static char *filter_glob_param; 18 static char *action_param; 19 20 module_param_named(filter_glob, filter_glob_param, charp, 0); 21 MODULE_PARM_DESC(filter_glob, 22 "Filter which KUnit test suites/tests run at boot-time, e.g. list* or list*.*del_test"); 23 module_param_named(action, action_param, charp, 0); 24 MODULE_PARM_DESC(action, 25 "Changes KUnit executor behavior, valid values are:\n" 26 "<none>: run the tests like normal\n" 27 "'list' to list test names instead of running them.\n"); 28 29 /* glob_match() needs NULL terminated strings, so we need a copy of filter_glob_param. */ 30 struct kunit_test_filter { 31 char *suite_glob; 32 char *test_glob; 33 }; 34 35 /* Split "suite_glob.test_glob" into two. Assumes filter_glob is not empty. */ 36 static void kunit_parse_filter_glob(struct kunit_test_filter *parsed, 37 const char *filter_glob) 38 { 39 const int len = strlen(filter_glob); 40 const char *period = strchr(filter_glob, '.'); 41 42 if (!period) { 43 parsed->suite_glob = kzalloc(len + 1, GFP_KERNEL); 44 parsed->test_glob = NULL; 45 strcpy(parsed->suite_glob, filter_glob); 46 return; 47 } 48 49 parsed->suite_glob = kzalloc(period - filter_glob + 1, GFP_KERNEL); 50 parsed->test_glob = kzalloc(len - (period - filter_glob) + 1, GFP_KERNEL); 51 52 strncpy(parsed->suite_glob, filter_glob, period - filter_glob); 53 strncpy(parsed->test_glob, period + 1, len - (period - filter_glob)); 54 } 55 56 /* Create a copy of suite with only tests that match test_glob. */ 57 static struct kunit_suite * 58 kunit_filter_tests(const struct kunit_suite *const suite, const char *test_glob) 59 { 60 int n = 0; 61 struct kunit_case *filtered, *test_case; 62 struct kunit_suite *copy; 63 64 kunit_suite_for_each_test_case(suite, test_case) { 65 if (!test_glob || glob_match(test_glob, test_case->name)) 66 ++n; 67 } 68 69 if (n == 0) 70 return NULL; 71 72 copy = kmemdup(suite, sizeof(*copy), GFP_KERNEL); 73 if (!copy) 74 return ERR_PTR(-ENOMEM); 75 76 filtered = kcalloc(n + 1, sizeof(*filtered), GFP_KERNEL); 77 if (!filtered) 78 return ERR_PTR(-ENOMEM); 79 80 n = 0; 81 kunit_suite_for_each_test_case(suite, test_case) { 82 if (!test_glob || glob_match(test_glob, test_case->name)) 83 filtered[n++] = *test_case; 84 } 85 86 copy->test_cases = filtered; 87 return copy; 88 } 89 90 static char *kunit_shutdown; 91 core_param(kunit_shutdown, kunit_shutdown, charp, 0644); 92 93 static struct kunit_suite * const * 94 kunit_filter_subsuite(struct kunit_suite * const * const subsuite, 95 struct kunit_test_filter *filter) 96 { 97 int i, n = 0; 98 struct kunit_suite **filtered, *filtered_suite; 99 100 n = 0; 101 for (i = 0; subsuite[i]; ++i) { 102 if (glob_match(filter->suite_glob, subsuite[i]->name)) 103 ++n; 104 } 105 106 if (n == 0) 107 return NULL; 108 109 filtered = kmalloc_array(n + 1, sizeof(*filtered), GFP_KERNEL); 110 if (!filtered) 111 return ERR_PTR(-ENOMEM); 112 113 n = 0; 114 for (i = 0; subsuite[i] != NULL; ++i) { 115 if (!glob_match(filter->suite_glob, subsuite[i]->name)) 116 continue; 117 filtered_suite = kunit_filter_tests(subsuite[i], filter->test_glob); 118 if (IS_ERR(filtered_suite)) 119 return ERR_CAST(filtered_suite); 120 else if (filtered_suite) 121 filtered[n++] = filtered_suite; 122 } 123 filtered[n] = NULL; 124 125 return filtered; 126 } 127 128 struct suite_set { 129 struct kunit_suite * const * const *start; 130 struct kunit_suite * const * const *end; 131 }; 132 133 static void kunit_free_subsuite(struct kunit_suite * const *subsuite) 134 { 135 unsigned int i; 136 137 for (i = 0; subsuite[i]; i++) 138 kfree(subsuite[i]); 139 140 kfree(subsuite); 141 } 142 143 static void kunit_free_suite_set(struct suite_set suite_set) 144 { 145 struct kunit_suite * const * const *suites; 146 147 for (suites = suite_set.start; suites < suite_set.end; suites++) 148 kunit_free_subsuite(*suites); 149 kfree(suite_set.start); 150 } 151 152 static struct suite_set kunit_filter_suites(const struct suite_set *suite_set, 153 const char *filter_glob, 154 int *err) 155 { 156 int i; 157 struct kunit_suite * const **copy, * const *filtered_subsuite; 158 struct suite_set filtered; 159 struct kunit_test_filter filter; 160 161 const size_t max = suite_set->end - suite_set->start; 162 163 copy = kmalloc_array(max, sizeof(*filtered.start), GFP_KERNEL); 164 filtered.start = copy; 165 if (!copy) { /* won't be able to run anything, return an empty set */ 166 filtered.end = copy; 167 return filtered; 168 } 169 170 kunit_parse_filter_glob(&filter, filter_glob); 171 172 for (i = 0; i < max; ++i) { 173 filtered_subsuite = kunit_filter_subsuite(suite_set->start[i], &filter); 174 if (IS_ERR(filtered_subsuite)) { 175 *err = PTR_ERR(filtered_subsuite); 176 return filtered; 177 } 178 if (filtered_subsuite) 179 *copy++ = filtered_subsuite; 180 } 181 filtered.end = copy; 182 183 kfree(filter.suite_glob); 184 kfree(filter.test_glob); 185 return filtered; 186 } 187 188 static void kunit_handle_shutdown(void) 189 { 190 if (!kunit_shutdown) 191 return; 192 193 if (!strcmp(kunit_shutdown, "poweroff")) 194 kernel_power_off(); 195 else if (!strcmp(kunit_shutdown, "halt")) 196 kernel_halt(); 197 else if (!strcmp(kunit_shutdown, "reboot")) 198 kernel_restart(NULL); 199 200 } 201 202 static void kunit_print_tap_header(struct suite_set *suite_set) 203 { 204 struct kunit_suite * const * const *suites, * const *subsuite; 205 int num_of_suites = 0; 206 207 for (suites = suite_set->start; suites < suite_set->end; suites++) 208 for (subsuite = *suites; *subsuite != NULL; subsuite++) 209 num_of_suites++; 210 211 pr_info("TAP version 14\n"); 212 pr_info("1..%d\n", num_of_suites); 213 } 214 215 static void kunit_exec_run_tests(struct suite_set *suite_set) 216 { 217 struct kunit_suite * const * const *suites; 218 219 kunit_print_tap_header(suite_set); 220 221 for (suites = suite_set->start; suites < suite_set->end; suites++) 222 __kunit_test_suites_init(*suites); 223 } 224 225 static void kunit_exec_list_tests(struct suite_set *suite_set) 226 { 227 unsigned int i; 228 struct kunit_suite * const * const *suites; 229 struct kunit_case *test_case; 230 231 /* Hack: print a tap header so kunit.py can find the start of KUnit output. */ 232 pr_info("TAP version 14\n"); 233 234 for (suites = suite_set->start; suites < suite_set->end; suites++) 235 for (i = 0; (*suites)[i] != NULL; i++) { 236 kunit_suite_for_each_test_case((*suites)[i], test_case) { 237 pr_info("%s.%s\n", (*suites)[i]->name, test_case->name); 238 } 239 } 240 } 241 242 int kunit_run_all_tests(void) 243 { 244 struct suite_set suite_set = { 245 .start = __kunit_suites_start, 246 .end = __kunit_suites_end, 247 }; 248 int err = 0; 249 250 if (filter_glob_param) { 251 suite_set = kunit_filter_suites(&suite_set, filter_glob_param, &err); 252 if (err) { 253 pr_err("kunit executor: error filtering suites: %d\n", err); 254 goto out; 255 } 256 } 257 258 if (!action_param) 259 kunit_exec_run_tests(&suite_set); 260 else if (strcmp(action_param, "list") == 0) 261 kunit_exec_list_tests(&suite_set); 262 else 263 pr_err("kunit executor: unknown action '%s'\n", action_param); 264 265 if (filter_glob_param) { /* a copy was made of each array */ 266 kunit_free_suite_set(suite_set); 267 } 268 269 270 out: 271 kunit_handle_shutdown(); 272 return err; 273 } 274 275 #if IS_BUILTIN(CONFIG_KUNIT_TEST) 276 #include "executor_test.c" 277 #endif 278 279 #endif /* IS_BUILTIN(CONFIG_KUNIT) */ 280