| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144 |
- // SPDX-License-Identifier: GPL-2.0-only
- #include <kunit/test.h>
- #include <linux/ratelimit.h>
- #include <linux/module.h>
- #include <linux/kthread.h>
- #include <linux/cpumask.h>
- /* a simple boot-time regression test */
- #define TESTRL_INTERVAL (5 * HZ)
- static DEFINE_RATELIMIT_STATE(testrl, TESTRL_INTERVAL, 3);
- #define test_ratelimited(test, expected) \
- KUNIT_ASSERT_EQ(test, ___ratelimit(&testrl, "test_ratelimit_smoke"), (expected))
- static void test_ratelimit_smoke(struct kunit *test)
- {
- // Check settings.
- KUNIT_ASSERT_GE(test, TESTRL_INTERVAL, 100);
- // Test normal operation.
- test_ratelimited(test, true);
- test_ratelimited(test, true);
- test_ratelimited(test, true);
- test_ratelimited(test, false);
- schedule_timeout_idle(TESTRL_INTERVAL / 2);
- test_ratelimited(test, false);
- schedule_timeout_idle(TESTRL_INTERVAL * 3 / 4);
- test_ratelimited(test, true);
- schedule_timeout_idle(2 * TESTRL_INTERVAL);
- test_ratelimited(test, true);
- test_ratelimited(test, true);
- schedule_timeout_idle(TESTRL_INTERVAL / 2 );
- test_ratelimited(test, true);
- schedule_timeout_idle(TESTRL_INTERVAL * 3 / 4);
- test_ratelimited(test, true);
- test_ratelimited(test, true);
- test_ratelimited(test, true);
- test_ratelimited(test, false);
- // Test disabling.
- testrl.burst = 0;
- test_ratelimited(test, false);
- testrl.burst = 2;
- testrl.interval = 0;
- test_ratelimited(test, true);
- test_ratelimited(test, true);
- test_ratelimited(test, true);
- test_ratelimited(test, true);
- test_ratelimited(test, true);
- test_ratelimited(test, true);
- test_ratelimited(test, true);
- // Testing re-enabling.
- testrl.interval = TESTRL_INTERVAL;
- test_ratelimited(test, true);
- test_ratelimited(test, true);
- test_ratelimited(test, false);
- test_ratelimited(test, false);
- }
- static struct ratelimit_state stressrl = RATELIMIT_STATE_INIT_FLAGS("stressrl", HZ / 10, 3,
- RATELIMIT_MSG_ON_RELEASE);
- static int doneflag;
- static const int stress_duration = 2 * HZ;
- struct stress_kthread {
- unsigned long nattempts;
- unsigned long nunlimited;
- unsigned long nlimited;
- unsigned long nmissed;
- struct task_struct *tp;
- };
- static int test_ratelimit_stress_child(void *arg)
- {
- struct stress_kthread *sktp = arg;
- set_user_nice(current, MAX_NICE);
- WARN_ON_ONCE(!sktp->tp);
- while (!READ_ONCE(doneflag)) {
- sktp->nattempts++;
- if (___ratelimit(&stressrl, __func__))
- sktp->nunlimited++;
- else
- sktp->nlimited++;
- cond_resched();
- }
- sktp->nmissed = ratelimit_state_reset_miss(&stressrl);
- return 0;
- }
- static void test_ratelimit_stress(struct kunit *test)
- {
- int i;
- const int n_stress_kthread = cpumask_weight(cpu_online_mask);
- struct stress_kthread skt = { 0 };
- struct stress_kthread *sktp = kzalloc_objs(*sktp, n_stress_kthread);
- KUNIT_EXPECT_NOT_NULL_MSG(test, sktp, "Memory allocation failure");
- for (i = 0; i < n_stress_kthread; i++) {
- sktp[i].tp = kthread_run(test_ratelimit_stress_child, &sktp[i], "%s/%i",
- "test_ratelimit_stress_child", i);
- KUNIT_EXPECT_NOT_NULL_MSG(test, sktp, "kthread creation failure");
- pr_alert("Spawned test_ratelimit_stress_child %d\n", i);
- }
- schedule_timeout_idle(stress_duration);
- WRITE_ONCE(doneflag, 1);
- for (i = 0; i < n_stress_kthread; i++) {
- kthread_stop(sktp[i].tp);
- skt.nattempts += sktp[i].nattempts;
- skt.nunlimited += sktp[i].nunlimited;
- skt.nlimited += sktp[i].nlimited;
- skt.nmissed += sktp[i].nmissed;
- }
- KUNIT_ASSERT_EQ_MSG(test, skt.nunlimited + skt.nlimited, skt.nattempts,
- "Outcomes not equal to attempts");
- KUNIT_ASSERT_EQ_MSG(test, skt.nlimited, skt.nmissed, "Misses not equal to limits");
- }
- static struct kunit_case ratelimit_test_cases[] = {
- KUNIT_CASE_SLOW(test_ratelimit_smoke),
- KUNIT_CASE_SLOW(test_ratelimit_stress),
- {}
- };
- static struct kunit_suite ratelimit_test_suite = {
- .name = "lib_ratelimit",
- .test_cases = ratelimit_test_cases,
- };
- kunit_test_suites(&ratelimit_test_suite);
- MODULE_DESCRIPTION("___ratelimit() KUnit test suite");
- MODULE_LICENSE("GPL");
|