1 // SPDX-License-Identifier: GPL-2.0 2 3 #include <kunit/test.h> 4 #include <linux/glob.h> 5 #include <linux/moduleparam.h> 6 7 /* 8 * These symbols point to the .kunit_test_suites section and are defined in 9 * include/asm-generic/vmlinux.lds.h, and consequently must be extern. 10 */ 11 extern struct kunit_suite * const * const __kunit_suites_start[]; 12 extern struct kunit_suite * const * const __kunit_suites_end[]; 13 14 #if IS_BUILTIN(CONFIG_KUNIT) 15 16 static char *filter_glob; 17 module_param(filter_glob, charp, 0); 18 MODULE_PARM_DESC(filter_glob, 19 "Filter which KUnit test suites run at boot-time, e.g. list*"); 20 21 static struct kunit_suite * const * 22 kunit_filter_subsuite(struct kunit_suite * const * const subsuite) 23 { 24 int i, n = 0; 25 struct kunit_suite **filtered; 26 27 n = 0; 28 for (i = 0; subsuite[i] != NULL; ++i) { 29 if (glob_match(filter_glob, subsuite[i]->name)) 30 ++n; 31 } 32 33 if (n == 0) 34 return NULL; 35 36 filtered = kmalloc_array(n + 1, sizeof(*filtered), GFP_KERNEL); 37 if (!filtered) 38 return NULL; 39 40 n = 0; 41 for (i = 0; subsuite[i] != NULL; ++i) { 42 if (glob_match(filter_glob, subsuite[i]->name)) 43 filtered[n++] = subsuite[i]; 44 } 45 filtered[n] = NULL; 46 47 return filtered; 48 } 49 50 struct suite_set { 51 struct kunit_suite * const * const *start; 52 struct kunit_suite * const * const *end; 53 }; 54 55 static struct suite_set kunit_filter_suites(void) 56 { 57 int i; 58 struct kunit_suite * const **copy, * const *filtered_subsuite; 59 struct suite_set filtered; 60 61 const size_t max = __kunit_suites_end - __kunit_suites_start; 62 63 if (!filter_glob) { 64 filtered.start = __kunit_suites_start; 65 filtered.end = __kunit_suites_end; 66 return filtered; 67 } 68 69 copy = kmalloc_array(max, sizeof(*filtered.start), GFP_KERNEL); 70 filtered.start = copy; 71 if (!copy) { /* won't be able to run anything, return an empty set */ 72 filtered.end = copy; 73 return filtered; 74 } 75 76 for (i = 0; i < max; ++i) { 77 filtered_subsuite = kunit_filter_subsuite(__kunit_suites_start[i]); 78 if (filtered_subsuite) 79 *copy++ = filtered_subsuite; 80 } 81 filtered.end = copy; 82 return filtered; 83 } 84 85 static void kunit_print_tap_header(struct suite_set *suite_set) 86 { 87 struct kunit_suite * const * const *suites, * const *subsuite; 88 int num_of_suites = 0; 89 90 for (suites = suite_set->start; suites < suite_set->end; suites++) 91 for (subsuite = *suites; *subsuite != NULL; subsuite++) 92 num_of_suites++; 93 94 pr_info("TAP version 14\n"); 95 pr_info("1..%d\n", num_of_suites); 96 } 97 98 int kunit_run_all_tests(void) 99 { 100 struct kunit_suite * const * const *suites; 101 102 struct suite_set suite_set = kunit_filter_suites(); 103 104 kunit_print_tap_header(&suite_set); 105 106 for (suites = suite_set.start; suites < suite_set.end; suites++) 107 __kunit_test_suites_init(*suites); 108 109 if (filter_glob) { /* a copy was made of each array */ 110 for (suites = suite_set.start; suites < suite_set.end; suites++) 111 kfree(*suites); 112 kfree(suite_set.start); 113 } 114 115 return 0; 116 } 117 118 #endif /* IS_BUILTIN(CONFIG_KUNIT) */ 119