diff options
author | Peter Zijlstra <peterz@infradead.org> | 2017-08-23 07:23:30 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2017-08-25 05:06:33 -0400 |
commit | e6f3faa734a00c606b7b06c6b9f15e5627d3245b (patch) | |
tree | 4c3f0047d1fa1796442512e03147c40c026f25a8 /include/linux/lockdep.h | |
parent | a1d14934ea4b9db816a8dbfeab1c3e7204a0d871 (diff) |
locking/lockdep: Fix workqueue crossrelease annotation
The new completion/crossrelease annotations interact unfavourable with
the extant flush_work()/flush_workqueue() annotations.
The problem is that when a single work class does:
wait_for_completion(&C)
and
complete(&C)
in different executions, we'll build dependencies like:
lock_map_acquire(W)
complete_acquire(C)
and
lock_map_acquire(W)
complete_release(C)
which results in the dependency chain: W->C->W, which lockdep thinks
spells deadlock, even though there is no deadlock potential since
works are ran concurrently.
One possibility would be to change the work 'lock' to recursive-read,
but that would mean hitting a lockdep limitation on recursive locks.
Also, unconditinoally switching to recursive-read here would fail to
detect the actual deadlock on single-threaded workqueues, which do
have a problem with this.
For now, forcefully disregard these locks for crossrelease.
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Acked-by: Tejun Heo <tj@kernel.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: boqun.feng@gmail.com
Cc: byungchul.park@lge.com
Cc: david@fromorbit.com
Cc: johannes@sipsolutions.net
Cc: oleg@redhat.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'include/linux/lockdep.h')
-rw-r--r-- | include/linux/lockdep.h | 10 |
1 files changed, 6 insertions, 4 deletions
diff --git a/include/linux/lockdep.h b/include/linux/lockdep.h index fc827cab6d6e..78bb7133abed 100644 --- a/include/linux/lockdep.h +++ b/include/linux/lockdep.h | |||
@@ -18,6 +18,8 @@ extern int lock_stat; | |||
18 | 18 | ||
19 | #define MAX_LOCKDEP_SUBCLASSES 8UL | 19 | #define MAX_LOCKDEP_SUBCLASSES 8UL |
20 | 20 | ||
21 | #include <linux/types.h> | ||
22 | |||
21 | #ifdef CONFIG_LOCKDEP | 23 | #ifdef CONFIG_LOCKDEP |
22 | 24 | ||
23 | #include <linux/linkage.h> | 25 | #include <linux/linkage.h> |
@@ -578,11 +580,11 @@ extern void lock_commit_crosslock(struct lockdep_map *lock); | |||
578 | #define STATIC_LOCKDEP_MAP_INIT(_name, _key) \ | 580 | #define STATIC_LOCKDEP_MAP_INIT(_name, _key) \ |
579 | { .name = (_name), .key = (void *)(_key), .cross = 0, } | 581 | { .name = (_name), .key = (void *)(_key), .cross = 0, } |
580 | 582 | ||
581 | extern void crossrelease_hist_start(enum xhlock_context_t c); | 583 | extern void crossrelease_hist_start(enum xhlock_context_t c, bool force); |
582 | extern void crossrelease_hist_end(enum xhlock_context_t c); | 584 | extern void crossrelease_hist_end(enum xhlock_context_t c); |
583 | extern void lockdep_init_task(struct task_struct *task); | 585 | extern void lockdep_init_task(struct task_struct *task); |
584 | extern void lockdep_free_task(struct task_struct *task); | 586 | extern void lockdep_free_task(struct task_struct *task); |
585 | #else | 587 | #else /* !CROSSRELEASE */ |
586 | #define lockdep_init_map_crosslock(m, n, k, s) do {} while (0) | 588 | #define lockdep_init_map_crosslock(m, n, k, s) do {} while (0) |
587 | /* | 589 | /* |
588 | * To initialize a lockdep_map statically use this macro. | 590 | * To initialize a lockdep_map statically use this macro. |
@@ -591,11 +593,11 @@ extern void lockdep_free_task(struct task_struct *task); | |||
591 | #define STATIC_LOCKDEP_MAP_INIT(_name, _key) \ | 593 | #define STATIC_LOCKDEP_MAP_INIT(_name, _key) \ |
592 | { .name = (_name), .key = (void *)(_key), } | 594 | { .name = (_name), .key = (void *)(_key), } |
593 | 595 | ||
594 | static inline void crossrelease_hist_start(enum xhlock_context_t c) {} | 596 | static inline void crossrelease_hist_start(enum xhlock_context_t c, bool force) {} |
595 | static inline void crossrelease_hist_end(enum xhlock_context_t c) {} | 597 | static inline void crossrelease_hist_end(enum xhlock_context_t c) {} |
596 | static inline void lockdep_init_task(struct task_struct *task) {} | 598 | static inline void lockdep_init_task(struct task_struct *task) {} |
597 | static inline void lockdep_free_task(struct task_struct *task) {} | 599 | static inline void lockdep_free_task(struct task_struct *task) {} |
598 | #endif | 600 | #endif /* CROSSRELEASE */ |
599 | 601 | ||
600 | #ifdef CONFIG_LOCK_STAT | 602 | #ifdef CONFIG_LOCK_STAT |
601 | 603 | ||