On Wed, 13 Dec 2023 at 09:02, Rae Moar <rmoar@xxxxxxxxxx> wrote: > > Add KUNIT_INIT_TABLE to the INIT_DATA linker section. > > Alter the KUnit macros to create init tests: > kunit_test_init_section_suites > > Update lib/kunit/executor.c to run both the suites in KUNIT_TABLE and > KUNIT_INIT_TABLE. > > Signed-off-by: Rae Moar <rmoar@xxxxxxxxxx> > --- > Changes since v3: > - Add to comments in test.h for kunit_test_init_section_suites macro to > note init tests cannot be run after boot and the structs cannot be > marked with __initdata > Thanks -- this is looking good. Reviewed-by: David Gow <davidgow@xxxxxxxxxx> Cheers, -- David > include/asm-generic/vmlinux.lds.h | 9 ++++- > include/kunit/test.h | 30 +++++++++------ > include/linux/module.h | 2 + > kernel/module/main.c | 3 ++ > lib/kunit/executor.c | 64 ++++++++++++++++++++++++++++--- > lib/kunit/test.c | 26 +++++++++---- > 6 files changed, 109 insertions(+), 25 deletions(-) > > diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h > index 1107905d37fc..5dd3a61d673d 100644 > --- a/include/asm-generic/vmlinux.lds.h > +++ b/include/asm-generic/vmlinux.lds.h > @@ -700,7 +700,8 @@ > THERMAL_TABLE(governor) \ > EARLYCON_TABLE() \ > LSM_TABLE() \ > - EARLY_LSM_TABLE() > + EARLY_LSM_TABLE() \ > + KUNIT_INIT_TABLE() > > #define INIT_TEXT \ > *(.init.text .init.text.*) \ > @@ -926,6 +927,12 @@ > . = ALIGN(8); \ > BOUNDED_SECTION_POST_LABEL(.kunit_test_suites, __kunit_suites, _start, _end) > > +/* Alignment must be consistent with (kunit_suite *) in include/kunit/test.h */ > +#define KUNIT_INIT_TABLE() \ > + . = ALIGN(8); \ > + BOUNDED_SECTION_POST_LABEL(.kunit_init_test_suites, \ > + __kunit_init_suites, _start, _end) > + > #ifdef CONFIG_BLK_DEV_INITRD > #define INIT_RAM_FS \ > . = ALIGN(4); \ > diff --git a/include/kunit/test.h b/include/kunit/test.h > index 20ed9f9275c9..fe79cd736e94 100644 > --- a/include/kunit/test.h > +++ b/include/kunit/test.h > @@ -337,6 +337,9 @@ void __kunit_test_suites_exit(struct kunit_suite **suites, int num_suites); > void kunit_exec_run_tests(struct kunit_suite_set *suite_set, bool builtin); > void kunit_exec_list_tests(struct kunit_suite_set *suite_set, bool include_attr); > > +struct kunit_suite_set kunit_merge_suite_sets(struct kunit_suite_set init_suite_set, > + struct kunit_suite_set suite_set); > + > #if IS_BUILTIN(CONFIG_KUNIT) > int kunit_run_all_tests(void); > #else > @@ -371,6 +374,11 @@ static inline int kunit_run_all_tests(void) > > #define kunit_test_suite(suite) kunit_test_suites(&suite) > > +#define __kunit_init_test_suites(unique_array, ...) \ > + static struct kunit_suite *unique_array[] \ > + __aligned(sizeof(struct kunit_suite *)) \ > + __used __section(".kunit_init_test_suites") = { __VA_ARGS__ } > + > /** > * kunit_test_init_section_suites() - used to register one or more &struct > * kunit_suite containing init functions or > @@ -378,21 +386,21 @@ static inline int kunit_run_all_tests(void) > * > * @__suites: a statically allocated list of &struct kunit_suite. > * > - * This functions identically as kunit_test_suites() except that it suppresses > - * modpost warnings for referencing functions marked __init or data marked > - * __initdata; this is OK because currently KUnit only runs tests upon boot > - * during the init phase or upon loading a module during the init phase. > + * This functions similar to kunit_test_suites() except that it compiles the > + * list of suites during init phase. > + * > + * This macro also suffixes the array and suite declarations it makes with > + * _probe; so that modpost suppresses warnings about referencing init data > + * for symbols named in this manner. > * > - * NOTE TO KUNIT DEVS: If we ever allow KUnit tests to be run after boot, these > - * tests must be excluded. > + * Note: these init tests are not able to be run after boot so there is no > + * "run" debugfs file generated for these tests. > * > - * The only thing this macro does that's different from kunit_test_suites is > - * that it suffixes the array and suite declarations it makes with _probe; > - * modpost suppresses warnings about referencing init data for symbols named in > - * this manner. > + * Also, do not mark the suite or test case structs with __initdata because > + * they will be used after the init phase with debugfs. > */ > #define kunit_test_init_section_suites(__suites...) \ > - __kunit_test_suites(CONCATENATE(__UNIQUE_ID(array), _probe), \ > + __kunit_init_test_suites(CONCATENATE(__UNIQUE_ID(array), _probe), \ > ##__suites) > > #define kunit_test_init_section_suite(suite) \ > diff --git a/include/linux/module.h b/include/linux/module.h > index a98e188cf37b..9cd0009bd050 100644 > --- a/include/linux/module.h > +++ b/include/linux/module.h > @@ -540,6 +540,8 @@ struct module { > struct static_call_site *static_call_sites; > #endif > #if IS_ENABLED(CONFIG_KUNIT) > + int num_kunit_init_suites; > + struct kunit_suite **kunit_init_suites; > int num_kunit_suites; > struct kunit_suite **kunit_suites; > #endif > diff --git a/kernel/module/main.c b/kernel/module/main.c > index 98fedfdb8db5..36681911c05a 100644 > --- a/kernel/module/main.c > +++ b/kernel/module/main.c > @@ -2199,6 +2199,9 @@ static int find_module_sections(struct module *mod, struct load_info *info) > mod->kunit_suites = section_objs(info, ".kunit_test_suites", > sizeof(*mod->kunit_suites), > &mod->num_kunit_suites); > + mod->kunit_init_suites = section_objs(info, ".kunit_init_test_suites", > + sizeof(*mod->kunit_init_suites), > + &mod->num_kunit_init_suites); > #endif > > mod->extable = section_objs(info, "__ex_table", > diff --git a/lib/kunit/executor.c b/lib/kunit/executor.c > index 1236b3cd2fbb..847329c51e91 100644 > --- a/lib/kunit/executor.c > +++ b/lib/kunit/executor.c > @@ -12,6 +12,8 @@ > */ > extern struct kunit_suite * const __kunit_suites_start[]; > extern struct kunit_suite * const __kunit_suites_end[]; > +extern struct kunit_suite * const __kunit_init_suites_start[]; > +extern struct kunit_suite * const __kunit_init_suites_end[]; > > static char *action_param; > > @@ -292,6 +294,33 @@ void kunit_exec_list_tests(struct kunit_suite_set *suite_set, bool include_attr) > } > } > > +struct kunit_suite_set kunit_merge_suite_sets(struct kunit_suite_set init_suite_set, > + struct kunit_suite_set suite_set) > +{ > + struct kunit_suite_set total_suite_set = {NULL, NULL}; > + struct kunit_suite **total_suite_start = NULL; > + size_t init_num_suites, num_suites, suite_size; > + > + init_num_suites = init_suite_set.end - init_suite_set.start; > + num_suites = suite_set.end - suite_set.start; > + suite_size = sizeof(suite_set.start); > + > + /* Allocate memory for array of all kunit suites */ > + total_suite_start = kmalloc_array(init_num_suites + num_suites, suite_size, GFP_KERNEL); > + if (!total_suite_start) > + return total_suite_set; > + > + /* Append init suites and then all other kunit suites */ > + memcpy(total_suite_start, init_suite_set.start, init_num_suites * suite_size); > + memcpy(total_suite_start + init_num_suites, suite_set.start, num_suites * suite_size); > + > + /* Set kunit suite set start and end */ > + total_suite_set.start = total_suite_start; > + total_suite_set.end = total_suite_start + (init_num_suites + num_suites); > + > + return total_suite_set; > +} > + > #if IS_BUILTIN(CONFIG_KUNIT) > > static char *kunit_shutdown; > @@ -313,21 +342,41 @@ static void kunit_handle_shutdown(void) > > int kunit_run_all_tests(void) > { > - struct kunit_suite_set suite_set = { > + struct kunit_suite_set suite_set = {NULL, NULL}; > + struct kunit_suite_set filtered_suite_set = {NULL, NULL}; > + struct kunit_suite_set init_suite_set = { > + __kunit_init_suites_start, __kunit_init_suites_end, > + }; > + struct kunit_suite_set normal_suite_set = { > __kunit_suites_start, __kunit_suites_end, > }; > + size_t init_num_suites = init_suite_set.end - init_suite_set.start; > int err = 0; > + > + if (init_num_suites > 0) { > + suite_set = kunit_merge_suite_sets(init_suite_set, normal_suite_set); > + if (!suite_set.start) > + goto out; > + } else > + suite_set = normal_suite_set; > + > if (!kunit_enabled()) { > pr_info("kunit: disabled\n"); > - goto out; > + goto free_out; > } > > if (filter_glob_param || filter_param) { > - suite_set = kunit_filter_suites(&suite_set, filter_glob_param, > + filtered_suite_set = kunit_filter_suites(&suite_set, filter_glob_param, > filter_param, filter_action_param, &err); > + > + /* Free original suite set before using filtered suite set */ > + if (init_num_suites > 0) > + kfree(suite_set.start); > + suite_set = filtered_suite_set; > + > if (err) { > pr_err("kunit executor: error filtering suites: %d\n", err); > - goto out; > + goto free_out; > } > } > > @@ -340,9 +389,12 @@ int kunit_run_all_tests(void) > else > pr_err("kunit executor: unknown action '%s'\n", action_param); > > - if (filter_glob_param || filter_param) { /* a copy was made of each suite */ > +free_out: > + if (filter_glob_param || filter_param) > kunit_free_suite_set(suite_set); > - } > + else if (init_num_suites > 0) > + /* Don't use kunit_free_suite_set because suites aren't individually allocated */ > + kfree(suite_set.start); > > out: > kunit_handle_shutdown(); > diff --git a/lib/kunit/test.c b/lib/kunit/test.c > index 0308865194bb..6c082911a85f 100644 > --- a/lib/kunit/test.c > +++ b/lib/kunit/test.c > @@ -704,28 +704,40 @@ EXPORT_SYMBOL_GPL(__kunit_test_suites_exit); > #ifdef CONFIG_MODULES > static void kunit_module_init(struct module *mod) > { > - struct kunit_suite_set suite_set = { > + struct kunit_suite_set suite_set, filtered_set; > + struct kunit_suite_set normal_suite_set = { > mod->kunit_suites, mod->kunit_suites + mod->num_kunit_suites, > }; > + struct kunit_suite_set init_suite_set = { > + mod->kunit_init_suites, mod->kunit_init_suites + mod->num_kunit_init_suites, > + }; > const char *action = kunit_action(); > int err = 0; > > - suite_set = kunit_filter_suites(&suite_set, > + if (mod->num_kunit_init_suites > 0) > + suite_set = kunit_merge_suite_sets(init_suite_set, normal_suite_set); > + else > + suite_set = normal_suite_set; > + > + filtered_set = kunit_filter_suites(&suite_set, > kunit_filter_glob() ?: "*.*", > kunit_filter(), kunit_filter_action(), > &err); > if (err) > pr_err("kunit module: error filtering suites: %d\n", err); > > - mod->kunit_suites = (struct kunit_suite **)suite_set.start; > - mod->num_kunit_suites = suite_set.end - suite_set.start; > + mod->kunit_suites = (struct kunit_suite **)filtered_set.start; > + mod->num_kunit_suites = filtered_set.end - filtered_set.start; > + > + if (mod->num_kunit_init_suites > 0) > + kfree(suite_set.start); > > if (!action) > - kunit_exec_run_tests(&suite_set, false); > + kunit_exec_run_tests(&filtered_set, false); > else if (!strcmp(action, "list")) > - kunit_exec_list_tests(&suite_set, false); > + kunit_exec_list_tests(&filtered_set, false); > else if (!strcmp(action, "list_attr")) > - kunit_exec_list_tests(&suite_set, true); > + kunit_exec_list_tests(&filtered_set, true); > else > pr_err("kunit: unknown action '%s'\n", action); > } > -- > 2.43.0.472.g3155946c3a-goog >
Attachment:
smime.p7s
Description: S/MIME Cryptographic Signature