blob: 3d9f70972cdfa7a0943653037f777b548dc85478 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001#ifndef _LINUX_PERCPU_COUNTER_H
2#define _LINUX_PERCPU_COUNTER_H
3/*
4 * A simple "approximate counter" for use in ext2 and ext3 superblocks.
5 *
6 * WARNING: these things are HUGE. 4 kbytes per counter on 32-way P4.
7 */
8
Linus Torvalds1da177e2005-04-16 15:20:36 -07009#include <linux/spinlock.h>
10#include <linux/smp.h>
Andrew Mortonc67ad912007-07-15 23:39:51 -070011#include <linux/list.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070012#include <linux/threads.h>
13#include <linux/percpu.h>
Mingming Cao0216bfc2006-06-23 02:05:41 -070014#include <linux/types.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070015
16#ifdef CONFIG_SMP
17
18struct percpu_counter {
19 spinlock_t lock;
Mingming Cao0216bfc2006-06-23 02:05:41 -070020 s64 count;
Andrew Mortonc67ad912007-07-15 23:39:51 -070021#ifdef CONFIG_HOTPLUG_CPU
22 struct list_head list; /* All percpu_counters are on a list */
23#endif
Mingming Cao0216bfc2006-06-23 02:05:41 -070024 s32 *counters;
Linus Torvalds1da177e2005-04-16 15:20:36 -070025};
26
27#if NR_CPUS >= 16
28#define FBC_BATCH (NR_CPUS*2)
29#else
30#define FBC_BATCH (NR_CPUS*4)
31#endif
32
Andrew Mortonc67ad912007-07-15 23:39:51 -070033void percpu_counter_init(struct percpu_counter *fbc, s64 amount);
34void percpu_counter_destroy(struct percpu_counter *fbc);
Mingming Cao0216bfc2006-06-23 02:05:41 -070035void percpu_counter_mod(struct percpu_counter *fbc, s32 amount);
36s64 percpu_counter_sum(struct percpu_counter *fbc);
Linus Torvalds1da177e2005-04-16 15:20:36 -070037
Mingming Cao0216bfc2006-06-23 02:05:41 -070038static inline s64 percpu_counter_read(struct percpu_counter *fbc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070039{
40 return fbc->count;
41}
42
43/*
44 * It is possible for the percpu_counter_read() to return a small negative
45 * number for some counter which should never be negative.
Mingming Cao0216bfc2006-06-23 02:05:41 -070046 *
Linus Torvalds1da177e2005-04-16 15:20:36 -070047 */
Mingming Cao0216bfc2006-06-23 02:05:41 -070048static inline s64 percpu_counter_read_positive(struct percpu_counter *fbc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070049{
Mingming Cao0216bfc2006-06-23 02:05:41 -070050 s64 ret = fbc->count;
Linus Torvalds1da177e2005-04-16 15:20:36 -070051
52 barrier(); /* Prevent reloads of fbc->count */
Mingming Cao0216bfc2006-06-23 02:05:41 -070053 if (ret >= 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -070054 return ret;
55 return 1;
56}
57
58#else
59
60struct percpu_counter {
Mingming Cao0216bfc2006-06-23 02:05:41 -070061 s64 count;
Linus Torvalds1da177e2005-04-16 15:20:36 -070062};
63
Mingming Cao0216bfc2006-06-23 02:05:41 -070064static inline void percpu_counter_init(struct percpu_counter *fbc, s64 amount)
Linus Torvalds1da177e2005-04-16 15:20:36 -070065{
Mingming Cao0216bfc2006-06-23 02:05:41 -070066 fbc->count = amount;
Linus Torvalds1da177e2005-04-16 15:20:36 -070067}
68
69static inline void percpu_counter_destroy(struct percpu_counter *fbc)
70{
71}
72
73static inline void
Mingming Cao0216bfc2006-06-23 02:05:41 -070074percpu_counter_mod(struct percpu_counter *fbc, s32 amount)
Linus Torvalds1da177e2005-04-16 15:20:36 -070075{
76 preempt_disable();
77 fbc->count += amount;
78 preempt_enable();
79}
80
Mingming Cao0216bfc2006-06-23 02:05:41 -070081static inline s64 percpu_counter_read(struct percpu_counter *fbc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070082{
83 return fbc->count;
84}
85
Mingming Cao0216bfc2006-06-23 02:05:41 -070086static inline s64 percpu_counter_read_positive(struct percpu_counter *fbc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070087{
88 return fbc->count;
89}
90
Mingming Cao0216bfc2006-06-23 02:05:41 -070091static inline s64 percpu_counter_sum(struct percpu_counter *fbc)
Andrew Mortone2bab3d2006-03-07 21:55:31 -080092{
93 return percpu_counter_read_positive(fbc);
94}
95
Linus Torvalds1da177e2005-04-16 15:20:36 -070096#endif /* CONFIG_SMP */
97
98static inline void percpu_counter_inc(struct percpu_counter *fbc)
99{
100 percpu_counter_mod(fbc, 1);
101}
102
103static inline void percpu_counter_dec(struct percpu_counter *fbc)
104{
105 percpu_counter_mod(fbc, -1);
106}
107
108#endif /* _LINUX_PERCPU_COUNTER_H */