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