Skip to content

Commit 3593e67

Browse files
committed
Merge tag 'linux_kselftest-kunit-fixes-7.0-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/shuah/linux-kselftest
Pull kunit fixes from Shuah Khan: - Fix rust warnings when CONFIG_PRINTK is disabled - Reduce stack usage in kunit_run_tests() to fix warnings when CONFIG_FRAME_WARN is set to a relatively low value - Update email address for David Gow - Copy caller args in kunit tool in run_kernel to prevent mutation * tag 'linux_kselftest-kunit-fixes-7.0-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/shuah/linux-kselftest: kunit: reduce stack usage in kunit_run_tests() kunit: tool: copy caller args in run_kernel to prevent mutation rust: kunit: fix warning when !CONFIG_PRINTK MAINTAINERS: Update email address for David Gow
2 parents 6516904 + b11b9b6 commit 3593e67

6 files changed

Lines changed: 166 additions & 110 deletions

File tree

.mailmap

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,7 @@ Daniele Alessandrelli <daniele.alessandrelli@gmail.com> <daniele.alessandrelli@i
219219
Danilo Krummrich <dakr@kernel.org> <dakr@redhat.com>
220220
David Brownell <david-b@pacbell.net>
221221
David Collins <quic_collinsd@quicinc.com> <collinsd@codeaurora.org>
222+
David Gow <david@davidgow.net> <davidgow@google.com>
222223
David Heidelberg <david@ixit.cz> <d.okias@gmail.com>
223224
David Hildenbrand <david@kernel.org> <david@redhat.com>
224225
David Rheinsberg <david@readahead.eu> <dh.herrmann@gmail.com>

MAINTAINERS

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13938,7 +13938,7 @@ F: fs/smb/server/
1393813938

1393913939
KERNEL UNIT TESTING FRAMEWORK (KUnit)
1394013940
M: Brendan Higgins <brendan.higgins@linux.dev>
13941-
M: David Gow <davidgow@google.com>
13941+
M: David Gow <david@davidgow.net>
1394213942
R: Rae Moar <raemoar63@gmail.com>
1394313943
L: linux-kselftest@vger.kernel.org
1394413944
L: kunit-dev@googlegroups.com
@@ -14758,7 +14758,7 @@ F: drivers/misc/lis3lv02d/
1475814758
F: drivers/platform/x86/hp/hp_accel.c
1475914759

1476014760
LIST KUNIT TEST
14761-
M: David Gow <davidgow@google.com>
14761+
M: David Gow <david@davidgow.net>
1476214762
L: linux-kselftest@vger.kernel.org
1476314763
L: kunit-dev@googlegroups.com
1476414764
S: Maintained

lib/kunit/test.c

Lines changed: 125 additions & 106 deletions
Original file line numberDiff line numberDiff line change
@@ -94,19 +94,19 @@ struct kunit_result_stats {
9494
unsigned long total;
9595
};
9696

97-
static bool kunit_should_print_stats(struct kunit_result_stats stats)
97+
static bool kunit_should_print_stats(struct kunit_result_stats *stats)
9898
{
9999
if (kunit_stats_enabled == 0)
100100
return false;
101101

102102
if (kunit_stats_enabled == 2)
103103
return true;
104104

105-
return (stats.total > 1);
105+
return (stats->total > 1);
106106
}
107107

108108
static void kunit_print_test_stats(struct kunit *test,
109-
struct kunit_result_stats stats)
109+
struct kunit_result_stats *stats)
110110
{
111111
if (!kunit_should_print_stats(stats))
112112
return;
@@ -115,10 +115,10 @@ static void kunit_print_test_stats(struct kunit *test,
115115
KUNIT_SUBTEST_INDENT
116116
"# %s: pass:%lu fail:%lu skip:%lu total:%lu",
117117
test->name,
118-
stats.passed,
119-
stats.failed,
120-
stats.skipped,
121-
stats.total);
118+
stats->passed,
119+
stats->failed,
120+
stats->skipped,
121+
stats->total);
122122
}
123123

124124
/* Append formatted message to log. */
@@ -600,26 +600,26 @@ static void kunit_run_case_catch_errors(struct kunit_suite *suite,
600600
}
601601

602602
static void kunit_print_suite_stats(struct kunit_suite *suite,
603-
struct kunit_result_stats suite_stats,
604-
struct kunit_result_stats param_stats)
603+
struct kunit_result_stats *suite_stats,
604+
struct kunit_result_stats *param_stats)
605605
{
606606
if (kunit_should_print_stats(suite_stats)) {
607607
kunit_log(KERN_INFO, suite,
608608
"# %s: pass:%lu fail:%lu skip:%lu total:%lu",
609609
suite->name,
610-
suite_stats.passed,
611-
suite_stats.failed,
612-
suite_stats.skipped,
613-
suite_stats.total);
610+
suite_stats->passed,
611+
suite_stats->failed,
612+
suite_stats->skipped,
613+
suite_stats->total);
614614
}
615615

616616
if (kunit_should_print_stats(param_stats)) {
617617
kunit_log(KERN_INFO, suite,
618618
"# Totals: pass:%lu fail:%lu skip:%lu total:%lu",
619-
param_stats.passed,
620-
param_stats.failed,
621-
param_stats.skipped,
622-
param_stats.total);
619+
param_stats->passed,
620+
param_stats->failed,
621+
param_stats->skipped,
622+
param_stats->total);
623623
}
624624
}
625625

@@ -681,13 +681,116 @@ static void kunit_init_parent_param_test(struct kunit_case *test_case, struct ku
681681
}
682682
}
683683

684-
int kunit_run_tests(struct kunit_suite *suite)
684+
static noinline_for_stack void
685+
kunit_run_param_test(struct kunit_suite *suite, struct kunit_case *test_case,
686+
struct kunit *test,
687+
struct kunit_result_stats *suite_stats,
688+
struct kunit_result_stats *total_stats,
689+
struct kunit_result_stats *param_stats)
685690
{
686691
char param_desc[KUNIT_PARAM_DESC_SIZE];
692+
const void *curr_param;
693+
694+
kunit_init_parent_param_test(test_case, test);
695+
if (test_case->status == KUNIT_FAILURE) {
696+
kunit_update_stats(param_stats, test->status);
697+
return;
698+
}
699+
/* Get initial param. */
700+
param_desc[0] = '\0';
701+
/* TODO: Make generate_params try-catch */
702+
curr_param = test_case->generate_params(test, NULL, param_desc);
703+
test_case->status = KUNIT_SKIPPED;
704+
kunit_log(KERN_INFO, test, KUNIT_SUBTEST_INDENT KUNIT_SUBTEST_INDENT
705+
"KTAP version 1\n");
706+
kunit_log(KERN_INFO, test, KUNIT_SUBTEST_INDENT KUNIT_SUBTEST_INDENT
707+
"# Subtest: %s", test_case->name);
708+
if (test->params_array.params &&
709+
test_case->generate_params == kunit_array_gen_params) {
710+
kunit_log(KERN_INFO, test, KUNIT_SUBTEST_INDENT
711+
KUNIT_SUBTEST_INDENT "1..%zd\n",
712+
test->params_array.num_params);
713+
}
714+
715+
while (curr_param) {
716+
struct kunit param_test = {
717+
.param_value = curr_param,
718+
.param_index = ++test->param_index,
719+
.parent = test,
720+
};
721+
kunit_init_test(&param_test, test_case->name, NULL);
722+
param_test.log = test_case->log;
723+
kunit_run_case_catch_errors(suite, test_case, &param_test);
724+
725+
if (param_desc[0] == '\0') {
726+
snprintf(param_desc, sizeof(param_desc),
727+
"param-%d", param_test.param_index);
728+
}
729+
730+
kunit_print_ok_not_ok(&param_test, KUNIT_LEVEL_CASE_PARAM,
731+
param_test.status,
732+
param_test.param_index,
733+
param_desc,
734+
param_test.status_comment);
735+
736+
kunit_update_stats(param_stats, param_test.status);
737+
738+
/* Get next param. */
739+
param_desc[0] = '\0';
740+
curr_param = test_case->generate_params(test, curr_param,
741+
param_desc);
742+
}
743+
/*
744+
* TODO: Put into a try catch. Since we don't need suite->exit
745+
* for it we can't reuse kunit_try_run_cleanup for this yet.
746+
*/
747+
if (test_case->param_exit)
748+
test_case->param_exit(test);
749+
/* TODO: Put this kunit_cleanup into a try-catch. */
750+
kunit_cleanup(test);
751+
}
752+
753+
static noinline_for_stack void
754+
kunit_run_one_test(struct kunit_suite *suite, struct kunit_case *test_case,
755+
struct kunit_result_stats *suite_stats,
756+
struct kunit_result_stats *total_stats)
757+
{
758+
struct kunit test = { .param_value = NULL, .param_index = 0 };
759+
struct kunit_result_stats param_stats = { 0 };
760+
761+
kunit_init_test(&test, test_case->name, test_case->log);
762+
if (test_case->status == KUNIT_SKIPPED) {
763+
/* Test marked as skip */
764+
test.status = KUNIT_SKIPPED;
765+
kunit_update_stats(&param_stats, test.status);
766+
} else if (!test_case->generate_params) {
767+
/* Non-parameterised test. */
768+
test_case->status = KUNIT_SKIPPED;
769+
kunit_run_case_catch_errors(suite, test_case, &test);
770+
kunit_update_stats(&param_stats, test.status);
771+
} else {
772+
kunit_run_param_test(suite, test_case, &test, suite_stats,
773+
total_stats, &param_stats);
774+
}
775+
kunit_print_attr((void *)test_case, true, KUNIT_LEVEL_CASE);
776+
777+
kunit_print_test_stats(&test, &param_stats);
778+
779+
kunit_print_ok_not_ok(&test, KUNIT_LEVEL_CASE, test_case->status,
780+
kunit_test_case_num(suite, test_case),
781+
test_case->name,
782+
test.status_comment);
783+
784+
kunit_update_stats(suite_stats, test_case->status);
785+
kunit_accumulate_stats(total_stats, param_stats);
786+
}
787+
788+
789+
int kunit_run_tests(struct kunit_suite *suite)
790+
{
687791
struct kunit_case *test_case;
688792
struct kunit_result_stats suite_stats = { 0 };
689793
struct kunit_result_stats total_stats = { 0 };
690-
const void *curr_param;
691794

692795
/* Taint the kernel so we know we've run tests. */
693796
add_taint(TAINT_TEST, LOCKDEP_STILL_OK);
@@ -703,97 +806,13 @@ int kunit_run_tests(struct kunit_suite *suite)
703806

704807
kunit_print_suite_start(suite);
705808

706-
kunit_suite_for_each_test_case(suite, test_case) {
707-
struct kunit test = { .param_value = NULL, .param_index = 0 };
708-
struct kunit_result_stats param_stats = { 0 };
709-
710-
kunit_init_test(&test, test_case->name, test_case->log);
711-
if (test_case->status == KUNIT_SKIPPED) {
712-
/* Test marked as skip */
713-
test.status = KUNIT_SKIPPED;
714-
kunit_update_stats(&param_stats, test.status);
715-
} else if (!test_case->generate_params) {
716-
/* Non-parameterised test. */
717-
test_case->status = KUNIT_SKIPPED;
718-
kunit_run_case_catch_errors(suite, test_case, &test);
719-
kunit_update_stats(&param_stats, test.status);
720-
} else {
721-
kunit_init_parent_param_test(test_case, &test);
722-
if (test_case->status == KUNIT_FAILURE) {
723-
kunit_update_stats(&param_stats, test.status);
724-
goto test_case_end;
725-
}
726-
/* Get initial param. */
727-
param_desc[0] = '\0';
728-
/* TODO: Make generate_params try-catch */
729-
curr_param = test_case->generate_params(&test, NULL, param_desc);
730-
test_case->status = KUNIT_SKIPPED;
731-
kunit_log(KERN_INFO, &test, KUNIT_SUBTEST_INDENT KUNIT_SUBTEST_INDENT
732-
"KTAP version 1\n");
733-
kunit_log(KERN_INFO, &test, KUNIT_SUBTEST_INDENT KUNIT_SUBTEST_INDENT
734-
"# Subtest: %s", test_case->name);
735-
if (test.params_array.params &&
736-
test_case->generate_params == kunit_array_gen_params) {
737-
kunit_log(KERN_INFO, &test, KUNIT_SUBTEST_INDENT
738-
KUNIT_SUBTEST_INDENT "1..%zd\n",
739-
test.params_array.num_params);
740-
}
741-
742-
while (curr_param) {
743-
struct kunit param_test = {
744-
.param_value = curr_param,
745-
.param_index = ++test.param_index,
746-
.parent = &test,
747-
};
748-
kunit_init_test(&param_test, test_case->name, NULL);
749-
param_test.log = test_case->log;
750-
kunit_run_case_catch_errors(suite, test_case, &param_test);
751-
752-
if (param_desc[0] == '\0') {
753-
snprintf(param_desc, sizeof(param_desc),
754-
"param-%d", param_test.param_index);
755-
}
756-
757-
kunit_print_ok_not_ok(&param_test, KUNIT_LEVEL_CASE_PARAM,
758-
param_test.status,
759-
param_test.param_index,
760-
param_desc,
761-
param_test.status_comment);
762-
763-
kunit_update_stats(&param_stats, param_test.status);
764-
765-
/* Get next param. */
766-
param_desc[0] = '\0';
767-
curr_param = test_case->generate_params(&test, curr_param,
768-
param_desc);
769-
}
770-
/*
771-
* TODO: Put into a try catch. Since we don't need suite->exit
772-
* for it we can't reuse kunit_try_run_cleanup for this yet.
773-
*/
774-
if (test_case->param_exit)
775-
test_case->param_exit(&test);
776-
/* TODO: Put this kunit_cleanup into a try-catch. */
777-
kunit_cleanup(&test);
778-
}
779-
test_case_end:
780-
kunit_print_attr((void *)test_case, true, KUNIT_LEVEL_CASE);
781-
782-
kunit_print_test_stats(&test, param_stats);
783-
784-
kunit_print_ok_not_ok(&test, KUNIT_LEVEL_CASE, test_case->status,
785-
kunit_test_case_num(suite, test_case),
786-
test_case->name,
787-
test.status_comment);
788-
789-
kunit_update_stats(&suite_stats, test_case->status);
790-
kunit_accumulate_stats(&total_stats, param_stats);
791-
}
809+
kunit_suite_for_each_test_case(suite, test_case)
810+
kunit_run_one_test(suite, test_case, &suite_stats, &total_stats);
792811

793812
if (suite->suite_exit)
794813
suite->suite_exit(suite);
795814

796-
kunit_print_suite_stats(suite, suite_stats, total_stats);
815+
kunit_print_suite_stats(suite, &suite_stats, &total_stats);
797816
suite_end:
798817
kunit_print_suite_end(suite);
799818

rust/kernel/kunit.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@ use crate::prelude::*;
1414
/// Public but hidden since it should only be used from KUnit generated code.
1515
#[doc(hidden)]
1616
pub fn err(args: fmt::Arguments<'_>) {
17+
// `args` is unused if `CONFIG_PRINTK` is not set - this avoids a build-time warning.
18+
#[cfg(not(CONFIG_PRINTK))]
19+
let _ = args;
20+
1721
// SAFETY: The format string is null-terminated and the `%pA` specifier matches the argument we
1822
// are passing.
1923
#[cfg(CONFIG_PRINTK)]
@@ -30,6 +34,10 @@ pub fn err(args: fmt::Arguments<'_>) {
3034
/// Public but hidden since it should only be used from KUnit generated code.
3135
#[doc(hidden)]
3236
pub fn info(args: fmt::Arguments<'_>) {
37+
// `args` is unused if `CONFIG_PRINTK` is not set - this avoids a build-time warning.
38+
#[cfg(not(CONFIG_PRINTK))]
39+
let _ = args;
40+
3341
// SAFETY: The format string is null-terminated and the `%pA` specifier matches the argument we
3442
// are passing.
3543
#[cfg(CONFIG_PRINTK)]

tools/testing/kunit/kunit_kernel.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -346,8 +346,10 @@ def build_kernel(self, jobs: int, build_dir: str, make_options: Optional[List[st
346346
return self.validate_config(build_dir)
347347

348348
def run_kernel(self, args: Optional[List[str]]=None, build_dir: str='', filter_glob: str='', filter: str='', filter_action: Optional[str]=None, timeout: Optional[int]=None) -> Iterator[str]:
349-
if not args:
350-
args = []
349+
# Copy to avoid mutating the caller-supplied list. exec_tests() reuses
350+
# the same args across repeated run_kernel() calls (e.g. --run_isolated),
351+
# so appending to the original would accumulate stale flags on each call.
352+
args = list(args) if args else []
351353
if filter_glob:
352354
args.append('kunit.filter_glob=' + filter_glob)
353355
if filter:

tools/testing/kunit/kunit_tool_test.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -503,6 +503,32 @@ def fake_start(unused_args, unused_build_dir):
503503
with open(kunit_kernel.get_outfile_path(build_dir), 'rt') as outfile:
504504
self.assertEqual(outfile.read(), 'hi\nbye\n', msg='Missing some output')
505505

506+
def test_run_kernel_args_not_mutated(self):
507+
"""Verify run_kernel() copies args so callers can reuse them."""
508+
start_calls = []
509+
510+
def fake_start(start_args, unused_build_dir):
511+
start_calls.append(list(start_args))
512+
return subprocess.Popen(['printf', 'KTAP version 1\n'],
513+
text=True, stdout=subprocess.PIPE)
514+
515+
with tempfile.TemporaryDirectory('') as build_dir:
516+
tree = kunit_kernel.LinuxSourceTree(build_dir,
517+
kunitconfig_paths=[os.devnull])
518+
with mock.patch.object(tree._ops, 'start', side_effect=fake_start), \
519+
mock.patch.object(kunit_kernel.subprocess, 'call'):
520+
kernel_args = ['mem=1G']
521+
for _ in tree.run_kernel(args=kernel_args, build_dir=build_dir,
522+
filter_glob='suite.test1'):
523+
pass
524+
for _ in tree.run_kernel(args=kernel_args, build_dir=build_dir,
525+
filter_glob='suite.test2'):
526+
pass
527+
self.assertEqual(kernel_args, ['mem=1G'],
528+
'run_kernel() should not modify caller args')
529+
self.assertIn('kunit.filter_glob=suite.test1', start_calls[0])
530+
self.assertIn('kunit.filter_glob=suite.test2', start_calls[1])
531+
506532
def test_build_reconfig_no_config(self):
507533
with tempfile.TemporaryDirectory('') as build_dir:
508534
with open(kunit_kernel.get_kunitconfig_path(build_dir), 'w') as f:

0 commit comments

Comments
 (0)