projects/linux·blob master · refs

153 lines · 3.9 KiB

1// SPDX-License-Identifier: GPL-2.0-only
2
3#include <kunit/test.h>
4
5#include <linux/ratelimit.h>
6#include <linux/module.h>
7#include <linux/kthread.h>
8#include <linux/cpumask.h>
9
10/* a simple boot-time regression test */
11
12#define TESTRL_INTERVAL (5 * HZ)
13static DEFINE_RATELIMIT_STATE(testrl, TESTRL_INTERVAL, 3);
14
15#define test_ratelimited(test, expected) \
16 KUNIT_ASSERT_EQ(test, ___ratelimit(&testrl, "test_ratelimit_smoke"), (expected))
17
18static void test_ratelimit_smoke(struct kunit *test)
19{
20 // Check settings.
21 KUNIT_ASSERT_GE(test, TESTRL_INTERVAL, 100);
22
23 // Test normal operation.
24 test_ratelimited(test, true);
25 test_ratelimited(test, true);
26 test_ratelimited(test, true);
27 test_ratelimited(test, false);
28
29 schedule_timeout_idle(TESTRL_INTERVAL / 2);
30 test_ratelimited(test, false);
31
32 schedule_timeout_idle(TESTRL_INTERVAL * 3 / 4);
33 test_ratelimited(test, true);
34
35 schedule_timeout_idle(2 * TESTRL_INTERVAL);
36 test_ratelimited(test, true);
37 test_ratelimited(test, true);
38
39 schedule_timeout_idle(TESTRL_INTERVAL / 2 );
40 test_ratelimited(test, true);
41 schedule_timeout_idle(TESTRL_INTERVAL * 3 / 4);
42 test_ratelimited(test, true);
43 test_ratelimited(test, true);
44 test_ratelimited(test, true);
45 test_ratelimited(test, false);
46
47 // Test disabling.
48 testrl.burst = 0;
49 test_ratelimited(test, false);
50 testrl.burst = 2;
51 testrl.interval = 0;
52 test_ratelimited(test, true);
53 test_ratelimited(test, true);
54 test_ratelimited(test, true);
55 test_ratelimited(test, true);
56 test_ratelimited(test, true);
57 test_ratelimited(test, true);
58 test_ratelimited(test, true);
59
60 // Testing re-enabling.
61 testrl.interval = TESTRL_INTERVAL;
62 test_ratelimited(test, true);
63 test_ratelimited(test, true);
64 test_ratelimited(test, false);
65 test_ratelimited(test, false);
66}
67
68static struct ratelimit_state stressrl = RATELIMIT_STATE_INIT_FLAGS("stressrl", HZ / 10, 3,
69 RATELIMIT_MSG_ON_RELEASE);
70
71static const int stress_duration = 2 * HZ;
72
73struct stress_kthread {
74 unsigned long nattempts;
75 unsigned long nunlimited;
76 unsigned long nlimited;
77 unsigned long nmissed;
78 struct task_struct *tp;
79};
80
81static int test_ratelimit_stress_child(void *arg)
82{
83 struct stress_kthread *sktp = arg;
84
85 set_user_nice(current, MAX_NICE);
86
87 while (!kthread_should_stop()) {
88 sktp->nattempts++;
89 if (___ratelimit(&stressrl, __func__))
90 sktp->nunlimited++;
91 else
92 sktp->nlimited++;
93 cond_resched();
94 }
95
96 sktp->nmissed = ratelimit_state_reset_miss(&stressrl);
97 return 0;
98}
99
100static void test_ratelimit_stress(struct kunit *test)
101{
102 int i;
103 const int n_stress_kthread = cpumask_weight(cpu_online_mask);
104 struct stress_kthread skt = { 0 };
105 struct stress_kthread *sktp = kzalloc_objs(*sktp, n_stress_kthread);
106 int n_started = 0;
107
108 KUNIT_ASSERT_NOT_NULL_MSG(test, sktp, "Memory allocation failure");
109 for (i = 0; i < n_stress_kthread; i++) {
110 sktp[i].tp = kthread_run(test_ratelimit_stress_child, &sktp[i], "%s/%i",
111 "test_ratelimit_stress_child", i);
112 if (IS_ERR(sktp[i].tp)) {
113 KUNIT_FAIL(test, "kthread_run failed: %ld", PTR_ERR(sktp[i].tp));
114 goto out_stop;
115 }
116 n_started++;
117 pr_alert("Spawned test_ratelimit_stress_child %d\n", i);
118 }
119 schedule_timeout_idle(stress_duration);
120
121out_stop:
122 for (i = 0; i < n_started; i++) {
123 kthread_stop(sktp[i].tp);
124 skt.nattempts += sktp[i].nattempts;
125 skt.nunlimited += sktp[i].nunlimited;
126 skt.nlimited += sktp[i].nlimited;
127 skt.nmissed += sktp[i].nmissed;
128 }
129 if (n_started == n_stress_kthread) {
130 KUNIT_ASSERT_EQ_MSG(test, skt.nunlimited + skt.nlimited, skt.nattempts,
131 "Outcomes not equal to attempts");
132 KUNIT_ASSERT_EQ_MSG(test, skt.nlimited, skt.nmissed,
133 "Misses not equal to limits");
134 }
135
136 kfree(sktp);
137}
138
139static struct kunit_case ratelimit_test_cases[] = {
140 KUNIT_CASE_SLOW(test_ratelimit_smoke),
141 KUNIT_CASE_SLOW(test_ratelimit_stress),
142 {}
143};
144
145static struct kunit_suite ratelimit_test_suite = {
146 .name = "lib_ratelimit",
147 .test_cases = ratelimit_test_cases,
148};
149
150kunit_test_suites(&ratelimit_test_suite);
151
152MODULE_DESCRIPTION("___ratelimit() KUnit test suite");
153MODULE_LICENSE("GPL");