Isabella Basso: 2 igt_kmod: add compatibility for KUnit tests/kms_kunit: add KUnit damage helper test 5 files changed, 247 insertions(+), 11 deletions(-)
Copy & paste the following snippet into your terminal to import this patchset into git:
curl -s https://lists.sr.ht/~lkcamp/patches/patches/30163/mbox | git am -3Learn more about email & git
This adds functions for both executing the tests as well as parsing TAP kmsg output. Changes since v1: - Correct handling of read to deal with partial buffer. Signed-off-by: Isabella Basso <isabbasso@riseup.net> --- lib/igt_kmod.c | 169 +++++++++++++++++++++++++++++++++++++++++++++++++ lib/igt_kmod.h | 13 ++++ 2 files changed, 182 insertions(+) diff --git a/lib/igt_kmod.c b/lib/igt_kmod.c index cf7a3b22..5d8e8b94 100644 --- a/lib/igt_kmod.c +++ b/lib/igt_kmod.c @@ -345,6 +345,175 @@ igt_kmod_list_loaded(void) kmod_module_unref_list(list); } +static void kmsg_parse_tap(int fd) +{ + char record[4096 + 1]; + const char *num_tests_str, *nok_str, *ok_str, *end_str_success, *end_str_fail; + bool has_num = false; + + num_tests_str = ".."; + nok_str = " not ok "; + ok_str = " ok "; + end_str_fail = "not ok "; + end_str_success = "ok "; + + if (fd == -1) { + igt_warn("Unable to retrieve kernel log (from /dev/kmsg)\n"); + return; + } + + record[sizeof(record) - 1] = '\0'; + + for (;;) { + const char *end, *result; + ssize_t r; + + r = read(fd, record, sizeof(record) - 1); + if (r < 0) { + if (errno == EINTR) + continue; + + if (errno == EPIPE) { + igt_warn("kmsg truncated: too many messages. You may want to increase log_buf_len in kmcdline\n"); + continue; + } + + if (errno != EAGAIN) + igt_warn("kmsg truncated: unknown error (%m)\n"); + + break; + } + + /* deal with partial string from read */ + if (record[r - 1] == NULL) { + fseek(fd, 0, end); + continue; + } + + if (!has_num) { + result = strstr(record, num_tests_str); + if (result) { + result += strlen(num_tests_str); + end = strchrnul(result, '\n'); + igt_info("[IGT] running %.*s tests...\n", + (int)(end - result), result); + has_num = true; + } + continue; + } + + /* all results have 'ok' in them */ + result = strstr(record, "ok"); + + if (result) { + end = strchrnul(result, '\n'); + + /* subtest succeded (i.e. ok_str) */ + result = strstr(record, ok_str); + + if (result) { + result += strlen(ok_str); + igt_info("[IGT] SUBTEST %.*s\n", + (int)(end - result), result); + continue; + } + + /* subtest failed (i.e. nok_str) */ + result = strstr(record, nok_str); + + if (result) { + result += strlen(nok_str); + igt_warn("[IGT] SUBTEST FAILED %.*s\n", + (int)(end - result), result); + continue; + } + + /* test ended (i.e. end_str_success) */ + result = strchr(record, ';') + 1; + + if (strncmp(result, end_str_success, strlen(end_str_success)) == 0) { + igt_info("[IGT] TEST SUCCEEDED %.*s\n", + (int)(end - result), result); + + igt_success(); + } + + if (strncmp(result, end_str_fail, strlen(end_str_fail)) == 0) { + igt_warn("[IGT] TEST FAILED %.*s\n", + (int)(end - result), result); + igt_fail(IGT_EXIT_FAILURE); + } + } + } +} + +/** + * igt_kunit: tests a kunit module + * @mod_name: the name of the module + * @options: options to load the module + * @req_mods: array with additional dependencies to run the KUnit test + * @req_mod_len: size of req_mods array + * + * Loads the kunit module, parses its dmesg output, then unloads it + */ +void igt_kunit(const char *mod_name, const char *options, + const char **req_mods, int req_mod_len) +{ + int kmsg_fd, cmi; + struct igt_kselftest tst; + const char *norm_name; + + /* get normalized module name */ + igt_require(igt_kselftest_init(&tst, mod_name) == 0); + + norm_name = kmod_module_get_name(tst.kmod); + + if (!igt_kmod_is_loaded(norm_name)) { + /* The kunit module is required for running any kunit tests */ + if (!igt_kmod_is_loaded("kunit")) + igt_require(igt_kmod_load("kunit", NULL) == 0); + + for (cmi = 0; cmi < req_mod_len; cmi++) { + if (strcmp(req_mods[cmi], "kunit") == 0) + continue; + if (igt_kmod_load(req_mods[cmi], NULL)) + goto unload; + } + } else { + /* Unload module if loaded (maybe previous run bailed out?) */ + igt_kmod_unload(mod_name, 0); + } + + kmsg_fd = open("/dev/kmsg", O_RDONLY | O_NONBLOCK); + + if (kmsg_fd < 0) { + igt_warn("Could not open /dev/kmsg"); + goto unload; + } + + if (lseek(kmsg_fd, 0, SEEK_END)) { + igt_warn("Could not seek the end of /dev/kmsg"); + close(kmsg_fd); + goto unload; + } + + igt_require(igt_kmod_load(mod_name, options) == 0); + + kmsg_parse_tap(kmsg_fd); + + igt_kmod_unload(mod_name, 0); + + close(kmsg_fd); +unload: + igt_kmod_unload("kunit", 0); + + for (cmi--; cmi >= 0; cmi--) { + if (strcmp(req_mods[cmi], "kunit") == 0) + continue; + igt_kmod_unload(req_mods[cmi], 0); + } +} + /** * igt_i915_driver_load: * @opts: options to pass to i915 driver diff --git a/lib/igt_kmod.h b/lib/igt_kmod.h index 0898122b..60e7a750 100644 --- a/lib/igt_kmod.h +++ b/lib/igt_kmod.h @@ -28,6 +28,16 @@ #include "igt_list.h" +#define MAX_MOD_NAME_LEN 40 + +/** + * ARRAY_SIZE: + * @arr: static array + * + * Macro to compute the size of the static array @arr. + */ +#define ARRAY_SIZE(arr) (sizeof(arr)/sizeof(arr[0])) + bool igt_kmod_is_loaded(const char *mod_name); void igt_kmod_list_loaded(void); @@ -36,6 +46,9 @@ bool igt_kmod_has_param(const char *mod_name, const char *param); int igt_kmod_load(const char *mod_name, const char *opts); int igt_kmod_unload(const char *mod_name, unsigned int flags); +void igt_kunit(const char *mod_name, const char *options, + const char **req_mods, int req_mod_len); + int igt_i915_driver_load(const char *opts); int igt_i915_driver_unload(void); int __igt_i915_driver_unload(const char **whom); -- 2.35.1
This adds a converted KUnit test module to IGT. Signed-off-by: Isabella Basso <isabbasso@riseup.net> --- lib/igt_kmod.c | 41 ++++++++++++++++++++++++++++++----------- tests/kms_kunit.c | 34 ++++++++++++++++++++++++++++++++++ tests/meson.build | 1 + 3 files changed, 65 insertions(+), 11 deletions(-) create mode 100644 tests/kms_kunit.c diff --git a/lib/igt_kmod.c b/lib/igt_kmod.c index 5d8e8b94..14f1939d 100644 --- a/lib/igt_kmod.c +++ b/lib/igt_kmod.c @@ -364,12 +364,24 @@ static void kmsg_parse_tap(int fd) record[sizeof(record) - 1] = '\0'; - for (;;) { + while (true) { const char *end, *result; ssize_t r; + bool skip = true; - r = read(fd, record, sizeof(record) - 1); - if (r < 0) { + if (!skip) { + end = strchrnul(record, '\n'); + } else { + end = NULL; + skip = false; + } + + r = read(fd, record, + end != NULL ? + (int) (end - record) : + sizeof(record) - 1); + + if (r <= 0) { if (errno == EINTR) continue; @@ -384,19 +396,19 @@ static void kmsg_parse_tap(int fd) break; } - /* deal with partial string from read */ - if (record[r - 1] == NULL) { - fseek(fd, 0, end); - continue; - } - if (!has_num) { result = strstr(record, num_tests_str); if (result) { result += strlen(num_tests_str); end = strchrnul(result, '\n'); - igt_info("[IGT] running %.*s tests...\n", - (int)(end - result), result); + /* in case line > 4096 */ + if (end == NULL) { + igt_info("%s\n", record); + } + else { + igt_info("[IGT] running %.*s tests...\n", + (int)(end - result), result); + } has_num = true; } continue; @@ -407,6 +419,11 @@ static void kmsg_parse_tap(int fd) if (result) { end = strchrnul(result, '\n'); + /* in case line > 4096 */ + if (end == NULL) { + igt_info("%s\n", record); + continue; + } /* subtest succeded (i.e. ok_str) */ result = strstr(record, ok_str); @@ -429,6 +446,7 @@ static void kmsg_parse_tap(int fd) } /* test ended (i.e. end_str_success) */ + /* we should skip the ; in the beginning of the string */ result = strchr(record, ';') + 1; if (strncmp(result, end_str_success, strlen(end_str_success)) == 0) { @@ -444,6 +462,7 @@ static void kmsg_parse_tap(int fd) igt_fail(IGT_EXIT_FAILURE); } } + skip = true; } } diff --git a/tests/kms_kunit.c b/tests/kms_kunit.c new file mode 100644 index 00000000..31566910 --- /dev/null +++ b/tests/kms_kunit.c @@ -0,0 +1,34 @@ +/* + * Copyright © 2021 Isabella Basso do Amaral <isabbasso@riseup.net> + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include <libkmod.h> + +#include "igt.h" +#include "igt_kmod.h" + +IGT_TEST_DESCRIPTION("KUnit DRM damage helper module testing"); + +igt_simple_main +{ + igt_kunit("test-drm_damage_helper", NULL, NULL, 0); +} diff --git a/tests/meson.build b/tests/meson.build index 3dbba7a1..6d3685c3 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -36,6 +36,7 @@ test_progs = [ 'kms_hdmi_inject', 'kms_hdr', 'kms_invalid_mode', + 'kms_kunit', 'kms_lease', 'kms_multipipe_modeset', 'kms_panel_fitting', -- 2.35.1