diff options
Diffstat (limited to 'include/linux/seqlock.h')
-rw-r--r-- | include/linux/seqlock.h | 108 |
1 files changed, 101 insertions, 7 deletions
diff --git a/include/linux/seqlock.h b/include/linux/seqlock.h index 21a209336e79..cf87a24c0f92 100644 --- a/include/linux/seqlock.h +++ b/include/linux/seqlock.h | |||
@@ -34,6 +34,7 @@ | |||
34 | 34 | ||
35 | #include <linux/spinlock.h> | 35 | #include <linux/spinlock.h> |
36 | #include <linux/preempt.h> | 36 | #include <linux/preempt.h> |
37 | #include <linux/lockdep.h> | ||
37 | #include <asm/processor.h> | 38 | #include <asm/processor.h> |
38 | 39 | ||
39 | /* | 40 | /* |
@@ -44,10 +45,50 @@ | |||
44 | */ | 45 | */ |
45 | typedef struct seqcount { | 46 | typedef struct seqcount { |
46 | unsigned sequence; | 47 | unsigned sequence; |
48 | #ifdef CONFIG_DEBUG_LOCK_ALLOC | ||
49 | struct lockdep_map dep_map; | ||
50 | #endif | ||
47 | } seqcount_t; | 51 | } seqcount_t; |
48 | 52 | ||
49 | #define SEQCNT_ZERO { 0 } | 53 | static inline void __seqcount_init(seqcount_t *s, const char *name, |
50 | #define seqcount_init(x) do { *(x) = (seqcount_t) SEQCNT_ZERO; } while (0) | 54 | struct lock_class_key *key) |
55 | { | ||
56 | /* | ||
57 | * Make sure we are not reinitializing a held lock: | ||
58 | */ | ||
59 | lockdep_init_map(&s->dep_map, name, key, 0); | ||
60 | s->sequence = 0; | ||
61 | } | ||
62 | |||
63 | #ifdef CONFIG_DEBUG_LOCK_ALLOC | ||
64 | # define SEQCOUNT_DEP_MAP_INIT(lockname) \ | ||
65 | .dep_map = { .name = #lockname } \ | ||
66 | |||
67 | # define seqcount_init(s) \ | ||
68 | do { \ | ||
69 | static struct lock_class_key __key; \ | ||
70 | __seqcount_init((s), #s, &__key); \ | ||
71 | } while (0) | ||
72 | |||
73 | static inline void seqcount_lockdep_reader_access(const seqcount_t *s) | ||
74 | { | ||
75 | seqcount_t *l = (seqcount_t *)s; | ||
76 | unsigned long flags; | ||
77 | |||
78 | local_irq_save(flags); | ||
79 | seqcount_acquire_read(&l->dep_map, 0, 0, _RET_IP_); | ||
80 | seqcount_release(&l->dep_map, 1, _RET_IP_); | ||
81 | local_irq_restore(flags); | ||
82 | } | ||
83 | |||
84 | #else | ||
85 | # define SEQCOUNT_DEP_MAP_INIT(lockname) | ||
86 | # define seqcount_init(s) __seqcount_init(s, NULL, NULL) | ||
87 | # define seqcount_lockdep_reader_access(x) | ||
88 | #endif | ||
89 | |||
90 | #define SEQCNT_ZERO(lockname) { .sequence = 0, SEQCOUNT_DEP_MAP_INIT(lockname)} | ||
91 | |||
51 | 92 | ||
52 | /** | 93 | /** |
53 | * __read_seqcount_begin - begin a seq-read critical section (without barrier) | 94 | * __read_seqcount_begin - begin a seq-read critical section (without barrier) |
@@ -76,6 +117,22 @@ repeat: | |||
76 | } | 117 | } |
77 | 118 | ||
78 | /** | 119 | /** |
120 | * read_seqcount_begin_no_lockdep - start seq-read critical section w/o lockdep | ||
121 | * @s: pointer to seqcount_t | ||
122 | * Returns: count to be passed to read_seqcount_retry | ||
123 | * | ||
124 | * read_seqcount_begin_no_lockdep opens a read critical section of the given | ||
125 | * seqcount, but without any lockdep checking. Validity of the critical | ||
126 | * section is tested by checking read_seqcount_retry function. | ||
127 | */ | ||
128 | static inline unsigned read_seqcount_begin_no_lockdep(const seqcount_t *s) | ||
129 | { | ||
130 | unsigned ret = __read_seqcount_begin(s); | ||
131 | smp_rmb(); | ||
132 | return ret; | ||
133 | } | ||
134 | |||
135 | /** | ||
79 | * read_seqcount_begin - begin a seq-read critical section | 136 | * read_seqcount_begin - begin a seq-read critical section |
80 | * @s: pointer to seqcount_t | 137 | * @s: pointer to seqcount_t |
81 | * Returns: count to be passed to read_seqcount_retry | 138 | * Returns: count to be passed to read_seqcount_retry |
@@ -86,9 +143,8 @@ repeat: | |||
86 | */ | 143 | */ |
87 | static inline unsigned read_seqcount_begin(const seqcount_t *s) | 144 | static inline unsigned read_seqcount_begin(const seqcount_t *s) |
88 | { | 145 | { |
89 | unsigned ret = __read_seqcount_begin(s); | 146 | seqcount_lockdep_reader_access(s); |
90 | smp_rmb(); | 147 | return read_seqcount_begin_no_lockdep(s); |
91 | return ret; | ||
92 | } | 148 | } |
93 | 149 | ||
94 | /** | 150 | /** |
@@ -108,6 +164,8 @@ static inline unsigned read_seqcount_begin(const seqcount_t *s) | |||
108 | static inline unsigned raw_seqcount_begin(const seqcount_t *s) | 164 | static inline unsigned raw_seqcount_begin(const seqcount_t *s) |
109 | { | 165 | { |
110 | unsigned ret = ACCESS_ONCE(s->sequence); | 166 | unsigned ret = ACCESS_ONCE(s->sequence); |
167 | |||
168 | seqcount_lockdep_reader_access(s); | ||
111 | smp_rmb(); | 169 | smp_rmb(); |
112 | return ret & ~1; | 170 | return ret & ~1; |
113 | } | 171 | } |
@@ -152,14 +210,21 @@ static inline int read_seqcount_retry(const seqcount_t *s, unsigned start) | |||
152 | * Sequence counter only version assumes that callers are using their | 210 | * Sequence counter only version assumes that callers are using their |
153 | * own mutexing. | 211 | * own mutexing. |
154 | */ | 212 | */ |
155 | static inline void write_seqcount_begin(seqcount_t *s) | 213 | static inline void write_seqcount_begin_nested(seqcount_t *s, int subclass) |
156 | { | 214 | { |
157 | s->sequence++; | 215 | s->sequence++; |
158 | smp_wmb(); | 216 | smp_wmb(); |
217 | seqcount_acquire(&s->dep_map, subclass, 0, _RET_IP_); | ||
218 | } | ||
219 | |||
220 | static inline void write_seqcount_begin(seqcount_t *s) | ||
221 | { | ||
222 | write_seqcount_begin_nested(s, 0); | ||
159 | } | 223 | } |
160 | 224 | ||
161 | static inline void write_seqcount_end(seqcount_t *s) | 225 | static inline void write_seqcount_end(seqcount_t *s) |
162 | { | 226 | { |
227 | seqcount_release(&s->dep_map, 1, _RET_IP_); | ||
163 | smp_wmb(); | 228 | smp_wmb(); |
164 | s->sequence++; | 229 | s->sequence++; |
165 | } | 230 | } |
@@ -188,7 +253,7 @@ typedef struct { | |||
188 | */ | 253 | */ |
189 | #define __SEQLOCK_UNLOCKED(lockname) \ | 254 | #define __SEQLOCK_UNLOCKED(lockname) \ |
190 | { \ | 255 | { \ |
191 | .seqcount = SEQCNT_ZERO, \ | 256 | .seqcount = SEQCNT_ZERO(lockname), \ |
192 | .lock = __SPIN_LOCK_UNLOCKED(lockname) \ | 257 | .lock = __SPIN_LOCK_UNLOCKED(lockname) \ |
193 | } | 258 | } |
194 | 259 | ||
@@ -289,6 +354,35 @@ static inline void read_sequnlock_excl(seqlock_t *sl) | |||
289 | spin_unlock(&sl->lock); | 354 | spin_unlock(&sl->lock); |
290 | } | 355 | } |
291 | 356 | ||
357 | /** | ||
358 | * read_seqbegin_or_lock - begin a sequence number check or locking block | ||
359 | * @lock: sequence lock | ||
360 | * @seq : sequence number to be checked | ||
361 | * | ||
362 | * First try it once optimistically without taking the lock. If that fails, | ||
363 | * take the lock. The sequence number is also used as a marker for deciding | ||
364 | * whether to be a reader (even) or writer (odd). | ||
365 | * N.B. seq must be initialized to an even number to begin with. | ||
366 | */ | ||
367 | static inline void read_seqbegin_or_lock(seqlock_t *lock, int *seq) | ||
368 | { | ||
369 | if (!(*seq & 1)) /* Even */ | ||
370 | *seq = read_seqbegin(lock); | ||
371 | else /* Odd */ | ||
372 | read_seqlock_excl(lock); | ||
373 | } | ||
374 | |||
375 | static inline int need_seqretry(seqlock_t *lock, int seq) | ||
376 | { | ||
377 | return !(seq & 1) && read_seqretry(lock, seq); | ||
378 | } | ||
379 | |||
380 | static inline void done_seqretry(seqlock_t *lock, int seq) | ||
381 | { | ||
382 | if (seq & 1) | ||
383 | read_sequnlock_excl(lock); | ||
384 | } | ||
385 | |||
292 | static inline void read_seqlock_excl_bh(seqlock_t *sl) | 386 | static inline void read_seqlock_excl_bh(seqlock_t *sl) |
293 | { | 387 | { |
294 | spin_lock_bh(&sl->lock); | 388 | spin_lock_bh(&sl->lock); |