aboutsummaryrefslogtreecommitdiffstats
path: root/lib/percpu_counter.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/percpu_counter.c')
-rw-r--r--lib/percpu_counter.c55
1 files changed, 52 insertions, 3 deletions
diff --git a/lib/percpu_counter.c b/lib/percpu_counter.c
index ec9048e74f44..604678d7d06d 100644
--- a/lib/percpu_counter.c
+++ b/lib/percpu_counter.c
@@ -8,10 +8,53 @@
8#include <linux/init.h> 8#include <linux/init.h>
9#include <linux/cpu.h> 9#include <linux/cpu.h>
10#include <linux/module.h> 10#include <linux/module.h>
11#include <linux/debugobjects.h>
11 12
12static LIST_HEAD(percpu_counters); 13static LIST_HEAD(percpu_counters);
13static DEFINE_MUTEX(percpu_counters_lock); 14static DEFINE_MUTEX(percpu_counters_lock);
14 15
16#ifdef CONFIG_DEBUG_OBJECTS_PERCPU_COUNTER
17
18static struct debug_obj_descr percpu_counter_debug_descr;
19
20static int percpu_counter_fixup_free(void *addr, enum debug_obj_state state)
21{
22 struct percpu_counter *fbc = addr;
23
24 switch (state) {
25 case ODEBUG_STATE_ACTIVE:
26 percpu_counter_destroy(fbc);
27 debug_object_free(fbc, &percpu_counter_debug_descr);
28 return 1;
29 default:
30 return 0;
31 }
32}
33
34static struct debug_obj_descr percpu_counter_debug_descr = {
35 .name = "percpu_counter",
36 .fixup_free = percpu_counter_fixup_free,
37};
38
39static inline void debug_percpu_counter_activate(struct percpu_counter *fbc)
40{
41 debug_object_init(fbc, &percpu_counter_debug_descr);
42 debug_object_activate(fbc, &percpu_counter_debug_descr);
43}
44
45static inline void debug_percpu_counter_deactivate(struct percpu_counter *fbc)
46{
47 debug_object_deactivate(fbc, &percpu_counter_debug_descr);
48 debug_object_free(fbc, &percpu_counter_debug_descr);
49}
50
51#else /* CONFIG_DEBUG_OBJECTS_PERCPU_COUNTER */
52static inline void debug_percpu_counter_activate(struct percpu_counter *fbc)
53{ }
54static inline void debug_percpu_counter_deactivate(struct percpu_counter *fbc)
55{ }
56#endif /* CONFIG_DEBUG_OBJECTS_PERCPU_COUNTER */
57
15void percpu_counter_set(struct percpu_counter *fbc, s64 amount) 58void percpu_counter_set(struct percpu_counter *fbc, s64 amount)
16{ 59{
17 int cpu; 60 int cpu;
@@ -30,9 +73,9 @@ void __percpu_counter_add(struct percpu_counter *fbc, s64 amount, s32 batch)
30{ 73{
31 s64 count; 74 s64 count;
32 s32 *pcount; 75 s32 *pcount;
33 int cpu = get_cpu();
34 76
35 pcount = per_cpu_ptr(fbc->counters, cpu); 77 preempt_disable();
78 pcount = this_cpu_ptr(fbc->counters);
36 count = *pcount + amount; 79 count = *pcount + amount;
37 if (count >= batch || count <= -batch) { 80 if (count >= batch || count <= -batch) {
38 spin_lock(&fbc->lock); 81 spin_lock(&fbc->lock);
@@ -42,7 +85,7 @@ void __percpu_counter_add(struct percpu_counter *fbc, s64 amount, s32 batch)
42 } else { 85 } else {
43 *pcount = count; 86 *pcount = count;
44 } 87 }
45 put_cpu(); 88 preempt_enable();
46} 89}
47EXPORT_SYMBOL(__percpu_counter_add); 90EXPORT_SYMBOL(__percpu_counter_add);
48 91
@@ -75,7 +118,11 @@ int __percpu_counter_init(struct percpu_counter *fbc, s64 amount,
75 fbc->counters = alloc_percpu(s32); 118 fbc->counters = alloc_percpu(s32);
76 if (!fbc->counters) 119 if (!fbc->counters)
77 return -ENOMEM; 120 return -ENOMEM;
121
122 debug_percpu_counter_activate(fbc);
123
78#ifdef CONFIG_HOTPLUG_CPU 124#ifdef CONFIG_HOTPLUG_CPU
125 INIT_LIST_HEAD(&fbc->list);
79 mutex_lock(&percpu_counters_lock); 126 mutex_lock(&percpu_counters_lock);
80 list_add(&fbc->list, &percpu_counters); 127 list_add(&fbc->list, &percpu_counters);
81 mutex_unlock(&percpu_counters_lock); 128 mutex_unlock(&percpu_counters_lock);
@@ -89,6 +136,8 @@ void percpu_counter_destroy(struct percpu_counter *fbc)
89 if (!fbc->counters) 136 if (!fbc->counters)
90 return; 137 return;
91 138
139 debug_percpu_counter_deactivate(fbc);
140
92#ifdef CONFIG_HOTPLUG_CPU 141#ifdef CONFIG_HOTPLUG_CPU
93 mutex_lock(&percpu_counters_lock); 142 mutex_lock(&percpu_counters_lock);
94 list_del(&fbc->list); 143 list_del(&fbc->list);