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/sched/debug.h> 22 #include <linux/delay.h> 23 #include <linux/export.h> 24 #include <linux/spinlock.h> 25 #include <linux/kallsyms.h> 26 #include <linux/syscalls.h> 27 #include <linux/interrupt.h> 28 #include <linux/rbtree.h> 29 #include <linux/fs.h> 30 #include <linux/debug_locks.h> 31 32 #include "rtmutex_common.h" 33 34 static void printk_task(struct task_struct *p) 35 { 36 if (p) 37 printk("%16s:%5d [%p, %3d]", p->comm, task_pid_nr(p), p, p->prio); 38 else 39 printk("<none>"); 40 } 41 42 static void printk_lock(struct rt_mutex *lock, int print_owner) 43 { 44 if (lock->name) 45 printk(" [%p] {%s}\n", 46 lock, lock->name); 47 else 48 printk(" [%p] {%s:%d}\n", 49 lock, lock->file, lock->line); 50 51 if (print_owner && rt_mutex_owner(lock)) { 52 printk(".. ->owner: %p\n", lock->owner); 53 printk(".. held by: "); 54 printk_task(rt_mutex_owner(lock)); 55 printk("\n"); 56 } 57 } 58 59 void rt_mutex_debug_task_free(struct task_struct *task) 60 { 61 DEBUG_LOCKS_WARN_ON(!RB_EMPTY_ROOT(&task->pi_waiters)); 62 DEBUG_LOCKS_WARN_ON(task->pi_blocked_on); 63 } 64 65 /* 66 * We fill out the fields in the waiter to store the information about 67 * the deadlock. We print when we return. act_waiter can be NULL in 68 * case of a remove waiter operation. 69 */ 70 void debug_rt_mutex_deadlock(enum rtmutex_chainwalk chwalk, 71 struct rt_mutex_waiter *act_waiter, 72 struct rt_mutex *lock) 73 { 74 struct task_struct *task; 75 76 if (!debug_locks || chwalk == RT_MUTEX_FULL_CHAINWALK || !act_waiter) 77 return; 78 79 task = rt_mutex_owner(act_waiter->lock); 80 if (task && task != current) { 81 act_waiter->deadlock_task_pid = get_pid(task_pid(task)); 82 act_waiter->deadlock_lock = lock; 83 } 84 } 85 86 void debug_rt_mutex_print_deadlock(struct rt_mutex_waiter *waiter) 87 { 88 struct task_struct *task; 89 90 if (!waiter->deadlock_lock || !debug_locks) 91 return; 92 93 rcu_read_lock(); 94 task = pid_task(waiter->deadlock_task_pid, PIDTYPE_PID); 95 if (!task) { 96 rcu_read_unlock(); 97 return; 98 } 99 100 if (!debug_locks_off()) { 101 rcu_read_unlock(); 102 return; 103 } 104 105 pr_warn("\n"); 106 pr_warn("============================================\n"); 107 pr_warn("WARNING: circular locking deadlock detected!\n"); 108 pr_warn("%s\n", print_tainted()); 109 pr_warn("--------------------------------------------\n"); 110 printk("%s/%d is deadlocking current task %s/%d\n\n", 111 task->comm, task_pid_nr(task), 112 current->comm, task_pid_nr(current)); 113 114 printk("\n1) %s/%d is trying to acquire this lock:\n", 115 current->comm, task_pid_nr(current)); 116 printk_lock(waiter->lock, 1); 117 118 printk("\n2) %s/%d is blocked on this lock:\n", 119 task->comm, task_pid_nr(task)); 120 printk_lock(waiter->deadlock_lock, 1); 121 122 debug_show_held_locks(current); 123 debug_show_held_locks(task); 124 125 printk("\n%s/%d's [blocked] stackdump:\n\n", 126 task->comm, task_pid_nr(task)); 127 show_stack(task, NULL); 128 printk("\n%s/%d's [current] stackdump:\n\n", 129 current->comm, task_pid_nr(current)); 130 dump_stack(); 131 debug_show_all_locks(); 132 rcu_read_unlock(); 133 134 printk("[ turning off deadlock detection." 135 "Please report this trace. ]\n\n"); 136 } 137 138 void debug_rt_mutex_lock(struct rt_mutex *lock) 139 { 140 } 141 142 void debug_rt_mutex_unlock(struct rt_mutex *lock) 143 { 144 DEBUG_LOCKS_WARN_ON(rt_mutex_owner(lock) != current); 145 } 146 147 void 148 debug_rt_mutex_proxy_lock(struct rt_mutex *lock, struct task_struct *powner) 149 { 150 } 151 152 void debug_rt_mutex_proxy_unlock(struct rt_mutex *lock) 153 { 154 DEBUG_LOCKS_WARN_ON(!rt_mutex_owner(lock)); 155 } 156 157 void debug_rt_mutex_init_waiter(struct rt_mutex_waiter *waiter) 158 { 159 memset(waiter, 0x11, sizeof(*waiter)); 160 waiter->deadlock_task_pid = NULL; 161 } 162 163 void debug_rt_mutex_free_waiter(struct rt_mutex_waiter *waiter) 164 { 165 put_pid(waiter->deadlock_task_pid); 166 memset(waiter, 0x22, sizeof(*waiter)); 167 } 168 169 void debug_rt_mutex_init(struct rt_mutex *lock, const char *name) 170 { 171 /* 172 * Make sure we are not reinitializing a held lock: 173 */ 174 debug_check_no_locks_freed((void *)lock, sizeof(*lock)); 175 lock->name = name; 176 } 177 178
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.