@@ -374,7 +374,8 @@ ww_mutex_set_context_slowpath(struct ww_mutex *lock,
*/
static noinline
bool mutex_spin_on_owner(struct mutex *lock, struct task_struct *owner,
- bool use_ww_ctx, struct ww_acquire_ctx *ww_ctx)
+ bool use_ww_ctx, struct ww_acquire_ctx *ww_ctx,
+ struct mutex_waiter *waiter)
{
bool ret = true;
@@ -397,7 +398,7 @@ bool mutex_spin_on_owner(struct mutex *lock, struct task_struct *owner,
break;
}
- if (use_ww_ctx && ww_ctx && ww_ctx->acquired > 0) {
+ if (use_ww_ctx && ww_ctx) {
struct ww_mutex *ww;
ww = container_of(lock, struct ww_mutex, base);
@@ -413,7 +414,30 @@ bool mutex_spin_on_owner(struct mutex *lock, struct task_struct *owner,
* Check this in every inner iteration because we may
* be racing against another thread's ww_mutex_lock.
*/
- if (READ_ONCE(ww->ctx)) {
+ if (ww_ctx->acquired > 0 && READ_ONCE(ww->ctx)) {
+ ret = false;
+ break;
+ }
+
+ /*
+ * If we aren't on the wait list yet, cancel the spin
+ * if there are waiters. We want to avoid stealing the
+ * lock from a waiter with an earlier stamp, since the
+ * other thread may already own a lock that we also
+ * need.
+ */
+ if (!waiter &&
+ (atomic_long_read(&lock->owner) &
+ MUTEX_FLAG_WAITERS)) {
+ ret = false;
+ break;
+ }
+
+ /*
+ * Similarly, stop spinning if we are no longer the
+ * first waiter.
+ */
+ if (waiter && !__mutex_waiter_is_first(lock, waiter)) {
ret = false;
break;
}
@@ -479,7 +503,8 @@ static inline int mutex_can_spin_on_owner(struct mutex *lock)
*/
static bool mutex_optimistic_spin(struct mutex *lock,
struct ww_acquire_ctx *ww_ctx,
- const bool use_ww_ctx, const bool waiter)
+ const bool use_ww_ctx,
+ struct mutex_waiter *waiter)
{
struct task_struct *task = current;
@@ -518,12 +543,12 @@ static bool mutex_optimistic_spin(struct mutex *lock,
}
if (!mutex_spin_on_owner(lock, owner, use_ww_ctx,
- ww_ctx))
+ ww_ctx, waiter))
goto fail_unlock;
}
/* Try to acquire the mutex if it is unlocked. */
- if (__mutex_trylock(lock, waiter))
+ if (__mutex_trylock(lock, waiter != NULL))
break;
/*
@@ -565,7 +590,8 @@ static bool mutex_optimistic_spin(struct mutex *lock,
#else
static bool mutex_optimistic_spin(struct mutex *lock,
struct ww_acquire_ctx *ww_ctx,
- const bool use_ww_ctx, const bool waiter)
+ const bool use_ww_ctx,
+ struct mutex_waiter *waiter)
{
return false;
}
@@ -725,7 +751,7 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass,
mutex_acquire_nest(&lock->dep_map, subclass, 0, nest_lock, ip);
if (__mutex_trylock(lock, false) ||
- mutex_optimistic_spin(lock, ww_ctx, use_ww_ctx, false)) {
+ mutex_optimistic_spin(lock, ww_ctx, use_ww_ctx, NULL)) {
/* got the lock, yay! */
lock_acquired(&lock->dep_map, ip);
if (use_ww_ctx && ww_ctx) {
@@ -830,8 +856,10 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass,
* state back to RUNNING and fall through the next schedule(),
* or we must see its unlock and acquire.
*/
- if ((first && mutex_optimistic_spin(lock, ww_ctx, use_ww_ctx, true)) ||
- __mutex_trylock(lock, use_ww_ctx || first))
+ if ((first &&
+ mutex_optimistic_spin(lock, ww_ctx, use_ww_ctx,
+ &waiter)) ||
+ __mutex_trylock(lock, use_ww_ctx || first))
break;
spin_lock_mutex(&lock->wait_lock, flags);