aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/sysctl_binary.c
diff options
context:
space:
mode:
authorLen Brown <len.brown@intel.com>2009-12-24 01:19:00 -0500
committerLen Brown <len.brown@intel.com>2009-12-24 01:19:00 -0500
commitfcb11235d3910c39afece52f6e106a9ca565d34b (patch)
tree07412f9c367f5f9bf6ad7ccd6fa8146c4aba68af /kernel/sysctl_binary.c
parent78a5331dddcffabadef024ccc051f7a519b13238 (diff)
parent44ef00e6482e755f36629773abc2aee83a6f53e3 (diff)
Merge branch 'misc-2.6.33' into release
Diffstat (limited to 'kernel/sysctl_binary.c')
0 files changed, 0 insertions, 0 deletions
div class='alt'>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62




                           
                  



                                
                                                
 
                               
 
                                                       




                                               
                                                     
 
                            




                                            
                                           



                                
                                  
 



                                                      
                    





                                                                          


                             

                    










                                                            
#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);