0001
0002 #include <linux/slab.h>
0003 #include <linux/spinlock.h>
0004 #include <linux/once.h>
0005 #include <linux/random.h>
0006 #include <linux/module.h>
0007
0008 struct once_work {
0009 struct work_struct work;
0010 struct static_key_true *key;
0011 struct module *module;
0012 };
0013
0014 static void once_deferred(struct work_struct *w)
0015 {
0016 struct once_work *work;
0017
0018 work = container_of(w, struct once_work, work);
0019 BUG_ON(!static_key_enabled(work->key));
0020 static_branch_disable(work->key);
0021 module_put(work->module);
0022 kfree(work);
0023 }
0024
0025 static void once_disable_jump(struct static_key_true *key, struct module *mod)
0026 {
0027 struct once_work *w;
0028
0029 w = kmalloc(sizeof(*w), GFP_ATOMIC);
0030 if (!w)
0031 return;
0032
0033 INIT_WORK(&w->work, once_deferred);
0034 w->key = key;
0035 w->module = mod;
0036 __module_get(mod);
0037 schedule_work(&w->work);
0038 }
0039
0040 static DEFINE_SPINLOCK(once_lock);
0041
0042 bool __do_once_start(bool *done, unsigned long *flags)
0043 __acquires(once_lock)
0044 {
0045 spin_lock_irqsave(&once_lock, *flags);
0046 if (*done) {
0047 spin_unlock_irqrestore(&once_lock, *flags);
0048
0049
0050
0051
0052 __acquire(once_lock);
0053 return false;
0054 }
0055
0056 return true;
0057 }
0058 EXPORT_SYMBOL(__do_once_start);
0059
0060 void __do_once_done(bool *done, struct static_key_true *once_key,
0061 unsigned long *flags, struct module *mod)
0062 __releases(once_lock)
0063 {
0064 *done = true;
0065 spin_unlock_irqrestore(&once_lock, *flags);
0066 once_disable_jump(once_key, mod);
0067 }
0068 EXPORT_SYMBOL(__do_once_done);