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.

lib/crc: crc_kunit: Test CRC computation in interrupt contexts

Test that if CRCs are computed in task, softirq, and hardirq context
concurrently, then all results are as expected. Implement this using
kunit_run_irq_test() which is also used by the lib/crypto/ tests.

As with the corresponding lib/crypto/ tests, the purpose of this is to
test fallback code paths and to exercise edge cases in the
architecture's support for in-kernel FPU/SIMD/vector.

Remove the code from crc_test() that sometimes disabled interrupts, as
that was just an incomplete attempt to achieve similar test coverage.

Link: https://lore.kernel.org/r/20250811182631.376302-3-ebiggers@kernel.org
Signed-off-by: Eric Biggers <ebiggers@kernel.org>

+53 -9
+53 -9
lib/crc/tests/crc_kunit.c
··· 6 6 * 7 7 * Author: Eric Biggers <ebiggers@google.com> 8 8 */ 9 + #include <kunit/run-in-irq-context.h> 9 10 #include <kunit/test.h> 10 11 #include <linux/crc7.h> 11 12 #include <linux/crc16.h> ··· 142 141 return len % (max_length + 1); 143 142 } 144 143 144 + #define IRQ_TEST_DATA_LEN 512 145 + #define IRQ_TEST_NUM_BUFFERS 3 /* matches max concurrency level */ 146 + 147 + struct crc_irq_test_state { 148 + const struct crc_variant *v; 149 + u64 initial_crc; 150 + u64 expected_crcs[IRQ_TEST_NUM_BUFFERS]; 151 + atomic_t seqno; 152 + }; 153 + 154 + /* 155 + * Compute the CRC of one of the test messages and verify that it matches the 156 + * expected CRC from @state->expected_crcs. To increase the chance of detecting 157 + * problems, cycle through multiple messages. 158 + */ 159 + static bool crc_irq_test_func(void *state_) 160 + { 161 + struct crc_irq_test_state *state = state_; 162 + const struct crc_variant *v = state->v; 163 + u32 i = (u32)atomic_inc_return(&state->seqno) % IRQ_TEST_NUM_BUFFERS; 164 + u64 actual_crc = v->func(state->initial_crc, 165 + &test_buffer[i * IRQ_TEST_DATA_LEN], 166 + IRQ_TEST_DATA_LEN); 167 + 168 + return actual_crc == state->expected_crcs[i]; 169 + } 170 + 171 + /* 172 + * Test that if CRCs are computed in task, softirq, and hardirq context 173 + * concurrently, then all results are as expected. 174 + */ 175 + static void crc_interrupt_context_test(struct kunit *test, 176 + const struct crc_variant *v) 177 + { 178 + struct crc_irq_test_state state = { 179 + .v = v, 180 + .initial_crc = generate_random_initial_crc(v), 181 + }; 182 + 183 + for (int i = 0; i < IRQ_TEST_NUM_BUFFERS; i++) { 184 + state.expected_crcs[i] = crc_ref( 185 + v, state.initial_crc, 186 + &test_buffer[i * IRQ_TEST_DATA_LEN], IRQ_TEST_DATA_LEN); 187 + } 188 + 189 + kunit_run_irq_test(test, crc_irq_test_func, 100000, &state); 190 + } 191 + 145 192 /* Test that v->func gives the same CRCs as a reference implementation. */ 146 193 static void crc_test(struct kunit *test, const struct crc_variant *v) 147 194 { ··· 198 149 for (i = 0; i < CRC_KUNIT_NUM_TEST_ITERS; i++) { 199 150 u64 init_crc, expected_crc, actual_crc; 200 151 size_t len, offset; 201 - bool nosimd; 202 152 203 153 init_crc = generate_random_initial_crc(v); 204 154 len = generate_random_length(CRC_KUNIT_MAX_LEN); ··· 216 168 /* Refresh the data occasionally. */ 217 169 prandom_bytes_state(&rng, &test_buffer[offset], len); 218 170 219 - nosimd = rand32() % 8 == 0; 220 - 221 171 /* 222 172 * Compute the CRC, and verify that it equals the CRC computed 223 173 * by a simple bit-at-a-time reference implementation. 224 174 */ 225 175 expected_crc = crc_ref(v, init_crc, &test_buffer[offset], len); 226 - if (nosimd) 227 - local_irq_disable(); 228 176 actual_crc = v->func(init_crc, &test_buffer[offset], len); 229 - if (nosimd) 230 - local_irq_enable(); 231 177 KUNIT_EXPECT_EQ_MSG(test, expected_crc, actual_crc, 232 - "Wrong result with len=%zu offset=%zu nosimd=%d", 233 - len, offset, nosimd); 178 + "Wrong result with len=%zu offset=%zu", 179 + len, offset); 234 180 } 181 + 182 + crc_interrupt_context_test(test, v); 235 183 } 236 184 237 185 static __always_inline void