Back to home page

LXR

 
 

    


0001 #include <linux/slab.h>
0002 #include <linux/spinlock.h>
0003 #include <linux/once.h>
0004 #include <linux/random.h>
0005 
0006 struct once_work {
0007     struct work_struct work;
0008     struct static_key *key;
0009 };
0010 
0011 static void once_deferred(struct work_struct *w)
0012 {
0013     struct once_work *work;
0014 
0015     work = container_of(w, struct once_work, work);
0016     BUG_ON(!static_key_enabled(work->key));
0017     static_key_slow_dec(work->key);
0018     kfree(work);
0019 }
0020 
0021 static void once_disable_jump(struct static_key *key)
0022 {
0023     struct once_work *w;
0024 
0025     w = kmalloc(sizeof(*w), GFP_ATOMIC);
0026     if (!w)
0027         return;
0028 
0029     INIT_WORK(&w->work, once_deferred);
0030     w->key = key;
0031     schedule_work(&w->work);
0032 }
0033 
0034 static DEFINE_SPINLOCK(once_lock);
0035 
0036 bool __do_once_start(bool *done, unsigned long *flags)
0037     __acquires(once_lock)
0038 {
0039     spin_lock_irqsave(&once_lock, *flags);
0040     if (*done) {
0041         spin_unlock_irqrestore(&once_lock, *flags);
0042         /* Keep sparse happy by restoring an even lock count on
0043          * this lock. In case we return here, we don't call into
0044          * __do_once_done but return early in the DO_ONCE() macro.
0045          */
0046         __acquire(once_lock);
0047         return false;
0048     }
0049 
0050     return true;
0051 }
0052 EXPORT_SYMBOL(__do_once_start);
0053 
0054 void __do_once_done(bool *done, struct static_key *once_key,
0055             unsigned long *flags)
0056     __releases(once_lock)
0057 {
0058     *done = true;
0059     spin_unlock_irqrestore(&once_lock, *flags);
0060     once_disable_jump(once_key);
0061 }
0062 EXPORT_SYMBOL(__do_once_done);