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

kunit, lib/crypto: Move run_irq_test() to common header

Rename run_irq_test() to kunit_run_irq_test() and move it to a public
header so that it can be reused by crc_kunit.

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

+133 -119
+129
include/kunit/run-in-irq-context.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0-or-later */ 2 + /* 3 + * Helper function for testing code in interrupt contexts 4 + * 5 + * Copyright 2025 Google LLC 6 + */ 7 + #ifndef _KUNIT_RUN_IN_IRQ_CONTEXT_H 8 + #define _KUNIT_RUN_IN_IRQ_CONTEXT_H 9 + 10 + #include <kunit/test.h> 11 + #include <linux/timekeeping.h> 12 + #include <linux/hrtimer.h> 13 + #include <linux/workqueue.h> 14 + 15 + #define KUNIT_IRQ_TEST_HRTIMER_INTERVAL us_to_ktime(5) 16 + 17 + struct kunit_irq_test_state { 18 + bool (*func)(void *test_specific_state); 19 + void *test_specific_state; 20 + bool task_func_reported_failure; 21 + bool hardirq_func_reported_failure; 22 + bool softirq_func_reported_failure; 23 + unsigned long hardirq_func_calls; 24 + unsigned long softirq_func_calls; 25 + struct hrtimer timer; 26 + struct work_struct bh_work; 27 + }; 28 + 29 + static enum hrtimer_restart kunit_irq_test_timer_func(struct hrtimer *timer) 30 + { 31 + struct kunit_irq_test_state *state = 32 + container_of(timer, typeof(*state), timer); 33 + 34 + WARN_ON_ONCE(!in_hardirq()); 35 + state->hardirq_func_calls++; 36 + 37 + if (!state->func(state->test_specific_state)) 38 + state->hardirq_func_reported_failure = true; 39 + 40 + hrtimer_forward_now(&state->timer, KUNIT_IRQ_TEST_HRTIMER_INTERVAL); 41 + queue_work(system_bh_wq, &state->bh_work); 42 + return HRTIMER_RESTART; 43 + } 44 + 45 + static void kunit_irq_test_bh_work_func(struct work_struct *work) 46 + { 47 + struct kunit_irq_test_state *state = 48 + container_of(work, typeof(*state), bh_work); 49 + 50 + WARN_ON_ONCE(!in_serving_softirq()); 51 + state->softirq_func_calls++; 52 + 53 + if (!state->func(state->test_specific_state)) 54 + state->softirq_func_reported_failure = true; 55 + } 56 + 57 + /* 58 + * Helper function which repeatedly runs the given @func in task, softirq, and 59 + * hardirq context concurrently, and reports a failure to KUnit if any 60 + * invocation of @func in any context returns false. @func is passed 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. 63 + * 64 + * The main purpose of this interrupt context testing is to validate fallback 65 + * code paths that run in contexts where the normal code path cannot be used, 66 + * typically due to the FPU or vector registers already being in-use in kernel 67 + * mode. These code paths aren't covered when the test code is executed only by 68 + * the KUnit test runner thread in task context. The reason for the concurrency 69 + * is because merely using hardirq context is not sufficient to reach a fallback 70 + * code path on some architectures; the hardirq actually has to occur while the 71 + * FPU or vector unit was already in-use in kernel mode. 72 + * 73 + * Another purpose of this testing is to detect issues with the architecture's 74 + * irq_fpu_usable() and kernel_fpu_begin/end() or equivalent functions, 75 + * especially in softirq context when the softirq may have interrupted a task 76 + * already using kernel-mode FPU or vector (if the arch didn't prevent that). 77 + * Crypto functions are often executed in softirqs, so this is important. 78 + */ 79 + static inline void kunit_run_irq_test(struct kunit *test, bool (*func)(void *), 80 + int max_iterations, 81 + void *test_specific_state) 82 + { 83 + struct kunit_irq_test_state state = { 84 + .func = func, 85 + .test_specific_state = test_specific_state, 86 + }; 87 + unsigned long end_jiffies; 88 + 89 + /* 90 + * Set up a hrtimer (the way we access hardirq context) and a work 91 + * struct for the BH workqueue (the way we access softirq context). 92 + */ 93 + hrtimer_setup_on_stack(&state.timer, kunit_irq_test_timer_func, 94 + CLOCK_MONOTONIC, HRTIMER_MODE_REL_HARD); 95 + INIT_WORK_ONSTACK(&state.bh_work, kunit_irq_test_bh_work_func); 96 + 97 + /* Run for up to max_iterations or 1 second, whichever comes first. */ 98 + end_jiffies = jiffies + HZ; 99 + hrtimer_start(&state.timer, KUNIT_IRQ_TEST_HRTIMER_INTERVAL, 100 + HRTIMER_MODE_REL_HARD); 101 + for (int i = 0; i < max_iterations && !time_after(jiffies, end_jiffies); 102 + i++) { 103 + if (!func(test_specific_state)) 104 + state.task_func_reported_failure = true; 105 + } 106 + 107 + /* Cancel the timer and work. */ 108 + hrtimer_cancel(&state.timer); 109 + flush_work(&state.bh_work); 110 + 111 + /* Sanity check: the timer and BH functions should have been run. */ 112 + KUNIT_EXPECT_GT_MSG(test, state.hardirq_func_calls, 0, 113 + "Timer function was not called"); 114 + KUNIT_EXPECT_GT_MSG(test, state.softirq_func_calls, 0, 115 + "BH work function was not called"); 116 + 117 + /* Check for incorrect hash values reported from any context. */ 118 + KUNIT_EXPECT_FALSE_MSG( 119 + test, state.task_func_reported_failure, 120 + "Incorrect hash values reported from task context"); 121 + KUNIT_EXPECT_FALSE_MSG( 122 + test, state.hardirq_func_reported_failure, 123 + "Incorrect hash values reported from hardirq context"); 124 + KUNIT_EXPECT_FALSE_MSG( 125 + test, state.softirq_func_reported_failure, 126 + "Incorrect hash values reported from softirq context"); 127 + } 128 + 129 + #endif /* _KUNIT_RUN_IN_IRQ_CONTEXT_H */
+4 -119
lib/crypto/tests/hash-test-template.h
··· 5 5 * 6 6 * Copyright 2025 Google LLC 7 7 */ 8 + #include <kunit/run-in-irq-context.h> 8 9 #include <kunit/test.h> 9 - #include <linux/hrtimer.h> 10 - #include <linux/timekeeping.h> 11 10 #include <linux/vmalloc.h> 12 - #include <linux/workqueue.h> 13 11 14 12 /* test_buf is a guarded buffer, i.e. &test_buf[TEST_BUF_LEN] is not mapped. */ 15 13 #define TEST_BUF_LEN 16384 ··· 317 319 "Hash context was not zeroized by finalization"); 318 320 } 319 321 320 - #define IRQ_TEST_HRTIMER_INTERVAL us_to_ktime(5) 321 - 322 - struct hash_irq_test_state { 323 - bool (*func)(void *test_specific_state); 324 - void *test_specific_state; 325 - bool task_func_reported_failure; 326 - bool hardirq_func_reported_failure; 327 - bool softirq_func_reported_failure; 328 - unsigned long hardirq_func_calls; 329 - unsigned long softirq_func_calls; 330 - struct hrtimer timer; 331 - struct work_struct bh_work; 332 - }; 333 - 334 - static enum hrtimer_restart hash_irq_test_timer_func(struct hrtimer *timer) 335 - { 336 - struct hash_irq_test_state *state = 337 - container_of(timer, typeof(*state), timer); 338 - 339 - WARN_ON_ONCE(!in_hardirq()); 340 - state->hardirq_func_calls++; 341 - 342 - if (!state->func(state->test_specific_state)) 343 - state->hardirq_func_reported_failure = true; 344 - 345 - hrtimer_forward_now(&state->timer, IRQ_TEST_HRTIMER_INTERVAL); 346 - queue_work(system_bh_wq, &state->bh_work); 347 - return HRTIMER_RESTART; 348 - } 349 - 350 - static void hash_irq_test_bh_work_func(struct work_struct *work) 351 - { 352 - struct hash_irq_test_state *state = 353 - container_of(work, typeof(*state), bh_work); 354 - 355 - WARN_ON_ONCE(!in_serving_softirq()); 356 - state->softirq_func_calls++; 357 - 358 - if (!state->func(state->test_specific_state)) 359 - state->softirq_func_reported_failure = true; 360 - } 361 - 362 - /* 363 - * Helper function which repeatedly runs the given @func in task, softirq, and 364 - * hardirq context concurrently, and reports a failure to KUnit if any 365 - * invocation of @func in any context returns false. @func is passed 366 - * @test_specific_state as its argument. At most 3 invocations of @func will 367 - * run concurrently: one in each of task, softirq, and hardirq context. 368 - * 369 - * The main purpose of this interrupt context testing is to validate fallback 370 - * code paths that run in contexts where the normal code path cannot be used, 371 - * typically due to the FPU or vector registers already being in-use in kernel 372 - * mode. These code paths aren't covered when the test code is executed only by 373 - * the KUnit test runner thread in task context. The reason for the concurrency 374 - * is because merely using hardirq context is not sufficient to reach a fallback 375 - * code path on some architectures; the hardirq actually has to occur while the 376 - * FPU or vector unit was already in-use in kernel mode. 377 - * 378 - * Another purpose of this testing is to detect issues with the architecture's 379 - * irq_fpu_usable() and kernel_fpu_begin/end() or equivalent functions, 380 - * especially in softirq context when the softirq may have interrupted a task 381 - * already using kernel-mode FPU or vector (if the arch didn't prevent that). 382 - * Crypto functions are often executed in softirqs, so this is important. 383 - */ 384 - static void run_irq_test(struct kunit *test, bool (*func)(void *), 385 - int max_iterations, void *test_specific_state) 386 - { 387 - struct hash_irq_test_state state = { 388 - .func = func, 389 - .test_specific_state = test_specific_state, 390 - }; 391 - unsigned long end_jiffies; 392 - 393 - /* 394 - * Set up a hrtimer (the way we access hardirq context) and a work 395 - * struct for the BH workqueue (the way we access softirq context). 396 - */ 397 - hrtimer_setup_on_stack(&state.timer, hash_irq_test_timer_func, 398 - CLOCK_MONOTONIC, HRTIMER_MODE_REL_HARD); 399 - INIT_WORK_ONSTACK(&state.bh_work, hash_irq_test_bh_work_func); 400 - 401 - /* Run for up to max_iterations or 1 second, whichever comes first. */ 402 - end_jiffies = jiffies + HZ; 403 - hrtimer_start(&state.timer, IRQ_TEST_HRTIMER_INTERVAL, 404 - HRTIMER_MODE_REL_HARD); 405 - for (int i = 0; i < max_iterations && !time_after(jiffies, end_jiffies); 406 - i++) { 407 - if (!func(test_specific_state)) 408 - state.task_func_reported_failure = true; 409 - } 410 - 411 - /* Cancel the timer and work. */ 412 - hrtimer_cancel(&state.timer); 413 - flush_work(&state.bh_work); 414 - 415 - /* Sanity check: the timer and BH functions should have been run. */ 416 - KUNIT_EXPECT_GT_MSG(test, state.hardirq_func_calls, 0, 417 - "Timer function was not called"); 418 - KUNIT_EXPECT_GT_MSG(test, state.softirq_func_calls, 0, 419 - "BH work function was not called"); 420 - 421 - /* Check for incorrect hash values reported from any context. */ 422 - KUNIT_EXPECT_FALSE_MSG( 423 - test, state.task_func_reported_failure, 424 - "Incorrect hash values reported from task context"); 425 - KUNIT_EXPECT_FALSE_MSG( 426 - test, state.hardirq_func_reported_failure, 427 - "Incorrect hash values reported from hardirq context"); 428 - KUNIT_EXPECT_FALSE_MSG( 429 - test, state.softirq_func_reported_failure, 430 - "Incorrect hash values reported from softirq context"); 431 - } 432 - 433 322 #define IRQ_TEST_DATA_LEN 256 434 323 #define IRQ_TEST_NUM_BUFFERS 3 /* matches max concurrency level */ 435 324 ··· 354 469 HASH(&test_buf[i * IRQ_TEST_DATA_LEN], IRQ_TEST_DATA_LEN, 355 470 state.expected_hashes[i]); 356 471 357 - run_irq_test(test, hash_irq_test1_func, 100000, &state); 472 + kunit_run_irq_test(test, hash_irq_test1_func, 100000, &state); 358 473 } 359 474 360 475 struct hash_irq_test2_hash_ctx { ··· 385 500 if (WARN_ON_ONCE(ctx == &state->ctxs[ARRAY_SIZE(state->ctxs)])) { 386 501 /* 387 502 * This should never happen, as the number of contexts is equal 388 - * to the maximum concurrency level of run_irq_test(). 503 + * to the maximum concurrency level of kunit_run_irq_test(). 389 504 */ 390 505 return false; 391 506 } ··· 451 566 state->update_lens[state->num_steps++] = remaining; 452 567 state->num_steps += 2; /* for init and final */ 453 568 454 - run_irq_test(test, hash_irq_test2_func, 250000, state); 569 + kunit_run_irq_test(test, hash_irq_test2_func, 250000, state); 455 570 } 456 571 457 572 #define UNKEYED_HASH_KUNIT_CASES \