aboutsummaryrefslogtreecommitdiffstats
path: root/lib/percpu_counter.c
diff options
context:
space:
mode:
authorAndrew Morton <akpm@linux-foundation.org>2007-07-16 02:39:51 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-07-16 12:05:41 -0400
commitc67ad917cbf21b2862e2cf8e8b28339872ef7927 (patch)
tree362d8cf8668998b8cd5deb611693f584b8df5ee5 /lib/percpu_counter.c
parent85420ccad1610f123365eec89848ef25641bc6b7 (diff)
percpu_counters(): use cpu notifiers
per-cpu counters presently must iterate over all possible CPUs in the exhaustive percpu_counter_sum(). But it can be much better to only iterate over the presently-online CPUs. To do this, we must arrange for an offlined CPU's count to be spilled into the counter's central count. We can do this for all percpu_counters in the machine by linking them into a single global list and walking that list at CPU_DEAD time. (I hope. Might have race windows in which the percpu_counter_sum() count is inaccurate?) Cc: Gautham R Shenoy <ego@in.ibm.com> Cc: Oleg Nesterov <oleg@tv-sign.ru> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'lib/percpu_counter.c')
-rw-r--r--lib/percpu_counter.c66
1 files changed, 66 insertions, 0 deletions
diff --git a/lib/percpu_counter.c b/lib/percpu_counter.c
index 850449080e1c..8901c4e9c2e6 100644
--- a/lib/percpu_counter.c
+++ b/lib/percpu_counter.c
@@ -3,8 +3,17 @@
3 */ 3 */
4 4
5#include <linux/percpu_counter.h> 5#include <linux/percpu_counter.h>
6#include <linux/notifier.h>
7#include <linux/mutex.h>
8#include <linux/init.h>
9#include <linux/cpu.h>
6#include <linux/module.h> 10#include <linux/module.h>
7 11
12#ifdef CONFIG_HOTPLUG_CPU
13static LIST_HEAD(percpu_counters);
14static DEFINE_MUTEX(percpu_counters_lock);
15#endif
16
8void percpu_counter_mod(struct percpu_counter *fbc, s32 amount) 17void percpu_counter_mod(struct percpu_counter *fbc, s32 amount)
9{ 18{
10 long count; 19 long count;
@@ -44,3 +53,60 @@ s64 percpu_counter_sum(struct percpu_counter *fbc)
44 return ret < 0 ? 0 : ret; 53 return ret < 0 ? 0 : ret;
45} 54}
46EXPORT_SYMBOL(percpu_counter_sum); 55EXPORT_SYMBOL(percpu_counter_sum);
56
57void percpu_counter_init(struct percpu_counter *fbc, s64 amount)
58{
59 spin_lock_init(&fbc->lock);
60 fbc->count = amount;
61 fbc->counters = alloc_percpu(s32);
62#ifdef CONFIG_HOTPLUG_CPU
63 mutex_lock(&percpu_counters_lock);
64 list_add(&fbc->list, &percpu_counters);
65 mutex_unlock(&percpu_counters_lock);
66#endif
67}
68EXPORT_SYMBOL(percpu_counter_init);
69
70void percpu_counter_destroy(struct percpu_counter *fbc)
71{
72 free_percpu(fbc->counters);
73#ifdef CONFIG_HOTPLUG_CPU
74 mutex_lock(&percpu_counters_lock);
75 list_del(&fbc->list);
76 mutex_unlock(&percpu_counters_lock);
77#endif
78}
79EXPORT_SYMBOL(percpu_counter_destroy);
80
81#ifdef CONFIG_HOTPLUG_CPU
82static int __cpuinit percpu_counter_hotcpu_callback(struct notifier_block *nb,
83 unsigned long action, void *hcpu)
84{
85 unsigned int cpu;
86 struct percpu_counter *fbc;
87
88 if (action != CPU_DEAD)
89 return NOTIFY_OK;
90
91 cpu = (unsigned long)hcpu;
92 mutex_lock(&percpu_counters_lock);
93 list_for_each_entry(fbc, &percpu_counters, list) {
94 s32 *pcount;
95
96 spin_lock(&fbc->lock);
97 pcount = per_cpu_ptr(fbc->counters, cpu);
98 fbc->count += *pcount;
99 *pcount = 0;
100 spin_unlock(&fbc->lock);
101 }
102 mutex_unlock(&percpu_counters_lock);
103 return NOTIFY_OK;
104}
105
106static int __init percpu_counter_startup(void)
107{
108 hotcpu_notifier(percpu_counter_hotcpu_callback, 0);
109 return 0;
110}
111module_init(percpu_counter_startup);
112#endif