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 | |
| 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')
| -rw-r--r-- | include/linux/init_task.h | 8 | ||||
| -rw-r--r-- | include/linux/lockdep.h | 8 | ||||
| -rw-r--r-- | include/linux/seqlock.h | 79 |
3 files changed, 82 insertions, 13 deletions
diff --git a/include/linux/init_task.h b/include/linux/init_task.h index 5cd0f0949927..b0ed422e4e4a 100644 --- a/include/linux/init_task.h +++ b/include/linux/init_task.h | |||
| @@ -32,10 +32,10 @@ extern struct fs_struct init_fs; | |||
| 32 | #endif | 32 | #endif |
| 33 | 33 | ||
| 34 | #ifdef CONFIG_CPUSETS | 34 | #ifdef CONFIG_CPUSETS |
| 35 | #define INIT_CPUSET_SEQ \ | 35 | #define INIT_CPUSET_SEQ(tsk) \ |
| 36 | .mems_allowed_seq = SEQCNT_ZERO, | 36 | .mems_allowed_seq = SEQCNT_ZERO(tsk.mems_allowed_seq), |
| 37 | #else | 37 | #else |
| 38 | #define INIT_CPUSET_SEQ | 38 | #define INIT_CPUSET_SEQ(tsk) |
| 39 | #endif | 39 | #endif |
| 40 | 40 | ||
| 41 | #define INIT_SIGNALS(sig) { \ | 41 | #define INIT_SIGNALS(sig) { \ |
| @@ -220,7 +220,7 @@ extern struct task_group root_task_group; | |||
| 220 | INIT_FTRACE_GRAPH \ | 220 | INIT_FTRACE_GRAPH \ |
| 221 | INIT_TRACE_RECURSION \ | 221 | INIT_TRACE_RECURSION \ |
| 222 | INIT_TASK_RCU_PREEMPT(tsk) \ | 222 | INIT_TASK_RCU_PREEMPT(tsk) \ |
| 223 | INIT_CPUSET_SEQ \ | 223 | INIT_CPUSET_SEQ(tsk) \ |
| 224 | INIT_VTIME(tsk) \ | 224 | INIT_VTIME(tsk) \ |
| 225 | } | 225 | } |
| 226 | 226 | ||
diff --git a/include/linux/lockdep.h b/include/linux/lockdep.h index cfc2f119779a..92b1bfc5da60 100644 --- a/include/linux/lockdep.h +++ b/include/linux/lockdep.h | |||
| @@ -497,6 +497,10 @@ static inline void print_irqtrace_events(struct task_struct *curr) | |||
| 497 | #define rwlock_acquire_read(l, s, t, i) lock_acquire_shared_recursive(l, s, t, NULL, i) | 497 | #define rwlock_acquire_read(l, s, t, i) lock_acquire_shared_recursive(l, s, t, NULL, i) |
| 498 | #define rwlock_release(l, n, i) lock_release(l, n, i) | 498 | #define rwlock_release(l, n, i) lock_release(l, n, i) |
| 499 | 499 | ||
| 500 | #define seqcount_acquire(l, s, t, i) lock_acquire_exclusive(l, s, t, NULL, i) | ||
| 501 | #define seqcount_acquire_read(l, s, t, i) lock_acquire_shared_recursive(l, s, t, NULL, i) | ||
| 502 | #define seqcount_release(l, n, i) lock_release(l, n, i) | ||
| 503 | |||
| 500 | #define mutex_acquire(l, s, t, i) lock_acquire_exclusive(l, s, t, NULL, i) | 504 | #define mutex_acquire(l, s, t, i) lock_acquire_exclusive(l, s, t, NULL, i) |
| 501 | #define mutex_acquire_nest(l, s, t, n, i) lock_acquire_exclusive(l, s, t, n, i) | 505 | #define mutex_acquire_nest(l, s, t, n, i) lock_acquire_exclusive(l, s, t, n, i) |
| 502 | #define mutex_release(l, n, i) lock_release(l, n, i) | 506 | #define mutex_release(l, n, i) lock_release(l, n, i) |
| @@ -504,11 +508,11 @@ static inline void print_irqtrace_events(struct task_struct *curr) | |||
| 504 | #define rwsem_acquire(l, s, t, i) lock_acquire_exclusive(l, s, t, NULL, i) | 508 | #define rwsem_acquire(l, s, t, i) lock_acquire_exclusive(l, s, t, NULL, i) |
| 505 | #define rwsem_acquire_nest(l, s, t, n, i) lock_acquire_exclusive(l, s, t, n, i) | 509 | #define rwsem_acquire_nest(l, s, t, n, i) lock_acquire_exclusive(l, s, t, n, i) |
| 506 | #define rwsem_acquire_read(l, s, t, i) lock_acquire_shared(l, s, t, NULL, i) | 510 | #define rwsem_acquire_read(l, s, t, i) lock_acquire_shared(l, s, t, NULL, i) |
| 507 | # define rwsem_release(l, n, i) lock_release(l, n, i) | 511 | #define rwsem_release(l, n, i) lock_release(l, n, i) |
| 508 | 512 | ||
| 509 | #define lock_map_acquire(l) lock_acquire_exclusive(l, 0, 0, NULL, _THIS_IP_) | 513 | #define lock_map_acquire(l) lock_acquire_exclusive(l, 0, 0, NULL, _THIS_IP_) |
| 510 | #define lock_map_acquire_read(l) lock_acquire_shared_recursive(l, 0, 0, NULL, _THIS_IP_) | 514 | #define lock_map_acquire_read(l) lock_acquire_shared_recursive(l, 0, 0, NULL, _THIS_IP_) |
| 511 | # define lock_map_release(l) lock_release(l, 1, _THIS_IP_) | 515 | #define lock_map_release(l) lock_release(l, 1, _THIS_IP_) |
| 512 | 516 | ||
| 513 | #ifdef CONFIG_PROVE_LOCKING | 517 | #ifdef CONFIG_PROVE_LOCKING |
| 514 | # define might_lock(lock) \ | 518 | # define might_lock(lock) \ |
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 | ||
