Commit a63b03e2d2477586440741677ecac45bcf28d7b1
Committed by
Ingo Molnar
1 parent
11c8f01b42
Exists in
ti-lsk-linux-4.1.y
and in
10 other branches
mutex: Always clear owner field upon mutex_unlock()
Currently if DEBUG_MUTEXES is enabled, the mutex->owner field is only cleared iff debug_locks is active. This exposes a race to other users of the field where the mutex->owner may be still set to a stale value, potentially upsetting mutex_spin_on_owner() among others. References: https://bugs.freedesktop.org/show_bug.cgi?id=87955 Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Acked-by: Davidlohr Bueso <dave@stgolabs.net> Cc: Daniel Vetter <daniel.vetter@ffwll.ch> Cc: Linus Torvalds <torvalds@linux-foundation.org> Link: http://lkml.kernel.org/r/1420540175-30204-1-git-send-email-chris@chris-wilson.co.uk Signed-off-by: Ingo Molnar <mingo@kernel.org>
Showing 1 changed file with 1 additions and 1 deletions Inline Diff
kernel/locking/mutex-debug.c
1 | /* | 1 | /* |
2 | * kernel/mutex-debug.c | 2 | * kernel/mutex-debug.c |
3 | * | 3 | * |
4 | * Debugging code for mutexes | 4 | * Debugging code for mutexes |
5 | * | 5 | * |
6 | * Started by Ingo Molnar: | 6 | * Started by Ingo Molnar: |
7 | * | 7 | * |
8 | * Copyright (C) 2004, 2005, 2006 Red Hat, Inc., Ingo Molnar <mingo@redhat.com> | 8 | * Copyright (C) 2004, 2005, 2006 Red Hat, Inc., Ingo Molnar <mingo@redhat.com> |
9 | * | 9 | * |
10 | * lock debugging, locking tree, deadlock detection started by: | 10 | * lock debugging, locking tree, deadlock detection started by: |
11 | * | 11 | * |
12 | * Copyright (C) 2004, LynuxWorks, Inc., Igor Manyilov, Bill Huey | 12 | * Copyright (C) 2004, LynuxWorks, Inc., Igor Manyilov, Bill Huey |
13 | * Released under the General Public License (GPL). | 13 | * Released under the General Public License (GPL). |
14 | */ | 14 | */ |
15 | #include <linux/mutex.h> | 15 | #include <linux/mutex.h> |
16 | #include <linux/delay.h> | 16 | #include <linux/delay.h> |
17 | #include <linux/export.h> | 17 | #include <linux/export.h> |
18 | #include <linux/poison.h> | 18 | #include <linux/poison.h> |
19 | #include <linux/sched.h> | 19 | #include <linux/sched.h> |
20 | #include <linux/spinlock.h> | 20 | #include <linux/spinlock.h> |
21 | #include <linux/kallsyms.h> | 21 | #include <linux/kallsyms.h> |
22 | #include <linux/interrupt.h> | 22 | #include <linux/interrupt.h> |
23 | #include <linux/debug_locks.h> | 23 | #include <linux/debug_locks.h> |
24 | 24 | ||
25 | #include "mutex-debug.h" | 25 | #include "mutex-debug.h" |
26 | 26 | ||
27 | /* | 27 | /* |
28 | * Must be called with lock->wait_lock held. | 28 | * Must be called with lock->wait_lock held. |
29 | */ | 29 | */ |
30 | void debug_mutex_lock_common(struct mutex *lock, struct mutex_waiter *waiter) | 30 | void debug_mutex_lock_common(struct mutex *lock, struct mutex_waiter *waiter) |
31 | { | 31 | { |
32 | memset(waiter, MUTEX_DEBUG_INIT, sizeof(*waiter)); | 32 | memset(waiter, MUTEX_DEBUG_INIT, sizeof(*waiter)); |
33 | waiter->magic = waiter; | 33 | waiter->magic = waiter; |
34 | INIT_LIST_HEAD(&waiter->list); | 34 | INIT_LIST_HEAD(&waiter->list); |
35 | } | 35 | } |
36 | 36 | ||
37 | void debug_mutex_wake_waiter(struct mutex *lock, struct mutex_waiter *waiter) | 37 | void debug_mutex_wake_waiter(struct mutex *lock, struct mutex_waiter *waiter) |
38 | { | 38 | { |
39 | SMP_DEBUG_LOCKS_WARN_ON(!spin_is_locked(&lock->wait_lock)); | 39 | SMP_DEBUG_LOCKS_WARN_ON(!spin_is_locked(&lock->wait_lock)); |
40 | DEBUG_LOCKS_WARN_ON(list_empty(&lock->wait_list)); | 40 | DEBUG_LOCKS_WARN_ON(list_empty(&lock->wait_list)); |
41 | DEBUG_LOCKS_WARN_ON(waiter->magic != waiter); | 41 | DEBUG_LOCKS_WARN_ON(waiter->magic != waiter); |
42 | DEBUG_LOCKS_WARN_ON(list_empty(&waiter->list)); | 42 | DEBUG_LOCKS_WARN_ON(list_empty(&waiter->list)); |
43 | } | 43 | } |
44 | 44 | ||
45 | void debug_mutex_free_waiter(struct mutex_waiter *waiter) | 45 | void debug_mutex_free_waiter(struct mutex_waiter *waiter) |
46 | { | 46 | { |
47 | DEBUG_LOCKS_WARN_ON(!list_empty(&waiter->list)); | 47 | DEBUG_LOCKS_WARN_ON(!list_empty(&waiter->list)); |
48 | memset(waiter, MUTEX_DEBUG_FREE, sizeof(*waiter)); | 48 | memset(waiter, MUTEX_DEBUG_FREE, sizeof(*waiter)); |
49 | } | 49 | } |
50 | 50 | ||
51 | void debug_mutex_add_waiter(struct mutex *lock, struct mutex_waiter *waiter, | 51 | void debug_mutex_add_waiter(struct mutex *lock, struct mutex_waiter *waiter, |
52 | struct thread_info *ti) | 52 | struct thread_info *ti) |
53 | { | 53 | { |
54 | SMP_DEBUG_LOCKS_WARN_ON(!spin_is_locked(&lock->wait_lock)); | 54 | SMP_DEBUG_LOCKS_WARN_ON(!spin_is_locked(&lock->wait_lock)); |
55 | 55 | ||
56 | /* Mark the current thread as blocked on the lock: */ | 56 | /* Mark the current thread as blocked on the lock: */ |
57 | ti->task->blocked_on = waiter; | 57 | ti->task->blocked_on = waiter; |
58 | } | 58 | } |
59 | 59 | ||
60 | void mutex_remove_waiter(struct mutex *lock, struct mutex_waiter *waiter, | 60 | void mutex_remove_waiter(struct mutex *lock, struct mutex_waiter *waiter, |
61 | struct thread_info *ti) | 61 | struct thread_info *ti) |
62 | { | 62 | { |
63 | DEBUG_LOCKS_WARN_ON(list_empty(&waiter->list)); | 63 | DEBUG_LOCKS_WARN_ON(list_empty(&waiter->list)); |
64 | DEBUG_LOCKS_WARN_ON(waiter->task != ti->task); | 64 | DEBUG_LOCKS_WARN_ON(waiter->task != ti->task); |
65 | DEBUG_LOCKS_WARN_ON(ti->task->blocked_on != waiter); | 65 | DEBUG_LOCKS_WARN_ON(ti->task->blocked_on != waiter); |
66 | ti->task->blocked_on = NULL; | 66 | ti->task->blocked_on = NULL; |
67 | 67 | ||
68 | list_del_init(&waiter->list); | 68 | list_del_init(&waiter->list); |
69 | waiter->task = NULL; | 69 | waiter->task = NULL; |
70 | } | 70 | } |
71 | 71 | ||
72 | void debug_mutex_unlock(struct mutex *lock) | 72 | void debug_mutex_unlock(struct mutex *lock) |
73 | { | 73 | { |
74 | if (likely(debug_locks)) { | 74 | if (likely(debug_locks)) { |
75 | DEBUG_LOCKS_WARN_ON(lock->magic != lock); | 75 | DEBUG_LOCKS_WARN_ON(lock->magic != lock); |
76 | 76 | ||
77 | if (!lock->owner) | 77 | if (!lock->owner) |
78 | DEBUG_LOCKS_WARN_ON(!lock->owner); | 78 | DEBUG_LOCKS_WARN_ON(!lock->owner); |
79 | else | 79 | else |
80 | DEBUG_LOCKS_WARN_ON(lock->owner != current); | 80 | DEBUG_LOCKS_WARN_ON(lock->owner != current); |
81 | 81 | ||
82 | DEBUG_LOCKS_WARN_ON(!lock->wait_list.prev && !lock->wait_list.next); | 82 | DEBUG_LOCKS_WARN_ON(!lock->wait_list.prev && !lock->wait_list.next); |
83 | mutex_clear_owner(lock); | ||
84 | } | 83 | } |
85 | 84 | ||
86 | /* | 85 | /* |
87 | * __mutex_slowpath_needs_to_unlock() is explicitly 0 for debug | 86 | * __mutex_slowpath_needs_to_unlock() is explicitly 0 for debug |
88 | * mutexes so that we can do it here after we've verified state. | 87 | * mutexes so that we can do it here after we've verified state. |
89 | */ | 88 | */ |
89 | mutex_clear_owner(lock); | ||
90 | atomic_set(&lock->count, 1); | 90 | atomic_set(&lock->count, 1); |
91 | } | 91 | } |
92 | 92 | ||
93 | void debug_mutex_init(struct mutex *lock, const char *name, | 93 | void debug_mutex_init(struct mutex *lock, const char *name, |
94 | struct lock_class_key *key) | 94 | struct lock_class_key *key) |
95 | { | 95 | { |
96 | #ifdef CONFIG_DEBUG_LOCK_ALLOC | 96 | #ifdef CONFIG_DEBUG_LOCK_ALLOC |
97 | /* | 97 | /* |
98 | * Make sure we are not reinitializing a held lock: | 98 | * Make sure we are not reinitializing a held lock: |
99 | */ | 99 | */ |
100 | debug_check_no_locks_freed((void *)lock, sizeof(*lock)); | 100 | debug_check_no_locks_freed((void *)lock, sizeof(*lock)); |
101 | lockdep_init_map(&lock->dep_map, name, key, 0); | 101 | lockdep_init_map(&lock->dep_map, name, key, 0); |
102 | #endif | 102 | #endif |
103 | lock->magic = lock; | 103 | lock->magic = lock; |
104 | } | 104 | } |
105 | 105 | ||
106 | /*** | 106 | /*** |
107 | * mutex_destroy - mark a mutex unusable | 107 | * mutex_destroy - mark a mutex unusable |
108 | * @lock: the mutex to be destroyed | 108 | * @lock: the mutex to be destroyed |
109 | * | 109 | * |
110 | * This function marks the mutex uninitialized, and any subsequent | 110 | * This function marks the mutex uninitialized, and any subsequent |
111 | * use of the mutex is forbidden. The mutex must not be locked when | 111 | * use of the mutex is forbidden. The mutex must not be locked when |
112 | * this function is called. | 112 | * this function is called. |
113 | */ | 113 | */ |
114 | void mutex_destroy(struct mutex *lock) | 114 | void mutex_destroy(struct mutex *lock) |
115 | { | 115 | { |
116 | DEBUG_LOCKS_WARN_ON(mutex_is_locked(lock)); | 116 | DEBUG_LOCKS_WARN_ON(mutex_is_locked(lock)); |
117 | lock->magic = NULL; | 117 | lock->magic = NULL; |
118 | } | 118 | } |
119 | 119 | ||
120 | EXPORT_SYMBOL_GPL(mutex_destroy); | 120 | EXPORT_SYMBOL_GPL(mutex_destroy); |
-
mentioned in commit a50940
-
mentioned in commit a50940
-
mentioned in commit a50940
-
mentioned in commit a50940
-
mentioned in commit a50940
-
mentioned in commit a50940
-
mentioned in commit a50940
-
mentioned in commit a50940
-
mentioned in commit a50940
-
mentioned in commit a50940
-
mentioned in commit a50940
-
mentioned in commit a50940
-
mentioned in commit a50940