diff options
author | John Stultz <john.stultz@linaro.org> | 2013-10-07 18:51:59 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2013-11-06 06:40:26 -0500 |
commit | 1ca7d67cf5d5a2aef26a8d9afd789006fa098347 (patch) | |
tree | 8f4f7d1f189d7a08983ab5ef522330f08f337459 /include/linux/seqlock.h | |
parent | 827da44c61419f29ae3be198c342e2147f1a10cb (diff) |
seqcount: Add lockdep functionality to seqcount/seqlock structures
Currently seqlocks and seqcounts don't support lockdep.
After running across a seqcount related deadlock in the timekeeping
code, I used a less-refined and more focused variant of this patch
to narrow down the cause of the issue.
This is a first-pass attempt to properly enable lockdep functionality
on seqlocks and seqcounts.
Since seqcounts are used in the vdso gettimeofday code, I've provided
non-lockdep accessors for those needs.
I've also handled one case where there were nested seqlock writers
and there may be more edge cases.
Comments and feedback would be appreciated!
Signed-off-by: John Stultz <john.stultz@linaro.org>
Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Cc: Eric Dumazet <eric.dumazet@gmail.com>
Cc: Li Zefan <lizefan@huawei.com>
Cc: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: "David S. Miller" <davem@davemloft.net>
Cc: netdev@vger.kernel.org
Link: http://lkml.kernel.org/r/1381186321-4906-3-git-send-email-john.stultz@linaro.org
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'include/linux/seqlock.h')
-rw-r--r-- | include/linux/seqlock.h | 79 |
1 files changed, 72 insertions, 7 deletions
diff --git a/include/linux/seqlock.h b/include/linux/seqlock.h index 21a209336e79..1e8a8b6e837d 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 | ||