blob: ec065387f44307852a512197a0ebfaa3c45dbbf6 [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);
Nikolay Borisov104b4e52017-06-20 21:01:20 +030042void percpu_counter_add_batch(struct percpu_counter *fbc, s64 amount,
43 s32 batch);
Andrew Morton02d21162008-12-09 13:14:14 -080044s64 __percpu_counter_sum(struct percpu_counter *fbc);
Dave Chinner80188b02015-05-29 07:39:34 +100045int __percpu_counter_compare(struct percpu_counter *fbc, s64 rhs, s32 batch);
46
47static inline int percpu_counter_compare(struct percpu_counter *fbc, s64 rhs)
48{
49 return __percpu_counter_compare(fbc, rhs, percpu_counter_batch);
50}
Linus Torvalds1da177e2005-04-16 15:20:36 -070051
Peter Zijlstra20e89762007-10-16 23:25:43 -070052static inline void percpu_counter_add(struct percpu_counter *fbc, s64 amount)
Peter Zijlstra252e0ba2007-10-16 23:25:43 -070053{
Nikolay Borisov104b4e52017-06-20 21:01:20 +030054 percpu_counter_add_batch(fbc, amount, percpu_counter_batch);
Peter Zijlstra252e0ba2007-10-16 23:25:43 -070055}
56
Peter Zijlstrabf1d89c2007-10-16 23:25:45 -070057static inline s64 percpu_counter_sum_positive(struct percpu_counter *fbc)
58{
Andrew Morton02d21162008-12-09 13:14:14 -080059 s64 ret = __percpu_counter_sum(fbc);
Peter Zijlstrabf1d89c2007-10-16 23:25:45 -070060 return ret < 0 ? 0 : ret;
61}
62
63static inline s64 percpu_counter_sum(struct percpu_counter *fbc)
64{
Andrew Morton02d21162008-12-09 13:14:14 -080065 return __percpu_counter_sum(fbc);
Peter Zijlstrabf1d89c2007-10-16 23:25:45 -070066}
67
Mingming Cao0216bfc2006-06-23 02:05:41 -070068static inline s64 percpu_counter_read(struct percpu_counter *fbc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070069{
70 return fbc->count;
71}
72
73/*
74 * It is possible for the percpu_counter_read() to return a small negative
75 * number for some counter which should never be negative.
Mingming Cao0216bfc2006-06-23 02:05:41 -070076 *
Linus Torvalds1da177e2005-04-16 15:20:36 -070077 */
Mingming Cao0216bfc2006-06-23 02:05:41 -070078static inline s64 percpu_counter_read_positive(struct percpu_counter *fbc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070079{
Mingming Cao0216bfc2006-06-23 02:05:41 -070080 s64 ret = fbc->count;
Linus Torvalds1da177e2005-04-16 15:20:36 -070081
82 barrier(); /* Prevent reloads of fbc->count */
Mingming Cao0216bfc2006-06-23 02:05:41 -070083 if (ret >= 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -070084 return ret;
Shaohua Lic84598b2011-05-24 17:13:35 -070085 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070086}
87
Theodore Ts'o7f93cff2010-10-27 21:30:13 -040088static inline int percpu_counter_initialized(struct percpu_counter *fbc)
89{
90 return (fbc->counters != NULL);
91}
92
Jesper Dangaard Brouer7fa4cf92013-02-04 23:14:12 +010093#else /* !CONFIG_SMP */
Linus Torvalds1da177e2005-04-16 15:20:36 -070094
95struct percpu_counter {
Mingming Cao0216bfc2006-06-23 02:05:41 -070096 s64 count;
Linus Torvalds1da177e2005-04-16 15:20:36 -070097};
98
Tejun Heo908c7f12014-09-08 09:51:29 +090099static inline int percpu_counter_init(struct percpu_counter *fbc, s64 amount,
100 gfp_t gfp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700101{
Mingming Cao0216bfc2006-06-23 02:05:41 -0700102 fbc->count = amount;
Peter Zijlstra833f4072007-10-16 23:25:45 -0700103 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700104}
105
106static inline void percpu_counter_destroy(struct percpu_counter *fbc)
107{
108}
109
Peter Zijlstra3a587f42007-10-16 23:25:44 -0700110static inline void percpu_counter_set(struct percpu_counter *fbc, s64 amount)
111{
112 fbc->count = amount;
113}
114
Tim Chen27f5e0f2010-08-09 17:19:04 -0700115static inline int percpu_counter_compare(struct percpu_counter *fbc, s64 rhs)
116{
117 if (fbc->count > rhs)
118 return 1;
119 else if (fbc->count < rhs)
120 return -1;
121 else
122 return 0;
123}
124
Dave Chinner80188b02015-05-29 07:39:34 +1000125static inline int
126__percpu_counter_compare(struct percpu_counter *fbc, s64 rhs, s32 batch)
127{
128 return percpu_counter_compare(fbc, rhs);
129}
130
Linus Torvalds1da177e2005-04-16 15:20:36 -0700131static inline void
Peter Zijlstra20e89762007-10-16 23:25:43 -0700132percpu_counter_add(struct percpu_counter *fbc, s64 amount)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700133{
134 preempt_disable();
135 fbc->count += amount;
136 preempt_enable();
137}
138
Anton Blanchard0c9cf2e2010-02-02 14:46:10 -0800139static inline void
Nikolay Borisov104b4e52017-06-20 21:01:20 +0300140percpu_counter_add_batch(struct percpu_counter *fbc, s64 amount, s32 batch)
Anton Blanchard0c9cf2e2010-02-02 14:46:10 -0800141{
142 percpu_counter_add(fbc, amount);
143}
144
Mingming Cao0216bfc2006-06-23 02:05:41 -0700145static inline s64 percpu_counter_read(struct percpu_counter *fbc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700146{
147 return fbc->count;
148}
149
Shaohua Lic84598b2011-05-24 17:13:35 -0700150/*
151 * percpu_counter is intended to track positive numbers. In the UP case the
152 * number should never be negative.
153 */
Mingming Cao0216bfc2006-06-23 02:05:41 -0700154static inline s64 percpu_counter_read_positive(struct percpu_counter *fbc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700155{
156 return fbc->count;
157}
158
Peter Zijlstra52d9f3b2007-10-16 23:25:44 -0700159static inline s64 percpu_counter_sum_positive(struct percpu_counter *fbc)
Andrew Mortone2bab3d2006-03-07 21:55:31 -0800160{
161 return percpu_counter_read_positive(fbc);
162}
163
Peter Zijlstrabf1d89c2007-10-16 23:25:45 -0700164static inline s64 percpu_counter_sum(struct percpu_counter *fbc)
165{
166 return percpu_counter_read(fbc);
167}
168
Theodore Ts'o7f93cff2010-10-27 21:30:13 -0400169static inline int percpu_counter_initialized(struct percpu_counter *fbc)
170{
171 return 1;
172}
173
Linus Torvalds1da177e2005-04-16 15:20:36 -0700174#endif /* CONFIG_SMP */
175
176static inline void percpu_counter_inc(struct percpu_counter *fbc)
177{
Peter Zijlstraaa0dff22007-10-16 23:25:42 -0700178 percpu_counter_add(fbc, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700179}
180
181static inline void percpu_counter_dec(struct percpu_counter *fbc)
182{
Peter Zijlstraaa0dff22007-10-16 23:25:42 -0700183 percpu_counter_add(fbc, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700184}
185
Peter Zijlstra3cb4f9f2007-10-16 23:25:42 -0700186static inline void percpu_counter_sub(struct percpu_counter *fbc, s64 amount)
187{
188 percpu_counter_add(fbc, -amount);
189}
190
Linus Torvalds1da177e2005-04-16 15:20:36 -0700191#endif /* _LINUX_PERCPU_COUNTER_H */