xref: /linux/kernel/trace/rv/rv_monitors_test.c (revision 55ee4b931a7ffedc886175d265dd6e6d08fd4151)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (C) 2026-2029 Red Hat, Inc. Gabriele Monaco <gmonaco@redhat.com>
4  *
5  * RV monitor kunit tests:
6  *   Tests the RV monitors by triggering fake events to verify monitor
7  *   behavior and reactions. Tests start from the first defined event and
8  *   trigger events in order to verify error detection.
9  */
10 #include <rv/kunit.h>
11 #include <kunit/test-bug.h>
12 #include <linux/kernel.h>
13 #include <linux/rv.h>
14 #include "rv.h"
15 
16 /*
17  * An easy way to pass the context is to use kunit_get_current_test()->priv,
18  * but this doesn't always work (e.g. a reactor running from another context
19  * like softirq). Store the current value here whenever a test is running.
20  */
21 static struct rv_kunit_ctx *active_ctx;
22 
23 __printf(1, 0)
24 static void rv_kunit_mock_react(const char *msg, va_list args)
25 {
26 	if (active_ctx)
27 		++active_ctx->reactions;
28 }
29 
30 /*
31  * teardown_test - Disable the monitor for a kunit test
32  *
33  * Since per-task monitors are special, make sure we reset all the ones we
34  * started manually here, if required.
35  */
36 void teardown_test(void *arg)
37 {
38 	const struct rv_kunit_mon *mon = arg;
39 	struct kunit *test = kunit_get_current_test();
40 
41 	if (test) {
42 		struct rv_kunit_ctx *ctx = test->priv;
43 
44 		RV_KUNIT_EXPECT_NO_REACTION(test, ctx);
45 
46 		if (mon->is_per_task && mon->task_reset) {
47 			for (int i = 0; i < ctx->mock_task_count; i++)
48 				mon->task_reset(ctx->mock_tasks[i]);
49 			synchronize_rcu();
50 		}
51 	}
52 
53 	mon->rv_this->enabled = 0;
54 
55 	if (mon->rv_this->reactor)
56 		mon->rv_this->react = mon->rv_this->reactor->react;
57 	else
58 		mon->rv_this->react = NULL;
59 	active_ctx = NULL;
60 	rv_mock_current(NULL);
61 
62 	if (mon->is_per_task)
63 		*mon->task_slot = RV_PER_TASK_MONITOR_INIT;
64 	else
65 		mon->monitor_destroy();
66 }
67 
68 /*
69  * prepare_test - Enable the monitor for a kunit test
70  *
71  * Do the bare minimum to set up the monitor, per-task monitors are special as
72  * "real" initialisation/destruction iterates over real tasks, and may register
73  * handlers. All we need is to select the right slot in the task_struct.
74  */
75 void prepare_test(struct kunit *test, const struct rv_kunit_mon *mon)
76 {
77 	KUNIT_ASSERT_FALSE(test, mon->rv_this->enabled);
78 
79 	active_ctx = test->priv;
80 	mon->rv_this->react = rv_kunit_mock_react;
81 
82 	if (mon->is_per_task)
83 		*mon->task_slot = 0;
84 	else
85 		KUNIT_ASSERT_EQ(test, mon->monitor_init(), 0);
86 
87 	mon->rv_this->enabled = 1;
88 
89 	KUNIT_ASSERT_EQ(test, 0,
90 			kunit_add_action_or_reset(test, teardown_test, (void *)mon));
91 }
92 
93 struct task_struct *rv_kunit_alloc_mock_task(struct kunit *test)
94 {
95 	struct rv_kunit_ctx *ctx = test->priv;
96 	struct task_struct *tsk;
97 
98 	KUNIT_ASSERT_LT(test, ctx->mock_task_count, RV_KUNIT_MAX_MOCK_TASKS);
99 
100 	tsk = kunit_kzalloc(test, sizeof(struct task_struct), GFP_KERNEL);
101 	KUNIT_ASSERT_NOT_NULL(test, tsk);
102 
103 	if (!IS_ENABLED(CONFIG_THREAD_INFO_IN_TASK)) {
104 		tsk->stack = kunit_kzalloc(test, sizeof(struct thread_info), GFP_KERNEL);
105 		KUNIT_ASSERT_NOT_NULL(test, tsk->stack);
106 	}
107 
108 	ctx->mock_tasks[ctx->mock_task_count++] = tsk;
109 	return tsk;
110 }
111 
112 static int rv_mon_test_init(struct kunit *test)
113 {
114 	struct rv_kunit_ctx *ctx;
115 
116 	ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL);
117 	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx);
118 
119 	test->priv = ctx;
120 
121 	return 0;
122 }
123 
124 static void __maybe_unused rv_test_stub(struct kunit *test)
125 {
126 	kunit_skip(test, "Monitor not enabled\n");
127 }
128 
129 /*
130  * rv_test_dummy - test reactions work as expected
131  */
132 static void rv_test_dummy(struct kunit *test)
133 {
134 	struct rv_kunit_ctx *ctx = test->priv;
135 	static struct rv_monitor dummy_monitor = {
136 		.name = "dummy",
137 		.react = rv_kunit_mock_react,
138 	};
139 
140 	active_ctx = ctx;
141 
142 	RV_KUNIT_EXPECT_REACTION_HERE(test, ctx)
143 		rv_react(&dummy_monitor, "dummy");
144 	RV_KUNIT_EXPECT_NO_REACTION(test, ctx);
145 
146 	active_ctx = NULL;
147 }
148 
149 #include "monitors/sco/sco_kunit.c"
150 #include "monitors/sssw/sssw_kunit.c"
151 #include "monitors/sts/sts_kunit.c"
152 #include "monitors/opid/opid_kunit.c"
153 #include "monitors/nomiss/nomiss_kunit.c"
154 #include "monitors/pagefault/pagefault_kunit.c"
155 #include "monitors/sleep/sleep_kunit.c"
156 
157 static struct kunit_case rv_mon_test_cases[] = {
158 	KUNIT_CASE(rv_test_dummy),
159 	KUNIT_CASE(rv_test_sco),
160 	KUNIT_CASE(rv_test_sssw),
161 	KUNIT_CASE(rv_test_sts),
162 	KUNIT_CASE(rv_test_opid),
163 	KUNIT_CASE(rv_test_nomiss),
164 	KUNIT_CASE(rv_test_pagefault),
165 	KUNIT_CASE(rv_test_sleep),
166 	{}
167 };
168 
169 static struct kunit_suite rv_mon_test_suite = {
170 	.name = "rv_mon",
171 	.suite_init = rv_set_testing,
172 	.suite_exit = rv_clear_testing,
173 	.init = rv_mon_test_init,
174 	.test_cases = rv_mon_test_cases,
175 };
176 
177 kunit_test_suites(&rv_mon_test_suite);
178 
179 MODULE_AUTHOR("Gabriele Monaco <gmonaco@redhat.com>");
180 MODULE_DESCRIPTION("RV monitor kunit tests: test monitors by triggering reactions");
181 MODULE_LICENSE("GPL");
182 MODULE_IMPORT_NS("EXPORTED_FOR_KUNIT_TESTING");
183