diff options
| author | Michal Marek <mmarek@suse.cz> | 2014-01-02 08:02:06 -0500 |
|---|---|---|
| committer | Michal Marek <mmarek@suse.cz> | 2014-01-02 08:02:06 -0500 |
| commit | 37e2c2a775fc887acd1432908478dfd532f7f00f (patch) | |
| tree | e51ebc699d8e262fd47e0913be6a711cb1a7b565 /kernel/locking/rtmutex-debug.c | |
| parent | 1c8ddae09f4c102b97c9086cc70347e89468a547 (diff) | |
| parent | 6ce4eac1f600b34f2f7f58f9cd8f0503d79e42ae (diff) | |
Merge commit v3.13-rc1 into kbuild/misc
Diffstat (limited to 'kernel/locking/rtmutex-debug.c')
| -rw-r--r-- | kernel/locking/rtmutex-debug.c | 187 |
1 files changed, 187 insertions, 0 deletions
diff --git a/kernel/locking/rtmutex-debug.c b/kernel/locking/rtmutex-debug.c new file mode 100644 index 000000000000..13b243a323fa --- /dev/null +++ b/kernel/locking/rtmutex-debug.c | |||
| @@ -0,0 +1,187 @@ | |||
| 1 | /* | ||
| 2 | * RT-Mutexes: blocking mutual exclusion locks with PI support | ||
| 3 | * | ||
| 4 | * started by Ingo Molnar and Thomas Gleixner: | ||
| 5 | * | ||
| 6 | * Copyright (C) 2004-2006 Red Hat, Inc., Ingo Molnar <mingo@redhat.com> | ||
| 7 | * Copyright (C) 2006 Timesys Corp., Thomas Gleixner <tglx@timesys.com> | ||
| 8 | * | ||
| 9 | * This code is based on the rt.c implementation in the preempt-rt tree. | ||
| 10 | * Portions of said code are | ||
| 11 | * | ||
| 12 | * Copyright (C) 2004 LynuxWorks, Inc., Igor Manyilov, Bill Huey | ||
| 13 | * Copyright (C) 2006 Esben Nielsen | ||
| 14 | * Copyright (C) 2006 Kihon Technologies Inc., | ||
| 15 | * Steven Rostedt <rostedt@goodmis.org> | ||
| 16 | * | ||
| 17 | * See rt.c in preempt-rt for proper credits and further information | ||
| 18 | */ | ||
| 19 | #include <linux/sched.h> | ||
| 20 | #include <linux/sched/rt.h> | ||
| 21 | #include <linux/delay.h> | ||
| 22 | #include <linux/export.h> | ||
| 23 | #include <linux/spinlock.h> | ||
| 24 | #include <linux/kallsyms.h> | ||
| 25 | #include <linux/syscalls.h> | ||
| 26 | #include <linux/interrupt.h> | ||
| 27 | #include <linux/plist.h> | ||
| 28 | #include <linux/fs.h> | ||
| 29 | #include <linux/debug_locks.h> | ||
| 30 | |||
| 31 | #include "rtmutex_common.h" | ||
| 32 | |||
| 33 | static void printk_task(struct task_struct *p) | ||
| 34 | { | ||
| 35 | if (p) | ||
| 36 | printk("%16s:%5d [%p, %3d]", p->comm, task_pid_nr(p), p, p->prio); | ||
| 37 | else | ||
| 38 | printk("<none>"); | ||
| 39 | } | ||
| 40 | |||
| 41 | static void printk_lock(struct rt_mutex *lock, int print_owner) | ||
| 42 | { | ||
| 43 | if (lock->name) | ||
| 44 | printk(" [%p] {%s}\n", | ||
| 45 | lock, lock->name); | ||
| 46 | else | ||
| 47 | printk(" [%p] {%s:%d}\n", | ||
| 48 | lock, lock->file, lock->line); | ||
| 49 | |||
| 50 | if (print_owner && rt_mutex_owner(lock)) { | ||
| 51 | printk(".. ->owner: %p\n", lock->owner); | ||
| 52 | printk(".. held by: "); | ||
| 53 | printk_task(rt_mutex_owner(lock)); | ||
| 54 | printk("\n"); | ||
| 55 | } | ||
| 56 | } | ||
| 57 | |||
| 58 | void rt_mutex_debug_task_free(struct task_struct *task) | ||
| 59 | { | ||
| 60 | DEBUG_LOCKS_WARN_ON(!plist_head_empty(&task->pi_waiters)); | ||
| 61 | DEBUG_LOCKS_WARN_ON(task->pi_blocked_on); | ||
| 62 | } | ||
| 63 | |||
| 64 | /* | ||
| 65 | * We fill out the fields in the waiter to store the information about | ||
| 66 | * the deadlock. We print when we return. act_waiter can be NULL in | ||
| 67 | * case of a remove waiter operation. | ||
| 68 | */ | ||
| 69 | void debug_rt_mutex_deadlock(int detect, struct rt_mutex_waiter *act_waiter, | ||
| 70 | struct rt_mutex *lock) | ||
| 71 | { | ||
| 72 | struct task_struct *task; | ||
| 73 | |||
| 74 | if (!debug_locks || detect || !act_waiter) | ||
| 75 | return; | ||
| 76 | |||
| 77 | task = rt_mutex_owner(act_waiter->lock); | ||
| 78 | if (task && task != current) { | ||
| 79 | act_waiter->deadlock_task_pid = get_pid(task_pid(task)); | ||
| 80 | act_waiter->deadlock_lock = lock; | ||
| 81 | } | ||
| 82 | } | ||
| 83 | |||
| 84 | void debug_rt_mutex_print_deadlock(struct rt_mutex_waiter *waiter) | ||
| 85 | { | ||
| 86 | struct task_struct *task; | ||
| 87 | |||
| 88 | if (!waiter->deadlock_lock || !debug_locks) | ||
| 89 | return; | ||
| 90 | |||
| 91 | rcu_read_lock(); | ||
| 92 | task = pid_task(waiter->deadlock_task_pid, PIDTYPE_PID); | ||
| 93 | if (!task) { | ||
| 94 | rcu_read_unlock(); | ||
| 95 | return; | ||
| 96 | } | ||
| 97 | |||
| 98 | if (!debug_locks_off()) { | ||
| 99 | rcu_read_unlock(); | ||
| 100 | return; | ||
| 101 | } | ||
| 102 | |||
| 103 | printk("\n============================================\n"); | ||
| 104 | printk( "[ BUG: circular locking deadlock detected! ]\n"); | ||
| 105 | printk("%s\n", print_tainted()); | ||
| 106 | printk( "--------------------------------------------\n"); | ||
| 107 | printk("%s/%d is deadlocking current task %s/%d\n\n", | ||
| 108 | task->comm, task_pid_nr(task), | ||
| 109 | current->comm, task_pid_nr(current)); | ||
| 110 | |||
| 111 | printk("\n1) %s/%d is trying to acquire this lock:\n", | ||
| 112 | current->comm, task_pid_nr(current)); | ||
| 113 | printk_lock(waiter->lock, 1); | ||
| 114 | |||
| 115 | printk("\n2) %s/%d is blocked on this lock:\n", | ||
| 116 | task->comm, task_pid_nr(task)); | ||
| 117 | printk_lock(waiter->deadlock_lock, 1); | ||
| 118 | |||
| 119 | debug_show_held_locks(current); | ||
| 120 | debug_show_held_locks(task); | ||
| 121 | |||
| 122 | printk("\n%s/%d's [blocked] stackdump:\n\n", | ||
| 123 | task->comm, task_pid_nr(task)); | ||
| 124 | show_stack(task, NULL); | ||
| 125 | printk("\n%s/%d's [current] stackdump:\n\n", | ||
| 126 | current->comm, task_pid_nr(current)); | ||
| 127 | dump_stack(); | ||
| 128 | debug_show_all_locks(); | ||
| 129 | rcu_read_unlock(); | ||
| 130 | |||
| 131 | printk("[ turning off deadlock detection." | ||
| 132 | "Please report this trace. ]\n\n"); | ||
| 133 | } | ||
| 134 | |||
| 135 | void debug_rt_mutex_lock(struct rt_mutex *lock) | ||
| 136 | { | ||
| 137 | } | ||
| 138 | |||
| 139 | void debug_rt_mutex_unlock(struct rt_mutex *lock) | ||
| 140 | { | ||
| 141 | DEBUG_LOCKS_WARN_ON(rt_mutex_owner(lock) != current); | ||
| 142 | } | ||
| 143 | |||
| 144 | void | ||
| 145 | debug_rt_mutex_proxy_lock(struct rt_mutex *lock, struct task_struct *powner) | ||
| 146 | { | ||
| 147 | } | ||
| 148 | |||
| 149 | void debug_rt_mutex_proxy_unlock(struct rt_mutex *lock) | ||
| 150 | { | ||
| 151 | DEBUG_LOCKS_WARN_ON(!rt_mutex_owner(lock)); | ||
| 152 | } | ||
| 153 | |||
| 154 | void debug_rt_mutex_init_waiter(struct rt_mutex_waiter *waiter) | ||
| 155 | { | ||
| 156 | memset(waiter, 0x11, sizeof(*waiter)); | ||
| 157 | plist_node_init(&waiter->list_entry, MAX_PRIO); | ||
| 158 | plist_node_init(&waiter->pi_list_entry, MAX_PRIO); | ||
| 159 | waiter->deadlock_task_pid = NULL; | ||
| 160 | } | ||
| 161 | |||
| 162 | void debug_rt_mutex_free_waiter(struct rt_mutex_waiter *waiter) | ||
| 163 | { | ||
| 164 | put_pid(waiter->deadlock_task_pid); | ||
| 165 | DEBUG_LOCKS_WARN_ON(!plist_node_empty(&waiter->list_entry)); | ||
| 166 | DEBUG_LOCKS_WARN_ON(!plist_node_empty(&waiter->pi_list_entry)); | ||
| 167 | memset(waiter, 0x22, sizeof(*waiter)); | ||
| 168 | } | ||
| 169 | |||
| 170 | void debug_rt_mutex_init(struct rt_mutex *lock, const char *name) | ||
| 171 | { | ||
| 172 | /* | ||
| 173 | * Make sure we are not reinitializing a held lock: | ||
| 174 | */ | ||
| 175 | debug_check_no_locks_freed((void *)lock, sizeof(*lock)); | ||
| 176 | lock->name = name; | ||
| 177 | } | ||
| 178 | |||
| 179 | void | ||
| 180 | rt_mutex_deadlock_account_lock(struct rt_mutex *lock, struct task_struct *task) | ||
| 181 | { | ||
| 182 | } | ||
| 183 | |||
| 184 | void rt_mutex_deadlock_account_unlock(struct task_struct *task) | ||
| 185 | { | ||
| 186 | } | ||
| 187 | |||
