| 1 | |
| 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 |
|
| 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 | |
| 21 | KUNIT_ASSERT_GE(test, TESTRL_INTERVAL, 100);
|
| 22 |
|
| 23 | |
| 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 | |
| 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 | |
| 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 const int stress_duration = 2 * HZ;
|
| 72 |
|
| 73 | struct 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 |
|
| 81 | static 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 |
|
| 100 | static 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 |
|
| 121 | out_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 |
|
| 139 | static struct kunit_case ratelimit_test_cases[] = {
|
| 140 | KUNIT_CASE_SLOW(test_ratelimit_smoke),
|
| 141 | KUNIT_CASE_SLOW(test_ratelimit_stress),
|
| 142 | {}
|
| 143 | };
|
| 144 |
|
| 145 | static struct kunit_suite ratelimit_test_suite = {
|
| 146 | .name = "lib_ratelimit",
|
| 147 | .test_cases = ratelimit_test_cases,
|
| 148 | };
|
| 149 |
|
| 150 | kunit_test_suites(&ratelimit_test_suite);
|
| 151 |
|
| 152 | MODULE_DESCRIPTION("___ratelimit() KUnit test suite");
|
| 153 | MODULE_LICENSE("GPL");
|