forked from mirrors/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>
This commit is contained in:
		
							parent
							
								
									6c4ea2f48d
								
							
						
					
					
						commit
						c72a870926
					
				
					 2 changed files with 78 additions and 0 deletions
				
			
		|  | @ -8,12 +8,14 @@ | ||||||
| #include <linux/module.h> | #include <linux/module.h> | ||||||
| 
 | 
 | ||||||
| #include <kunit/test.h> | #include <kunit/test.h> | ||||||
|  | #include <kunit/test-bug.h> | ||||||
| 
 | 
 | ||||||
| #include "string-stream.h" | #include "string-stream.h" | ||||||
| #include "debugfs.h" | #include "debugfs.h" | ||||||
| 
 | 
 | ||||||
| #define KUNIT_DEBUGFS_ROOT             "kunit" | #define KUNIT_DEBUGFS_ROOT             "kunit" | ||||||
| #define KUNIT_DEBUGFS_RESULTS          "results" | #define KUNIT_DEBUGFS_RESULTS          "results" | ||||||
|  | #define KUNIT_DEBUGFS_RUN              "run" | ||||||
| 
 | 
 | ||||||
| /*
 | /*
 | ||||||
|  * Create a debugfs representation of test suites: |  * Create a debugfs representation of test suites: | ||||||
|  | @ -21,6 +23,8 @@ | ||||||
|  * Path						Semantics |  * Path						Semantics | ||||||
|  * /sys/kernel/debug/kunit/<testsuite>/results	Show results of last run for |  * /sys/kernel/debug/kunit/<testsuite>/results	Show results of last run for | ||||||
|  *						testsuite |  *						testsuite | ||||||
|  |  * /sys/kernel/debug/kunit/<testsuite>/run	Write to this file to trigger | ||||||
|  |  *						testsuite to run | ||||||
|  * |  * | ||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
|  | @ -101,6 +105,51 @@ static int debugfs_results_open(struct inode *inode, struct file *file) | ||||||
| 	return single_open(file, debugfs_print_results, suite); | 	return single_open(file, debugfs_print_results, suite); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | /*
 | ||||||
|  |  * Print a usage message to the debugfs "run" file | ||||||
|  |  * (/sys/kernel/debug/kunit/<testsuite>/run) if opened. | ||||||
|  |  */ | ||||||
|  | static int debugfs_print_run(struct seq_file *seq, void *v) | ||||||
|  | { | ||||||
|  | 	struct kunit_suite *suite = (struct kunit_suite *)seq->private; | ||||||
|  | 
 | ||||||
|  | 	seq_puts(seq, "Write to this file to trigger the test suite to run.\n"); | ||||||
|  | 	seq_printf(seq, "usage: echo \"any string\" > /sys/kernel/debugfs/kunit/%s/run\n", | ||||||
|  | 			suite->name); | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /*
 | ||||||
|  |  * The debugfs "run" file (/sys/kernel/debug/kunit/<testsuite>/run) | ||||||
|  |  * contains no information. Write to the file to trigger the test suite | ||||||
|  |  * to run. | ||||||
|  |  */ | ||||||
|  | static int debugfs_run_open(struct inode *inode, struct file *file) | ||||||
|  | { | ||||||
|  | 	struct kunit_suite *suite; | ||||||
|  | 
 | ||||||
|  | 	suite = (struct kunit_suite *)inode->i_private; | ||||||
|  | 
 | ||||||
|  | 	return single_open(file, debugfs_print_run, suite); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /*
 | ||||||
|  |  * Trigger a test suite to run by writing to the suite's "run" debugfs | ||||||
|  |  * file found at: /sys/kernel/debug/kunit/<testsuite>/run | ||||||
|  |  * | ||||||
|  |  * Note: what is written to this file will not be saved. | ||||||
|  |  */ | ||||||
|  | static ssize_t debugfs_run(struct file *file, | ||||||
|  | 		const char __user *buf, size_t count, loff_t *ppos) | ||||||
|  | { | ||||||
|  | 	struct inode *f_inode = file->f_inode; | ||||||
|  | 	struct kunit_suite *suite = (struct kunit_suite *) f_inode->i_private; | ||||||
|  | 
 | ||||||
|  | 	__kunit_test_suites_init(&suite, 1); | ||||||
|  | 
 | ||||||
|  | 	return count; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| static const struct file_operations debugfs_results_fops = { | static const struct file_operations debugfs_results_fops = { | ||||||
| 	.open = debugfs_results_open, | 	.open = debugfs_results_open, | ||||||
| 	.read = seq_read, | 	.read = seq_read, | ||||||
|  | @ -108,11 +157,23 @@ static const struct file_operations debugfs_results_fops = { | ||||||
| 	.release = debugfs_release, | 	.release = debugfs_release, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | static const struct file_operations debugfs_run_fops = { | ||||||
|  | 	.open = debugfs_run_open, | ||||||
|  | 	.read = seq_read, | ||||||
|  | 	.write = debugfs_run, | ||||||
|  | 	.llseek = seq_lseek, | ||||||
|  | 	.release = debugfs_release, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| void kunit_debugfs_create_suite(struct kunit_suite *suite) | void kunit_debugfs_create_suite(struct kunit_suite *suite) | ||||||
| { | { | ||||||
| 	struct kunit_case *test_case; | 	struct kunit_case *test_case; | ||||||
| 	struct string_stream *stream; | 	struct string_stream *stream; | ||||||
| 
 | 
 | ||||||
|  | 	/* If suite log already allocated, do not create new debugfs files. */ | ||||||
|  | 	if (suite->log) | ||||||
|  | 		return; | ||||||
|  | 
 | ||||||
| 	/*
 | 	/*
 | ||||||
| 	 * Allocate logs before creating debugfs representation. | 	 * Allocate logs before creating debugfs representation. | ||||||
| 	 * The suite->log and test_case->log pointer are expected to be NULL | 	 * The suite->log and test_case->log pointer are expected to be NULL | ||||||
|  | @ -140,6 +201,13 @@ void kunit_debugfs_create_suite(struct kunit_suite *suite) | ||||||
| 	debugfs_create_file(KUNIT_DEBUGFS_RESULTS, S_IFREG | 0444, | 	debugfs_create_file(KUNIT_DEBUGFS_RESULTS, S_IFREG | 0444, | ||||||
| 			    suite->debugfs, | 			    suite->debugfs, | ||||||
| 			    suite, &debugfs_results_fops); | 			    suite, &debugfs_results_fops); | ||||||
|  | 
 | ||||||
|  | 	/* Do not create file to re-run test if test runs on init */ | ||||||
|  | 	if (!suite->is_init) { | ||||||
|  | 		debugfs_create_file(KUNIT_DEBUGFS_RUN, S_IFREG | 0644, | ||||||
|  | 				    suite->debugfs, | ||||||
|  | 				    suite, &debugfs_run_fops); | ||||||
|  | 	} | ||||||
| 	return; | 	return; | ||||||
| 
 | 
 | ||||||
| err: | err: | ||||||
|  |  | ||||||
|  | @ -13,6 +13,7 @@ | ||||||
| #include <linux/kernel.h> | #include <linux/kernel.h> | ||||||
| #include <linux/module.h> | #include <linux/module.h> | ||||||
| #include <linux/moduleparam.h> | #include <linux/moduleparam.h> | ||||||
|  | #include <linux/mutex.h> | ||||||
| #include <linux/panic.h> | #include <linux/panic.h> | ||||||
| #include <linux/sched/debug.h> | #include <linux/sched/debug.h> | ||||||
| #include <linux/sched.h> | #include <linux/sched.h> | ||||||
|  | @ -22,6 +23,8 @@ | ||||||
| #include "string-stream.h" | #include "string-stream.h" | ||||||
| #include "try-catch-impl.h" | #include "try-catch-impl.h" | ||||||
| 
 | 
 | ||||||
|  | static DEFINE_MUTEX(kunit_run_lock); | ||||||
|  | 
 | ||||||
| /*
 | /*
 | ||||||
|  * Hook to fail the current test and print an error message to the log. |  * Hook to fail the current test and print an error message to the log. | ||||||
|  */ |  */ | ||||||
|  | @ -692,6 +695,7 @@ static void kunit_init_suite(struct kunit_suite *suite) | ||||||
| 	kunit_debugfs_create_suite(suite); | 	kunit_debugfs_create_suite(suite); | ||||||
| 	suite->status_comment[0] = '\0'; | 	suite->status_comment[0] = '\0'; | ||||||
| 	suite->suite_init_err = 0; | 	suite->suite_init_err = 0; | ||||||
|  | 	string_stream_clear(suite->log); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool kunit_enabled(void) | bool kunit_enabled(void) | ||||||
|  | @ -710,6 +714,11 @@ int __kunit_test_suites_init(struct kunit_suite * const * const suites, int num_ | ||||||
| 
 | 
 | ||||||
| 	kunit_suite_counter = 1; | 	kunit_suite_counter = 1; | ||||||
| 
 | 
 | ||||||
|  | 	/* Use mutex lock to guard against running tests concurrently. */ | ||||||
|  | 	if (mutex_lock_interruptible(&kunit_run_lock)) { | ||||||
|  | 		pr_err("kunit: test interrupted\n"); | ||||||
|  | 		return -EINTR; | ||||||
|  | 	} | ||||||
| 	static_branch_inc(&kunit_running); | 	static_branch_inc(&kunit_running); | ||||||
| 
 | 
 | ||||||
| 	for (i = 0; i < num_suites; i++) { | 	for (i = 0; i < num_suites; i++) { | ||||||
|  | @ -718,6 +727,7 @@ int __kunit_test_suites_init(struct kunit_suite * const * const suites, int num_ | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	static_branch_dec(&kunit_running); | 	static_branch_dec(&kunit_running); | ||||||
|  | 	mutex_unlock(&kunit_run_lock); | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
| EXPORT_SYMBOL_GPL(__kunit_test_suites_init); | EXPORT_SYMBOL_GPL(__kunit_test_suites_init); | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue
	
	 Rae Moar
						Rae Moar