1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (c) 2020, Oracle and/or its affiliates. 4 * Author: Alan Maguire <alan.maguire@oracle.com> 5 */ 6 7 #include <linux/debugfs.h> 8 #include <linux/module.h> 9 10 #include <kunit/test.h> 11 #include <kunit/test-bug.h> 12 13 #include "string-stream.h" 14 #include "debugfs.h" 15 16 #define KUNIT_DEBUGFS_ROOT "kunit" 17 #define KUNIT_DEBUGFS_RESULTS "results" 18 #define KUNIT_DEBUGFS_RUN "run" 19 20 /* 21 * Create a debugfs representation of test suites: 22 * 23 * Path Semantics 24 * /sys/kernel/debug/kunit/<testsuite>/results Show results of last run for 25 * testsuite 26 * /sys/kernel/debug/kunit/<testsuite>/run Write to this file to trigger 27 * testsuite to run 28 * 29 */ 30 31 static struct dentry *debugfs_rootdir; 32 33 void kunit_debugfs_cleanup(void) 34 { 35 debugfs_remove_recursive(debugfs_rootdir); 36 } 37 38 void kunit_debugfs_init(void) 39 { 40 if (!debugfs_rootdir) 41 debugfs_rootdir = debugfs_create_dir(KUNIT_DEBUGFS_ROOT, NULL); 42 } 43 44 static void debugfs_print_result(struct seq_file *seq, struct string_stream *log) 45 { 46 struct string_stream_fragment *frag_container; 47 48 if (!log) 49 return; 50 51 /* 52 * Walk the fragments so we don't need to allocate a temporary 53 * buffer to hold the entire string. 54 */ 55 spin_lock(&log->lock); 56 list_for_each_entry(frag_container, &log->fragments, node) 57 seq_printf(seq, "%s", frag_container->fragment); 58 spin_unlock(&log->lock); 59 } 60 61 /* 62 * /sys/kernel/debug/kunit/<testsuite>/results shows all results for testsuite. 63 */ 64 static int debugfs_print_results(struct seq_file *seq, void *v) 65 { 66 struct kunit_suite *suite = (struct kunit_suite *)seq->private; 67 enum kunit_status success; 68 struct kunit_case *test_case; 69 70 if (!suite) 71 return 0; 72 73 success = kunit_suite_has_succeeded(suite); 74 75 /* Print KTAP header so the debugfs log can be parsed as valid KTAP. */ 76 seq_puts(seq, "KTAP version 1\n"); 77 seq_puts(seq, "1..1\n"); 78 79 if (suite->status != KUNIT_SKIPPED) { 80 /* Print suite header because it is not stored in the test logs. */ 81 seq_puts(seq, 82 KUNIT_SUBTEST_INDENT "KTAP version 1\n"); 83 seq_printf(seq, 84 KUNIT_SUBTEST_INDENT "# Subtest: %s\n", 85 suite->name); 86 seq_printf(seq, 87 KUNIT_SUBTEST_INDENT "1..%zd\n", 88 kunit_suite_num_test_cases(suite)); 89 90 kunit_suite_for_each_test_case(suite, test_case) 91 debugfs_print_result(seq, test_case->log); 92 } 93 94 debugfs_print_result(seq, suite->log); 95 96 if (suite->status != KUNIT_SKIPPED) 97 seq_printf(seq, "%s %d %s\n", 98 kunit_status_to_ok_not_ok(success), 1, suite->name); 99 else 100 seq_printf(seq, "%s %d %s # SKIP %s\n", 101 kunit_status_to_ok_not_ok(success), 1, suite->name, 102 suite->status_comment); 103 return 0; 104 } 105 106 static int debugfs_release(struct inode *inode, struct file *file) 107 { 108 return single_release(inode, file); 109 } 110 111 static int debugfs_results_open(struct inode *inode, struct file *file) 112 { 113 struct kunit_suite *suite; 114 115 suite = (struct kunit_suite *)inode->i_private; 116 117 return single_open(file, debugfs_print_results, suite); 118 } 119 120 /* 121 * Print a usage message to the debugfs "run" file 122 * (/sys/kernel/debug/kunit/<testsuite>/run) if opened. 123 */ 124 static int debugfs_print_run(struct seq_file *seq, void *v) 125 { 126 struct kunit_suite *suite = (struct kunit_suite *)seq->private; 127 128 seq_puts(seq, "Write to this file to trigger the test suite to run.\n"); 129 seq_printf(seq, "usage: echo \"any string\" > /sys/kernel/debugfs/kunit/%s/run\n", 130 suite->name); 131 return 0; 132 } 133 134 /* 135 * The debugfs "run" file (/sys/kernel/debug/kunit/<testsuite>/run) 136 * contains no information. Write to the file to trigger the test suite 137 * to run. 138 */ 139 static int debugfs_run_open(struct inode *inode, struct file *file) 140 { 141 struct kunit_suite *suite; 142 143 suite = (struct kunit_suite *)inode->i_private; 144 145 return single_open(file, debugfs_print_run, suite); 146 } 147 148 /* 149 * Trigger a test suite to run by writing to the suite's "run" debugfs 150 * file found at: /sys/kernel/debug/kunit/<testsuite>/run 151 * 152 * Note: what is written to this file will not be saved. 153 */ 154 static ssize_t debugfs_run(struct file *file, 155 const char __user *buf, size_t count, loff_t *ppos) 156 { 157 struct inode *f_inode = file->f_inode; 158 struct kunit_suite *suite = (struct kunit_suite *) f_inode->i_private; 159 160 __kunit_test_suites_init(&suite, 1, true); 161 162 return count; 163 } 164 165 static const struct file_operations debugfs_results_fops = { 166 .open = debugfs_results_open, 167 .read = seq_read, 168 .llseek = seq_lseek, 169 .release = debugfs_release, 170 }; 171 172 static const struct file_operations debugfs_run_fops = { 173 .open = debugfs_run_open, 174 .read = seq_read, 175 .write = debugfs_run, 176 .llseek = seq_lseek, 177 .release = debugfs_release, 178 }; 179 180 void kunit_debugfs_create_suite(struct kunit_suite *suite) 181 { 182 struct kunit_case *test_case; 183 struct string_stream *stream; 184 185 /* If suite log already allocated, do not create new debugfs files. */ 186 if (suite->log) 187 return; 188 189 /* 190 * Allocate logs before creating debugfs representation. 191 * The suite->log and test_case->log pointer are expected to be NULL 192 * if there isn't a log, so only set it if the log stream was created 193 * successfully. 194 */ 195 stream = alloc_string_stream(GFP_KERNEL); 196 if (IS_ERR(stream)) 197 return; 198 199 string_stream_set_append_newlines(stream, true); 200 suite->log = stream; 201 202 kunit_suite_for_each_test_case(suite, test_case) { 203 stream = alloc_string_stream(GFP_KERNEL); 204 if (IS_ERR(stream)) 205 goto err; 206 207 string_stream_set_append_newlines(stream, true); 208 test_case->log = stream; 209 } 210 211 suite->debugfs = debugfs_create_dir(suite->name, debugfs_rootdir); 212 213 debugfs_create_file(KUNIT_DEBUGFS_RESULTS, S_IFREG | 0444, 214 suite->debugfs, 215 suite, &debugfs_results_fops); 216 217 /* Do not create file to re-run test if test runs on init */ 218 if (!suite->is_init) { 219 debugfs_create_file(KUNIT_DEBUGFS_RUN, S_IFREG | 0644, 220 suite->debugfs, 221 suite, &debugfs_run_fops); 222 } 223 return; 224 225 err: 226 string_stream_destroy(suite->log); 227 suite->log = NULL; 228 kunit_suite_for_each_test_case(suite, test_case) { 229 string_stream_destroy(test_case->log); 230 test_case->log = NULL; 231 } 232 } 233 234 void kunit_debugfs_destroy_suite(struct kunit_suite *suite) 235 { 236 struct kunit_case *test_case; 237 238 debugfs_remove_recursive(suite->debugfs); 239 string_stream_destroy(suite->log); 240 kunit_suite_for_each_test_case(suite, test_case) 241 string_stream_destroy(test_case->log); 242 } 243