| .. | .. |
|---|
| 5 | 5 | #include <linux/types.h> |
|---|
| 6 | 6 | #include <linux/jump_label.h> |
|---|
| 7 | 7 | |
|---|
| 8 | +/* Helpers used from arbitrary contexts. |
|---|
| 9 | + * Hard irqs are blocked, be cautious. |
|---|
| 10 | + */ |
|---|
| 8 | 11 | bool __do_once_start(bool *done, unsigned long *flags); |
|---|
| 9 | 12 | void __do_once_done(bool *done, struct static_key_true *once_key, |
|---|
| 10 | | - unsigned long *flags, struct module *mod); |
|---|
| 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); |
|---|
| 11 | 19 | |
|---|
| 12 | 20 | /* Call a function exactly once. The idea of DO_ONCE() is to perform |
|---|
| 13 | 21 | * a function call such as initialization of random seeds, etc, only |
|---|
| .. | .. |
|---|
| 46 | 54 | if (unlikely(___ret)) { \ |
|---|
| 47 | 55 | func(__VA_ARGS__); \ |
|---|
| 48 | 56 | __do_once_done(&___done, &___once_key, \ |
|---|
| 49 | | - &___flags, THIS_MODULE); \ |
|---|
| 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); \ |
|---|
| 50 | 75 | } \ |
|---|
| 51 | 76 | } \ |
|---|
| 52 | 77 | ___ret; \ |
|---|
| .. | .. |
|---|
| 57 | 82 | #define get_random_once_wait(buf, nbytes) \ |
|---|
| 58 | 83 | DO_ONCE(get_random_bytes_wait, (buf), (nbytes)) \ |
|---|
| 59 | 84 | |
|---|
| 85 | +#define get_random_slow_once(buf, nbytes) \ |
|---|
| 86 | + DO_ONCE_SLOW(get_random_bytes, (buf), (nbytes)) |
|---|
| 87 | + |
|---|
| 60 | 88 | #endif /* _LINUX_ONCE_H */ |
|---|