]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
kunit: add KUNIT_INIT_TABLE to init linker section
authorRae Moar <rmoar@google.com>
Wed, 13 Dec 2023 19:44:17 +0000 (19:44 +0000)
committerShuah Khan <skhan@linuxfoundation.org>
Mon, 18 Dec 2023 20:21:15 +0000 (13:21 -0700)
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.

Reviewed-by: David Gow <davidgow@google.com>
Signed-off-by: Rae Moar <rmoar@google.com>
Signed-off-by: Shuah Khan <skhan@linuxfoundation.org>
include/asm-generic/vmlinux.lds.h
include/kunit/test.h
include/linux/module.h
kernel/module/main.c
lib/kunit/executor.c
lib/kunit/test.c

index 1107905d37fc68cfbdac4f6a54fbeb8245474958..5dd3a61d673d4f9492da2162d15944e0faa636a9 100644 (file)
        THERMAL_TABLE(governor)                                         \
        EARLYCON_TABLE()                                                \
        LSM_TABLE()                                                     \
-       EARLY_LSM_TABLE()
+       EARLY_LSM_TABLE()                                               \
+       KUNIT_INIT_TABLE()
 
 #define INIT_TEXT                                                      \
        *(.init.text .init.text.*)                                      \
                . = 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);                                                   \
index 20ed9f9275c9008c2b784e32f335049fdc775766..fe79cd736e94ce436c9d415cf7ead03567e0365f 100644 (file)
@@ -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)   \
index a98e188cf37b8182b8654b3be069f93ce1d97174..9cd0009bd050ca3814c3e246e7f4701f6a2f4917 100644 (file)
@@ -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
index 98fedfdb8db52fc358c2d3838ce9fd8a35bea068..36681911c05acd779c42d016ae7275a503c2ab9a 100644 (file)
@@ -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",
index 1236b3cd2fbb21822ccf8b099d0d0df63cff6a37..847329c51e9167b801d97ce6d8766b811d43d52c 100644 (file)
@@ -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();
index 7deee3701d206f0ff254342702344f0071c56c32..6b60d85ce1080cda88cd2cf686ff506f14aaa058 100644 (file)
@@ -742,28 +742,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);
 }