blob: 50e50095c8d172777c4ea2857435444385b81ece [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);
Tim Chen27f5e0f2010-08-09 17:19:04 -070044int percpu_counter_compare(struct percpu_counter *fbc, s64 rhs);
Linus Torvalds1da177e2005-04-16 15:20:36 -070045
Peter Zijlstra20e89762007-10-16 23:25:43 -070046static inline void percpu_counter_add(struct percpu_counter *fbc, s64 amount)
Peter Zijlstra252e0ba2007-10-16 23:25:43 -070047{
Eric Dumazet179f7eb2009-01-06 14:41:04 -080048 __percpu_counter_add(fbc, amount, percpu_counter_batch);
Peter Zijlstra252e0ba2007-10-16 23:25:43 -070049}
50
Peter Zijlstrabf1d89c2007-10-16 23:25:45 -070051static inline s64 percpu_counter_sum_positive(struct percpu_counter *fbc)
52{
Andrew Morton02d21162008-12-09 13:14:14 -080053 s64 ret = __percpu_counter_sum(fbc);
Peter Zijlstrabf1d89c2007-10-16 23:25:45 -070054 return ret < 0 ? 0 : ret;
55}
56
57static inline s64 percpu_counter_sum(struct percpu_counter *fbc)
58{
Andrew Morton02d21162008-12-09 13:14:14 -080059 return __percpu_counter_sum(fbc);
Peter Zijlstrabf1d89c2007-10-16 23:25:45 -070060}
61
Mingming Cao0216bfc2006-06-23 02:05:41 -070062static inline s64 percpu_counter_read(struct percpu_counter *fbc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070063{
64 return fbc->count;
65}
66
67/*
68 * It is possible for the percpu_counter_read() to return a small negative
69 * number for some counter which should never be negative.
Mingming Cao0216bfc2006-06-23 02:05:41 -070070 *
Linus Torvalds1da177e2005-04-16 15:20:36 -070071 */
Mingming Cao0216bfc2006-06-23 02:05:41 -070072static inline s64 percpu_counter_read_positive(struct percpu_counter *fbc)
Linus Torvalds1da177e2005-04-16 15:20:36 -070073{
Mingming Cao0216bfc2006-06-23 02:05:41 -070074 s64 ret = fbc->count;
Linus Torvalds1da177e2005-04-16 15:20:36 -070075
76 barrier(); /* Prevent reloads of fbc->count */
Mingming Cao0216bfc2006-06-23 02:05:41 -070077 if (ret >= 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -070078 return ret;
Shaohua Lic84598b2011-05-24 17:13:35 -070079 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070080}
81
Theodore Ts'o7f93cff2010-10-27 21:30:13 -040082static inline int percpu_counter_initialized(struct percpu_counter *fbc)
83{
84 return (fbc->counters != NULL);
85}
86
Jesper Dangaard Brouer7fa4cf92013-02-04 23:14:12 +010087#else /* !CONFIG_SMP */
Linus Torvalds1da177e2005-04-16 15:20:36 -070088
89struct percpu_counter {
Mingming Cao0216bfc2006-06-23 02:05:41 -070090 s64 count;
Linus Torvalds1da177e2005-04-16 15:20:36 -070091};
92
Tejun Heo908c7f12014-09-08 09:51:29 +090093static inline int percpu_counter_init(struct percpu_counter *fbc, s64 amount,
94 gfp_t gfp)
Linus Torvalds1da177e2005-04-16 15:20:36 -070095{
Mingming Cao0216bfc2006-06-23 02:05:41 -070096 fbc->count = amount;
Peter Zijlstra833f4072007-10-16 23:25:45 -070097 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070098}
99
100static inline void percpu_counter_destroy(struct percpu_counter *fbc)
101{
102}
103
Peter Zijlstra3a587f42007-10-16 23:25:44 -0700104static inline void percpu_counter_set(struct percpu_counter *fbc, s64 amount)
105{
106 fbc->count = amount;
107}
108
Tim Chen27f5e0f2010-08-09 17:19:04 -0700109static inline int percpu_counter_compare(struct percpu_counter *fbc, s64 rhs)
110{
111 if (fbc->count > rhs)
112 return 1;
113 else if (fbc->count < rhs)
114 return -1;
115 else
116 return 0;
117}
118
Linus Torvalds1da177e2005-04-16 15:20:36 -0700119static inline void
Peter Zijlstra20e89762007-10-16 23:25:43 -0700120percpu_counter_add(struct percpu_counter *fbc, s64 amount)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700121{
122 preempt_disable();
123 fbc->count += amount;
124 preempt_enable();
125}
126
Anton Blanchard0c9cf2e2010-02-02 14:46:10 -0800127static inline void
128__percpu_counter_add(struct percpu_counter *fbc, s64 amount, s32 batch)
129{
130 percpu_counter_add(fbc, amount);
131}
132
Mingming Cao0216bfc2006-06-23 02:05:41 -0700133static inline s64 percpu_counter_read(struct percpu_counter *fbc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700134{
135 return fbc->count;
136}
137
Shaohua Lic84598b2011-05-24 17:13:35 -0700138/*
139 * percpu_counter is intended to track positive numbers. In the UP case the
140 * number should never be negative.
141 */
Mingming Cao0216bfc2006-06-23 02:05:41 -0700142static inline s64 percpu_counter_read_positive(struct percpu_counter *fbc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143{
144 return fbc->count;
145}
146
Peter Zijlstra52d9f3b2007-10-16 23:25:44 -0700147static inline s64 percpu_counter_sum_positive(struct percpu_counter *fbc)
Andrew Mortone2bab3d2006-03-07 21:55:31 -0800148{
149 return percpu_counter_read_positive(fbc);
150}
151
Peter Zijlstrabf1d89c2007-10-16 23:25:45 -0700152static inline s64 percpu_counter_sum(struct percpu_counter *fbc)
153{
154 return percpu_counter_read(fbc);
155}
156
Theodore Ts'o7f93cff2010-10-27 21:30:13 -0400157static inline int percpu_counter_initialized(struct percpu_counter *fbc)
158{
159 return 1;
160}
161
Linus Torvalds1da177e2005-04-16 15:20:36 -0700162#endif /* CONFIG_SMP */
163
164static inline void percpu_counter_inc(struct percpu_counter *fbc)
165{
Peter Zijlstraaa0dff22007-10-16 23:25:42 -0700166 percpu_counter_add(fbc, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700167}
168
169static inline void percpu_counter_dec(struct percpu_counter *fbc)
170{
Peter Zijlstraaa0dff22007-10-16 23:25:42 -0700171 percpu_counter_add(fbc, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172}
173
Peter Zijlstra3cb4f9f2007-10-16 23:25:42 -0700174static inline void percpu_counter_sub(struct percpu_counter *fbc, s64 amount)
175{
176 percpu_counter_add(fbc, -amount);
177}
178
Linus Torvalds1da177e2005-04-16 15:20:36 -0700179#endif /* _LINUX_PERCPU_COUNTER_H */