From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753470AbaEVDZp (ORCPT ); Wed, 21 May 2014 23:25:45 -0400 Received: from www.linutronix.de ([62.245.132.108]:46260 "EHLO Galois.linutronix.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751017AbaEVDZn (ORCPT ); Wed, 21 May 2014 23:25:43 -0400 Message-Id: <20140522031950.168005692@linutronix.de> User-Agent: quilt/0.60-1 Date: Thu, 22 May 2014 03:25:54 -0000 From: Thomas Gleixner To: LKML Cc: Ingo Molnar , Peter Zijlstra , Steven Rostedt , Lai Jiangshan Subject: [patch 5/6] rtmutex: Clarify the lock chain walk References: <20140522031841.797415507@linutronix.de> Content-Disposition: inline; filename=rtmutex-clarify-chain-walk.patch X-Linutronix-Spam-Score: -1.0 X-Linutronix-Spam-Level: - X-Linutronix-Spam-Status: No , -1.0 points, 5.0 required, ALL_TRUSTED=-1,SHORTCIRCUIT=-0.0001 Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Add a separate local variable for the boost/deboost logic to make the code more readable. Add comments where appropriate. Signed-off-by: Thomas Gleixner --- kernel/locking/rtmutex.c | 50 +++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 42 insertions(+), 8 deletions(-) Index: tip/kernel/locking/rtmutex.c =================================================================== --- tip.orig/kernel/locking/rtmutex.c +++ tip/kernel/locking/rtmutex.c @@ -302,9 +302,10 @@ static int rt_mutex_adjust_prio_chain(st struct rt_mutex_waiter *orig_waiter, struct task_struct *top_task) { - struct rt_mutex *lock; struct rt_mutex_waiter *waiter, *top_waiter = orig_waiter; + struct rt_mutex_waiter *prerequeue_top_waiter; int detect_deadlock, ret = 0, depth = 0; + struct rt_mutex *lock; unsigned long flags; detect_deadlock = rt_mutex_cond_detect_deadlock(orig_waiter, @@ -379,6 +380,11 @@ static int rt_mutex_adjust_prio_chain(st } lock = waiter->lock; + /* + * We need to trylock here as we are holding task->pi_lock, + * which is the reverse lock order versus the other rtmutex + * operations. + */ if (!raw_spin_trylock(&lock->wait_lock)) { raw_spin_unlock_irqrestore(&task->pi_lock, flags); cpu_relax(); @@ -398,7 +404,11 @@ static int rt_mutex_adjust_prio_chain(st goto out_unlock_pi; } - top_waiter = rt_mutex_top_waiter(lock); + /* + * Store the top waiter before doing any requeue operation. We + * need it for the boost/deboost decision below. + */ + prerequeue_top_waiter = rt_mutex_top_waiter(lock); /* Requeue the waiter */ rt_mutex_dequeue(lock, waiter); @@ -407,13 +417,18 @@ static int rt_mutex_adjust_prio_chain(st /* Release the task */ raw_spin_unlock_irqrestore(&task->pi_lock, flags); + + /* + * We must abort the chain walk if there is no lock owner even + * in the dead lock detection case, as we have nothing to + * follow here. + */ if (!rt_mutex_owner(lock)) { /* * If the requeue above changed the top waiter, then we need * to wake the new top waiter up to try to get the lock. */ - - if (top_waiter != rt_mutex_top_waiter(lock)) + if (prerequeue_top_waiter != rt_mutex_top_waiter(lock)) wake_up_process(rt_mutex_top_waiter(lock)->task); raw_spin_unlock(&lock->wait_lock); goto out_put_task; @@ -426,17 +441,31 @@ static int rt_mutex_adjust_prio_chain(st raw_spin_lock_irqsave(&task->pi_lock, flags); if (waiter == rt_mutex_top_waiter(lock)) { - /* Boost the owner */ - rt_mutex_dequeue_pi(task, top_waiter); + /* + * The waiter became the top waiter on the + * lock. Remove the previous top waiter from the tasks + * pi waiters list and add waiter to it. + */ + rt_mutex_dequeue_pi(task, prerequeue_top_waiter); rt_mutex_enqueue_pi(task, waiter); __rt_mutex_adjust_prio(task); - } else if (top_waiter == waiter) { - /* Deboost the owner */ + } else if (prerequeue_top_waiter == waiter) { + /* + * The waiter was the top waiter on the lock. Remove + * waiter from the tasks pi waiters list and add the + * new top waiter to it. + */ rt_mutex_dequeue_pi(task, waiter); waiter = rt_mutex_top_waiter(lock); rt_mutex_enqueue_pi(task, waiter); __rt_mutex_adjust_prio(task); + + } else { + /* + * Nothing changed. No need to do any priority + * adjustment. + */ } raw_spin_unlock_irqrestore(&task->pi_lock, flags); @@ -444,6 +473,11 @@ static int rt_mutex_adjust_prio_chain(st top_waiter = rt_mutex_top_waiter(lock); raw_spin_unlock(&lock->wait_lock); + /* + * If the current waiter is not the top waiter on the lock, + * then we can stop the chain walk here if we are not in full + * deadlock detection mode. + */ if (!detect_deadlock && waiter != top_waiter) goto out_put_task;