diff options
author | Mandeep Singh Baines <msb@chromium.org> | 2013-02-27 20:03:18 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-02-27 22:10:11 -0500 |
commit | 6aa9707099c4b25700940eb3d016f16c4434360d (patch) | |
tree | 6996f5789a3c0a09eea2fe57d318c1d387c24f3a | |
parent | c2c1b089b44b783bd50fae4bccaa6f367f92e492 (diff) |
lockdep: check that no locks held at freeze time
We shouldn't try_to_freeze if locks are held. Holding a lock can cause a
deadlock if the lock is later acquired in the suspend or hibernate path
(e.g. by dpm). Holding a lock can also cause a deadlock in the case of
cgroup_freezer if a lock is held inside a frozen cgroup that is later
acquired by a process outside that group.
[akpm@linux-foundation.org: export debug_check_no_locks_held]
Signed-off-by: Mandeep Singh Baines <msb@chromium.org>
Cc: Ben Chan <benchan@chromium.org>
Cc: Oleg Nesterov <oleg@redhat.com>
Cc: Tejun Heo <tj@kernel.org>
Cc: Rafael J. Wysocki <rjw@sisk.pl>
Cc: Ingo Molnar <mingo@redhat.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r-- | include/linux/debug_locks.h | 4 | ||||
-rw-r--r-- | include/linux/freezer.h | 3 | ||||
-rw-r--r-- | kernel/exit.c | 2 | ||||
-rw-r--r-- | kernel/lockdep.c | 17 |
4 files changed, 14 insertions, 12 deletions
diff --git a/include/linux/debug_locks.h b/include/linux/debug_locks.h index 3bd46f766751..a975de1ff59f 100644 --- a/include/linux/debug_locks.h +++ b/include/linux/debug_locks.h | |||
@@ -51,7 +51,7 @@ struct task_struct; | |||
51 | extern void debug_show_all_locks(void); | 51 | extern void debug_show_all_locks(void); |
52 | extern void debug_show_held_locks(struct task_struct *task); | 52 | extern void debug_show_held_locks(struct task_struct *task); |
53 | extern void debug_check_no_locks_freed(const void *from, unsigned long len); | 53 | extern void debug_check_no_locks_freed(const void *from, unsigned long len); |
54 | extern void debug_check_no_locks_held(struct task_struct *task); | 54 | extern void debug_check_no_locks_held(void); |
55 | #else | 55 | #else |
56 | static inline void debug_show_all_locks(void) | 56 | static inline void debug_show_all_locks(void) |
57 | { | 57 | { |
@@ -67,7 +67,7 @@ debug_check_no_locks_freed(const void *from, unsigned long len) | |||
67 | } | 67 | } |
68 | 68 | ||
69 | static inline void | 69 | static inline void |
70 | debug_check_no_locks_held(struct task_struct *task) | 70 | debug_check_no_locks_held(void) |
71 | { | 71 | { |
72 | } | 72 | } |
73 | #endif | 73 | #endif |
diff --git a/include/linux/freezer.h b/include/linux/freezer.h index e70df40d84f6..043a5cf8b5ba 100644 --- a/include/linux/freezer.h +++ b/include/linux/freezer.h | |||
@@ -3,6 +3,7 @@ | |||
3 | #ifndef FREEZER_H_INCLUDED | 3 | #ifndef FREEZER_H_INCLUDED |
4 | #define FREEZER_H_INCLUDED | 4 | #define FREEZER_H_INCLUDED |
5 | 5 | ||
6 | #include <linux/debug_locks.h> | ||
6 | #include <linux/sched.h> | 7 | #include <linux/sched.h> |
7 | #include <linux/wait.h> | 8 | #include <linux/wait.h> |
8 | #include <linux/atomic.h> | 9 | #include <linux/atomic.h> |
@@ -48,6 +49,8 @@ extern void thaw_kernel_threads(void); | |||
48 | 49 | ||
49 | static inline bool try_to_freeze(void) | 50 | static inline bool try_to_freeze(void) |
50 | { | 51 | { |
52 | if (!(current->flags & PF_NOFREEZE)) | ||
53 | debug_check_no_locks_held(); | ||
51 | might_sleep(); | 54 | might_sleep(); |
52 | if (likely(!freezing(current))) | 55 | if (likely(!freezing(current))) |
53 | return false; | 56 | return false; |
diff --git a/kernel/exit.c b/kernel/exit.c index 7dd20408707c..aaf97c122e8a 100644 --- a/kernel/exit.c +++ b/kernel/exit.c | |||
@@ -835,7 +835,7 @@ void do_exit(long code) | |||
835 | /* | 835 | /* |
836 | * Make sure we are holding no locks: | 836 | * Make sure we are holding no locks: |
837 | */ | 837 | */ |
838 | debug_check_no_locks_held(tsk); | 838 | debug_check_no_locks_held(); |
839 | /* | 839 | /* |
840 | * We can do this unlocked here. The futex code uses this flag | 840 | * We can do this unlocked here. The futex code uses this flag |
841 | * just to verify whether the pi state cleanup has been done | 841 | * just to verify whether the pi state cleanup has been done |
diff --git a/kernel/lockdep.c b/kernel/lockdep.c index 8a0efac4f99d..259db207b5d9 100644 --- a/kernel/lockdep.c +++ b/kernel/lockdep.c | |||
@@ -4088,7 +4088,7 @@ void debug_check_no_locks_freed(const void *mem_from, unsigned long mem_len) | |||
4088 | } | 4088 | } |
4089 | EXPORT_SYMBOL_GPL(debug_check_no_locks_freed); | 4089 | EXPORT_SYMBOL_GPL(debug_check_no_locks_freed); |
4090 | 4090 | ||
4091 | static void print_held_locks_bug(struct task_struct *curr) | 4091 | static void print_held_locks_bug(void) |
4092 | { | 4092 | { |
4093 | if (!debug_locks_off()) | 4093 | if (!debug_locks_off()) |
4094 | return; | 4094 | return; |
@@ -4097,22 +4097,21 @@ static void print_held_locks_bug(struct task_struct *curr) | |||
4097 | 4097 | ||
4098 | printk("\n"); | 4098 | printk("\n"); |
4099 | printk("=====================================\n"); | 4099 | printk("=====================================\n"); |
4100 | printk("[ BUG: lock held at task exit time! ]\n"); | 4100 | printk("[ BUG: %s/%d still has locks held! ]\n", |
4101 | current->comm, task_pid_nr(current)); | ||
4101 | print_kernel_ident(); | 4102 | print_kernel_ident(); |
4102 | printk("-------------------------------------\n"); | 4103 | printk("-------------------------------------\n"); |
4103 | printk("%s/%d is exiting with locks still held!\n", | 4104 | lockdep_print_held_locks(current); |
4104 | curr->comm, task_pid_nr(curr)); | ||
4105 | lockdep_print_held_locks(curr); | ||
4106 | |||
4107 | printk("\nstack backtrace:\n"); | 4105 | printk("\nstack backtrace:\n"); |
4108 | dump_stack(); | 4106 | dump_stack(); |
4109 | } | 4107 | } |
4110 | 4108 | ||
4111 | void debug_check_no_locks_held(struct task_struct *task) | 4109 | void debug_check_no_locks_held(void) |
4112 | { | 4110 | { |
4113 | if (unlikely(task->lockdep_depth > 0)) | 4111 | if (unlikely(current->lockdep_depth > 0)) |
4114 | print_held_locks_bug(task); | 4112 | print_held_locks_bug(); |
4115 | } | 4113 | } |
4114 | EXPORT_SYMBOL_GPL(debug_check_no_locks_held); | ||
4116 | 4115 | ||
4117 | void debug_show_all_locks(void) | 4116 | void debug_show_all_locks(void) |
4118 | { | 4117 | { |