Branch data 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 : 3 : static void once_deferred(struct work_struct *w) 13 : : { 14 : : struct once_work *work; 15 : : 16 : : work = container_of(w, struct once_work, work); 17 : 3 : BUG_ON(!static_key_enabled(work->key)); 18 : 3 : static_branch_disable(work->key); 19 : 3 : kfree(work); 20 : 3 : } 21 : : 22 : 3 : static void once_disable_jump(struct static_key_true *key) 23 : : { 24 : : struct once_work *w; 25 : : 26 : : w = kmalloc(sizeof(*w), GFP_ATOMIC); 27 : 3 : if (!w) 28 : 3 : return; 29 : : 30 : 3 : INIT_WORK(&w->work, once_deferred); 31 : 3 : w->key = key; 32 : 3 : schedule_work(&w->work); 33 : : } 34 : : 35 : : static DEFINE_SPINLOCK(once_lock); 36 : : 37 : 3 : bool __do_once_start(bool *done, unsigned long *flags) 38 : : __acquires(once_lock) 39 : : { 40 : 3 : spin_lock_irqsave(&once_lock, *flags); 41 : 3 : if (*done) { 42 : : 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 : : __acquire(once_lock); 48 : 3 : return false; 49 : : } 50 : : 51 : : return true; 52 : : } 53 : : EXPORT_SYMBOL(__do_once_start); 54 : : 55 : 3 : void __do_once_done(bool *done, struct static_key_true *once_key, 56 : : unsigned long *flags) 57 : : __releases(once_lock) 58 : : { 59 : 3 : *done = true; 60 : 3 : spin_unlock_irqrestore(&once_lock, *flags); 61 : 3 : once_disable_jump(once_key); 62 : 3 : } 63 : : EXPORT_SYMBOL(__do_once_done);