2022-06-21 08:57:15

by David Gow

[permalink] [raw]
Subject: [PATCH v2 0/5] Rework KUnit test execution in modules

This patch series makes two changes to how KUnit test suites are stored
and executed:
- The .kunit_test_suites section is now used for tests in modules (in
lieu of a module_init funciton), as well as for built-in tests. The
module loader will now trigger test execution. This frees up the
module_init function for other uses.
- Instead of storing an array of arrays of suites, have the
kunit_test_suite() and kunit_test_suites() macros append to one global
(or per-module) list of test suites. This removes a needless layer of
indirection, and removes the need to NULL-terminate suite_sets.

The upshot of this is that it should now be possible to use the
kunit_test_suite() and kunit_test_suites() macros to register test
suites even from within modules which otherwise had module_init
functions. This was proving to be quite a common issue, resulting in
several modules calling into KUnit's private suite execution functions
to run their tests (often introducing incompatibilities with the KUnit
tooling).

This series also fixes the thunderbolt, nitro_enclaves, and
sdhci-of-aspeed tests to use kunit_test_suite() now that it works. This
is required, as otherwise the first two patches may break these tests
entirely.

Huge thanks to Jeremy Kerr, who designed and implemented the module
loader changes, and to Daniel Latypov for pushing the simplification of
the nested arrays in .kunit_test_suites.

I've tested this series both with builtin tests, and with modules on
x86_64, but there's always the possibility that there's something subtle
and nasty on another architecture, so please test!

Cheers,
-- David

Changes since v1:
https://lore.kernel.org/linux-kselftest/[email protected]/
- Fix a compile issue when CONFIG_KUNIT=m (Thanks Christophe)
- No longer NULL-terminate suite_sets.
- Move the thunderbird Kconfig to the correct patch (Thanks Andra)
- Add all the Tested-by and Acked-by tags.

---
Daniel Latypov (1):
kunit: flatten kunit_suite*** to kunit_suite** in .kunit_test_suites

David Gow (3):
thunderbolt: test: Use kunit_test_suite() macro
nitro_enclaves: test: Use kunit_test_suite() macro
mmc: sdhci-of-aspeed: test: Use kunit_test_suite() macro

Jeremy Kerr (1):
kunit: unify module and builtin suite definitions

drivers/mmc/host/Kconfig | 5 +-
drivers/mmc/host/sdhci-of-aspeed-test.c | 8 +-
drivers/mmc/host/sdhci-of-aspeed.c | 27 ----
drivers/thunderbolt/Kconfig | 5 +-
drivers/thunderbolt/domain.c | 3 -
drivers/thunderbolt/tb.h | 8 -
drivers/thunderbolt/test.c | 12 +-
drivers/virt/nitro_enclaves/Kconfig | 5 +-
drivers/virt/nitro_enclaves/ne_misc_dev.c | 27 ----
.../virt/nitro_enclaves/ne_misc_dev_test.c | 5 +-
include/kunit/test.h | 60 ++------
include/linux/module.h | 5 +
kernel/module/main.c | 6 +
lib/kunit/executor.c | 115 ++++----------
lib/kunit/executor_test.c | 144 +++++-------------
lib/kunit/test.c | 54 ++++++-
16 files changed, 152 insertions(+), 337 deletions(-)

--
2.37.0.rc0.104.g0611611a94-goog


2022-06-21 08:57:32

by David Gow

[permalink] [raw]
Subject: [PATCH v2 2/5] kunit: flatten kunit_suite*** to kunit_suite** in .kunit_test_suites

From: Daniel Latypov <[email protected]>

We currently store kunit suites in the .kunit_test_suites ELF section as
a `struct kunit_suite***` (modulo some `const`s).
For every test file, we store a struct kunit_suite** NULL-terminated array.

This adds quite a bit of complexity to the test filtering code in the
executor.

Instead, let's just make the .kunit_test_suites section contain a single
giant array of struct kunit_suite pointers, which can then be directly
manipulated. This array is not NULL-terminated, and so none of the test
filtering code needs to NULL-terminate anything.

Tested-by: Maíra Canal <[email protected]>
Signed-off-by: Daniel Latypov <[email protected]>
Co-developed-by: David Gow <[email protected]>
Signed-off-by: David Gow <[email protected]>
---

Changes since v1:
https://lore.kernel.org/linux-kselftest/[email protected]/
- No longer NULL-terminate generated suite_sets
- Add Maíra's Tested-by tag.

Changes since RFC:
https://lore.kernel.org/linux-kselftest/[email protected]/
- Actually flatten the .kunit_test_suites ELF section,
rather than constructing the flattened version at runtime.
---
include/kunit/test.h | 13 ++--
include/linux/module.h | 2 +-
lib/kunit/executor.c | 115 ++++++++----------------------
lib/kunit/executor_test.c | 144 +++++++++++---------------------------
lib/kunit/test.c | 18 ++---
5 files changed, 82 insertions(+), 210 deletions(-)

diff --git a/include/kunit/test.h b/include/kunit/test.h
index 54306271cfbf..bd8d772979a6 100644
--- a/include/kunit/test.h
+++ b/include/kunit/test.h
@@ -237,9 +237,9 @@ size_t kunit_suite_num_test_cases(struct kunit_suite *suite);
unsigned int kunit_test_case_num(struct kunit_suite *suite,
struct kunit_case *test_case);

-int __kunit_test_suites_init(struct kunit_suite * const * const suites);
+int __kunit_test_suites_init(struct kunit_suite * const * const suites, int num_suites);

-void __kunit_test_suites_exit(struct kunit_suite **suites);
+void __kunit_test_suites_exit(struct kunit_suite **suites, int num_suites);

#if IS_BUILTIN(CONFIG_KUNIT)
int kunit_run_all_tests(void);
@@ -250,10 +250,10 @@ static inline int kunit_run_all_tests(void)
}
#endif /* IS_BUILTIN(CONFIG_KUNIT) */

-#define __kunit_test_suites(unique_array, unique_suites, ...) \
- static struct kunit_suite *unique_array[] = { __VA_ARGS__, NULL }; \
- static struct kunit_suite **unique_suites \
- __used __section(".kunit_test_suites") = unique_array
+#define __kunit_test_suites(unique_array, ...) \
+ static struct kunit_suite *unique_array[] \
+ __aligned(sizeof(struct kunit_suite *)) \
+ __used __section(".kunit_test_suites") = { __VA_ARGS__ }

/**
* kunit_test_suites() - used to register one or more &struct kunit_suite
@@ -271,7 +271,6 @@ static inline int kunit_run_all_tests(void)
*/
#define kunit_test_suites(__suites...) \
__kunit_test_suites(__UNIQUE_ID(array), \
- __UNIQUE_ID(suites), \
##__suites)

#define kunit_test_suite(suite) kunit_test_suites(&suite)
diff --git a/include/linux/module.h b/include/linux/module.h
index 2490223c975d..518296ea7f73 100644
--- a/include/linux/module.h
+++ b/include/linux/module.h
@@ -507,7 +507,7 @@ struct module {
#endif
#if IS_ENABLED(CONFIG_KUNIT)
int num_kunit_suites;
- struct kunit_suite ***kunit_suites;
+ struct kunit_suite **kunit_suites;
#endif


diff --git a/lib/kunit/executor.c b/lib/kunit/executor.c
index 96f96e42ce06..2ae9a037a80f 100644
--- a/lib/kunit/executor.c
+++ b/lib/kunit/executor.c
@@ -9,8 +9,8 @@
* These symbols point to the .kunit_test_suites section and are defined in
* include/asm-generic/vmlinux.lds.h, and consequently must be extern.
*/
-extern struct kunit_suite * const * const __kunit_suites_start[];
-extern struct kunit_suite * const * const __kunit_suites_end[];
+extern struct kunit_suite * const __kunit_suites_start[];
+extern struct kunit_suite * const __kunit_suites_end[];

#if IS_BUILTIN(CONFIG_KUNIT)

@@ -92,62 +92,18 @@ kunit_filter_tests(struct kunit_suite *const suite, const char *test_glob)
static char *kunit_shutdown;
core_param(kunit_shutdown, kunit_shutdown, charp, 0644);

-static struct kunit_suite * const *
-kunit_filter_subsuite(struct kunit_suite * const * const subsuite,
- struct kunit_test_filter *filter)
-{
- int i, n = 0;
- struct kunit_suite **filtered, *filtered_suite;
-
- n = 0;
- for (i = 0; subsuite[i]; ++i) {
- if (glob_match(filter->suite_glob, subsuite[i]->name))
- ++n;
- }
-
- if (n == 0)
- return NULL;
-
- filtered = kmalloc_array(n + 1, sizeof(*filtered), GFP_KERNEL);
- if (!filtered)
- return ERR_PTR(-ENOMEM);
-
- n = 0;
- for (i = 0; subsuite[i] != NULL; ++i) {
- if (!glob_match(filter->suite_glob, subsuite[i]->name))
- continue;
- filtered_suite = kunit_filter_tests(subsuite[i], filter->test_glob);
- if (IS_ERR(filtered_suite))
- return ERR_CAST(filtered_suite);
- else if (filtered_suite)
- filtered[n++] = filtered_suite;
- }
- filtered[n] = NULL;
-
- return filtered;
-}
-
+/* Stores an array of suites, end points one past the end */
struct suite_set {
- struct kunit_suite * const * const *start;
- struct kunit_suite * const * const *end;
+ struct kunit_suite * const *start;
+ struct kunit_suite * const *end;
};

-static void kunit_free_subsuite(struct kunit_suite * const *subsuite)
-{
- unsigned int i;
-
- for (i = 0; subsuite[i]; i++)
- kfree(subsuite[i]);
-
- kfree(subsuite);
-}
-
static void kunit_free_suite_set(struct suite_set suite_set)
{
- struct kunit_suite * const * const *suites;
+ struct kunit_suite * const *suites;

for (suites = suite_set.start; suites < suite_set.end; suites++)
- kunit_free_subsuite(*suites);
+ kfree(*suites);
kfree(suite_set.start);
}

@@ -156,7 +112,7 @@ static struct suite_set kunit_filter_suites(const struct suite_set *suite_set,
int *err)
{
int i;
- struct kunit_suite * const **copy, * const *filtered_subsuite;
+ struct kunit_suite **copy, *filtered_suite;
struct suite_set filtered;
struct kunit_test_filter filter;

@@ -171,14 +127,19 @@ static struct suite_set kunit_filter_suites(const struct suite_set *suite_set,

kunit_parse_filter_glob(&filter, filter_glob);

- for (i = 0; i < max; ++i) {
- filtered_subsuite = kunit_filter_subsuite(suite_set->start[i], &filter);
- if (IS_ERR(filtered_subsuite)) {
- *err = PTR_ERR(filtered_subsuite);
+ for (i = 0; &suite_set->start[i] != suite_set->end; i++) {
+ if (!glob_match(filter.suite_glob, suite_set->start[i]->name))
+ continue;
+
+ filtered_suite = kunit_filter_tests(suite_set->start[i], filter.test_glob);
+ if (IS_ERR(filtered_suite)) {
+ *err = PTR_ERR(filtered_suite);
return filtered;
}
- if (filtered_subsuite)
- *copy++ = filtered_subsuite;
+ if (!filtered_suite)
+ continue;
+
+ *copy++ = filtered_suite;
}
filtered.end = copy;

@@ -201,52 +162,33 @@ static void kunit_handle_shutdown(void)

}

-static void kunit_print_tap_header(struct suite_set *suite_set)
-{
- struct kunit_suite * const * const *suites, * const *subsuite;
- int num_of_suites = 0;
-
- for (suites = suite_set->start; suites < suite_set->end; suites++)
- for (subsuite = *suites; *subsuite != NULL; subsuite++)
- num_of_suites++;
-
- pr_info("TAP version 14\n");
- pr_info("1..%d\n", num_of_suites);
-}
-
static void kunit_exec_run_tests(struct suite_set *suite_set)
{
- struct kunit_suite * const * const *suites;
+ size_t num_suites = suite_set->end - suite_set->start;

- kunit_print_tap_header(suite_set);
+ pr_info("TAP version 14\n");
+ pr_info("1..%zu\n", num_suites);

- for (suites = suite_set->start; suites < suite_set->end; suites++)
- __kunit_test_suites_init(*suites);
+ __kunit_test_suites_init(suite_set->start, num_suites);
}

static void kunit_exec_list_tests(struct suite_set *suite_set)
{
- unsigned int i;
- struct kunit_suite * const * const *suites;
+ struct kunit_suite * const *suites;
struct kunit_case *test_case;

/* Hack: print a tap header so kunit.py can find the start of KUnit output. */
pr_info("TAP version 14\n");

for (suites = suite_set->start; suites < suite_set->end; suites++)
- for (i = 0; (*suites)[i] != NULL; i++) {
- kunit_suite_for_each_test_case((*suites)[i], test_case) {
- pr_info("%s.%s\n", (*suites)[i]->name, test_case->name);
- }
+ kunit_suite_for_each_test_case((*suites), test_case) {
+ pr_info("%s.%s\n", (*suites)->name, test_case->name);
}
}

int kunit_run_all_tests(void)
{
- struct suite_set suite_set = {
- .start = __kunit_suites_start,
- .end = __kunit_suites_end,
- };
+ struct suite_set suite_set = {__kunit_suites_start, __kunit_suites_end};
int err = 0;

if (filter_glob_param) {
@@ -264,11 +206,10 @@ int kunit_run_all_tests(void)
else
pr_err("kunit executor: unknown action '%s'\n", action_param);

- if (filter_glob_param) { /* a copy was made of each array */
+ if (filter_glob_param) { /* a copy was made of each suite */
kunit_free_suite_set(suite_set);
}

-
out:
kunit_handle_shutdown();
return err;
diff --git a/lib/kunit/executor_test.c b/lib/kunit/executor_test.c
index eac6ff480273..0cea31c27b23 100644
--- a/lib/kunit/executor_test.c
+++ b/lib/kunit/executor_test.c
@@ -9,8 +9,6 @@
#include <kunit/test.h>

static void kfree_at_end(struct kunit *test, const void *to_free);
-static void free_subsuite_at_end(struct kunit *test,
- struct kunit_suite *const *to_free);
static struct kunit_suite *alloc_fake_suite(struct kunit *test,
const char *suite_name,
struct kunit_case *test_cases);
@@ -41,126 +39,80 @@ static void parse_filter_test(struct kunit *test)
kfree(filter.test_glob);
}

-static void filter_subsuite_test(struct kunit *test)
+static void filter_suites_test(struct kunit *test)
{
- struct kunit_suite *subsuite[3] = {NULL, NULL, NULL};
- struct kunit_suite * const *filtered;
- struct kunit_test_filter filter = {
- .suite_glob = "suite2",
- .test_glob = NULL,
- };
+ struct kunit_suite *subsuite[3] = {NULL, NULL};
+ struct suite_set suite_set = {.start = subsuite, .end = &subsuite[2]};
+ struct suite_set got;
+ int err = 0;

subsuite[0] = alloc_fake_suite(test, "suite1", dummy_test_cases);
subsuite[1] = alloc_fake_suite(test, "suite2", dummy_test_cases);

/* Want: suite1, suite2, NULL -> suite2, NULL */
- filtered = kunit_filter_subsuite(subsuite, &filter);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, filtered);
- free_subsuite_at_end(test, filtered);
+ got = kunit_filter_suites(&suite_set, "suite2", &err);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, got.start);
+ KUNIT_ASSERT_EQ(test, err, 0);
+ kfree_at_end(test, got.start);

/* Validate we just have suite2 */
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, filtered[0]);
- KUNIT_EXPECT_STREQ(test, (const char *)filtered[0]->name, "suite2");
- KUNIT_EXPECT_FALSE(test, filtered[1]);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, got.start[0]);
+ KUNIT_EXPECT_STREQ(test, (const char *)got.start[0]->name, "suite2");
+
+ /* Contains one element (end is 1 past end) */
+ KUNIT_ASSERT_EQ(test, got.end - got.start, 1);
}

-static void filter_subsuite_test_glob_test(struct kunit *test)
+static void filter_suites_test_glob_test(struct kunit *test)
{
- struct kunit_suite *subsuite[3] = {NULL, NULL, NULL};
- struct kunit_suite * const *filtered;
- struct kunit_test_filter filter = {
- .suite_glob = "suite2",
- .test_glob = "test2",
- };
+ struct kunit_suite *subsuite[3] = {NULL, NULL};
+ struct suite_set suite_set = {.start = subsuite, .end = &subsuite[2]};
+ struct suite_set got;
+ int err = 0;

subsuite[0] = alloc_fake_suite(test, "suite1", dummy_test_cases);
subsuite[1] = alloc_fake_suite(test, "suite2", dummy_test_cases);

/* Want: suite1, suite2, NULL -> suite2 (just test1), NULL */
- filtered = kunit_filter_subsuite(subsuite, &filter);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, filtered);
- free_subsuite_at_end(test, filtered);
+ got = kunit_filter_suites(&suite_set, "suite2.test2", &err);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, got.start);
+ KUNIT_ASSERT_EQ(test, err, 0);
+ kfree_at_end(test, got.start);

/* Validate we just have suite2 */
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, filtered[0]);
- KUNIT_EXPECT_STREQ(test, (const char *)filtered[0]->name, "suite2");
- KUNIT_EXPECT_FALSE(test, filtered[1]);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, got.start[0]);
+ KUNIT_EXPECT_STREQ(test, (const char *)got.start[0]->name, "suite2");
+ KUNIT_ASSERT_EQ(test, got.end - got.start, 1);

/* Now validate we just have test2 */
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, filtered[0]->test_cases);
- KUNIT_EXPECT_STREQ(test, (const char *)filtered[0]->test_cases[0].name, "test2");
- KUNIT_EXPECT_FALSE(test, filtered[0]->test_cases[1].name);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, got.start[0]->test_cases);
+ KUNIT_EXPECT_STREQ(test, (const char *)got.start[0]->test_cases[0].name, "test2");
+ KUNIT_EXPECT_FALSE(test, got.start[0]->test_cases[1].name);
}

-static void filter_subsuite_to_empty_test(struct kunit *test)
+static void filter_suites_to_empty_test(struct kunit *test)
{
- struct kunit_suite *subsuite[3] = {NULL, NULL, NULL};
- struct kunit_suite * const *filtered;
- struct kunit_test_filter filter = {
- .suite_glob = "not_found",
- .test_glob = NULL,
- };
+ struct kunit_suite *subsuite[3] = {NULL, NULL};
+ struct suite_set suite_set = {.start = subsuite, .end = &subsuite[2]};
+ struct suite_set got;
+ int err = 0;

subsuite[0] = alloc_fake_suite(test, "suite1", dummy_test_cases);
subsuite[1] = alloc_fake_suite(test, "suite2", dummy_test_cases);

- filtered = kunit_filter_subsuite(subsuite, &filter);
- free_subsuite_at_end(test, filtered); /* just in case */
+ got = kunit_filter_suites(&suite_set, "not_found", &err);
+ KUNIT_ASSERT_EQ(test, err, 0);
+ kfree_at_end(test, got.start); /* just in case */

- KUNIT_EXPECT_FALSE_MSG(test, filtered,
- "should be NULL to indicate no match");
-}
-
-static void kfree_subsuites_at_end(struct kunit *test, struct suite_set *suite_set)
-{
- struct kunit_suite * const * const *suites;
-
- kfree_at_end(test, suite_set->start);
- for (suites = suite_set->start; suites < suite_set->end; suites++)
- free_subsuite_at_end(test, *suites);
-}
-
-static void filter_suites_test(struct kunit *test)
-{
- /* Suites per-file are stored as a NULL terminated array */
- struct kunit_suite *subsuites[2][2] = {
- {NULL, NULL},
- {NULL, NULL},
- };
- /* Match the memory layout of suite_set */
- struct kunit_suite * const * const suites[2] = {
- subsuites[0], subsuites[1],
- };
-
- const struct suite_set suite_set = {
- .start = suites,
- .end = suites + 2,
- };
- struct suite_set filtered = {.start = NULL, .end = NULL};
- int err = 0;
-
- /* Emulate two files, each having one suite */
- subsuites[0][0] = alloc_fake_suite(test, "suite0", dummy_test_cases);
- subsuites[1][0] = alloc_fake_suite(test, "suite1", dummy_test_cases);
-
- /* Filter out suite1 */
- filtered = kunit_filter_suites(&suite_set, "suite0", &err);
- kfree_subsuites_at_end(test, &filtered); /* let us use ASSERTs without leaking */
- KUNIT_EXPECT_EQ(test, err, 0);
- KUNIT_ASSERT_EQ(test, filtered.end - filtered.start, (ptrdiff_t)1);
-
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, filtered.start);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, filtered.start[0]);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, filtered.start[0][0]);
- KUNIT_EXPECT_STREQ(test, (const char *)filtered.start[0][0]->name, "suite0");
+ KUNIT_EXPECT_PTR_EQ_MSG(test, got.start, got.end,
+ "should be empty to indicate no match");
}

static struct kunit_case executor_test_cases[] = {
KUNIT_CASE(parse_filter_test),
- KUNIT_CASE(filter_subsuite_test),
- KUNIT_CASE(filter_subsuite_test_glob_test),
- KUNIT_CASE(filter_subsuite_to_empty_test),
KUNIT_CASE(filter_suites_test),
+ KUNIT_CASE(filter_suites_test_glob_test),
+ KUNIT_CASE(filter_suites_to_empty_test),
{}
};

@@ -190,20 +142,6 @@ static void kfree_at_end(struct kunit *test, const void *to_free)
(void *)to_free);
}

-static void free_subsuite_res_free(struct kunit_resource *res)
-{
- kunit_free_subsuite(res->data);
-}
-
-static void free_subsuite_at_end(struct kunit *test,
- struct kunit_suite *const *to_free)
-{
- if (IS_ERR_OR_NULL(to_free))
- return;
- kunit_alloc_resource(test, NULL, free_subsuite_res_free,
- GFP_KERNEL, (void *)to_free);
-}
-
static struct kunit_suite *alloc_fake_suite(struct kunit *test,
const char *suite_name,
struct kunit_case *test_cases)
diff --git a/lib/kunit/test.c b/lib/kunit/test.c
index 3052526b9b89..b6495c7f9a7e 100644
--- a/lib/kunit/test.c
+++ b/lib/kunit/test.c
@@ -582,11 +582,11 @@ static void kunit_init_suite(struct kunit_suite *suite)
suite->suite_init_err = 0;
}

-int __kunit_test_suites_init(struct kunit_suite * const * const suites)
+int __kunit_test_suites_init(struct kunit_suite * const * const suites, int num_suites)
{
unsigned int i;

- for (i = 0; suites[i] != NULL; i++) {
+ for (i = 0; i < num_suites; i++) {
kunit_init_suite(suites[i]);
kunit_run_tests(suites[i]);
}
@@ -599,11 +599,11 @@ static void kunit_exit_suite(struct kunit_suite *suite)
kunit_debugfs_destroy_suite(suite);
}

-void __kunit_test_suites_exit(struct kunit_suite **suites)
+void __kunit_test_suites_exit(struct kunit_suite **suites, int num_suites)
{
unsigned int i;

- for (i = 0; suites[i] != NULL; i++)
+ for (i = 0; i < num_suites; i++)
kunit_exit_suite(suites[i]);

kunit_suite_counter = 1;
@@ -613,18 +613,12 @@ EXPORT_SYMBOL_GPL(__kunit_test_suites_exit);
#ifdef CONFIG_MODULES
static void kunit_module_init(struct module *mod)
{
- unsigned int i;
-
- for (i = 0; i < mod->num_kunit_suites; i++)
- __kunit_test_suites_init(mod->kunit_suites[i]);
+ __kunit_test_suites_init(mod->kunit_suites, mod->num_kunit_suites);
}

static void kunit_module_exit(struct module *mod)
{
- unsigned int i;
-
- for (i = 0; i < mod->num_kunit_suites; i++)
- __kunit_test_suites_exit(mod->kunit_suites[i]);
+ __kunit_test_suites_exit(mod->kunit_suites, mod->num_kunit_suites);
}

static int kunit_module_notify(struct notifier_block *nb, unsigned long val,
--
2.37.0.rc0.104.g0611611a94-goog

2022-06-21 08:57:33

by David Gow

[permalink] [raw]
Subject: [PATCH v2 1/5] kunit: unify module and builtin suite definitions

From: Jeremy Kerr <[email protected]>

Currently, KUnit runs built-in tests and tests loaded from modules
differently. For built-in tests, the kunit_test_suite{,s}() macro adds a
list of suites in the .kunit_test_suites linker section. However, for
kernel modules, a module_init() function is used to run the test suites.

This causes problems if tests are included in a module which already
defines module_init/exit_module functions, as they'll conflict with the
kunit-provided ones.

This change removes the kunit-defined module inits, and instead parses
the kunit tests from their own section in the module. After module init,
we call __kunit_test_suites_init() on the contents of that section,
which prepares and runs the suite.

This essentially unifies the module- and non-module kunit init formats.

Tested-by: Maíra Canal <[email protected]>
Signed-off-by: Jeremy Kerr <[email protected]>
Signed-off-by: Daniel Latypov <[email protected]>
Signed-off-by: David Gow <[email protected]>
---

Changes since v1:
https://lore.kernel.org/linux-kselftest/[email protected]/
- Fix a compile error with CONFIG_KUNIT=m (Thanks Christophe Leroy,
kernel test robot)
- Add Maíra's Tested-by.

Changes since RFC:
https://lore.kernel.org/linux-kselftest/101d12fc9250b7a445ff50a9e7a25cd74d0e16eb.camel@codeconstruct.com.au/
- I've basically just rebased it, tweaked some wording, and it made it
still compile when CONFIG_MODULES is not set.

---
include/kunit/test.h | 47 ++++----------------------------------
include/linux/module.h | 5 ++++
kernel/module/main.c | 6 +++++
lib/kunit/test.c | 52 +++++++++++++++++++++++++++++++++++++++++-
4 files changed, 67 insertions(+), 43 deletions(-)

diff --git a/include/kunit/test.h b/include/kunit/test.h
index 8ffcd7de9607..54306271cfbf 100644
--- a/include/kunit/test.h
+++ b/include/kunit/test.h
@@ -250,41 +250,8 @@ static inline int kunit_run_all_tests(void)
}
#endif /* IS_BUILTIN(CONFIG_KUNIT) */

-#ifdef MODULE
-/**
- * kunit_test_suites_for_module() - used to register one or more
- * &struct kunit_suite with KUnit.
- *
- * @__suites: a statically allocated list of &struct kunit_suite.
- *
- * Registers @__suites with the test framework. See &struct kunit_suite for
- * more information.
- *
- * If a test suite is built-in, module_init() gets translated into
- * an initcall which we don't want as the idea is that for builtins
- * the executor will manage execution. So ensure we do not define
- * module_{init|exit} functions for the builtin case when registering
- * suites via kunit_test_suites() below.
- */
-#define kunit_test_suites_for_module(__suites) \
- static int __init kunit_test_suites_init(void) \
- { \
- return __kunit_test_suites_init(__suites); \
- } \
- module_init(kunit_test_suites_init); \
- \
- static void __exit kunit_test_suites_exit(void) \
- { \
- return __kunit_test_suites_exit(__suites); \
- } \
- module_exit(kunit_test_suites_exit)
-#else
-#define kunit_test_suites_for_module(__suites)
-#endif /* MODULE */
-
#define __kunit_test_suites(unique_array, unique_suites, ...) \
static struct kunit_suite *unique_array[] = { __VA_ARGS__, NULL }; \
- kunit_test_suites_for_module(unique_array); \
static struct kunit_suite **unique_suites \
__used __section(".kunit_test_suites") = unique_array

@@ -294,16 +261,12 @@ static inline int kunit_run_all_tests(void)
*
* @__suites: a statically allocated list of &struct kunit_suite.
*
- * Registers @suites with the test framework. See &struct kunit_suite for
- * more information.
- *
- * When builtin, KUnit tests are all run via executor; this is done
- * by placing the array of struct kunit_suite * in the .kunit_test_suites
- * ELF section.
+ * Registers @suites with the test framework.
+ * This is done by placing the array of struct kunit_suite * in the
+ * .kunit_test_suites ELF section.
*
- * An alternative is to build the tests as a module. Because modules do not
- * support multiple initcall()s, we need to initialize an array of suites for a
- * module.
+ * When builtin, KUnit tests are all run via the executor at boot, and when
+ * built as a module, they run on module load.
*
*/
#define kunit_test_suites(__suites...) \
diff --git a/include/linux/module.h b/include/linux/module.h
index abd9fa916b7d..2490223c975d 100644
--- a/include/linux/module.h
+++ b/include/linux/module.h
@@ -505,6 +505,11 @@ struct module {
int num_static_call_sites;
struct static_call_site *static_call_sites;
#endif
+#if IS_ENABLED(CONFIG_KUNIT)
+ int num_kunit_suites;
+ struct kunit_suite ***kunit_suites;
+#endif
+

#ifdef CONFIG_LIVEPATCH
bool klp; /* Is this a livepatch module? */
diff --git a/kernel/module/main.c b/kernel/module/main.c
index fed58d30725d..4542db7cdf54 100644
--- a/kernel/module/main.c
+++ b/kernel/module/main.c
@@ -2087,6 +2087,12 @@ static int find_module_sections(struct module *mod, struct load_info *info)
sizeof(*mod->static_call_sites),
&mod->num_static_call_sites);
#endif
+#ifdef CONFIG_KUNIT
+ mod->kunit_suites = section_objs(info, ".kunit_test_suites",
+ sizeof(*mod->kunit_suites),
+ &mod->num_kunit_suites);
+#endif
+
mod->extable = section_objs(info, "__ex_table",
sizeof(*mod->extable), &mod->num_exentries);

diff --git a/lib/kunit/test.c b/lib/kunit/test.c
index a5053a07409f..3052526b9b89 100644
--- a/lib/kunit/test.c
+++ b/lib/kunit/test.c
@@ -10,6 +10,7 @@
#include <kunit/test.h>
#include <kunit/test-bug.h>
#include <linux/kernel.h>
+#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/sched/debug.h>
#include <linux/sched.h>
@@ -609,6 +610,49 @@ void __kunit_test_suites_exit(struct kunit_suite **suites)
}
EXPORT_SYMBOL_GPL(__kunit_test_suites_exit);

+#ifdef CONFIG_MODULES
+static void kunit_module_init(struct module *mod)
+{
+ unsigned int i;
+
+ for (i = 0; i < mod->num_kunit_suites; i++)
+ __kunit_test_suites_init(mod->kunit_suites[i]);
+}
+
+static void kunit_module_exit(struct module *mod)
+{
+ unsigned int i;
+
+ for (i = 0; i < mod->num_kunit_suites; i++)
+ __kunit_test_suites_exit(mod->kunit_suites[i]);
+}
+
+static int kunit_module_notify(struct notifier_block *nb, unsigned long val,
+ void *data)
+{
+ struct module *mod = data;
+
+ switch (val) {
+ case MODULE_STATE_LIVE:
+ kunit_module_init(mod);
+ break;
+ case MODULE_STATE_GOING:
+ kunit_module_exit(mod);
+ break;
+ case MODULE_STATE_COMING:
+ case MODULE_STATE_UNFORMED:
+ break;
+ }
+
+ return 0;
+}
+
+static struct notifier_block kunit_mod_nb = {
+ .notifier_call = kunit_module_notify,
+ .priority = 0,
+};
+#endif
+
struct kunit_kmalloc_array_params {
size_t n;
size_t size;
@@ -703,13 +747,19 @@ EXPORT_SYMBOL_GPL(kunit_cleanup);
static int __init kunit_init(void)
{
kunit_debugfs_init();
-
+#ifdef CONFIG_MODULES
+ return register_module_notifier(&kunit_mod_nb);
+#else
return 0;
+#endif
}
late_initcall(kunit_init);

static void __exit kunit_exit(void)
{
+#ifdef CONFIG_MODULES
+ unregister_module_notifier(&kunit_mod_nb);
+#endif
kunit_debugfs_cleanup();
}
module_exit(kunit_exit);
--
2.37.0.rc0.104.g0611611a94-goog

2022-06-21 08:57:45

by David Gow

[permalink] [raw]
Subject: [PATCH v2 4/5] nitro_enclaves: test: Use kunit_test_suite() macro

The kunit_test_suite() macro previously conflicted with module_init,
making it unsuitable for use in the nitro_enclaves test. Now that it's
fixed, we can use it instead of a custom call into internal KUnit
functions to run the test.

As a side-effect, this means that the test results are properly included
with other suites when built-in. To celebrate, enable the test by
default when KUNIT_ALL_TESTS is set (and NITRO_ENCLAVES enabled).

The nitro_enclave tests can now be run via kunit_tool with:
./tools/testing/kunit/kunit.py run --arch=x86_64 \
--kconfig_add CONFIG_PCI=y --kconfig_add CONFIG_SMP=y \
--kconfig_add CONFIG_HOTPLUG_CPU=y \
--kconfig_add CONFIG_VIRT_DRIVERS=y \
--kconfig_add CONFIG_NITRO_ENCLAVES=y \
'ne_misc_dev_test'

(This is a pretty long command, so it may be worth adding a .kunitconfig
file at some point, instead.)

Acked-by: Paraschiv, Andra-Irina <[email protected]>
Signed-off-by: David Gow <[email protected]>
---

Changes since v1:
https://lore.kernel.org/linux-kselftest/[email protected]/
- Move the mistakenly-added thunderbolt Kconfig to the previous patch
(Thanks Andra)
- Add Andra's Acked-by tag.

---
drivers/virt/nitro_enclaves/Kconfig | 5 ++--
drivers/virt/nitro_enclaves/ne_misc_dev.c | 27 -------------------
.../virt/nitro_enclaves/ne_misc_dev_test.c | 5 +---
3 files changed, 4 insertions(+), 33 deletions(-)

diff --git a/drivers/virt/nitro_enclaves/Kconfig b/drivers/virt/nitro_enclaves/Kconfig
index 2d3d98158121..ce91add81401 100644
--- a/drivers/virt/nitro_enclaves/Kconfig
+++ b/drivers/virt/nitro_enclaves/Kconfig
@@ -16,8 +16,9 @@ config NITRO_ENCLAVES
The module will be called nitro_enclaves.

config NITRO_ENCLAVES_MISC_DEV_TEST
- bool "Tests for the misc device functionality of the Nitro Enclaves"
- depends on NITRO_ENCLAVES && KUNIT=y
+ bool "Tests for the misc device functionality of the Nitro Enclaves" if !KUNIT_ALL_TESTS
+ depends on NITRO_ENCLAVES && KUNIT
+ default KUNIT_ALL_TESTS
help
Enable KUnit tests for the misc device functionality of the Nitro
Enclaves. Select this option only if you will boot the kernel for
diff --git a/drivers/virt/nitro_enclaves/ne_misc_dev.c b/drivers/virt/nitro_enclaves/ne_misc_dev.c
index 20c881b6a4b6..241b94f62e56 100644
--- a/drivers/virt/nitro_enclaves/ne_misc_dev.c
+++ b/drivers/virt/nitro_enclaves/ne_misc_dev.c
@@ -1759,35 +1759,10 @@ static long ne_ioctl(struct file *file, unsigned int cmd, unsigned long arg)

#if defined(CONFIG_NITRO_ENCLAVES_MISC_DEV_TEST)
#include "ne_misc_dev_test.c"
-
-static inline int ne_misc_dev_test_init(void)
-{
- return __kunit_test_suites_init(ne_misc_dev_test_suites);
-}
-
-static inline void ne_misc_dev_test_exit(void)
-{
- __kunit_test_suites_exit(ne_misc_dev_test_suites);
-}
-#else
-static inline int ne_misc_dev_test_init(void)
-{
- return 0;
-}
-
-static inline void ne_misc_dev_test_exit(void)
-{
-}
#endif

static int __init ne_init(void)
{
- int rc = 0;
-
- rc = ne_misc_dev_test_init();
- if (rc < 0)
- return rc;
-
mutex_init(&ne_cpu_pool.mutex);

return pci_register_driver(&ne_pci_driver);
@@ -1798,8 +1773,6 @@ static void __exit ne_exit(void)
pci_unregister_driver(&ne_pci_driver);

ne_teardown_cpu_pool();
-
- ne_misc_dev_test_exit();
}

module_init(ne_init);
diff --git a/drivers/virt/nitro_enclaves/ne_misc_dev_test.c b/drivers/virt/nitro_enclaves/ne_misc_dev_test.c
index 265797bed0ea..74df43b925be 100644
--- a/drivers/virt/nitro_enclaves/ne_misc_dev_test.c
+++ b/drivers/virt/nitro_enclaves/ne_misc_dev_test.c
@@ -151,7 +151,4 @@ static struct kunit_suite ne_misc_dev_test_suite = {
.test_cases = ne_misc_dev_test_cases,
};

-static struct kunit_suite *ne_misc_dev_test_suites[] = {
- &ne_misc_dev_test_suite,
- NULL
-};
+kunit_test_suite(ne_misc_dev_test_suite);
--
2.37.0.rc0.104.g0611611a94-goog

2022-06-21 08:57:54

by David Gow

[permalink] [raw]
Subject: [PATCH v2 5/5] mmc: sdhci-of-aspeed: test: Use kunit_test_suite() macro

The kunit_test_suite() macro is no-longer incompatible with module_add,
so its use can be reinstated.

Since this fixes parsing with builtins and kunit_tool, also enable the
test by default when KUNIT_ALL_TESTS is enabled.

The test can now be run via kunit_tool with:
./tools/testing/kunit/kunit.py run --arch=x86_64 \
--kconfig_add CONFIG_OF=y --kconfig_add CONFIG_OF_ADDRESS=y \
--kconfig_add CONFIG_MMC=y --kconfig_add CONFIG_MMC_SDHCI=y \
--kconfig_add CONFIG_MMC_SDHCI_PLTFM=y \
--kconfig_add CONFIG_MMC_SDHCI_OF_ASPEED=y \
'sdhci-of-aspeed'

(It may be worth adding a .kunitconfig at some point, as there are
enough dependencies to make that command scarily long.)

Signed-off-by: David Gow <[email protected]>
---

No changes since v1:
https://lore.kernel.org/linux-kselftest/[email protected]/

---
drivers/mmc/host/Kconfig | 5 +++--
drivers/mmc/host/sdhci-of-aspeed-test.c | 8 +-------
drivers/mmc/host/sdhci-of-aspeed.c | 27 -------------------------
3 files changed, 4 insertions(+), 36 deletions(-)

diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index d6144978e32d..10c563999d3d 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -169,8 +169,9 @@ config MMC_SDHCI_OF_ASPEED
If unsure, say N.

config MMC_SDHCI_OF_ASPEED_TEST
- bool "Tests for the ASPEED SDHCI driver"
- depends on MMC_SDHCI_OF_ASPEED && KUNIT=y
+ bool "Tests for the ASPEED SDHCI driver" if !KUNIT_ALL_TESTS
+ depends on MMC_SDHCI_OF_ASPEED && KUNIT
+ default KUNIT_ALL_TESTS
help
Enable KUnit tests for the ASPEED SDHCI driver. Select this
option only if you will boot the kernel for the purpose of running
diff --git a/drivers/mmc/host/sdhci-of-aspeed-test.c b/drivers/mmc/host/sdhci-of-aspeed-test.c
index 1ed4f86291f2..ecb502606c53 100644
--- a/drivers/mmc/host/sdhci-of-aspeed-test.c
+++ b/drivers/mmc/host/sdhci-of-aspeed-test.c
@@ -96,10 +96,4 @@ static struct kunit_suite aspeed_sdhci_test_suite = {
.test_cases = aspeed_sdhci_test_cases,
};

-static struct kunit_suite *aspeed_sdc_test_suite_array[] = {
- &aspeed_sdhci_test_suite,
- NULL,
-};
-
-static struct kunit_suite **aspeed_sdc_test_suites
- __used __section(".kunit_test_suites") = aspeed_sdc_test_suite_array;
+kunit_test_suite(aspeed_sdhci_test_suite);
diff --git a/drivers/mmc/host/sdhci-of-aspeed.c b/drivers/mmc/host/sdhci-of-aspeed.c
index 6e4e132903a6..c10367946bc7 100644
--- a/drivers/mmc/host/sdhci-of-aspeed.c
+++ b/drivers/mmc/host/sdhci-of-aspeed.c
@@ -606,25 +606,6 @@ static struct platform_driver aspeed_sdc_driver = {

#if defined(CONFIG_MMC_SDHCI_OF_ASPEED_TEST)
#include "sdhci-of-aspeed-test.c"
-
-static inline int aspeed_sdc_tests_init(void)
-{
- return __kunit_test_suites_init(aspeed_sdc_test_suites);
-}
-
-static inline void aspeed_sdc_tests_exit(void)
-{
- __kunit_test_suites_exit(aspeed_sdc_test_suites);
-}
-#else
-static inline int aspeed_sdc_tests_init(void)
-{
- return 0;
-}
-
-static inline void aspeed_sdc_tests_exit(void)
-{
-}
#endif

static int __init aspeed_sdc_init(void)
@@ -639,12 +620,6 @@ static int __init aspeed_sdc_init(void)
if (rc < 0)
goto cleanup_sdhci;

- rc = aspeed_sdc_tests_init();
- if (rc < 0) {
- platform_driver_unregister(&aspeed_sdc_driver);
- goto cleanup_sdhci;
- }
-
return 0;

cleanup_sdhci:
@@ -656,8 +631,6 @@ module_init(aspeed_sdc_init);

static void __exit aspeed_sdc_exit(void)
{
- aspeed_sdc_tests_exit();
-
platform_driver_unregister(&aspeed_sdc_driver);
platform_driver_unregister(&aspeed_sdhci_driver);
}
--
2.37.0.rc0.104.g0611611a94-goog

2022-06-21 09:18:51

by David Gow

[permalink] [raw]
Subject: [PATCH v2 3/5] thunderbolt: test: Use kunit_test_suite() macro

The new implementation of kunit_test_suite() for modules no longer
conflicts with module_init, so can now be used by the thunderbolt tests.

Also update the Kconfig entry to enable the test when KUNIT_ALL_TESTS is
enabled.

This means that kunit_tool can now successfully run and parse the test
results with, for example:
./tools/testing/kunit/kunit.py run --arch=x86_64 \
--kconfig_add CONFIG_PCI=y --kconfig_add CONFIG_USB4=y \
'thunderbolt'

Acked-by: Mika Westerberg <[email protected]>
Signed-off-by: David Gow <[email protected]>
---

Changes since v1:
https://lore.kernel.org/linux-kselftest/[email protected]/
- Actually include the Kconfig changes, which were mistakenly added to
the next patch in the series in v1.
- Add Acked-by tag from Mika Westerberg

---
drivers/thunderbolt/Kconfig | 5 +++--
drivers/thunderbolt/domain.c | 3 ---
drivers/thunderbolt/tb.h | 8 --------
drivers/thunderbolt/test.c | 12 +-----------
4 files changed, 4 insertions(+), 24 deletions(-)

diff --git a/drivers/thunderbolt/Kconfig b/drivers/thunderbolt/Kconfig
index 4bfec8a28064..2a063d344b94 100644
--- a/drivers/thunderbolt/Kconfig
+++ b/drivers/thunderbolt/Kconfig
@@ -28,8 +28,9 @@ config USB4_DEBUGFS_WRITE
this for production systems or distro kernels.

config USB4_KUNIT_TEST
- bool "KUnit tests"
- depends on KUNIT=y
+ bool "KUnit tests" if !KUNIT_ALL_TESTS
+ depends on KUNIT
+ default KUNIT_ALL_TESTS

config USB4_DMA_TEST
tristate "DMA traffic test driver"
diff --git a/drivers/thunderbolt/domain.c b/drivers/thunderbolt/domain.c
index 2889a214dadc..99211f35a5cd 100644
--- a/drivers/thunderbolt/domain.c
+++ b/drivers/thunderbolt/domain.c
@@ -872,7 +872,6 @@ int tb_domain_init(void)
{
int ret;

- tb_test_init();
tb_debugfs_init();
tb_acpi_init();

@@ -890,7 +889,6 @@ int tb_domain_init(void)
err_acpi:
tb_acpi_exit();
tb_debugfs_exit();
- tb_test_exit();

return ret;
}
@@ -903,5 +901,4 @@ void tb_domain_exit(void)
tb_xdomain_exit();
tb_acpi_exit();
tb_debugfs_exit();
- tb_test_exit();
}
diff --git a/drivers/thunderbolt/tb.h b/drivers/thunderbolt/tb.h
index 4602c69913fa..a831faa50f65 100644
--- a/drivers/thunderbolt/tb.h
+++ b/drivers/thunderbolt/tb.h
@@ -1271,12 +1271,4 @@ static inline void tb_service_debugfs_init(struct tb_service *svc) { }
static inline void tb_service_debugfs_remove(struct tb_service *svc) { }
#endif

-#ifdef CONFIG_USB4_KUNIT_TEST
-int tb_test_init(void);
-void tb_test_exit(void);
-#else
-static inline int tb_test_init(void) { return 0; }
-static inline void tb_test_exit(void) { }
-#endif
-
#endif
diff --git a/drivers/thunderbolt/test.c b/drivers/thunderbolt/test.c
index ee37f8b58f50..24c06e7354cd 100644
--- a/drivers/thunderbolt/test.c
+++ b/drivers/thunderbolt/test.c
@@ -2817,14 +2817,4 @@ static struct kunit_suite tb_test_suite = {
.test_cases = tb_test_cases,
};

-static struct kunit_suite *tb_test_suites[] = { &tb_test_suite, NULL };
-
-int tb_test_init(void)
-{
- return __kunit_test_suites_init(tb_test_suites);
-}
-
-void tb_test_exit(void)
-{
- return __kunit_test_suites_exit(tb_test_suites);
-}
+kunit_test_suite(tb_test_suite);
--
2.37.0.rc0.104.g0611611a94-goog

2022-06-21 16:00:36

by Paraschiv, Andra-Irina

[permalink] [raw]
Subject: Re: [PATCH v2 4/5] nitro_enclaves: test: Use kunit_test_suite() macro



On 21.06.2022 11:53, David Gow wrote:
>
> The kunit_test_suite() macro previously conflicted with module_init,
> making it unsuitable for use in the nitro_enclaves test. Now that it's
> fixed, we can use it instead of a custom call into internal KUnit
> functions to run the test.
>
> As a side-effect, this means that the test results are properly included
> with other suites when built-in. To celebrate, enable the test by
> default when KUNIT_ALL_TESTS is set (and NITRO_ENCLAVES enabled).
>
> The nitro_enclave tests can now be run via kunit_tool with:
> ./tools/testing/kunit/kunit.py run --arch=x86_64 \
> --kconfig_add CONFIG_PCI=y --kconfig_add CONFIG_SMP=y \
> --kconfig_add CONFIG_HOTPLUG_CPU=y \
> --kconfig_add CONFIG_VIRT_DRIVERS=y \
> --kconfig_add CONFIG_NITRO_ENCLAVES=y \
> 'ne_misc_dev_test'
>
> (This is a pretty long command, so it may be worth adding a .kunitconfig
> file at some point, instead.)
>
> Acked-by: Paraschiv, Andra-Irina <[email protected]>
> Signed-off-by: David Gow <[email protected]>
> ---
>
> Changes since v1:
> https://lore.kernel.org/linux-kselftest/[email protected]/
> - Move the mistakenly-added thunderbolt Kconfig to the previous patch
> (Thanks Andra)
> - Add Andra's Acked-by tag.
>
> ---
> drivers/virt/nitro_enclaves/Kconfig | 5 ++--
> drivers/virt/nitro_enclaves/ne_misc_dev.c | 27 -------------------
> .../virt/nitro_enclaves/ne_misc_dev_test.c | 5 +---
> 3 files changed, 4 insertions(+), 33 deletions(-)

Reviewed-by: Andra Paraschiv <[email protected]>

Thank you, David, for the patch updates.

Added Greg to the list of mail recipients, to be aware of this patch
changes, given that the Nitro Enclaves kernel driver is tracked via the
char-misc tree.

Thanks,
Andra

>
> diff --git a/drivers/virt/nitro_enclaves/Kconfig b/drivers/virt/nitro_enclaves/Kconfig
> index 2d3d98158121..ce91add81401 100644
> --- a/drivers/virt/nitro_enclaves/Kconfig
> +++ b/drivers/virt/nitro_enclaves/Kconfig
> @@ -16,8 +16,9 @@ config NITRO_ENCLAVES
> The module will be called nitro_enclaves.
>
> config NITRO_ENCLAVES_MISC_DEV_TEST
> - bool "Tests for the misc device functionality of the Nitro Enclaves"
> - depends on NITRO_ENCLAVES && KUNIT=y
> + bool "Tests for the misc device functionality of the Nitro Enclaves" if !KUNIT_ALL_TESTS
> + depends on NITRO_ENCLAVES && KUNIT
> + default KUNIT_ALL_TESTS
> help
> Enable KUnit tests for the misc device functionality of the Nitro
> Enclaves. Select this option only if you will boot the kernel for
> diff --git a/drivers/virt/nitro_enclaves/ne_misc_dev.c b/drivers/virt/nitro_enclaves/ne_misc_dev.c
> index 20c881b6a4b6..241b94f62e56 100644
> --- a/drivers/virt/nitro_enclaves/ne_misc_dev.c
> +++ b/drivers/virt/nitro_enclaves/ne_misc_dev.c
> @@ -1759,35 +1759,10 @@ static long ne_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
>
> #if defined(CONFIG_NITRO_ENCLAVES_MISC_DEV_TEST)
> #include "ne_misc_dev_test.c"
> -
> -static inline int ne_misc_dev_test_init(void)
> -{
> - return __kunit_test_suites_init(ne_misc_dev_test_suites);
> -}
> -
> -static inline void ne_misc_dev_test_exit(void)
> -{
> - __kunit_test_suites_exit(ne_misc_dev_test_suites);
> -}
> -#else
> -static inline int ne_misc_dev_test_init(void)
> -{
> - return 0;
> -}
> -
> -static inline void ne_misc_dev_test_exit(void)
> -{
> -}
> #endif
>
> static int __init ne_init(void)
> {
> - int rc = 0;
> -
> - rc = ne_misc_dev_test_init();
> - if (rc < 0)
> - return rc;
> -
> mutex_init(&ne_cpu_pool.mutex);
>
> return pci_register_driver(&ne_pci_driver);
> @@ -1798,8 +1773,6 @@ static void __exit ne_exit(void)
> pci_unregister_driver(&ne_pci_driver);
>
> ne_teardown_cpu_pool();
> -
> - ne_misc_dev_test_exit();
> }
>
> module_init(ne_init);
> diff --git a/drivers/virt/nitro_enclaves/ne_misc_dev_test.c b/drivers/virt/nitro_enclaves/ne_misc_dev_test.c
> index 265797bed0ea..74df43b925be 100644
> --- a/drivers/virt/nitro_enclaves/ne_misc_dev_test.c
> +++ b/drivers/virt/nitro_enclaves/ne_misc_dev_test.c
> @@ -151,7 +151,4 @@ static struct kunit_suite ne_misc_dev_test_suite = {
> .test_cases = ne_misc_dev_test_cases,
> };
>
> -static struct kunit_suite *ne_misc_dev_test_suites[] = {
> - &ne_misc_dev_test_suite,
> - NULL
> -};
> +kunit_test_suite(ne_misc_dev_test_suite);
> --
> 2.37.0.rc0.104.g0611611a94-goog
>



Amazon Development Center (Romania) S.R.L. registered office: 27A Sf. Lazar Street, UBC5, floor 2, Iasi, Iasi County, 700045, Romania. Registered in Romania. Registration number J22/2621/2005.

2022-06-21 20:30:06

by Daniel Latypov

[permalink] [raw]
Subject: Re: [PATCH v2 3/5] thunderbolt: test: Use kunit_test_suite() macro

On Tue, Jun 21, 2022 at 1:54 AM David Gow <[email protected]> wrote:
>
> The new implementation of kunit_test_suite() for modules no longer
> conflicts with module_init, so can now be used by the thunderbolt tests.
>
> Also update the Kconfig entry to enable the test when KUNIT_ALL_TESTS is
> enabled.
>
> This means that kunit_tool can now successfully run and parse the test
> results with, for example:
> ./tools/testing/kunit/kunit.py run --arch=x86_64 \
> --kconfig_add CONFIG_PCI=y --kconfig_add CONFIG_USB4=y \
> 'thunderbolt'

With this, we can maybe revive
https://lore.kernel.org/lkml/[email protected]
by tacking it onto this series if a v3 goes out.
There is the open question of whether we should put UML-specific
config options in the file, though.

If we decide we don't want that, then we can defer it until I send out
the patches for "repeatable --kunitconfig" and we can add the
uml_pci.config file.

>
> Acked-by: Mika Westerberg <[email protected]>
> Signed-off-by: David Gow <[email protected]>

Acked-by: Daniel Latypov <[email protected]>

LGTM.

2022-06-21 20:39:27

by Daniel Latypov

[permalink] [raw]
Subject: Re: [PATCH v2 2/5] kunit: flatten kunit_suite*** to kunit_suite** in .kunit_test_suites

On Tue, Jun 21, 2022 at 1:54 AM 'David Gow' via KUnit Development
<[email protected]> wrote:
>
> From: Daniel Latypov <[email protected]>
>
> We currently store kunit suites in the .kunit_test_suites ELF section as
> a `struct kunit_suite***` (modulo some `const`s).
> For every test file, we store a struct kunit_suite** NULL-terminated array.
>
> This adds quite a bit of complexity to the test filtering code in the
> executor.
>
> Instead, let's just make the .kunit_test_suites section contain a single
> giant array of struct kunit_suite pointers, which can then be directly
> manipulated. This array is not NULL-terminated, and so none of the test
> filtering code needs to NULL-terminate anything.
>
> Tested-by: Maíra Canal <[email protected]>
> Signed-off-by: Daniel Latypov <[email protected]>
> Co-developed-by: David Gow <[email protected]>
> Signed-off-by: David Gow <[email protected]>
> ---
>
> Changes since v1:
> https://lore.kernel.org/linux-kselftest/[email protected]/
> - No longer NULL-terminate generated suite_sets

Nice!
Thanks for picking and cleaning this up!

Daniel

2022-06-21 22:30:09

by Daniel Latypov

[permalink] [raw]
Subject: Re: [PATCH v2 5/5] mmc: sdhci-of-aspeed: test: Use kunit_test_suite() macro

On Tue, Jun 21, 2022 at 1:54 AM David Gow <[email protected]> wrote:
>
> The kunit_test_suite() macro is no-longer incompatible with module_add,
> so its use can be reinstated.
>
> Since this fixes parsing with builtins and kunit_tool, also enable the
> test by default when KUNIT_ALL_TESTS is enabled.
>
> The test can now be run via kunit_tool with:
> ./tools/testing/kunit/kunit.py run --arch=x86_64 \
> --kconfig_add CONFIG_OF=y --kconfig_add CONFIG_OF_ADDRESS=y \
> --kconfig_add CONFIG_MMC=y --kconfig_add CONFIG_MMC_SDHCI=y \
> --kconfig_add CONFIG_MMC_SDHCI_PLTFM=y \
> --kconfig_add CONFIG_MMC_SDHCI_OF_ASPEED=y \
> 'sdhci-of-aspeed'
>
> (It may be worth adding a .kunitconfig at some point, as there are
> enough dependencies to make that command scarily long.)
>
> Signed-off-by: David Gow <[email protected]>

Acked-by: Daniel Latypov <[email protected]>

Minor, optional suggestion below.

> static int __init aspeed_sdc_init(void)
> @@ -639,12 +620,6 @@ static int __init aspeed_sdc_init(void)
> if (rc < 0)
> goto cleanup_sdhci;
>
> - rc = aspeed_sdc_tests_init();
> - if (rc < 0) {
> - platform_driver_unregister(&aspeed_sdc_driver);
> - goto cleanup_sdhci;
> - }
> -
> return 0;
>
> cleanup_sdhci:

This goto was added in 4af307f57426 ("mmc: sdhci-of-aspeed: Fix
kunit-related build error") to allow for this extra call to
aspeed_sdc_tests_init().

This could now be reverted back to what is
rc = platform_driver_register(&aspeed_sdc_driver);
if (rc < 0)
platform_driver_unregister(&aspeed_sdhci_driver);

return rc;

but let's see what the maintainers think.

2022-06-22 07:28:59

by David Gow

[permalink] [raw]
Subject: Re: [PATCH v2 3/5] thunderbolt: test: Use kunit_test_suite() macro

On Tue, Jun 21, 2022 at 4:54 PM David Gow <[email protected]> wrote:
>
> The new implementation of kunit_test_suite() for modules no longer
> conflicts with module_init, so can now be used by the thunderbolt tests.
>
> Also update the Kconfig entry to enable the test when KUNIT_ALL_TESTS is
> enabled.
>
> This means that kunit_tool can now successfully run and parse the test
> results with, for example:
> ./tools/testing/kunit/kunit.py run --arch=x86_64 \
> --kconfig_add CONFIG_PCI=y --kconfig_add CONFIG_USB4=y \
> 'thunderbolt'
>
> Acked-by: Mika Westerberg <[email protected]>
> Signed-off-by: David Gow <[email protected]>
> ---
>
> Changes since v1:
> https://lore.kernel.org/linux-kselftest/[email protected]/
> - Actually include the Kconfig changes, which were mistakenly added to
> the next patch in the series in v1.
> - Add Acked-by tag from Mika Westerberg
>
> ---
> drivers/thunderbolt/Kconfig | 5 +++--
> drivers/thunderbolt/domain.c | 3 ---
> drivers/thunderbolt/tb.h | 8 --------
> drivers/thunderbolt/test.c | 12 +-----------
> 4 files changed, 4 insertions(+), 24 deletions(-)
>
> diff --git a/drivers/thunderbolt/Kconfig b/drivers/thunderbolt/Kconfig
> index 4bfec8a28064..2a063d344b94 100644
> --- a/drivers/thunderbolt/Kconfig
> +++ b/drivers/thunderbolt/Kconfig
> @@ -28,8 +28,9 @@ config USB4_DEBUGFS_WRITE
> this for production systems or distro kernels.
>
> config USB4_KUNIT_TEST
> - bool "KUnit tests"
> - depends on KUNIT=y
> + bool "KUnit tests" if !KUNIT_ALL_TESTS
> + depends on KUNIT
> + default KUNIT_ALL_TESTS
>

FYI: It turns out we can't just replace the "depends on KUNIT=y" with
"depends on KUNIT" here, as it's still possible to have CONFIG_USB4=y
and CONFIG_KUNIT=m, which would lead to missing KUnit symbols during
link.

What does work is adding, in addition to "depends on KUNIT":
depends on (USB4=m || KUNIT=y)

Which will prevent the tests from being enabled in this situation.

I'll wait another day or so before sending out a v3 with this fixed,
in case there are any other issues which arise.

Cheers,
-- David


Attachments:
smime.p7s (3.91 kB)
S/MIME Cryptographic Signature

2022-06-23 12:34:46

by Ulf Hansson

[permalink] [raw]
Subject: Re: [PATCH v2 5/5] mmc: sdhci-of-aspeed: test: Use kunit_test_suite() macro

On Wed, 22 Jun 2022 at 00:19, Daniel Latypov <[email protected]> wrote:
>
> On Tue, Jun 21, 2022 at 1:54 AM David Gow <[email protected]> wrote:
> >
> > The kunit_test_suite() macro is no-longer incompatible with module_add,
> > so its use can be reinstated.
> >
> > Since this fixes parsing with builtins and kunit_tool, also enable the
> > test by default when KUNIT_ALL_TESTS is enabled.
> >
> > The test can now be run via kunit_tool with:
> > ./tools/testing/kunit/kunit.py run --arch=x86_64 \
> > --kconfig_add CONFIG_OF=y --kconfig_add CONFIG_OF_ADDRESS=y \
> > --kconfig_add CONFIG_MMC=y --kconfig_add CONFIG_MMC_SDHCI=y \
> > --kconfig_add CONFIG_MMC_SDHCI_PLTFM=y \
> > --kconfig_add CONFIG_MMC_SDHCI_OF_ASPEED=y \
> > 'sdhci-of-aspeed'
> >
> > (It may be worth adding a .kunitconfig at some point, as there are
> > enough dependencies to make that command scarily long.)
> >
> > Signed-off-by: David Gow <[email protected]>
>
> Acked-by: Daniel Latypov <[email protected]>
>
> Minor, optional suggestion below.
>
> > static int __init aspeed_sdc_init(void)
> > @@ -639,12 +620,6 @@ static int __init aspeed_sdc_init(void)
> > if (rc < 0)
> > goto cleanup_sdhci;
> >
> > - rc = aspeed_sdc_tests_init();
> > - if (rc < 0) {
> > - platform_driver_unregister(&aspeed_sdc_driver);
> > - goto cleanup_sdhci;
> > - }
> > -
> > return 0;
> >
> > cleanup_sdhci:
>
> This goto was added in 4af307f57426 ("mmc: sdhci-of-aspeed: Fix
> kunit-related build error") to allow for this extra call to
> aspeed_sdc_tests_init().
>
> This could now be reverted back to what is
> rc = platform_driver_register(&aspeed_sdc_driver);
> if (rc < 0)
> platform_driver_unregister(&aspeed_sdhci_driver);
>
> return rc;
>
> but let's see what the maintainers think.

I don't have a strong opinion on this, feel free to pick any of the options.

Acked-by: Ulf Hansson <[email protected]>

Kind regards
Uffe