Rather horrid patch this, surely there's a better way.. rcuc/1/13 is trying to acquire lock: ((console_sem).lock){-.-...}, at: but task is already holding lock: (&rt_rq->rt_runtime_lock){-.....}, at: which lock already depends on the new lock. the existing dependency chain (in reverse order) is: -> #3 (&rt_rq->rt_runtime_lock){-.....}: -> #2 (&rq->lock){-.-.-.}: -> #1 (&p->pi_lock){-.-.-.}: -> #0 ((console_sem).lock){-.-...}: Signed-off-by: Peter Zijlstra --- kernel/semaphore.c | 46 +++++++++++++++++++++++++--------------------- 1 file changed, 25 insertions(+), 21 deletions(-) --- a/kernel/semaphore.c +++ b/kernel/semaphore.c @@ -168,6 +168,14 @@ int down_timeout(struct semaphore *sem, } EXPORT_SYMBOL(down_timeout); +/* Functions for the contended case */ + +struct semaphore_waiter { + struct list_head list; + struct task_struct *task; + int up; +}; + /** * up - release the semaphore * @sem: the semaphore to release @@ -177,32 +185,36 @@ EXPORT_SYMBOL(down_timeout); */ void up(struct semaphore *sem) { + struct semaphore_waiter *waiter; + struct task_struct *task; unsigned long flags; raw_spin_lock_irqsave(&sem->lock, flags); - if (likely(list_empty(&sem->wait_list))) + if (likely(list_empty(&sem->wait_list))) { sem->count++; - else - __up(sem); + raw_spin_unlock_irqrestore(&sem->lock, flags); + return; + } + + waiter = list_first_entry(&sem->wait_list, struct semaphore_waiter, list); + task = waiter->task; + list_del(&waiter->list); + waiter->up = 1; + get_task_struct(task); raw_spin_unlock_irqrestore(&sem->lock, flags); + + wake_up_process(task); + put_task_struct(task); } EXPORT_SYMBOL(up); -/* Functions for the contended case */ - -struct semaphore_waiter { - struct list_head list; - struct task_struct *task; - int up; -}; - /* * Because this function is inlined, the 'state' parameter will be * constant, and thus optimised away by the compiler. Likewise the * 'timeout' parameter for the cases without timeouts. */ -static inline int __sched __down_common(struct semaphore *sem, long state, - long timeout) +static inline +int __sched __down_common(struct semaphore *sem, long state, long timeout) { struct task_struct *task = current; struct semaphore_waiter waiter; @@ -253,11 +265,3 @@ static noinline int __sched __down_timeo return __down_common(sem, TASK_UNINTERRUPTIBLE, jiffies); } -static noinline void __sched __up(struct semaphore *sem) -{ - struct semaphore_waiter *waiter = list_first_entry(&sem->wait_list, - struct semaphore_waiter, list); - list_del(&waiter->list); - waiter->up = 1; - wake_up_process(waiter->task); -} -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/