aboutsummaryrefslogtreecommitdiffstats
path: root/include/linux/u64_stats_sync.h
diff options
context:
space:
mode:
authorEric Dumazet <eric.dumazet@gmail.com>2010-06-22 13:22:17 -0400
committerDavid S. Miller <davem@davemloft.net>2010-06-23 15:59:47 -0400
commit16b8a4761cbe5082cd35641c066d7c4b6b83cdca (patch)
tree1721b297633a798beb166a4c8778edb1a8a474ad /include/linux/u64_stats_sync.h
parent6afff0caa721211e8c04bdc7627ee3bff95bcb95 (diff)
net: Introduce u64_stats_sync infrastructure
To properly implement 64bits network statistics on 32bit or 64bit hosts, we provide one new type and four methods, to ease conversions. Stats producer should use following template granted it already got an exclusive access to counters (include/linux/u64_stats_sync.h contains some documentation about details) u64_stats_update_begin(&stats->syncp); stats->bytes64 += len; stats->packets64++; u64_stats_update_end(&stats->syncp); While a consumer should use following template to get consistent snapshot : u64 tbytes, tpackets; unsigned int start; do { start = u64_stats_fetch_begin(&stats->syncp); tbytes = stats->bytes64; tpackets = stats->packets64; } while (u64_stats_fetch_retry(&stats->lock, syncp)); Suggested by David Miller, and comments courtesy of Nick Piggin. Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'include/linux/u64_stats_sync.h')
-rw-r--r--include/linux/u64_stats_sync.h107
1 files changed, 107 insertions, 0 deletions
diff --git a/include/linux/u64_stats_sync.h b/include/linux/u64_stats_sync.h
new file mode 100644
index 000000000000..d0505156ed52
--- /dev/null
+++ b/include/linux/u64_stats_sync.h
@@ -0,0 +1,107 @@
1#ifndef _LINUX_U64_STATS_SYNC_H
2#define _LINUX_U64_STATS_SYNC_H
3
4/*
5 * To properly implement 64bits network statistics on 32bit and 64bit hosts,
6 * we provide a synchronization point, that is a noop on 64bit or UP kernels.
7 *
8 * Key points :
9 * 1) Use a seqcount on SMP 32bits, with low overhead.
10 * 2) Whole thing is a noop on 64bit arches or UP kernels.
11 * 3) Write side must ensure mutual exclusion or one seqcount update could
12 * be lost, thus blocking readers forever.
13 * If this synchronization point is not a mutex, but a spinlock or
14 * spinlock_bh() or disable_bh() :
15 * 3.1) Write side should not sleep.
16 * 3.2) Write side should not allow preemption.
17 * 3.3) If applicable, interrupts should be disabled.
18 *
19 * 4) If reader fetches several counters, there is no guarantee the whole values
20 * are consistent (remember point 1) : this is a noop on 64bit arches anyway)
21 *
22 * 5) readers are allowed to sleep or be preempted/interrupted : They perform
23 * pure reads. But if they have to fetch many values, it's better to not allow
24 * preemptions/interruptions to avoid many retries.
25 *
26 * Usage :
27 *
28 * Stats producer (writer) should use following template granted it already got
29 * an exclusive access to counters (a lock is already taken, or per cpu
30 * data is used [in a non preemptable context])
31 *
32 * spin_lock_bh(...) or other synchronization to get exclusive access
33 * ...
34 * u64_stats_update_begin(&stats->syncp);
35 * stats->bytes64 += len; // non atomic operation
36 * stats->packets64++; // non atomic operation
37 * u64_stats_update_end(&stats->syncp);
38 *
39 * While a consumer (reader) should use following template to get consistent
40 * snapshot for each variable (but no guarantee on several ones)
41 *
42 * u64 tbytes, tpackets;
43 * unsigned int start;
44 *
45 * do {
46 * start = u64_stats_fetch_begin(&stats->syncp);
47 * tbytes = stats->bytes64; // non atomic operation
48 * tpackets = stats->packets64; // non atomic operation
49 * } while (u64_stats_fetch_retry(&stats->lock, syncp));
50 *
51 *
52 * Example of use in drivers/net/loopback.c, using per_cpu containers,
53 * in BH disabled context.
54 */
55#include <linux/seqlock.h>
56
57#if BITS_PER_LONG==32 && defined(CONFIG_SMP)
58struct u64_stats_sync {
59 seqcount_t seq;
60};
61
62static void inline u64_stats_update_begin(struct u64_stats_sync *syncp)
63{
64 write_seqcount_begin(&syncp->seq);
65}
66
67static void inline u64_stats_update_end(struct u64_stats_sync *syncp)
68{
69 write_seqcount_end(&syncp->seq);
70}
71
72static unsigned int inline u64_stats_fetch_begin(const struct u64_stats_sync *syncp)
73{
74 return read_seqcount_begin(&syncp->seq);
75}
76
77static bool inline u64_stats_fetch_retry(const struct u64_stats_sync *syncp,
78 unsigned int start)
79{
80 return read_seqcount_retry(&syncp->seq, start);
81}
82
83#else
84struct u64_stats_sync {
85};
86
87static void inline u64_stats_update_begin(struct u64_stats_sync *syncp)
88{
89}
90
91static void inline u64_stats_update_end(struct u64_stats_sync *syncp)
92{
93}
94
95static unsigned int inline u64_stats_fetch_begin(const struct u64_stats_sync *syncp)
96{
97 return 0;
98}
99
100static bool inline u64_stats_fetch_retry(const struct u64_stats_sync *syncp,
101 unsigned int start)
102{
103 return false;
104}
105#endif
106
107#endif /* _LINUX_U64_STATS_SYNC_H */