Skip to content

Commit 0561bd5

Browse files
committed
Merge tag 'ratelimit.2025.07.23a' of git://git.kernel.org/pub/scm/linux/kernel/git/paulmck/linux-rcu
Pull ratelimit test updates from Paul McKenney: "Add functional and stress tests: - Add trivial kunit test for ratelimit - Make the ratelimit test more reliable (Petr Mladek) - Add stress test for ratelimit" * tag 'ratelimit.2025.07.23a' of git://git.kernel.org/pub/scm/linux/kernel/git/paulmck/linux-rcu: lib: Add stress test for ratelimit lib: Make the ratelimit test more reliable lib: Add trivial kunit test for ratelimit
2 parents 9394264 + 5c23ce0 commit 0561bd5

File tree

3 files changed

+156
-0
lines changed

3 files changed

+156
-0
lines changed

lib/Kconfig.debug

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3214,6 +3214,17 @@ config TEST_OBJPOOL
32143214

32153215
If unsure, say N.
32163216

3217+
config RATELIMIT_KUNIT_TEST
3218+
tristate "KUnit Test for correctness and stress of ratelimit" if !KUNIT_ALL_TESTS
3219+
depends on KUNIT
3220+
default KUNIT_ALL_TESTS
3221+
help
3222+
This builds the "test_ratelimit" module that should be used
3223+
for correctness verification and concurrent testings of rate
3224+
limiting.
3225+
3226+
If unsure, say N.
3227+
32173228
config INT_POW_KUNIT_TEST
32183229
tristate "Integer exponentiation (int_pow) test" if !KUNIT_ALL_TESTS
32193230
depends on KUNIT

lib/tests/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,5 +46,6 @@ obj-$(CONFIG_STRING_KUNIT_TEST) += string_kunit.o
4646
obj-$(CONFIG_STRING_HELPERS_KUNIT_TEST) += string_helpers_kunit.o
4747
obj-$(CONFIG_USERCOPY_KUNIT_TEST) += usercopy_kunit.o
4848
obj-$(CONFIG_UTIL_MACROS_KUNIT) += util_macros_kunit.o
49+
obj-$(CONFIG_RATELIMIT_KUNIT_TEST) += test_ratelimit.o
4950

5051
obj-$(CONFIG_TEST_RUNTIME_MODULE) += module/

lib/tests/test_ratelimit.c

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
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)
13+
static 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+
18+
static 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+
68+
static struct ratelimit_state stressrl = RATELIMIT_STATE_INIT_FLAGS("stressrl", HZ / 10, 3,
69+
RATELIMIT_MSG_ON_RELEASE);
70+
71+
static int doneflag;
72+
static const int stress_duration = 2 * HZ;
73+
74+
struct stress_kthread {
75+
unsigned long nattempts;
76+
unsigned long nunlimited;
77+
unsigned long nlimited;
78+
unsigned long nmissed;
79+
struct task_struct *tp;
80+
};
81+
82+
static int test_ratelimit_stress_child(void *arg)
83+
{
84+
struct stress_kthread *sktp = arg;
85+
86+
set_user_nice(current, MAX_NICE);
87+
WARN_ON_ONCE(!sktp->tp);
88+
89+
while (!READ_ONCE(doneflag)) {
90+
sktp->nattempts++;
91+
if (___ratelimit(&stressrl, __func__))
92+
sktp->nunlimited++;
93+
else
94+
sktp->nlimited++;
95+
cond_resched();
96+
}
97+
98+
sktp->nmissed = ratelimit_state_reset_miss(&stressrl);
99+
return 0;
100+
}
101+
102+
static void test_ratelimit_stress(struct kunit *test)
103+
{
104+
int i;
105+
const int n_stress_kthread = cpumask_weight(cpu_online_mask);
106+
struct stress_kthread skt = { 0 };
107+
struct stress_kthread *sktp = kcalloc(n_stress_kthread, sizeof(*sktp), GFP_KERNEL);
108+
109+
KUNIT_EXPECT_NOT_NULL_MSG(test, sktp, "Memory allocation failure");
110+
for (i = 0; i < n_stress_kthread; i++) {
111+
sktp[i].tp = kthread_run(test_ratelimit_stress_child, &sktp[i], "%s/%i",
112+
"test_ratelimit_stress_child", i);
113+
KUNIT_EXPECT_NOT_NULL_MSG(test, sktp, "kthread creation failure");
114+
pr_alert("Spawned test_ratelimit_stress_child %d\n", i);
115+
}
116+
schedule_timeout_idle(stress_duration);
117+
WRITE_ONCE(doneflag, 1);
118+
for (i = 0; i < n_stress_kthread; i++) {
119+
kthread_stop(sktp[i].tp);
120+
skt.nattempts += sktp[i].nattempts;
121+
skt.nunlimited += sktp[i].nunlimited;
122+
skt.nlimited += sktp[i].nlimited;
123+
skt.nmissed += sktp[i].nmissed;
124+
}
125+
KUNIT_ASSERT_EQ_MSG(test, skt.nunlimited + skt.nlimited, skt.nattempts,
126+
"Outcomes not equal to attempts");
127+
KUNIT_ASSERT_EQ_MSG(test, skt.nlimited, skt.nmissed, "Misses not equal to limits");
128+
}
129+
130+
static struct kunit_case ratelimit_test_cases[] = {
131+
KUNIT_CASE_SLOW(test_ratelimit_smoke),
132+
KUNIT_CASE_SLOW(test_ratelimit_stress),
133+
{}
134+
};
135+
136+
static struct kunit_suite ratelimit_test_suite = {
137+
.name = "lib_ratelimit",
138+
.test_cases = ratelimit_test_cases,
139+
};
140+
141+
kunit_test_suites(&ratelimit_test_suite);
142+
143+
MODULE_DESCRIPTION("___ratelimit() KUnit test suite");
144+
MODULE_LICENSE("GPL");

0 commit comments

Comments
 (0)