From: Steven Rostedt <rostedt@goodmis.org>
To: linux-kernel@vger.kernel.org,
linux-rt-users <linux-rt-users@vger.kernel.org>
Cc: Thomas Gleixner <tglx@linutronix.de>,
Carsten Emde <C.Emde@osadl.org>,
Sebastian Andrzej Siewior <bigeasy@linutronix.de>,
John Kacur <jkacur@redhat.com>,
Paul Gortmaker <paul.gortmaker@windriver.com>
Subject: [PATCH RT 06/39] rtmutex: Document pi chain walk
Date: Thu, 12 Mar 2015 15:13:13 -0400 [thread overview]
Message-ID: <20150312191408.095525543@goodmis.org> (raw)
In-Reply-To: 20150312191307.081068717@goodmis.org
[-- Attachment #1: 0006-rtmutex-Document-pi-chain-walk.patch --]
[-- Type: text/plain, Size: 7249 bytes --]
3.14.34-rt32-rc1 stable review patch.
If anyone has any objections, please let me know.
------------------
From: Thomas Gleixner <tglx@linutronix.de>
upstream commit: 3eb65aeadf701976b084e9171e16bb7d1e83fbb0
Add commentry to document the chain walk and the protection mechanisms
and their scope.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Reviewed-by: Steven Rostedt <rostedt@goodmis.org>
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
---
kernel/locking/rtmutex.c | 100 ++++++++++++++++++++++++++++++++++++++++++-----
1 file changed, 91 insertions(+), 9 deletions(-)
diff --git a/kernel/locking/rtmutex.c b/kernel/locking/rtmutex.c
index 85f5369e27f3..400026ec7f05 100644
--- a/kernel/locking/rtmutex.c
+++ b/kernel/locking/rtmutex.c
@@ -358,6 +358,48 @@ static inline struct rt_mutex *task_blocked_on_lock(struct task_struct *p)
* @top_task: the current top waiter
*
* Returns 0 or -EDEADLK.
+ *
+ * Chain walk basics and protection scope
+ *
+ * [R] refcount on task
+ * [P] task->pi_lock held
+ * [L] rtmutex->wait_lock held
+ *
+ * Step Description Protected by
+ * function arguments:
+ * @task [R]
+ * @orig_lock if != NULL @top_task is blocked on it
+ * @next_lock Unprotected. Cannot be
+ * dereferenced. Only used for
+ * comparison.
+ * @orig_waiter if != NULL @top_task is blocked on it
+ * @top_task current, or in case of proxy
+ * locking protected by calling
+ * code
+ * again:
+ * loop_sanity_check();
+ * retry:
+ * [1] lock(task->pi_lock); [R] acquire [P]
+ * [2] waiter = task->pi_blocked_on; [P]
+ * [3] check_exit_conditions_1(); [P]
+ * [4] lock = waiter->lock; [P]
+ * [5] if (!try_lock(lock->wait_lock)) { [P] try to acquire [L]
+ * unlock(task->pi_lock); release [P]
+ * goto retry;
+ * }
+ * [6] check_exit_conditions_2(); [P] + [L]
+ * [7] requeue_lock_waiter(lock, waiter); [P] + [L]
+ * [8] unlock(task->pi_lock); release [P]
+ * put_task_struct(task); release [R]
+ * [9] check_exit_conditions_3(); [L]
+ * [10] task = owner(lock); [L]
+ * get_task_struct(task); [L] acquire [R]
+ * lock(task->pi_lock); [L] acquire [P]
+ * [11] requeue_pi_waiter(tsk, waiters(lock));[P] + [L]
+ * [12] check_exit_conditions_4(); [P] + [L]
+ * [13] unlock(task->pi_lock); release [P]
+ * unlock(lock->wait_lock); release [L]
+ * goto again;
*/
static int rt_mutex_adjust_prio_chain(struct task_struct *task,
int deadlock_detect,
@@ -382,6 +424,9 @@ static int rt_mutex_adjust_prio_chain(struct task_struct *task,
* carefully whether things change under us.
*/
again:
+ /*
+ * We limit the lock chain length for each invocation.
+ */
if (++depth > max_lock_depth) {
static int prev_max;
@@ -399,13 +444,28 @@ static int rt_mutex_adjust_prio_chain(struct task_struct *task,
return -EDEADLK;
}
+
+ /*
+ * We are fully preemptible here and only hold the refcount on
+ * @task. So everything can have changed under us since the
+ * caller or our own code below (goto retry/again) dropped all
+ * locks.
+ */
retry:
/*
- * Task can not go away as we did a get_task() before !
+ * [1] Task cannot go away as we did a get_task() before !
*/
raw_spin_lock_irqsave(&task->pi_lock, flags);
+ /*
+ * [2] Get the waiter on which @task is blocked on.
+ */
waiter = task->pi_blocked_on;
+
+ /*
+ * [3] check_exit_conditions_1() protected by task->pi_lock.
+ */
+
/*
* Check whether the end of the boosting chain has been
* reached or the state of the chain has changed while we
@@ -456,7 +516,15 @@ static int rt_mutex_adjust_prio_chain(struct task_struct *task,
if (!detect_deadlock && waiter->prio == task->prio)
goto out_unlock_pi;
+ /*
+ * [4] Get the next lock
+ */
lock = waiter->lock;
+ /*
+ * [5] 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();
@@ -464,6 +532,9 @@ static int rt_mutex_adjust_prio_chain(struct task_struct *task,
}
/*
+ * [6] check_exit_conditions_2() protected by task->pi_lock and
+ * lock->wait_lock.
+ *
* Deadlock detection. If the lock is the same as the original
* lock which caused us to walk the lock chain or if the
* current lock is owned by the task which initiated the chain
@@ -483,16 +554,18 @@ static int rt_mutex_adjust_prio_chain(struct task_struct *task,
*/
prerequeue_top_waiter = rt_mutex_top_waiter(lock);
- /* Requeue the waiter in the lock waiter list. */
+ /* [7] Requeue the waiter in the lock waiter list. */
rt_mutex_dequeue(lock, waiter);
waiter->prio = task->prio;
rt_mutex_enqueue(lock, waiter);
- /* Release the task */
+ /* [8] Release the task */
raw_spin_unlock_irqrestore(&task->pi_lock, flags);
put_task_struct(task);
/*
+ * [9] check_exit_conditions_3 protected by lock->wait_lock.
+ *
* 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. This is the end of the chain we are walking.
@@ -501,8 +574,9 @@ static int rt_mutex_adjust_prio_chain(struct task_struct *task,
struct rt_mutex_waiter *lock_top_waiter;
/*
- * 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 the requeue [7] above changed the top waiter,
+ * then we need to wake the new top waiter up to try
+ * to get the lock.
*/
lock_top_waiter = rt_mutex_top_waiter(lock);
if (prerequeue_top_waiter != lock_top_waiter)
@@ -511,11 +585,12 @@ static int rt_mutex_adjust_prio_chain(struct task_struct *task,
return 0;
}
- /* Grab the next task, i.e. the owner of @lock */
+ /* [10] Grab the next task, i.e. the owner of @lock */
task = rt_mutex_owner(lock);
get_task_struct(task);
raw_spin_lock_irqsave(&task->pi_lock, flags);
+ /* [11] requeue the pi waiters if necessary */
if (waiter == rt_mutex_top_waiter(lock)) {
/*
* The waiter became the new top (highest priority)
@@ -550,23 +625,30 @@ static int rt_mutex_adjust_prio_chain(struct task_struct *task,
}
/*
+ * [12] check_exit_conditions_4() protected by task->pi_lock
+ * and lock->wait_lock. The actual decisions are made after we
+ * dropped the locks.
+ *
* Check whether the task which owns the current lock is pi
* blocked itself. If yes we store a pointer to the lock for
* the lock chain change detection above. After we dropped
* task->pi_lock next_lock cannot be dereferenced anymore.
*/
next_lock = task_blocked_on_lock(task);
-
- raw_spin_unlock_irqrestore(&task->pi_lock, flags);
-
/*
* Store the top waiter of @lock for the end of chain walk
* decision below.
*/
top_waiter = rt_mutex_top_waiter(lock);
+
+ /* [13] Drop the locks */
+ raw_spin_unlock_irqrestore(&task->pi_lock, flags);
raw_spin_unlock(&lock->wait_lock);
/*
+ * Make the actual exit decisions [12], based on the stored
+ * values.
+ *
* We reached the end of the lock chain. Stop right here. No
* point to go back just to figure that out.
*/
--
2.1.4
next prev parent reply other threads:[~2015-03-12 19:13 UTC|newest]
Thread overview: 57+ messages / expand[flat|nested] mbox.gz Atom feed top
2015-03-12 19:13 [PATCH RT 00/39] Linux 3.14.34-rt32-rc1 Steven Rostedt
2015-03-12 19:13 ` [PATCH RT 01/39] gpio: omap: use raw locks for locking Steven Rostedt
2015-03-12 19:13 ` [PATCH RT 02/39] rtmutex: Simplify rtmutex_slowtrylock() Steven Rostedt
2015-03-12 19:13 ` [PATCH RT 03/39] rtmutex: Simplify and document try_to_take_rtmutex() Steven Rostedt
2015-03-12 19:13 ` [PATCH RT 04/39] rtmutex: No need to keep task ref for lock owner check Steven Rostedt
2015-03-12 19:13 ` [PATCH RT 05/39] rtmutex: Clarify the boost/deboost part Steven Rostedt
2015-03-12 19:13 ` Steven Rostedt [this message]
2015-03-12 19:13 ` [PATCH RT 07/39] rtmutex: Simplify remove_waiter() Steven Rostedt
2015-03-12 19:13 ` Steven Rostedt
2015-03-12 19:13 ` [PATCH RT 08/39] rtmutex: Confine deadlock logic to futex Steven Rostedt
2015-03-12 19:13 ` [PATCH RT 09/39] rtmutex: Cleanup deadlock detector debug logic Steven Rostedt
2015-03-12 19:13 ` [PATCH RT 10/39] rtmutex: Avoid pointless requeueing in the deadlock detection chain walk Steven Rostedt
2015-03-12 19:13 ` [PATCH RT 11/39] futex: Make unlock_pi more robust Steven Rostedt
2015-03-12 19:13 ` [PATCH RT 12/39] futex: Use futex_top_waiter() in lookup_pi_state() Steven Rostedt
2015-03-12 19:13 ` [PATCH RT 13/39] futex: Split out the waiter check from lookup_pi_state() Steven Rostedt
2015-03-12 19:13 ` [PATCH RT 14/39] futex: Split out the first waiter attachment " Steven Rostedt
2015-03-12 19:13 ` [PATCH RT 15/39] futex: Simplify futex_lock_pi_atomic() and make it more robust Steven Rostedt
2015-03-12 19:13 ` [PATCH RT 16/39] locking/rt-mutex: avoid a NULL pointer dereference on deadlock Steven Rostedt
2015-03-13 10:40 ` Sebastian Andrzej Siewior
2015-03-13 10:56 ` Sebastian Andrzej Siewior
2015-03-12 19:13 ` [PATCH RT 17/39] rtmutex.c: Fix incorrect waiter check Steven Rostedt
2015-03-12 19:13 ` [PATCH RT 18/39] rt,locking: fix __ww_mutex_lock_interruptible() lockdep annotation Steven Rostedt
2015-03-12 19:13 ` [PATCH RT 19/39] rtmutex: enable deadlock detection in ww_mutex_lock functions Steven Rostedt
2015-03-12 19:13 ` [PATCH RT 20/39] x86: UV: raw_spinlock conversion Steven Rostedt
2015-03-12 19:13 ` [PATCH RT 22/39] arm/futex: disable preemption during futex_atomic_cmpxchg_inatomic() Steven Rostedt
2015-03-12 19:13 ` [PATCH RT 23/39] ARM: cmpxchg: define __HAVE_ARCH_CMPXCHG for armv6 and later Steven Rostedt
2015-03-12 19:13 ` [PATCH RT 24/39] mips: rt: Replace pagefault_* to raw version Steven Rostedt
2015-03-12 19:13 ` [PATCH RT 25/39] sas-ata/isci: dontt disable interrupts in qc_issue handler Steven Rostedt
2015-03-12 19:13 ` [PATCH RT 26/39] scheduling while atomic in cgroup code Steven Rostedt
2015-03-17 20:10 ` Paul Gortmaker
2015-03-17 20:13 ` Steven Rostedt
2015-03-18 8:37 ` Sebastian Andrzej Siewior
2015-03-18 13:20 ` Steven Rostedt
2015-03-12 19:13 ` [PATCH RT 27/39] work-simple: Simple work queue implemenation Steven Rostedt
2015-03-12 19:13 ` [PATCH RT 28/39] sunrpc: make svc_xprt_do_enqueue() use get_cpu_light() Steven Rostedt
2015-03-12 19:13 ` [PATCH RT 29/39] Revert "rwsem-rt: Do not allow readers to nest" Steven Rostedt
2015-03-12 19:13 ` [PATCH RT 30/39] locking: ww_mutex: fix ww_mutex vs self-deadlock Steven Rostedt
2015-03-12 19:13 ` [PATCH RT 31/39] thermal: Defer thermal wakups to threads Steven Rostedt
2015-03-12 19:13 ` Steven Rostedt
2015-03-12 19:13 ` [PATCH RT 32/39] lockdep: selftest: fix warnings due to missing PREEMPT_RT conditionals Steven Rostedt
2015-03-12 19:13 ` [PATCH RT 33/39] fs/aio: simple simple work Steven Rostedt
2015-03-12 19:13 ` [PATCH RT 34/39] timers: Track total number of timers in list Steven Rostedt
2015-03-12 19:13 ` [PATCH RT 35/39] timers: Reduce __run_timers() latency for empty list Steven Rostedt
2015-03-12 19:13 ` [PATCH RT 36/39] timers: Reduce future __run_timers() latency for newly emptied list Steven Rostedt
2015-03-12 19:13 ` [PATCH RT 37/39] timers: Reduce future __run_timers() latency for first add to empty list Steven Rostedt
2015-03-12 19:13 ` [PATCH RT 38/39] staging: Mark rtl8821ae as broken Steven Rostedt
2015-03-12 19:13 ` [PATCH RT 39/39] Linux 3.14.34-rt32-rc1 Steven Rostedt
2015-03-13 4:49 ` [PATCH RT 00/39] " Mike Galbraith
2015-03-13 13:50 ` Steven Rostedt
2015-03-13 15:11 ` Steven Rostedt
2015-03-13 15:11 ` Steven Rostedt
2015-03-13 15:24 ` Steven Rostedt
2015-03-13 11:01 ` Sebastian Andrzej Siewior
2015-03-13 11:33 ` Sebastian Andrzej Siewior
2015-03-16 13:59 ` Sebastian Andrzej Siewior
2015-03-16 14:02 ` Steven Rostedt
2015-03-16 14:10 ` Sebastian Andrzej Siewior
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20150312191408.095525543@goodmis.org \
--to=rostedt@goodmis.org \
--cc=C.Emde@osadl.org \
--cc=bigeasy@linutronix.de \
--cc=jkacur@redhat.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-rt-users@vger.kernel.org \
--cc=paul.gortmaker@windriver.com \
--cc=tglx@linutronix.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.