blob: 84a1094496100906c1b89714f921451a00babb9f [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>
Tejun Heo908c7f12014-09-08 09:51:29 +090015#include <linux/gfp.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070016
17#ifdef CONFIG_SMP
18
19struct percpu_counter {
Thomas Gleixnerf032a452009-07-25 16:21:48 +020020 raw_spinlock_t lock;
Mingming Cao0216bfc2006-06-23 02:05:41 -070021 s64 count;
Andrew Mortonc67ad912007-07-15 23:39:51 -070022#ifdef CONFIG_HOTPLUG_CPU
23 struct list_head list; /* All percpu_counters are on a list */
24#endif
Tejun Heo43cf38e2010-02-02 14:38:57 +090025 s32 __percpu *counters;
Linus Torvalds1da177e2005-04-16 15:20:36 -070026};
27
Eric Dumazet179f7eb2009-01-06 14:41:04 -080028extern int percpu_counter_batch;
Linus Torvalds1da177e2005-04-16 15:20:36 -070029
Tejun Heo908c7f12014-09-08 09:51:29 +090030int __percpu_counter_init(struct percpu_counter *fbc, s64 amount, gfp_t gfp,
Peter Zijlstraea319512008-12-26 15:08:55 +010031 struct lock_class_key *key);
32
Tejun Heo908c7f12014-09-08 09:51:29 +090033#define percpu_counter_init(fbc, value, gfp) \
Peter Zijlstraea319512008-12-26 15:08:55 +010034 ({ \
35 static struct lock_class_key __key; \
36 \
Tejun Heo908c7f12014-09-08 09:51:29 +090037 __percpu_counter_init(fbc, value, gfp, &__key); \
Peter Zijlstraea319512008-12-26 15:08:55 +010038 })
39
Andrew Mortonc67ad912007-07-15 23:39:51 -070040void percpu_counter_destroy(struct percpu_counter *fbc);
Peter Zijlstra3a587f42007-10-16 23:25:44 -070041void percpu_counter_set(struct percpu_counter *fbc, s64 amount);
Peter Zijlstra20e89762007-10-16 23:25:43 -070042void __percpu_counter_add(struct percpu_counter *fbc, s64 amount, s32 batch);
Andrew Morton02d21162008-12-09 13:14:14 -080043s64 __percpu_counter_sum(struct percpu_counter *fbc);
Dave Chinner80188b02015-05-29 07:39:34 +100044int __percpu_counter_compare(struct percpu_counter *fbc, s64 rhs, s32 batch);
45
46static inline int percpu_counter_compare(struct percpu_counter *fbc, s64 rhs)
47{
48 return __percpu_counter_compare(fbc, rhs, percpu_counter_batch);
49}
Linus Torvalds1da177e2005-04-16 15:20:36 -070050
Peter Zijlstra20e89762007-10-16 23:25:43 -070051static inline void percpu_counter_add(struct percpu_counter *fbc, s64 amount)
Peter Zijlstra252e0ba2007-10-16 23:25:43 -070052{
Eric Dumazet179f7eb2009-01-06 14:41:04 -080053 __percpu_counter_add(fbc, amount, percpu_counter_batch);
Peter Zijlstra252e0ba2007-10-16 23:25:43 -070054}
55
Peter Zijlstrabf1d89c2007-10-16 23:25:45 -070056static inline s64 percpu_counter_sum_positive(struct percpu_counter *fbc)
57{
Andrew Morton02d21162008-12-09 13:14:14 -080058 s64 ret = __percpu_counter_sum(fbc);
Peter Zijlstrabf1d89c2007-10-16 23:25:45 -070059 return ret < 0 ? 0 : ret;
60}
61
62static inline s64 percpu_counter_sum(struct percpu_counter *fbc)
63{
Andrew Morton02d21162008-12-09 13:14:14 -080064 return __percpu_counter_sum(fbc);
Peter Zijlstrabf1d89c2007-10-16 23:25:45 -070065}
66
Mingming Cao0216bfc2006-06-23 02:05:41 -070067static inline s64 percpu_counter_read(struct percpu_counter *fbc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070068{
69 return fbc->count;
70}
71
72/*
73 * It is possible for the percpu_counter_read() to return a small negative
74 * number for some counter which should never be negative.
Mingming Cao0216bfc2006-06-23 02:05:41 -070075 *
Linus Torvalds1da177e2005-04-16 15:20:36 -070076 */
Mingming Cao0216bfc2006-06-23 02:05:41 -070077static inline s64 percpu_counter_read_positive(struct percpu_counter *fbc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070078{
Mingming Cao0216bfc2006-06-23 02:05:41 -070079 s64 ret = fbc->count;
Linus Torvalds1da177e2005-04-16 15:20:36 -070080
81 barrier(); /* Prevent reloads of fbc->count */
Mingming Cao0216bfc2006-06-23 02:05:41 -070082 if (ret >= 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -070083 return ret;
Shaohua Lic84598b2011-05-24 17:13:35 -070084 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070085}
86
Theodore Ts'o7f93cff2010-10-27 21:30:13 -040087static inline int percpu_counter_initialized(struct percpu_counter *fbc)
88{
89 return (fbc->counters != NULL);
90}
91
Jesper Dangaard Brouer7fa4cf92013-02-04 23:14:12 +010092#else /* !CONFIG_SMP */
Linus Torvalds1da177e2005-04-16 15:20:36 -070093
94struct percpu_counter {
Mingming Cao0216bfc2006-06-23 02:05:41 -070095 s64 count;
Linus Torvalds1da177e2005-04-16 15:20:36 -070096};
97
Tejun Heo908c7f12014-09-08 09:51:29 +090098static inline int percpu_counter_init(struct percpu_counter *fbc, s64 amount,
99 gfp_t gfp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700100{
Mingming Cao0216bfc2006-06-23 02:05:41 -0700101 fbc->count = amount;
Peter Zijlstra833f4072007-10-16 23:25:45 -0700102 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700103}
104
105static inline void percpu_counter_destroy(struct percpu_counter *fbc)
106{
107}
108
Peter Zijlstra3a587f42007-10-16 23:25:44 -0700109static inline void percpu_counter_set(struct percpu_counter *fbc, s64 amount)
110{
111 fbc->count = amount;
112}
113
Tim Chen27f5e0f2010-08-09 17:19:04 -0700114static inline int percpu_counter_compare(struct percpu_counter *fbc, s64 rhs)
115{
116 if (fbc->count > rhs)
117 return 1;
118 else if (fbc->count < rhs)
119 return -1;
120 else
121 return 0;
122}
123
Dave Chinner80188b02015-05-29 07:39:34 +1000124static inline int
125__percpu_counter_compare(struct percpu_counter *fbc, s64 rhs, s32 batch)
126{
127 return percpu_counter_compare(fbc, rhs);
128}
129
Linus Torvalds1da177e2005-04-16 15:20:36 -0700130static inline void
Peter Zijlstra20e89762007-10-16 23:25:43 -0700131percpu_counter_add(struct percpu_counter *fbc, s64 amount)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700132{
133 preempt_disable();
134 fbc->count += amount;
135 preempt_enable();
136}
137
Anton Blanchard0c9cf2e2010-02-02 14:46:10 -0800138static inline void
139__percpu_counter_add(struct percpu_counter *fbc, s64 amount, s32 batch)
140{
141 percpu_counter_add(fbc, amount);
142}
143
Mingming Cao0216bfc2006-06-23 02:05:41 -0700144static inline s64 percpu_counter_read(struct percpu_counter *fbc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700145{
146 return fbc->count;
147}
148
Shaohua Lic84598b2011-05-24 17:13:35 -0700149/*
150 * percpu_counter is intended to track positive numbers. In the UP case the
151 * number should never be negative.
152 */
Mingming Cao0216bfc2006-06-23 02:05:41 -0700153static inline s64 percpu_counter_read_positive(struct percpu_counter *fbc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154{
155 return fbc->count;
156}
157
Peter Zijlstra52d9f3b2007-10-16 23:25:44 -0700158static inline s64 percpu_counter_sum_positive(struct percpu_counter *fbc)
Andrew Mortone2bab3d2006-03-07 21:55:31 -0800159{
160 return percpu_counter_read_positive(fbc);
161}
162
Peter Zijlstrabf1d89c2007-10-16 23:25:45 -0700163static inline s64 percpu_counter_sum(struct percpu_counter *fbc)
164{
165 return percpu_counter_read(fbc);
166}
167
Theodore Ts'o7f93cff2010-10-27 21:30:13 -0400168static inline int percpu_counter_initialized(struct percpu_counter *fbc)
169{
170 return 1;
171}
172
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173#endif /* CONFIG_SMP */
174
175static inline void percpu_counter_inc(struct percpu_counter *fbc)
176{
Peter Zijlstraaa0dff22007-10-16 23:25:42 -0700177 percpu_counter_add(fbc, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700178}
179
180static inline void percpu_counter_dec(struct percpu_counter *fbc)
181{
Peter Zijlstraaa0dff22007-10-16 23:25:42 -0700182 percpu_counter_add(fbc, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700183}
184
Peter Zijlstra3cb4f9f2007-10-16 23:25:42 -0700185static inline void percpu_counter_sub(struct percpu_counter *fbc, s64 amount)
186{
187 percpu_counter_add(fbc, -amount);
188}
189
Linus Torvalds1da177e2005-04-16 15:20:36 -0700190#endif /* _LINUX_PERCPU_COUNTER_H */