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 | |
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>
-rw-r--r-- | include/linux/irqflags.h | 4 | ||||
-rw-r--r-- | include/linux/lockdep.h | 10 | ||||
-rw-r--r-- | kernel/locking/lockdep.c | 56 | ||||
-rw-r--r-- | kernel/workqueue.c | 23 |
4 files changed, 66 insertions, 27 deletions
diff --git a/include/linux/irqflags.h b/include/linux/irqflags.h index 5fdd93bb9300..9bc050bc81b2 100644 --- a/include/linux/irqflags.h +++ b/include/linux/irqflags.h | |||
@@ -26,7 +26,7 @@ | |||
26 | # define trace_hardirq_enter() \ | 26 | # define trace_hardirq_enter() \ |
27 | do { \ | 27 | do { \ |
28 | current->hardirq_context++; \ | 28 | current->hardirq_context++; \ |
29 | crossrelease_hist_start(XHLOCK_HARD); \ | 29 | crossrelease_hist_start(XHLOCK_HARD, 0);\ |
30 | } while (0) | 30 | } while (0) |
31 | # define trace_hardirq_exit() \ | 31 | # define trace_hardirq_exit() \ |
32 | do { \ | 32 | do { \ |
@@ -36,7 +36,7 @@ do { \ | |||
36 | # define lockdep_softirq_enter() \ | 36 | # define lockdep_softirq_enter() \ |
37 | do { \ | 37 | do { \ |
38 | current->softirq_context++; \ | 38 | current->softirq_context++; \ |
39 | crossrelease_hist_start(XHLOCK_SOFT); \ | 39 | crossrelease_hist_start(XHLOCK_SOFT, 0);\ |
40 | } while (0) | 40 | } while (0) |
41 | # define lockdep_softirq_exit() \ | 41 | # define lockdep_softirq_exit() \ |
42 | do { \ | 42 | do { \ |
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 | ||
diff --git a/kernel/locking/lockdep.c b/kernel/locking/lockdep.c index 66011c9f5df3..f73ca595b81e 100644 --- a/kernel/locking/lockdep.c +++ b/kernel/locking/lockdep.c | |||
@@ -4629,7 +4629,7 @@ asmlinkage __visible void lockdep_sys_exit(void) | |||
4629 | * the index to point to the last entry, which is already invalid. | 4629 | * the index to point to the last entry, which is already invalid. |
4630 | */ | 4630 | */ |
4631 | crossrelease_hist_end(XHLOCK_PROC); | 4631 | crossrelease_hist_end(XHLOCK_PROC); |
4632 | crossrelease_hist_start(XHLOCK_PROC); | 4632 | crossrelease_hist_start(XHLOCK_PROC, false); |
4633 | } | 4633 | } |
4634 | 4634 | ||
4635 | void lockdep_rcu_suspicious(const char *file, const int line, const char *s) | 4635 | void lockdep_rcu_suspicious(const char *file, const int line, const char *s) |
@@ -4725,25 +4725,25 @@ static inline void invalidate_xhlock(struct hist_lock *xhlock) | |||
4725 | /* | 4725 | /* |
4726 | * Lock history stacks; we have 3 nested lock history stacks: | 4726 | * Lock history stacks; we have 3 nested lock history stacks: |
4727 | * | 4727 | * |
4728 | * Hard IRQ | 4728 | * HARD(IRQ) |
4729 | * Soft IRQ | 4729 | * SOFT(IRQ) |
4730 | * History / Task | 4730 | * PROC(ess) |
4731 | * | 4731 | * |
4732 | * The thing is that once we complete a (Hard/Soft) IRQ the future task locks | 4732 | * The thing is that once we complete a HARD/SOFT IRQ the future task locks |
4733 | * should not depend on any of the locks observed while running the IRQ. | 4733 | * should not depend on any of the locks observed while running the IRQ. So |
4734 | * what we do is rewind the history buffer and erase all our knowledge of that | ||
4735 | * temporal event. | ||
4734 | * | 4736 | * |
4735 | * So what we do is rewind the history buffer and erase all our knowledge of | 4737 | * The PROCess one is special though; it is used to annotate independence |
4736 | * that temporal event. | 4738 | * inside a task. |
4737 | */ | 4739 | * |
4738 | 4740 | * Take for instance workqueues; each work is independent of the last. The | |
4739 | /* | 4741 | * completion of a future work does not depend on the completion of a past work |
4740 | * We need this to annotate lock history boundaries. Take for instance | 4742 | * (in general). Therefore we must not carry that (lock) dependency across |
4741 | * workqueues; each work is independent of the last. The completion of a future | 4743 | * works. |
4742 | * work does not depend on the completion of a past work (in general). | ||
4743 | * Therefore we must not carry that (lock) dependency across works. | ||
4744 | * | 4744 | * |
4745 | * This is true for many things; pretty much all kthreads fall into this | 4745 | * This is true for many things; pretty much all kthreads fall into this |
4746 | * pattern, where they have an 'idle' state and future completions do not | 4746 | * pattern, where they have an invariant state and future completions do not |
4747 | * depend on past completions. Its just that since they all have the 'same' | 4747 | * depend on past completions. Its just that since they all have the 'same' |
4748 | * form -- the kthread does the same over and over -- it doesn't typically | 4748 | * form -- the kthread does the same over and over -- it doesn't typically |
4749 | * matter. | 4749 | * matter. |
@@ -4751,15 +4751,31 @@ static inline void invalidate_xhlock(struct hist_lock *xhlock) | |||
4751 | * The same is true for system-calls, once a system call is completed (we've | 4751 | * The same is true for system-calls, once a system call is completed (we've |
4752 | * returned to userspace) the next system call does not depend on the lock | 4752 | * returned to userspace) the next system call does not depend on the lock |
4753 | * history of the previous system call. | 4753 | * history of the previous system call. |
4754 | * | ||
4755 | * They key property for independence, this invariant state, is that it must be | ||
4756 | * a point where we hold no locks and have no history. Because if we were to | ||
4757 | * hold locks, the restore at _end() would not necessarily recover it's history | ||
4758 | * entry. Similarly, independence per-definition means it does not depend on | ||
4759 | * prior state. | ||
4754 | */ | 4760 | */ |
4755 | void crossrelease_hist_start(enum xhlock_context_t c) | 4761 | void crossrelease_hist_start(enum xhlock_context_t c, bool force) |
4756 | { | 4762 | { |
4757 | struct task_struct *cur = current; | 4763 | struct task_struct *cur = current; |
4758 | 4764 | ||
4759 | if (cur->xhlocks) { | 4765 | if (!cur->xhlocks) |
4760 | cur->xhlock_idx_hist[c] = cur->xhlock_idx; | 4766 | return; |
4761 | cur->hist_id_save[c] = cur->hist_id; | 4767 | |
4768 | /* | ||
4769 | * We call this at an invariant point, no current state, no history. | ||
4770 | */ | ||
4771 | if (c == XHLOCK_PROC) { | ||
4772 | /* verified the former, ensure the latter */ | ||
4773 | WARN_ON_ONCE(!force && cur->lockdep_depth); | ||
4774 | invalidate_xhlock(&xhlock(cur->xhlock_idx)); | ||
4762 | } | 4775 | } |
4776 | |||
4777 | cur->xhlock_idx_hist[c] = cur->xhlock_idx; | ||
4778 | cur->hist_id_save[c] = cur->hist_id; | ||
4763 | } | 4779 | } |
4764 | 4780 | ||
4765 | void crossrelease_hist_end(enum xhlock_context_t c) | 4781 | void crossrelease_hist_end(enum xhlock_context_t c) |
diff --git a/kernel/workqueue.c b/kernel/workqueue.c index 8ad214dc15a9..c0331891dec1 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c | |||
@@ -2093,7 +2093,28 @@ __acquires(&pool->lock) | |||
2093 | 2093 | ||
2094 | lock_map_acquire(&pwq->wq->lockdep_map); | 2094 | lock_map_acquire(&pwq->wq->lockdep_map); |
2095 | lock_map_acquire(&lockdep_map); | 2095 | lock_map_acquire(&lockdep_map); |
2096 | crossrelease_hist_start(XHLOCK_PROC); | 2096 | /* |
2097 | * Strictly speaking we should do start(PROC) without holding any | ||
2098 | * locks, that is, before these two lock_map_acquire()'s. | ||
2099 | * | ||
2100 | * However, that would result in: | ||
2101 | * | ||
2102 | * A(W1) | ||
2103 | * WFC(C) | ||
2104 | * A(W1) | ||
2105 | * C(C) | ||
2106 | * | ||
2107 | * Which would create W1->C->W1 dependencies, even though there is no | ||
2108 | * actual deadlock possible. There are two solutions, using a | ||
2109 | * read-recursive acquire on the work(queue) 'locks', but this will then | ||
2110 | * hit the lockdep limitation on recursive locks, or simly discard | ||
2111 | * these locks. | ||
2112 | * | ||
2113 | * AFAICT there is no possible deadlock scenario between the | ||
2114 | * flush_work() and complete() primitives (except for single-threaded | ||
2115 | * workqueues), so hiding them isn't a problem. | ||
2116 | */ | ||
2117 | crossrelease_hist_start(XHLOCK_PROC, true); | ||
2097 | trace_workqueue_execute_start(work); | 2118 | trace_workqueue_execute_start(work); |
2098 | worker->current_func(work); | 2119 | worker->current_func(work); |
2099 | /* | 2120 | /* |