blob: e8fa2da13ba69d64cf2ea028ca6e176d3f9cd116 [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);
Peter Zijlstra20e89762007-10-16 23:25:43 -070035void __percpu_counter_add(struct percpu_counter *fbc, s64 amount, s32 batch);
Mingming Cao0216bfc2006-06-23 02:05:41 -070036s64 percpu_counter_sum(struct percpu_counter *fbc);
Linus Torvalds1da177e2005-04-16 15:20:36 -070037
Peter Zijlstra20e89762007-10-16 23:25:43 -070038static inline void percpu_counter_add(struct percpu_counter *fbc, s64 amount)
Peter Zijlstra252e0ba2007-10-16 23:25:43 -070039{
40 __percpu_counter_add(fbc, amount, FBC_BATCH);
41}
42
Mingming Cao0216bfc2006-06-23 02:05:41 -070043static inline s64 percpu_counter_read(struct percpu_counter *fbc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070044{
45 return fbc->count;
46}
47
48/*
49 * It is possible for the percpu_counter_read() to return a small negative
50 * number for some counter which should never be negative.
Mingming Cao0216bfc2006-06-23 02:05:41 -070051 *
Linus Torvalds1da177e2005-04-16 15:20:36 -070052 */
Mingming Cao0216bfc2006-06-23 02:05:41 -070053static inline s64 percpu_counter_read_positive(struct percpu_counter *fbc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070054{
Mingming Cao0216bfc2006-06-23 02:05:41 -070055 s64 ret = fbc->count;
Linus Torvalds1da177e2005-04-16 15:20:36 -070056
57 barrier(); /* Prevent reloads of fbc->count */
Mingming Cao0216bfc2006-06-23 02:05:41 -070058 if (ret >= 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -070059 return ret;
60 return 1;
61}
62
63#else
64
65struct percpu_counter {
Mingming Cao0216bfc2006-06-23 02:05:41 -070066 s64 count;
Linus Torvalds1da177e2005-04-16 15:20:36 -070067};
68
Mingming Cao0216bfc2006-06-23 02:05:41 -070069static inline void percpu_counter_init(struct percpu_counter *fbc, s64 amount)
Linus Torvalds1da177e2005-04-16 15:20:36 -070070{
Mingming Cao0216bfc2006-06-23 02:05:41 -070071 fbc->count = amount;
Linus Torvalds1da177e2005-04-16 15:20:36 -070072}
73
74static inline void percpu_counter_destroy(struct percpu_counter *fbc)
75{
76}
77
Peter Zijlstra252e0ba2007-10-16 23:25:43 -070078#define __percpu_counter_add(fbc, amount, batch) \
79 percpu_counter_add(fbc, amount)
80
Linus Torvalds1da177e2005-04-16 15:20:36 -070081static inline void
Peter Zijlstra20e89762007-10-16 23:25:43 -070082percpu_counter_add(struct percpu_counter *fbc, s64 amount)
Linus Torvalds1da177e2005-04-16 15:20:36 -070083{
84 preempt_disable();
85 fbc->count += amount;
86 preempt_enable();
87}
88
Mingming Cao0216bfc2006-06-23 02:05:41 -070089static inline s64 percpu_counter_read(struct percpu_counter *fbc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070090{
91 return fbc->count;
92}
93
Mingming Cao0216bfc2006-06-23 02:05:41 -070094static inline s64 percpu_counter_read_positive(struct percpu_counter *fbc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070095{
96 return fbc->count;
97}
98
Mingming Cao0216bfc2006-06-23 02:05:41 -070099static inline s64 percpu_counter_sum(struct percpu_counter *fbc)
Andrew Mortone2bab3d2006-03-07 21:55:31 -0800100{
101 return percpu_counter_read_positive(fbc);
102}
103
Linus Torvalds1da177e2005-04-16 15:20:36 -0700104#endif /* CONFIG_SMP */
105
106static inline void percpu_counter_inc(struct percpu_counter *fbc)
107{
Peter Zijlstraaa0dff22007-10-16 23:25:42 -0700108 percpu_counter_add(fbc, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109}
110
111static inline void percpu_counter_dec(struct percpu_counter *fbc)
112{
Peter Zijlstraaa0dff22007-10-16 23:25:42 -0700113 percpu_counter_add(fbc, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700114}
115
Peter Zijlstra3cb4f9f2007-10-16 23:25:42 -0700116static inline void percpu_counter_sub(struct percpu_counter *fbc, s64 amount)
117{
118 percpu_counter_add(fbc, -amount);
119}
120
Linus Torvalds1da177e2005-04-16 15:20:36 -0700121#endif /* _LINUX_PERCPU_COUNTER_H */