#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/once.h>
#include <linux/random.h>

struct once_work {
	struct work_struct work;
	struct static_key *key;
};

static void once_deferred(struct work_struct *w)
{
	struct once_work *work;

	work = container_of(w, struct once_work, work);
	BUG_ON(!static_key_enabled(work->key));
	static_key_slow_dec(work->key);
	kfree(work);
}

static void once_disable_jump(struct static_key *key)
{
	struct once_work *w;

	w = kmalloc(sizeof(*w), GFP_ATOMIC);
	if (!w)
		return;

	INIT_WORK(&w->work, once_deferred);
	w->key = key;
	schedule_work(&w->work);
}

static DEFINE_SPINLOCK(once_lock);

bool __do_once_start(bool *done, unsigned long *flags)
	__acquires(once_lock)
{
	spin_lock_irqsave(&once_lock, *flags);
	if (*done) {
		spin_unlock_irqrestore(&once_lock, *flags);
		/* Keep sparse happy by restoring an even lock count on
		 * this lock. In case we return here, we don't call into
		 * __do_once_done but return early in the DO_ONCE() macro.
		 */
		__acquire(once_lock);
		return false;
	}

	return true;
}
EXPORT_SYMBOL(__do_once_start);

void __do_once_done(bool *done, struct static_key *once_key,
		    unsigned long *flags)
	__releases(once_lock)
{
	*done = true;
	spin_unlock_irqrestore(&once_lock, *flags);
	once_disable_jump(once_key);
}
EXPORT_SYMBOL(__do_once_done);
witch'/></form></td></tr>
<tr><td class='sub'>net-next plumbings</td><td class='sub right'>Tobias Klauser</td></tr></table>
<table class='tabs'><tr><td>
<a href='/cgit.cgi/linux/net-next.git/'>summary</a><a href='/cgit.cgi/linux/net-next.git/refs/?id=9569a9a4547d5636827c3f6b09be73ed924b1d16'>refs</a><a class='active' href='/cgit.cgi/linux/net-next.git/log/net/6lowpan/nhc.c'>log</a><a href='/cgit.cgi/linux/net-next.git/tree/net/6lowpan/nhc.c?id=9569a9a4547d5636827c3f6b09be73ed924b1d16'>tree</a><a href='/cgit.cgi/linux/net-next.git/commit/net/6lowpan/nhc.c?id=9569a9a4547d5636827c3f6b09be73ed924b1d16'>commit</a><a href='/cgit.cgi/linux/net-next.git/diff/net/6lowpan/nhc.c?id=9569a9a4547d5636827c3f6b09be73ed924b1d16'>diff</a></td><td class='form'><form class='right' method='get' action='/cgit.cgi/linux/net-next.git/log/net/6lowpan/nhc.c'>
<input type='hidden' name='id' value='9569a9a4547d5636827c3f6b09be73ed924b1d16'/><select name='qt'>
<option value='grep'>log msg</option>
<option value='author'>author</option>
<option value='committer'>committer</option>
<option value='range'>range</option>
</select>
<input class='txt' type='search' size='10' name='q' value=''/>
<input type='submit' value='search'/>
</form>
</td></tr></table>
<div class='path'>path: <a href='/cgit.cgi/linux/net-next.git/log/?id=9569a9a4547d5636827c3f6b09be73ed924b1d16'>root</a>/<a href='/cgit.cgi/linux/net-next.git/log/net?id=9569a9a4547d5636827c3f6b09be73ed924b1d16'>net</a>/<a href='/cgit.cgi/linux/net-next.git/log/net/6lowpan?id=9569a9a4547d5636827c3f6b09be73ed924b1d16'>6lowpan</a>/<a href='/cgit.cgi/linux/net-next.git/log/net/6lowpan/nhc.c?id=9569a9a4547d5636827c3f6b09be73ed924b1d16'>nhc.c</a></div><div class='content'><table class='list nowrap'><tr class='nohover'><th class='left'>Age</th><th class='left'>Commit message (<a href='/cgit.cgi/linux/net-next.git/log/net/6lowpan/nhc.c?id=9569a9a4547d5636827c3f6b09be73ed924b1d16&amp;showmsg=1'>Expand</a>)</th><th class='left'>Author</th><th class='left'>Files</th><th class='left'>Lines</th></tr>