#if IS_BUILTIN(CONFIG_KUNIT)
 
-static char *filter_glob;
-module_param(filter_glob, charp, 0);
+static char *filter_glob_param;
+module_param_named(filter_glob, filter_glob_param, charp, 0);
 MODULE_PARM_DESC(filter_glob,
                "Filter which KUnit test suites run at boot-time, e.g. list*");
 
 core_param(kunit_shutdown, kunit_shutdown, charp, 0644);
 
 static struct kunit_suite * const *
-kunit_filter_subsuite(struct kunit_suite * const * const subsuite)
+kunit_filter_subsuite(struct kunit_suite * const * const subsuite,
+                       const char *filter_glob)
 {
        int i, n = 0;
        struct kunit_suite **filtered;
        struct kunit_suite * const * const *end;
 };
 
-static struct suite_set kunit_filter_suites(void)
+static struct suite_set kunit_filter_suites(const struct suite_set *suite_set,
+                                           const char *filter_glob)
 {
        int i;
        struct kunit_suite * const **copy, * const *filtered_subsuite;
        struct suite_set filtered;
 
-       const size_t max = __kunit_suites_end - __kunit_suites_start;
-
-       if (!filter_glob) {
-               filtered.start = __kunit_suites_start;
-               filtered.end = __kunit_suites_end;
-               return filtered;
-       }
+       const size_t max = suite_set->end - suite_set->start;
 
        copy = kmalloc_array(max, sizeof(*filtered.start), GFP_KERNEL);
        filtered.start = copy;
        }
 
        for (i = 0; i < max; ++i) {
-               filtered_subsuite = kunit_filter_subsuite(__kunit_suites_start[i]);
+               filtered_subsuite = kunit_filter_subsuite(suite_set->start[i], filter_glob);
                if (filtered_subsuite)
                        *copy++ = filtered_subsuite;
        }
 int kunit_run_all_tests(void)
 {
        struct kunit_suite * const * const *suites;
+       struct suite_set suite_set = {
+               .start = __kunit_suites_start,
+               .end = __kunit_suites_end,
+       };
 
-       struct suite_set suite_set = kunit_filter_suites();
+       if (filter_glob_param)
+               suite_set = kunit_filter_suites(&suite_set, filter_glob_param);
 
        kunit_print_tap_header(&suite_set);
 
        for (suites = suite_set.start; suites < suite_set.end; suites++)
                __kunit_test_suites_init(*suites);
 
-       if (filter_glob) { /* a copy was made of each array */
+       if (filter_glob_param) { /* a copy was made of each array */
                for (suites = suite_set.start; suites < suite_set.end; suites++)
                        kfree(*suites);
                kfree(suite_set.start);
        return 0;
 }
 
+#if IS_BUILTIN(CONFIG_KUNIT_TEST)
+#include "executor_test.c"
+#endif
+
 #endif /* IS_BUILTIN(CONFIG_KUNIT) */
 
--- /dev/null
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * KUnit test for the KUnit executor.
+ *
+ * Copyright (C) 2021, Google LLC.
+ * Author: Daniel Latypov <dlatypov@google.com>
+ */
+
+#include <kunit/test.h>
+
+static void kfree_at_end(struct kunit *test, const void *to_free);
+static struct kunit_suite *alloc_fake_suite(struct kunit *test,
+                                           const char *suite_name);
+
+static void filter_subsuite_test(struct kunit *test)
+{
+       struct kunit_suite *subsuite[3] = {NULL, NULL, NULL};
+       struct kunit_suite * const *filtered;
+
+       subsuite[0] = alloc_fake_suite(test, "suite1");
+       subsuite[1] = alloc_fake_suite(test, "suite2");
+
+       /* Want: suite1, suite2, NULL -> suite2, NULL */
+       filtered = kunit_filter_subsuite(subsuite, "suite2*");
+       KUNIT_ASSERT_NOT_ERR_OR_NULL(test, filtered);
+       kfree_at_end(test, filtered);
+
+       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]);
+}
+
+static void filter_subsuite_to_empty_test(struct kunit *test)
+{
+       struct kunit_suite *subsuite[3] = {NULL, NULL, NULL};
+       struct kunit_suite * const *filtered;
+
+       subsuite[0] = alloc_fake_suite(test, "suite1");
+       subsuite[1] = alloc_fake_suite(test, "suite2");
+
+       filtered = kunit_filter_subsuite(subsuite, "not_found");
+       kfree_at_end(test, filtered); /* 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++)
+               kfree_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};
+
+       /* Emulate two files, each having one suite */
+       subsuites[0][0] = alloc_fake_suite(test, "suite0");
+       subsuites[1][0] = alloc_fake_suite(test, "suite1");
+
+       /* Filter out suite1 */
+       filtered = kunit_filter_suites(&suite_set, "suite0");
+       kfree_subsuites_at_end(test, &filtered); /* let us use ASSERTs without leaking */
+       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_EXPECT_STREQ(test, (const char *)filtered.start[0][0]->name, "suite0");
+}
+
+static struct kunit_case executor_test_cases[] = {
+       KUNIT_CASE(filter_subsuite_test),
+       KUNIT_CASE(filter_subsuite_to_empty_test),
+       KUNIT_CASE(filter_suites_test),
+       {}
+};
+
+static struct kunit_suite executor_test_suite = {
+       .name = "kunit_executor_test",
+       .test_cases = executor_test_cases,
+};
+
+kunit_test_suites(&executor_test_suite);
+
+/* Test helpers */
+
+static void kfree_res_free(struct kunit_resource *res)
+{
+       kfree(res->data);
+}
+
+/* Use the resource API to register a call to kfree(to_free).
+ * Since we never actually use the resource, it's safe to use on const data.
+ */
+static void kfree_at_end(struct kunit *test, const void *to_free)
+{
+       /* kfree() handles NULL already, but avoid allocating a no-op cleanup. */
+       if (IS_ERR_OR_NULL(to_free))
+               return;
+       kunit_alloc_and_get_resource(test, NULL, kfree_res_free, GFP_KERNEL,
+                                    (void *)to_free);
+}
+
+static struct kunit_suite *alloc_fake_suite(struct kunit *test,
+                                           const char *suite_name)
+{
+       struct kunit_suite *suite;
+
+       /* We normally never expect to allocate suites, hence the non-const cast. */
+       suite = kunit_kzalloc(test, sizeof(*suite), GFP_KERNEL);
+       strncpy((char *)suite->name, suite_name, sizeof(suite->name) - 1);
+
+       return suite;
+}