Line data Source code
1 : // SPDX-License-Identifier: GPL-2.0 2 : #include <linux/slab.h> 3 : #include <linux/spinlock.h> 4 : #include <linux/once.h> 5 : #include <linux/random.h> 6 : 7 : struct once_work { 8 : struct work_struct work; 9 : struct static_key_true *key; 10 : }; 11 : 12 2 : static void once_deferred(struct work_struct *w) 13 : { 14 2 : struct once_work *work; 15 : 16 2 : work = container_of(w, struct once_work, work); 17 2 : BUG_ON(!static_key_enabled(work->key)); 18 2 : static_branch_disable(work->key); 19 2 : kfree(work); 20 2 : } 21 : 22 2 : static void once_disable_jump(struct static_key_true *key) 23 : { 24 2 : struct once_work *w; 25 : 26 2 : w = kmalloc(sizeof(*w), GFP_ATOMIC); 27 2 : if (!w) 28 : return; 29 : 30 2 : INIT_WORK(&w->work, once_deferred); 31 2 : w->key = key; 32 2 : schedule_work(&w->work); 33 : } 34 : 35 : static DEFINE_SPINLOCK(once_lock); 36 : 37 7 : bool __do_once_start(bool *done, unsigned long *flags) 38 : __acquires(once_lock) 39 : { 40 7 : spin_lock_irqsave(&once_lock, *flags); 41 7 : if (*done) { 42 5 : spin_unlock_irqrestore(&once_lock, *flags); 43 : /* Keep sparse happy by restoring an even lock count on 44 : * this lock. In case we return here, we don't call into 45 : * __do_once_done but return early in the DO_ONCE() macro. 46 : */ 47 5 : __acquire(once_lock); 48 5 : return false; 49 : } 50 : 51 : return true; 52 : } 53 : EXPORT_SYMBOL(__do_once_start); 54 : 55 2 : void __do_once_done(bool *done, struct static_key_true *once_key, 56 : unsigned long *flags) 57 : __releases(once_lock) 58 : { 59 2 : *done = true; 60 2 : spin_unlock_irqrestore(&once_lock, *flags); 61 2 : once_disable_jump(once_key); 62 2 : } 63 : EXPORT_SYMBOL(__do_once_done);