162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */ 262306a36Sopenharmony_ci#ifndef _LINUX_ONCE_H 362306a36Sopenharmony_ci#define _LINUX_ONCE_H 462306a36Sopenharmony_ci 562306a36Sopenharmony_ci#include <linux/types.h> 662306a36Sopenharmony_ci#include <linux/jump_label.h> 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci/* Helpers used from arbitrary contexts. 962306a36Sopenharmony_ci * Hard irqs are blocked, be cautious. 1062306a36Sopenharmony_ci */ 1162306a36Sopenharmony_cibool __do_once_start(bool *done, unsigned long *flags); 1262306a36Sopenharmony_civoid __do_once_done(bool *done, struct static_key_true *once_key, 1362306a36Sopenharmony_ci unsigned long *flags, struct module *mod); 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci/* Variant for process contexts only. */ 1662306a36Sopenharmony_cibool __do_once_sleepable_start(bool *done); 1762306a36Sopenharmony_civoid __do_once_sleepable_done(bool *done, struct static_key_true *once_key, 1862306a36Sopenharmony_ci struct module *mod); 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci/* Call a function exactly once. The idea of DO_ONCE() is to perform 2162306a36Sopenharmony_ci * a function call such as initialization of random seeds, etc, only 2262306a36Sopenharmony_ci * once, where DO_ONCE() can live in the fast-path. After @func has 2362306a36Sopenharmony_ci * been called with the passed arguments, the static key will patch 2462306a36Sopenharmony_ci * out the condition into a nop. DO_ONCE() guarantees type safety of 2562306a36Sopenharmony_ci * arguments! 2662306a36Sopenharmony_ci * 2762306a36Sopenharmony_ci * Note that the following is not equivalent ... 2862306a36Sopenharmony_ci * 2962306a36Sopenharmony_ci * DO_ONCE(func, arg); 3062306a36Sopenharmony_ci * DO_ONCE(func, arg); 3162306a36Sopenharmony_ci * 3262306a36Sopenharmony_ci * ... to this version: 3362306a36Sopenharmony_ci * 3462306a36Sopenharmony_ci * void foo(void) 3562306a36Sopenharmony_ci * { 3662306a36Sopenharmony_ci * DO_ONCE(func, arg); 3762306a36Sopenharmony_ci * } 3862306a36Sopenharmony_ci * 3962306a36Sopenharmony_ci * foo(); 4062306a36Sopenharmony_ci * foo(); 4162306a36Sopenharmony_ci * 4262306a36Sopenharmony_ci * In case the one-time invocation could be triggered from multiple 4362306a36Sopenharmony_ci * places, then a common helper function must be defined, so that only 4462306a36Sopenharmony_ci * a single static key will be placed there! 4562306a36Sopenharmony_ci */ 4662306a36Sopenharmony_ci#define DO_ONCE(func, ...) \ 4762306a36Sopenharmony_ci ({ \ 4862306a36Sopenharmony_ci bool ___ret = false; \ 4962306a36Sopenharmony_ci static bool __section(".data.once") ___done = false; \ 5062306a36Sopenharmony_ci static DEFINE_STATIC_KEY_TRUE(___once_key); \ 5162306a36Sopenharmony_ci if (static_branch_unlikely(&___once_key)) { \ 5262306a36Sopenharmony_ci unsigned long ___flags; \ 5362306a36Sopenharmony_ci ___ret = __do_once_start(&___done, &___flags); \ 5462306a36Sopenharmony_ci if (unlikely(___ret)) { \ 5562306a36Sopenharmony_ci func(__VA_ARGS__); \ 5662306a36Sopenharmony_ci __do_once_done(&___done, &___once_key, \ 5762306a36Sopenharmony_ci &___flags, THIS_MODULE); \ 5862306a36Sopenharmony_ci } \ 5962306a36Sopenharmony_ci } \ 6062306a36Sopenharmony_ci ___ret; \ 6162306a36Sopenharmony_ci }) 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci/* Variant of DO_ONCE() for process/sleepable contexts. */ 6462306a36Sopenharmony_ci#define DO_ONCE_SLEEPABLE(func, ...) \ 6562306a36Sopenharmony_ci ({ \ 6662306a36Sopenharmony_ci bool ___ret = false; \ 6762306a36Sopenharmony_ci static bool __section(".data.once") ___done = false; \ 6862306a36Sopenharmony_ci static DEFINE_STATIC_KEY_TRUE(___once_key); \ 6962306a36Sopenharmony_ci if (static_branch_unlikely(&___once_key)) { \ 7062306a36Sopenharmony_ci ___ret = __do_once_sleepable_start(&___done); \ 7162306a36Sopenharmony_ci if (unlikely(___ret)) { \ 7262306a36Sopenharmony_ci func(__VA_ARGS__); \ 7362306a36Sopenharmony_ci __do_once_sleepable_done(&___done, &___once_key,\ 7462306a36Sopenharmony_ci THIS_MODULE); \ 7562306a36Sopenharmony_ci } \ 7662306a36Sopenharmony_ci } \ 7762306a36Sopenharmony_ci ___ret; \ 7862306a36Sopenharmony_ci }) 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci#define get_random_once(buf, nbytes) \ 8162306a36Sopenharmony_ci DO_ONCE(get_random_bytes, (buf), (nbytes)) 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci#define get_random_sleepable_once(buf, nbytes) \ 8462306a36Sopenharmony_ci DO_ONCE_SLEEPABLE(get_random_bytes, (buf), (nbytes)) 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci#endif /* _LINUX_ONCE_H */ 87