blob: 66b5de404f22fa1c9af9e5224e879bdb6b3f290e [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>
11#include <linux/threads.h>
12#include <linux/percpu.h>
13
14#ifdef CONFIG_SMP
15
16struct percpu_counter {
17 spinlock_t lock;
18 long count;
19 long *counters;
20};
21
22#if NR_CPUS >= 16
23#define FBC_BATCH (NR_CPUS*2)
24#else
25#define FBC_BATCH (NR_CPUS*4)
26#endif
27
28static inline void percpu_counter_init(struct percpu_counter *fbc)
29{
30 spin_lock_init(&fbc->lock);
31 fbc->count = 0;
32 fbc->counters = alloc_percpu(long);
33}
34
35static inline void percpu_counter_destroy(struct percpu_counter *fbc)
36{
37 free_percpu(fbc->counters);
38}
39
40void percpu_counter_mod(struct percpu_counter *fbc, long amount);
Andrew Mortone2bab3d2006-03-07 21:55:31 -080041long percpu_counter_sum(struct percpu_counter *fbc);
Linus Torvalds1da177e2005-04-16 15:20:36 -070042
43static inline long percpu_counter_read(struct percpu_counter *fbc)
44{
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.
51 */
52static inline long percpu_counter_read_positive(struct percpu_counter *fbc)
53{
54 long ret = fbc->count;
55
56 barrier(); /* Prevent reloads of fbc->count */
57 if (ret > 0)
58 return ret;
59 return 1;
60}
61
62#else
63
64struct percpu_counter {
65 long count;
66};
67
68static inline void percpu_counter_init(struct percpu_counter *fbc)
69{
70 fbc->count = 0;
71}
72
73static inline void percpu_counter_destroy(struct percpu_counter *fbc)
74{
75}
76
77static inline void
78percpu_counter_mod(struct percpu_counter *fbc, long amount)
79{
80 preempt_disable();
81 fbc->count += amount;
82 preempt_enable();
83}
84
85static inline long percpu_counter_read(struct percpu_counter *fbc)
86{
87 return fbc->count;
88}
89
90static inline long percpu_counter_read_positive(struct percpu_counter *fbc)
91{
92 return fbc->count;
93}
94
Andrew Mortone2bab3d2006-03-07 21:55:31 -080095static inline long percpu_counter_sum(struct percpu_counter *fbc)
96{
97 return percpu_counter_read_positive(fbc);
98}
99
Linus Torvalds1da177e2005-04-16 15:20:36 -0700100#endif /* CONFIG_SMP */
101
102static inline void percpu_counter_inc(struct percpu_counter *fbc)
103{
104 percpu_counter_mod(fbc, 1);
105}
106
107static inline void percpu_counter_dec(struct percpu_counter *fbc)
108{
109 percpu_counter_mod(fbc, -1);
110}
111
112#endif /* _LINUX_PERCPU_COUNTER_H */