Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

kunit: Enforce task execution in {soft,hard}irq contexts

The kunit_run_irq_test() helper allows a function to be run in hardirq
and softirq contexts (in addition to the task context). It does this by
running the user-provided function concurrently in the three contexts,
until either a timeout has expired or a number of iterations have
completed in the normal task context.

However, on setups where the initialisation of the hardirq and softirq
contexts (or, indeed, the scheduling of those tasks) is significantly
slower than the function execution, it's possible for that number of
iterations to be exceeded before any runs in irq contexts actually
occur. This occurs with the polyval.test_polyval_preparekey_in_irqs
test, which runs 20000 iterations of the relatively fast preparekey
function, and therefore fails often under many UML, 32-bit arm, m68k and
other environments.

Instead, ensure that the max_iterations limit counts executions in all
three contexts, and requires at least one of each. This will cause the
test to continue iterating until at least the irq contexts have been
tested, or the 1s wall-clock limit has been exceeded. This causes the
test to pass in all of my environments.

In so doing, we also update the task counters to atomic ints, to better
match both the 'int' max_iterations input, and to ensure they are
correctly updated across contexts.

Finally, we also fix a few potential assertion messages to be
less-specific to the original crypto usecases.

Fixes: 950a81224e8b ("lib/crypto: tests: Add hash-test-template.h and gen-hash-testvecs.py")
Signed-off-by: David Gow <davidgow@google.com>
Link: https://lore.kernel.org/r/20251219085259.1163048-1-davidgow@google.com
Signed-off-by: Eric Biggers <ebiggers@kernel.org>

authored by

David Gow and committed by
Eric Biggers
c31f4aa8 9448598b

+33 -20
+33 -20
include/kunit/run-in-irq-context.h
··· 20 20 bool task_func_reported_failure; 21 21 bool hardirq_func_reported_failure; 22 22 bool softirq_func_reported_failure; 23 - unsigned long hardirq_func_calls; 24 - unsigned long softirq_func_calls; 23 + atomic_t hardirq_func_calls; 24 + atomic_t softirq_func_calls; 25 25 struct hrtimer timer; 26 26 struct work_struct bh_work; 27 27 }; ··· 32 32 container_of(timer, typeof(*state), timer); 33 33 34 34 WARN_ON_ONCE(!in_hardirq()); 35 - state->hardirq_func_calls++; 35 + atomic_inc(&state->hardirq_func_calls); 36 36 37 37 if (!state->func(state->test_specific_state)) 38 38 state->hardirq_func_reported_failure = true; ··· 48 48 container_of(work, typeof(*state), bh_work); 49 49 50 50 WARN_ON_ONCE(!in_serving_softirq()); 51 - state->softirq_func_calls++; 51 + atomic_inc(&state->softirq_func_calls); 52 52 53 53 if (!state->func(state->test_specific_state)) 54 54 state->softirq_func_reported_failure = true; ··· 59 59 * hardirq context concurrently, and reports a failure to KUnit if any 60 60 * invocation of @func in any context returns false. @func is passed 61 61 * @test_specific_state as its argument. At most 3 invocations of @func will 62 - * run concurrently: one in each of task, softirq, and hardirq context. 62 + * run concurrently: one in each of task, softirq, and hardirq context. @func 63 + * will continue running until either @max_iterations calls have been made (so 64 + * long as at least one each runs in task, softirq, and hardirq contexts), or 65 + * one second has passed. 63 66 * 64 67 * The main purpose of this interrupt context testing is to validate fallback 65 68 * code paths that run in contexts where the normal code path cannot be used, ··· 88 85 .test_specific_state = test_specific_state, 89 86 }; 90 87 unsigned long end_jiffies; 88 + int hardirq_calls, softirq_calls; 89 + bool allctx = false; 91 90 92 91 /* 93 92 * Set up a hrtimer (the way we access hardirq context) and a work ··· 99 94 CLOCK_MONOTONIC, HRTIMER_MODE_REL_HARD); 100 95 INIT_WORK_ONSTACK(&state.bh_work, kunit_irq_test_bh_work_func); 101 96 102 - /* Run for up to max_iterations or 1 second, whichever comes first. */ 97 + /* 98 + * Run for up to max_iterations (including at least one task, softirq, 99 + * and hardirq), or 1 second, whichever comes first. 100 + */ 103 101 end_jiffies = jiffies + HZ; 104 102 hrtimer_start(&state.timer, KUNIT_IRQ_TEST_HRTIMER_INTERVAL, 105 103 HRTIMER_MODE_REL_HARD); 106 - for (int i = 0; i < max_iterations && !time_after(jiffies, end_jiffies); 107 - i++) { 104 + for (int task_calls = 0, calls = 0; 105 + ((calls < max_iterations) || !allctx) && 106 + !time_after(jiffies, end_jiffies); 107 + task_calls++) { 108 108 if (!func(test_specific_state)) 109 109 state.task_func_reported_failure = true; 110 + 111 + hardirq_calls = atomic_read(&state.hardirq_func_calls); 112 + softirq_calls = atomic_read(&state.softirq_func_calls); 113 + calls = task_calls + hardirq_calls + softirq_calls; 114 + allctx = (task_calls > 0) && (hardirq_calls > 0) && 115 + (softirq_calls > 0); 110 116 } 111 117 112 118 /* Cancel the timer and work. */ ··· 125 109 flush_work(&state.bh_work); 126 110 127 111 /* Sanity check: the timer and BH functions should have been run. */ 128 - KUNIT_EXPECT_GT_MSG(test, state.hardirq_func_calls, 0, 112 + KUNIT_EXPECT_GT_MSG(test, atomic_read(&state.hardirq_func_calls), 0, 129 113 "Timer function was not called"); 130 - KUNIT_EXPECT_GT_MSG(test, state.softirq_func_calls, 0, 114 + KUNIT_EXPECT_GT_MSG(test, atomic_read(&state.softirq_func_calls), 0, 131 115 "BH work function was not called"); 132 116 133 - /* Check for incorrect hash values reported from any context. */ 134 - KUNIT_EXPECT_FALSE_MSG( 135 - test, state.task_func_reported_failure, 136 - "Incorrect hash values reported from task context"); 137 - KUNIT_EXPECT_FALSE_MSG( 138 - test, state.hardirq_func_reported_failure, 139 - "Incorrect hash values reported from hardirq context"); 140 - KUNIT_EXPECT_FALSE_MSG( 141 - test, state.softirq_func_reported_failure, 142 - "Incorrect hash values reported from softirq context"); 117 + /* Check for failure reported from any context. */ 118 + KUNIT_EXPECT_FALSE_MSG(test, state.task_func_reported_failure, 119 + "Failure reported from task context"); 120 + KUNIT_EXPECT_FALSE_MSG(test, state.hardirq_func_reported_failure, 121 + "Failure reported from hardirq context"); 122 + KUNIT_EXPECT_FALSE_MSG(test, state.softirq_func_reported_failure, 123 + "Failure reported from softirq context"); 143 124 } 144 125 145 126 #endif /* _KUNIT_RUN_IN_IRQ_CONTEXT_H */