Hi Janusz, On 2024-03-27 at 12:22:54 +0100, Janusz Krzysztofik wrote: > KUnit can provide KTAP reports from test modules via debugfs files, one > per test suite. Using that source of test results instead of extracting > them from dmesg, where they may be interleaved with other kernel messages, > seems more easy to handle and less error prone. Switch to it. > > If KUnit debugfs support is found not configured then fall back to legacy > processing path. > > Signed-off-by: Janusz Krzysztofik <janusz.krzysztofik@xxxxxxxxxxxxxxx> > --- > lib/igt_kmod.c | 143 ++++++++++++++++++++++++++++++++++++------------- > 1 file changed, 105 insertions(+), 38 deletions(-) > > diff --git a/lib/igt_kmod.c b/lib/igt_kmod.c > index 1ec9c8a602..a5b170ca9c 100644 > --- a/lib/igt_kmod.c > +++ b/lib/igt_kmod.c > @@ -28,6 +28,7 @@ > #include <limits.h> > #include <pthread.h> > #include <signal.h> > +#include <stdio.h> > #include <stdlib.h> > #include <string.h> > #include <sys/stat.h> > @@ -39,6 +40,7 @@ > > #include "igt_aux.h" > #include "igt_core.h" > +#include "igt_debugfs.h" > #include "igt_kmod.h" > #include "igt_ktap.h" > #include "igt_sysfs.h" > @@ -864,6 +866,31 @@ static int open_parameters(const char *module_name) > return open(path, O_RDONLY); > } > > +static DIR *kunit_debugfs_open(void) > +{ > + const char *debugfs_path = igt_debugfs_mount(); > + int debugfs_fd, kunit_fd; > + DIR *kunit_dir; > + > + if (igt_debug_on(!debugfs_path)) > + return NULL; > + > + debugfs_fd = open(debugfs_path, O_DIRECTORY); > + if (igt_debug_on(debugfs_fd < 0)) > + return NULL; > + > + kunit_fd = openat(debugfs_fd, "kunit", O_DIRECTORY); > + close(debugfs_fd); > + if (igt_debug_on(kunit_fd < 0)) > + return NULL; > + > + kunit_dir = fdopendir(kunit_fd); > + if (igt_debug_on(!kunit_dir)) > + close(kunit_fd); imho here: close(kunit_fd); igt_debug_on(!kunit_dir); > + > + return kunit_dir; > +} > + > static bool kunit_set_filtering(const char *filter_glob, const char *filter, > const char *filter_action) > { > @@ -1071,23 +1098,48 @@ static void kunit_results_free(struct igt_list_head *results, > free(*suite_name); > } > > -static int kunit_get_results(struct igt_list_head *results, int kmsg_fd, > - struct igt_ktap_results **ktap) > +static int kunit_get_results(struct igt_list_head *results, int debugfs_fd, > + const char *suite, struct igt_ktap_results **ktap) > { > - int err; > + FILE *results_stream; > + int ret, results_fd; > + char *buf = NULL; > + size_t size = 0; > + ssize_t len; > + > + if (igt_debug_on((ret = openat(debugfs_fd, suite, O_DIRECTORY), ret < 0))) > + return ret; > + > + results_fd = openat(ret, "results", O_RDONLY); > + close(ret); > + if (igt_debug_on(results_fd < 0)) > + return results_fd; > + > + results_stream = fdopen(results_fd, "r"); > + if (igt_debug_on(!results_stream)) { > + close(results_fd); > + return -errno; > + } > > *ktap = igt_ktap_alloc(results); > - if (igt_debug_on(!*ktap)) > - return -ENOMEM; > + if (igt_debug_on(!*ktap)) { > + ret = -ENOMEM; > + goto out_fclose; > + } > + > + while (len = getline(&buf, &size, results_stream), len > 0) { > + ret = igt_ktap_parse(buf, *ktap); > + if (ret != -EINPROGRESS) > + break; > + } > > - do > - igt_debug_on((err = kunit_kmsg_result_get(results, NULL, kmsg_fd, *ktap), > - err && err != -EINPROGRESS)); > - while (err == -EINPROGRESS); > + free(buf); > > igt_ktap_free(ktap); > +out_fclose: > + fclose(results_stream); > > - return err; > + return ret; > } > > static void __igt_kunit_legacy(struct igt_ktest *tst, > @@ -1101,7 +1153,13 @@ static void __igt_kunit_legacy(struct igt_ktest *tst, > pthread_mutexattr_t attr; > IGT_LIST_HEAD(results); > unsigned long taints; > - int ret; > + int flags, ret; > + > + igt_skip_on_f(tst->kmsg < 0, "Could not open /dev/kmsg\n"); > + > + igt_skip_on((flags = fcntl(tst->kmsg, F_GETFL, 0), flags < 0)); > + igt_skip_on_f(fcntl(tst->kmsg, F_SETFL, flags & ~O_NONBLOCK) == -1, > + "Could not set /dev/kmsg to blocking mode\n"); > > igt_skip_on(lseek(tst->kmsg, 0, SEEK_END) < 0); > > @@ -1224,30 +1282,20 @@ static void __igt_kunit_legacy(struct igt_ktest *tst, > igt_skip_on_f(ret, "KTAP parser failed\n"); > } > > -static void kunit_get_tests_timeout(int signal) > -{ > - igt_skip("Timed out while trying to extract a list of KUnit test cases from /dev/kmsg\n"); > -} > - > static bool kunit_get_tests(struct igt_list_head *tests, > struct igt_ktest *tst, > const char *suite, > const char *opts, > + DIR *debugfs_dir, > struct igt_ktap_results **ktap) > { > - struct sigaction sigalrm = { .sa_handler = kunit_get_tests_timeout, }, > - *saved; > struct igt_ktap_result *r, *rn; > + struct dirent *subdir; > unsigned long taints; > - int flags, err; > - > - igt_skip_on_f(tst->kmsg < 0, "Could not open /dev/kmsg\n"); > + int debugfs_fd; > > - igt_skip_on((flags = fcntl(tst->kmsg, F_GETFL, 0), flags < 0)); > - igt_skip_on_f(fcntl(tst->kmsg, F_SETFL, flags & ~O_NONBLOCK) == -1, > - "Could not set /dev/kmsg to blocking mode\n"); > - > - igt_skip_on(lseek(tst->kmsg, 0, SEEK_END) < 0); > + if (igt_debug_on(!debugfs_dir)) > + return false; imho this should be before you set blocking mode or before you call this function. > > /* > * To get a list of test cases provided by a kunit test module, ask the > @@ -1260,19 +1308,32 @@ static bool kunit_get_tests(struct igt_list_head *tests, > if (igt_debug_on(!kunit_set_filtering(suite, "module=none", "skip"))) > return false; > > + if (!suite) { > + seekdir(debugfs_dir, 2); /* directory itself and its parent */ > + errno = 0; > + igt_skip_on_f(readdir(debugfs_dir) || errno, > + "Require empty KUnit debugfs directory\n"); > + rewinddir(debugfs_dir); > + } > + > igt_skip_on(modprobe(tst->kmod, opts)); > igt_skip_on(igt_kernel_tainted(&taints)); > > - igt_skip_on(sigaction(SIGALRM, &sigalrm, saved)); > - alarm(10); Why you removed alarm(10)? Regards, Kamil > + debugfs_fd = dirfd(debugfs_dir); > + if (suite) { > + igt_skip_on(kunit_get_results(tests, debugfs_fd, suite, ktap)); > > - err = kunit_get_results(tests, tst->kmsg, ktap); > + } else while (subdir = readdir(debugfs_dir), subdir) { > + if (!(subdir->d_type & DT_DIR)) > + continue; > > - alarm(0); > - igt_debug_on(sigaction(SIGALRM, saved, NULL)); > + if (!strcmp(subdir->d_name, ".") || !strcmp(subdir->d_name, "..")) > + continue; > > - igt_skip_on_f(err, > - "KTAP parser failed while getting a list of test cases\n"); > + igt_warn_on_f(kunit_get_results(tests, debugfs_fd, subdir->d_name, ktap), > + "parsing KTAP report from test suite \"%s\" failed\n", > + subdir->d_name); > + } > > igt_list_for_each_entry_safe(r, rn, tests, link) > igt_require_f(r->code == IGT_EXIT_SKIP, > @@ -1287,6 +1348,7 @@ static void __igt_kunit(struct igt_ktest *tst, > const char *subtest, > const char *suite, > const char *opts, > + int debugfs_fd, > struct igt_list_head *tests, > struct igt_ktap_results **ktap) > { > @@ -1307,8 +1369,6 @@ static void __igt_kunit(struct igt_ktest *tst, > > igt_skip_on(igt_kernel_tainted(&taints)); > > - igt_fail_on(lseek(tst->kmsg, 0, SEEK_END) == -1 && errno); > - > igt_assert_lt(snprintf(glob, sizeof(glob), "%s.%s", > t->suite_name, t->case_name), > sizeof(glob)); > @@ -1317,7 +1377,8 @@ static void __igt_kunit(struct igt_ktest *tst, > igt_assert_eq(modprobe(tst->kmod, opts), 0); > igt_assert_eq(igt_kernel_tainted(&taints), 0); > > - igt_assert_eq(kunit_get_results(&results, tst->kmsg, ktap), 0); > + igt_assert_eq(kunit_get_results(&results, debugfs_fd, > + t->suite_name, ktap), 0); > > for (i = 0; i < 2; i++) { > kunit_result_free(&r, &suite_name, &case_name); > @@ -1388,6 +1449,7 @@ void igt_kunit(const char *module_name, const char *suite, const char *opts) > struct igt_ktest tst = { .kmsg = -1, }; > struct igt_ktap_results *ktap = NULL; > const char *subtest = suite; > + DIR *debugfs_dir = NULL; > IGT_LIST_HEAD(tests); > > /* > @@ -1435,10 +1497,12 @@ void igt_kunit(const char *module_name, const char *suite, const char *opts) > * LTS kernels not capable of using KUnit filters for > * listing test cases in KTAP format, with igt_require. > */ > - if (!kunit_get_tests(&tests, &tst, suite, opts, &ktap)) > + debugfs_dir = kunit_debugfs_open(); > + if (!kunit_get_tests(&tests, &tst, suite, opts, debugfs_dir, &ktap)) > __igt_kunit_legacy(&tst, subtest, opts); > else > - __igt_kunit(&tst, subtest, suite, opts, &tests, &ktap); > + __igt_kunit(&tst, subtest, suite, opts, > + dirfd(debugfs_dir), &tests, &ktap); > } > > igt_fixture { > @@ -1448,6 +1512,9 @@ void igt_kunit(const char *module_name, const char *suite, const char *opts) > > kunit_results_free(&tests, &suite_name, &case_name); > > + if (debugfs_dir) > + closedir(debugfs_dir); > + > igt_ktest_end(&tst); > } > > -- > 2.44.0 >