45b617a29c64eb2854ca0fd143818146234a9c78
[sliver-openvswitch.git] / datapath / linux / compat / include / linux / u64_stats_sync.h
1 #ifndef _LINUX_U64_STATS_SYNC_WRAPPER_H
2 #define _LINUX_U64_STATS_SYNC_WRAPPER_H
3
4 #include <linux/version.h>
5
6 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36)
7 #include_next <linux/u64_stats_sync.h>
8 #else
9
10 /*
11  * To properly implement 64bits network statistics on 32bit and 64bit hosts,
12  * we provide a synchronization point, that is a noop on 64bit or UP kernels.
13  *
14  * Key points :
15  * 1) Use a seqcount on SMP 32bits, with low overhead.
16  * 2) Whole thing is a noop on 64bit arches or UP kernels.
17  * 3) Write side must ensure mutual exclusion or one seqcount update could
18  *    be lost, thus blocking readers forever.
19  *    If this synchronization point is not a mutex, but a spinlock or
20  *    spinlock_bh() or disable_bh() :
21  * 3.1) Write side should not sleep.
22  * 3.2) Write side should not allow preemption.
23  * 3.3) If applicable, interrupts should be disabled.
24  *
25  * 4) If reader fetches several counters, there is no guarantee the whole values
26  *    are consistent (remember point 1) : this is a noop on 64bit arches anyway)
27  *
28  * 5) readers are allowed to sleep or be preempted/interrupted : They perform
29  *    pure reads. But if they have to fetch many values, it's better to not allow
30  *    preemptions/interruptions to avoid many retries.
31  *
32  * 6) If counter might be written by an interrupt, readers should block interrupts.
33  *    (On UP, there is no seqcount_t protection, a reader allowing interrupts could
34  *     read partial values)
35  *
36  * 7) For softirq uses, readers can use u64_stats_fetch_begin_bh() and
37  *    u64_stats_fetch_retry_bh() helpers
38  *
39  * Usage :
40  *
41  * Stats producer (writer) should use following template granted it already got
42  * an exclusive access to counters (a lock is already taken, or per cpu
43  * data is used [in a non preemptable context])
44  *
45  *   spin_lock_bh(...) or other synchronization to get exclusive access
46  *   ...
47  *   u64_stats_update_begin(&stats->syncp);
48  *   stats->bytes64 += len; // non atomic operation
49  *   stats->packets64++;    // non atomic operation
50  *   u64_stats_update_end(&stats->syncp);
51  *
52  * While a consumer (reader) should use following template to get consistent
53  * snapshot for each variable (but no guarantee on several ones)
54  *
55  * u64 tbytes, tpackets;
56  * unsigned int start;
57  *
58  * do {
59  *         start = u64_stats_fetch_begin(&stats->syncp);
60  *         tbytes = stats->bytes64; // non atomic operation
61  *         tpackets = stats->packets64; // non atomic operation
62  * } while (u64_stats_fetch_retry(&stats->syncp, start));
63  *
64  *
65  * Example of use in drivers/net/loopback.c, using per_cpu containers,
66  * in BH disabled context.
67  */
68 #include <linux/seqlock.h>
69
70 struct u64_stats_sync {
71 #if BITS_PER_LONG==32 && defined(CONFIG_SMP)
72         seqcount_t      seq;
73 #endif
74 };
75
76 static inline void u64_stats_update_begin(struct u64_stats_sync *syncp)
77 {
78 #if BITS_PER_LONG==32 && defined(CONFIG_SMP)
79         write_seqcount_begin(&syncp->seq);
80 #endif
81 }
82
83 static inline void u64_stats_update_end(struct u64_stats_sync *syncp)
84 {
85 #if BITS_PER_LONG==32 && defined(CONFIG_SMP)
86         write_seqcount_end(&syncp->seq);
87 #endif
88 }
89
90 static inline unsigned int u64_stats_fetch_begin(const struct u64_stats_sync *syncp)
91 {
92 #if BITS_PER_LONG==32 && defined(CONFIG_SMP)
93         return read_seqcount_begin(&syncp->seq);
94 #else
95 #if BITS_PER_LONG==32
96         preempt_disable();
97 #endif
98         return 0;
99 #endif
100 }
101
102 static inline bool u64_stats_fetch_retry(const struct u64_stats_sync *syncp,
103                                          unsigned int start)
104 {
105 #if BITS_PER_LONG==32 && defined(CONFIG_SMP)
106         return read_seqcount_retry(&syncp->seq, start);
107 #else
108 #if BITS_PER_LONG==32
109         preempt_enable();
110 #endif
111         return false;
112 #endif
113 }
114
115 /*
116  * In case softirq handlers can update u64 counters, readers can use following helpers
117  * - SMP 32bit arches use seqcount protection, irq safe.
118  * - UP 32bit must disable BH.
119  * - 64bit have no problem atomically reading u64 values, irq safe.
120  */
121 static inline unsigned int u64_stats_fetch_begin_bh(const struct u64_stats_sync *syncp)
122 {
123 #if BITS_PER_LONG==32 && defined(CONFIG_SMP)
124         return read_seqcount_begin(&syncp->seq);
125 #else
126 #if BITS_PER_LONG==32
127         local_bh_disable();
128 #endif
129         return 0;
130 #endif
131 }
132
133 static inline bool u64_stats_fetch_retry_bh(const struct u64_stats_sync *syncp,
134                                          unsigned int start)
135 {
136 #if BITS_PER_LONG==32 && defined(CONFIG_SMP)
137         return read_seqcount_retry(&syncp->seq, start);
138 #else
139 #if BITS_PER_LONG==32
140         local_bh_enable();
141 #endif
142         return false;
143 #endif
144 }
145
146 #endif /* Linux kernel < 2.6.36 */
147 #endif /* _LINUX_U64_STATS_SYNC_WRAPPER_H */