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