From: "Nicolai Hähnle" <nhaehnle@gmail.com>
To: linux-kernel@vger.kernel.org
Cc: "Nicolai Hähnle" <Nicolai.Haehnle@amd.com>,
"Peter Zijlstra" <peterz@infradead.org>,
"Ingo Molnar" <mingo@redhat.com>,
"Maarten Lankhorst" <dev@mblankhorst.nl>,
"Daniel Vetter" <daniel@ffwll.ch>,
"Chris Wilson" <chris@chris-wilson.co.uk>,
dri-devel@lists.freedesktop.org
Subject: [PATCH v3 09/12] locking/ww_mutex: Re-check ww->ctx in the inner optimistic spin loop
Date: Wed, 21 Dec 2016 19:46:37 +0100 [thread overview]
Message-ID: <1482346000-9927-10-git-send-email-nhaehnle@gmail.com> (raw)
In-Reply-To: <1482346000-9927-1-git-send-email-nhaehnle@gmail.com>
From: Nicolai Hähnle <Nicolai.Haehnle@amd.com>
In the following scenario, thread #1 should back off its attempt to lock
ww1 and unlock ww2 (assuming the acquire context stamps are ordered
accordingly).
Thread #0 Thread #1
--------- ---------
successfully lock ww2
set ww1->base.owner
attempt to lock ww1
confirm ww1->ctx == NULL
enter mutex_spin_on_owner
set ww1->ctx
What was likely to happen previously is:
attempt to lock ww2
refuse to spin because
ww2->ctx != NULL
schedule()
detect thread #0 is off CPU
stop optimistic spin
return -EDEADLK
unlock ww2
wakeup thread #0
lock ww2
Now, we are more likely to see:
detect ww1->ctx != NULL
stop optimistic spin
return -EDEADLK
unlock ww2
successfully lock ww2
... because thread #1 will stop its optimistic spin as soon as possible.
The whole scenario is quite unlikely, since it requires thread #1 to get
between thread #0 setting the owner and setting the ctx. But since we're
idling here anyway, the additional check is basically free.
Found by inspection.
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Maarten Lankhorst <dev@mblankhorst.nl>
Cc: Daniel Vetter <daniel@ffwll.ch>
Cc: Chris Wilson <chris@chris-wilson.co.uk>
Cc: dri-devel@lists.freedesktop.org
Signed-off-by: Nicolai Hähnle <Nicolai.Haehnle@amd.com>
---
kernel/locking/mutex.c | 44 ++++++++++++++++++++++++++------------------
1 file changed, 26 insertions(+), 18 deletions(-)
diff --git a/kernel/locking/mutex.c b/kernel/locking/mutex.c
index c3f70dd..6f62695 100644
--- a/kernel/locking/mutex.c
+++ b/kernel/locking/mutex.c
@@ -373,7 +373,8 @@ ww_mutex_set_context_slowpath(struct ww_mutex *lock,
* access and not reliable.
*/
static noinline
-bool mutex_spin_on_owner(struct mutex *lock, struct task_struct *owner)
+bool mutex_spin_on_owner(struct mutex *lock, struct task_struct *owner,
+ bool use_ww_ctx, struct ww_acquire_ctx *ww_ctx)
{
bool ret = true;
@@ -396,6 +397,28 @@ bool mutex_spin_on_owner(struct mutex *lock, struct task_struct *owner)
break;
}
+ if (use_ww_ctx && ww_ctx && ww_ctx->acquired > 0) {
+ struct ww_mutex *ww;
+
+ ww = container_of(lock, struct ww_mutex, base);
+
+ /*
+ * If ww->ctx is set the contents are undefined, only
+ * by acquiring wait_lock there is a guarantee that
+ * they are not invalid when reading.
+ *
+ * As such, when deadlock detection needs to be
+ * performed the optimistic spinning cannot be done.
+ *
+ * Check this in every inner iteration because we may
+ * be racing against another thread's ww_mutex_lock.
+ */
+ if (READ_ONCE(ww->ctx)) {
+ ret = false;
+ break;
+ }
+ }
+
cpu_relax();
}
rcu_read_unlock();
@@ -483,22 +506,6 @@ static bool mutex_optimistic_spin(struct mutex *lock,
for (;;) {
struct task_struct *owner;
- if (use_ww_ctx && ww_ctx && ww_ctx->acquired > 0) {
- struct ww_mutex *ww;
-
- ww = container_of(lock, struct ww_mutex, base);
- /*
- * If ww->ctx is set the contents are undefined, only
- * by acquiring wait_lock there is a guarantee that
- * they are not invalid when reading.
- *
- * As such, when deadlock detection needs to be
- * performed the optimistic spinning cannot be done.
- */
- if (READ_ONCE(ww->ctx))
- goto fail_unlock;
- }
-
/*
* If there's an owner, wait for it to either
* release the lock or go to sleep.
@@ -510,7 +517,8 @@ static bool mutex_optimistic_spin(struct mutex *lock,
break;
}
- if (!mutex_spin_on_owner(lock, owner))
+ if (!mutex_spin_on_owner(lock, owner, use_ww_ctx,
+ ww_ctx))
goto fail_unlock;
}
--
2.7.4
next prev parent reply other threads:[~2016-12-21 18:46 UTC|newest]
Thread overview: 18+ messages / expand[flat|nested] mbox.gz Atom feed top
[not found] <1482346000-9927-1-git-send-email-nhaehnle@gmail.com>
2016-12-21 18:46 ` [PATCH v3 01/12] drm/vgem: Use ww_mutex_(un)lock even with a NULL context Nicolai Hähnle
2016-12-21 18:46 ` [PATCH v3 02/12] locking/mutex: Fix a race with handoffs and interruptible waits Nicolai Hähnle
2016-12-21 18:46 ` [PATCH v3 03/12] locking/ww_mutex: Extract stamp comparison to __ww_mutex_stamp_after Nicolai Hähnle
2016-12-22 1:58 ` zhoucm1
2016-12-22 8:43 ` Nicolai Hähnle
2016-12-21 18:46 ` [PATCH v3 04/12] locking/ww_mutex: Set use_ww_ctx even when locking without a context Nicolai Hähnle
2016-12-21 18:46 ` [PATCH v3 05/12] locking/ww_mutex: Remove the __ww_mutex_lock inline wrappers Nicolai Hähnle
2016-12-23 10:48 ` Peter Zijlstra
2016-12-23 11:16 ` Nicolai Hähnle
2016-12-23 12:13 ` Peter Zijlstra
2016-12-21 18:46 ` [PATCH v3 06/12] locking/ww_mutex: Add waiters in stamp order Nicolai Hähnle
2016-12-21 18:46 ` [PATCH v3 07/12] locking/ww_mutex: Notify waiters that have to back off while adding tasks to wait list Nicolai Hähnle
2016-12-21 18:46 ` [PATCH v3 08/12] locking/ww_mutex: Wake at most one waiter for back off when acquiring the lock Nicolai Hähnle
2016-12-21 18:46 ` Nicolai Hähnle [this message]
2016-12-21 18:46 ` [PATCH v3 10/12] locking/ww_mutex: Yield to other waiters from optimistic spin Nicolai Hähnle
2017-01-05 17:47 ` Peter Zijlstra
2016-12-21 18:46 ` [PATCH v3 11/12] locking/mutex: Initialize mutex_waiter::ww_ctx with poison when debugging Nicolai Hähnle
2016-12-21 18:46 ` [PATCH v3 12/12] Documentation/locking/ww_mutex: Update the design document Nicolai Hähnle
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=1482346000-9927-10-git-send-email-nhaehnle@gmail.com \
--to=nhaehnle@gmail.com \
--cc=Nicolai.Haehnle@amd.com \
--cc=chris@chris-wilson.co.uk \
--cc=daniel@ffwll.ch \
--cc=dev@mblankhorst.nl \
--cc=dri-devel@lists.freedesktop.org \
--cc=linux-kernel@vger.kernel.org \
--cc=mingo@redhat.com \
--cc=peterz@infradead.org \
/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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox