1 /* SPDX-License-Identifier: GPL-2.0 */ 2 #ifndef _LINUX_ONCE_H 3 #define _LINUX_ONCE_H 4 5 #include <linux/types.h> 6 #include <linux/jump_label.h> 7 8 /* Helpers used from arbitrary contexts. 9 * Hard irqs are blocked, be cautious. 10 */ 11 bool __do_once_start(bool *done, unsigned long *flags); 12 void __do_once_done(bool *done, struct static_key_true *once_key, 13 unsigned long *flags); 14 15 /* Variant for process contexts only. */ 16 bool __do_once_slow_start(bool *done); 17 void __do_once_slow_done(bool *done, struct static_key_true *once_key, 18 struct module *mod); 19 20 /* Call a function exactly once. The idea of DO_ONCE() is to perform 21 * a function call such as initialization of random seeds, etc, only 22 * once, where DO_ONCE() can live in the fast-path. After @func has 23 * been called with the passed arguments, the static key will patch 24 * out the condition into a nop. DO_ONCE() guarantees type safety of 25 * arguments! 26 * 27 * Not that the following is not equivalent ... 28 * 29 * DO_ONCE(func, arg); 30 * DO_ONCE(func, arg); 31 * 32 * ... to this version: 33 * 34 * void foo(void) 35 * { 36 * DO_ONCE(func, arg); 37 * } 38 * 39 * foo(); 40 * foo(); 41 * 42 * In case the one-time invocation could be triggered from multiple 43 * places, then a common helper function must be defined, so that only 44 * a single static key will be placed there! 45 */ 46 #define DO_ONCE(func, ...) \ 47 ({ \ 48 bool ___ret = false; \ 49 static bool ___done = false; \ 50 static DEFINE_STATIC_KEY_TRUE(___once_key); \ 51 if (static_branch_unlikely(&___once_key)) { \ 52 unsigned long ___flags; \ 53 ___ret = __do_once_start(&___done, &___flags); \ 54 if (unlikely(___ret)) { \ 55 func(__VA_ARGS__); \ 56 __do_once_done(&___done, &___once_key, \ 57 &___flags); \ 58 } \ 59 } \ 60 ___ret; \ 61 }) 62 63 /* Variant of DO_ONCE() for process/sleepable contexts. */ 64 #define DO_ONCE_SLOW(func, ...) \ 65 ({ \ 66 bool ___ret = false; \ 67 static bool __section(".data.once") ___done = false; \ 68 static DEFINE_STATIC_KEY_TRUE(___once_key); \ 69 if (static_branch_unlikely(&___once_key)) { \ 70 ___ret = __do_once_slow_start(&___done); \ 71 if (unlikely(___ret)) { \ 72 func(__VA_ARGS__); \ 73 __do_once_slow_done(&___done, &___once_key, \ 74 THIS_MODULE); \ 75 } \ 76 } \ 77 ___ret; \ 78 }) 79 80 #define get_random_once(buf, nbytes) \ 81 DO_ONCE(get_random_bytes, (buf), (nbytes)) 82 #define get_random_once_wait(buf, nbytes) \ 83 DO_ONCE(get_random_bytes_wait, (buf), (nbytes)) \ 84 85 #define get_random_slow_once(buf, nbytes) \ 86 DO_ONCE_SLOW(get_random_bytes, (buf), (nbytes)) 87 88 #endif /* _LINUX_ONCE_H */ 89