blob: 4f052496cdfd79b4db4ac104384b212c5790f1ad [file] [log] [blame]
Greg Kroah-Hartmanb2441312017-11-01 15:07:57 +01001/* SPDX-License-Identifier: GPL-2.0 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002#ifndef _LINUX_PERCPU_COUNTER_H
3#define _LINUX_PERCPU_COUNTER_H
4/*
5 * A simple "approximate counter" for use in ext2 and ext3 superblocks.
6 *
7 * WARNING: these things are HUGE. 4 kbytes per counter on 32-way P4.
8 */
9
Linus Torvalds1da177e2005-04-16 15:20:36 -070010#include <linux/spinlock.h>
11#include <linux/smp.h>
Andrew Mortonc67ad912007-07-15 23:39:51 -070012#include <linux/list.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070013#include <linux/threads.h>
14#include <linux/percpu.h>
Mingming Cao0216bfc2006-06-23 02:05:41 -070015#include <linux/types.h>
Tejun Heo908c7f12014-09-08 09:51:29 +090016#include <linux/gfp.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070017
18#ifdef CONFIG_SMP
19
20struct percpu_counter {
Thomas Gleixnerf032a452009-07-25 16:21:48 +020021 raw_spinlock_t lock;
Mingming Cao0216bfc2006-06-23 02:05:41 -070022 s64 count;
Andrew Mortonc67ad912007-07-15 23:39:51 -070023#ifdef CONFIG_HOTPLUG_CPU
24 struct list_head list; /* All percpu_counters are on a list */
25#endif
Tejun Heo43cf38e2010-02-02 14:38:57 +090026 s32 __percpu *counters;
Linus Torvalds1da177e2005-04-16 15:20:36 -070027};
28
Eric Dumazet179f7eb2009-01-06 14:41:04 -080029extern int percpu_counter_batch;
Linus Torvalds1da177e2005-04-16 15:20:36 -070030
Tejun Heo908c7f12014-09-08 09:51:29 +090031int __percpu_counter_init(struct percpu_counter *fbc, s64 amount, gfp_t gfp,
Peter Zijlstraea319512008-12-26 15:08:55 +010032 struct lock_class_key *key);
33
Tejun Heo908c7f12014-09-08 09:51:29 +090034#define percpu_counter_init(fbc, value, gfp) \
Peter Zijlstraea319512008-12-26 15:08:55 +010035 ({ \
36 static struct lock_class_key __key; \
37 \
Tejun Heo908c7f12014-09-08 09:51:29 +090038 __percpu_counter_init(fbc, value, gfp, &__key); \
Peter Zijlstraea319512008-12-26 15:08:55 +010039 })
40
Andrew Mortonc67ad912007-07-15 23:39:51 -070041void percpu_counter_destroy(struct percpu_counter *fbc);
Peter Zijlstra3a587f42007-10-16 23:25:44 -070042void percpu_counter_set(struct percpu_counter *fbc, s64 amount);
Nikolay Borisov104b4e52017-06-20 21:01:20 +030043void percpu_counter_add_batch(struct percpu_counter *fbc, s64 amount,
44 s32 batch);
Andrew Morton02d2116882008-12-09 13:14:14 -080045s64 __percpu_counter_sum(struct percpu_counter *fbc);
Dave Chinner80188b02015-05-29 07:39:34 +100046int __percpu_counter_compare(struct percpu_counter *fbc, s64 rhs, s32 batch);
47
48static inline int percpu_counter_compare(struct percpu_counter *fbc, s64 rhs)
49{
50 return __percpu_counter_compare(fbc, rhs, percpu_counter_batch);
51}
Linus Torvalds1da177e2005-04-16 15:20:36 -070052
Peter Zijlstra20e89762007-10-16 23:25:43 -070053static inline void percpu_counter_add(struct percpu_counter *fbc, s64 amount)
Peter Zijlstra252e0ba2007-10-16 23:25:43 -070054{
Nikolay Borisov104b4e52017-06-20 21:01:20 +030055 percpu_counter_add_batch(fbc, amount, percpu_counter_batch);
Peter Zijlstra252e0ba2007-10-16 23:25:43 -070056}
57
Peter Zijlstrabf1d89c2007-10-16 23:25:45 -070058static inline s64 percpu_counter_sum_positive(struct percpu_counter *fbc)
59{
Andrew Morton02d2116882008-12-09 13:14:14 -080060 s64 ret = __percpu_counter_sum(fbc);
Peter Zijlstrabf1d89c2007-10-16 23:25:45 -070061 return ret < 0 ? 0 : ret;
62}
63
64static inline s64 percpu_counter_sum(struct percpu_counter *fbc)
65{
Andrew Morton02d2116882008-12-09 13:14:14 -080066 return __percpu_counter_sum(fbc);
Peter Zijlstrabf1d89c2007-10-16 23:25:45 -070067}
68
Mingming Cao0216bfc2006-06-23 02:05:41 -070069static inline s64 percpu_counter_read(struct percpu_counter *fbc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070070{
71 return fbc->count;
72}
73
74/*
75 * It is possible for the percpu_counter_read() to return a small negative
76 * number for some counter which should never be negative.
Mingming Cao0216bfc2006-06-23 02:05:41 -070077 *
Linus Torvalds1da177e2005-04-16 15:20:36 -070078 */
Mingming Cao0216bfc2006-06-23 02:05:41 -070079static inline s64 percpu_counter_read_positive(struct percpu_counter *fbc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070080{
Mingming Cao0216bfc2006-06-23 02:05:41 -070081 s64 ret = fbc->count;
Linus Torvalds1da177e2005-04-16 15:20:36 -070082
83 barrier(); /* Prevent reloads of fbc->count */
Mingming Cao0216bfc2006-06-23 02:05:41 -070084 if (ret >= 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -070085 return ret;
Shaohua Lic84598b2011-05-24 17:13:35 -070086 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070087}
88
guoyayun85dcbba2017-12-15 14:48:32 +080089static inline bool percpu_counter_initialized(struct percpu_counter *fbc)
Theodore Ts'o7f93cff2010-10-27 21:30:13 -040090{
91 return (fbc->counters != NULL);
92}
93
Jesper Dangaard Brouer7fa4cf92013-02-04 23:14:12 +010094#else /* !CONFIG_SMP */
Linus Torvalds1da177e2005-04-16 15:20:36 -070095
96struct percpu_counter {
Mingming Cao0216bfc2006-06-23 02:05:41 -070097 s64 count;
Linus Torvalds1da177e2005-04-16 15:20:36 -070098};
99
Tejun Heo908c7f12014-09-08 09:51:29 +0900100static inline int percpu_counter_init(struct percpu_counter *fbc, s64 amount,
101 gfp_t gfp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700102{
Mingming Cao0216bfc2006-06-23 02:05:41 -0700103 fbc->count = amount;
Peter Zijlstra833f4072007-10-16 23:25:45 -0700104 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700105}
106
107static inline void percpu_counter_destroy(struct percpu_counter *fbc)
108{
109}
110
Peter Zijlstra3a587f42007-10-16 23:25:44 -0700111static inline void percpu_counter_set(struct percpu_counter *fbc, s64 amount)
112{
113 fbc->count = amount;
114}
115
Tim Chen27f5e0f2010-08-09 17:19:04 -0700116static inline int percpu_counter_compare(struct percpu_counter *fbc, s64 rhs)
117{
118 if (fbc->count > rhs)
119 return 1;
120 else if (fbc->count < rhs)
121 return -1;
122 else
123 return 0;
124}
125
Dave Chinner80188b02015-05-29 07:39:34 +1000126static inline int
127__percpu_counter_compare(struct percpu_counter *fbc, s64 rhs, s32 batch)
128{
129 return percpu_counter_compare(fbc, rhs);
130}
131
Linus Torvalds1da177e2005-04-16 15:20:36 -0700132static inline void
Peter Zijlstra20e89762007-10-16 23:25:43 -0700133percpu_counter_add(struct percpu_counter *fbc, s64 amount)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700134{
135 preempt_disable();
136 fbc->count += amount;
137 preempt_enable();
138}
139
Anton Blanchard0c9cf2e2010-02-02 14:46:10 -0800140static inline void
Nikolay Borisov104b4e52017-06-20 21:01:20 +0300141percpu_counter_add_batch(struct percpu_counter *fbc, s64 amount, s32 batch)
Anton Blanchard0c9cf2e2010-02-02 14:46:10 -0800142{
143 percpu_counter_add(fbc, amount);
144}
145
Mingming Cao0216bfc2006-06-23 02:05:41 -0700146static inline s64 percpu_counter_read(struct percpu_counter *fbc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700147{
148 return fbc->count;
149}
150
Shaohua Lic84598b2011-05-24 17:13:35 -0700151/*
152 * percpu_counter is intended to track positive numbers. In the UP case the
153 * number should never be negative.
154 */
Mingming Cao0216bfc2006-06-23 02:05:41 -0700155static inline s64 percpu_counter_read_positive(struct percpu_counter *fbc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700156{
157 return fbc->count;
158}
159
Peter Zijlstra52d9f3b2007-10-16 23:25:44 -0700160static inline s64 percpu_counter_sum_positive(struct percpu_counter *fbc)
Andrew Mortone2bab3d2006-03-07 21:55:31 -0800161{
162 return percpu_counter_read_positive(fbc);
163}
164
Peter Zijlstrabf1d89c2007-10-16 23:25:45 -0700165static inline s64 percpu_counter_sum(struct percpu_counter *fbc)
166{
167 return percpu_counter_read(fbc);
168}
169
guoyayun85dcbba2017-12-15 14:48:32 +0800170static inline bool percpu_counter_initialized(struct percpu_counter *fbc)
Theodore Ts'o7f93cff2010-10-27 21:30:13 -0400171{
guoyayun85dcbba2017-12-15 14:48:32 +0800172 return true;
Theodore Ts'o7f93cff2010-10-27 21:30:13 -0400173}
174
Linus Torvalds1da177e2005-04-16 15:20:36 -0700175#endif /* CONFIG_SMP */
176
177static inline void percpu_counter_inc(struct percpu_counter *fbc)
178{
Peter Zijlstraaa0dff22007-10-16 23:25:42 -0700179 percpu_counter_add(fbc, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180}
181
182static inline void percpu_counter_dec(struct percpu_counter *fbc)
183{
Peter Zijlstraaa0dff22007-10-16 23:25:42 -0700184 percpu_counter_add(fbc, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700185}
186
Peter Zijlstra3cb4f9f2007-10-16 23:25:42 -0700187static inline void percpu_counter_sub(struct percpu_counter *fbc, s64 amount)
188{
189 percpu_counter_add(fbc, -amount);
190}
191
Linus Torvalds1da177e2005-04-16 15:20:36 -0700192#endif /* _LINUX_PERCPU_COUNTER_H */