Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

kunit: add ability to run tests after boot using debugfs

Add functionality to run built-in tests after boot by writing to a
debugfs file.

Add a new debugfs file labeled "run" for each test suite to use for
this purpose.

As an example, write to the file using the following:

echo "any string" > /sys/kernel/debugfs/kunit/<testsuite>/run

This will trigger the test suite to run and will print results to the
kernel log.

To guard against running tests concurrently with this feature, add a
mutex lock around running kunit. This supports the current practice of
not allowing tests to be run concurrently on the same kernel.

This new functionality could be used to design a parameter
injection feature in the future.

Fixed up merge conflict duing rebase to Linux 6.7-rc6
Signed-off-by: Shuah Khan <skhan@linuxfoundation.org>

Reviewed-by: David Gow <davidgow@google.com>
Signed-off-by: Rae Moar <rmoar@google.com>
Signed-off-by: Shuah Khan <skhan@linuxfoundation.org>

authored by

Rae Moar and committed by
Shuah Khan
c72a8709 6c4ea2f4

+78
+68
lib/kunit/debugfs.c
··· 8 8 #include <linux/module.h> 9 9 10 10 #include <kunit/test.h> 11 + #include <kunit/test-bug.h> 11 12 12 13 #include "string-stream.h" 13 14 #include "debugfs.h" 14 15 15 16 #define KUNIT_DEBUGFS_ROOT "kunit" 16 17 #define KUNIT_DEBUGFS_RESULTS "results" 18 + #define KUNIT_DEBUGFS_RUN "run" 17 19 18 20 /* 19 21 * Create a debugfs representation of test suites: ··· 23 21 * Path Semantics 24 22 * /sys/kernel/debug/kunit/<testsuite>/results Show results of last run for 25 23 * testsuite 24 + * /sys/kernel/debug/kunit/<testsuite>/run Write to this file to trigger 25 + * testsuite to run 26 26 * 27 27 */ 28 28 ··· 105 101 return single_open(file, debugfs_print_results, suite); 106 102 } 107 103 104 + /* 105 + * Print a usage message to the debugfs "run" file 106 + * (/sys/kernel/debug/kunit/<testsuite>/run) if opened. 107 + */ 108 + static int debugfs_print_run(struct seq_file *seq, void *v) 109 + { 110 + struct kunit_suite *suite = (struct kunit_suite *)seq->private; 111 + 112 + seq_puts(seq, "Write to this file to trigger the test suite to run.\n"); 113 + seq_printf(seq, "usage: echo \"any string\" > /sys/kernel/debugfs/kunit/%s/run\n", 114 + suite->name); 115 + return 0; 116 + } 117 + 118 + /* 119 + * The debugfs "run" file (/sys/kernel/debug/kunit/<testsuite>/run) 120 + * contains no information. Write to the file to trigger the test suite 121 + * to run. 122 + */ 123 + static int debugfs_run_open(struct inode *inode, struct file *file) 124 + { 125 + struct kunit_suite *suite; 126 + 127 + suite = (struct kunit_suite *)inode->i_private; 128 + 129 + return single_open(file, debugfs_print_run, suite); 130 + } 131 + 132 + /* 133 + * Trigger a test suite to run by writing to the suite's "run" debugfs 134 + * file found at: /sys/kernel/debug/kunit/<testsuite>/run 135 + * 136 + * Note: what is written to this file will not be saved. 137 + */ 138 + static ssize_t debugfs_run(struct file *file, 139 + const char __user *buf, size_t count, loff_t *ppos) 140 + { 141 + struct inode *f_inode = file->f_inode; 142 + struct kunit_suite *suite = (struct kunit_suite *) f_inode->i_private; 143 + 144 + __kunit_test_suites_init(&suite, 1); 145 + 146 + return count; 147 + } 148 + 108 149 static const struct file_operations debugfs_results_fops = { 109 150 .open = debugfs_results_open, 110 151 .read = seq_read, 152 + .llseek = seq_lseek, 153 + .release = debugfs_release, 154 + }; 155 + 156 + static const struct file_operations debugfs_run_fops = { 157 + .open = debugfs_run_open, 158 + .read = seq_read, 159 + .write = debugfs_run, 111 160 .llseek = seq_lseek, 112 161 .release = debugfs_release, 113 162 }; ··· 169 112 { 170 113 struct kunit_case *test_case; 171 114 struct string_stream *stream; 115 + 116 + /* If suite log already allocated, do not create new debugfs files. */ 117 + if (suite->log) 118 + return; 172 119 173 120 /* 174 121 * Allocate logs before creating debugfs representation. ··· 201 140 debugfs_create_file(KUNIT_DEBUGFS_RESULTS, S_IFREG | 0444, 202 141 suite->debugfs, 203 142 suite, &debugfs_results_fops); 143 + 144 + /* Do not create file to re-run test if test runs on init */ 145 + if (!suite->is_init) { 146 + debugfs_create_file(KUNIT_DEBUGFS_RUN, S_IFREG | 0644, 147 + suite->debugfs, 148 + suite, &debugfs_run_fops); 149 + } 204 150 return; 205 151 206 152 err:
+10
lib/kunit/test.c
··· 13 13 #include <linux/kernel.h> 14 14 #include <linux/module.h> 15 15 #include <linux/moduleparam.h> 16 + #include <linux/mutex.h> 16 17 #include <linux/panic.h> 17 18 #include <linux/sched/debug.h> 18 19 #include <linux/sched.h> ··· 22 21 #include "hooks-impl.h" 23 22 #include "string-stream.h" 24 23 #include "try-catch-impl.h" 24 + 25 + static DEFINE_MUTEX(kunit_run_lock); 25 26 26 27 /* 27 28 * Hook to fail the current test and print an error message to the log. ··· 695 692 kunit_debugfs_create_suite(suite); 696 693 suite->status_comment[0] = '\0'; 697 694 suite->suite_init_err = 0; 695 + string_stream_clear(suite->log); 698 696 } 699 697 700 698 bool kunit_enabled(void) ··· 714 710 715 711 kunit_suite_counter = 1; 716 712 713 + /* Use mutex lock to guard against running tests concurrently. */ 714 + if (mutex_lock_interruptible(&kunit_run_lock)) { 715 + pr_err("kunit: test interrupted\n"); 716 + return -EINTR; 717 + } 717 718 static_branch_inc(&kunit_running); 718 719 719 720 for (i = 0; i < num_suites; i++) { ··· 727 718 } 728 719 729 720 static_branch_dec(&kunit_running); 721 + mutex_unlock(&kunit_run_lock); 730 722 return 0; 731 723 } 732 724 EXPORT_SYMBOL_GPL(__kunit_test_suites_init);