|
@@ -25,6 +25,7 @@
|
|
|
#include <linux/spinlock.h>
|
|
|
#include <linux/interrupt.h>
|
|
|
#include <linux/debug_locks.h>
|
|
|
+#include <linux/mcs_spinlock.h>
|
|
|
|
|
|
/*
|
|
|
* In the DEBUG case we are using the "NULL fastpath" for mutexes,
|
|
@@ -52,7 +53,7 @@ __mutex_init(struct mutex *lock, const char *name, struct lock_class_key *key)
|
|
|
INIT_LIST_HEAD(&lock->wait_list);
|
|
|
mutex_clear_owner(lock);
|
|
|
#ifdef CONFIG_MUTEX_SPIN_ON_OWNER
|
|
|
- lock->spin_mlock = NULL;
|
|
|
+ lock->mcs_lock = NULL;
|
|
|
#endif
|
|
|
|
|
|
debug_mutex_init(lock, name, key);
|
|
@@ -111,62 +112,7 @@ EXPORT_SYMBOL(mutex_lock);
|
|
|
* more or less simultaneously, the spinners need to acquire a MCS lock
|
|
|
* first before spinning on the owner field.
|
|
|
*
|
|
|
- * We don't inline mspin_lock() so that perf can correctly account for the
|
|
|
- * time spent in this lock function.
|
|
|
*/
|
|
|
-struct mspin_node {
|
|
|
- struct mspin_node *next ;
|
|
|
- int locked; /* 1 if lock acquired */
|
|
|
-};
|
|
|
-#define MLOCK(mutex) ((struct mspin_node **)&((mutex)->spin_mlock))
|
|
|
-
|
|
|
-static noinline
|
|
|
-void mspin_lock(struct mspin_node **lock, struct mspin_node *node)
|
|
|
-{
|
|
|
- struct mspin_node *prev;
|
|
|
-
|
|
|
- /* Init node */
|
|
|
- node->locked = 0;
|
|
|
- node->next = NULL;
|
|
|
-
|
|
|
- prev = xchg(lock, node);
|
|
|
- if (likely(prev == NULL)) {
|
|
|
- /* Lock acquired */
|
|
|
- node->locked = 1;
|
|
|
- return;
|
|
|
- }
|
|
|
- ACCESS_ONCE(prev->next) = node;
|
|
|
- /*
|
|
|
- * Wait until the lock holder passes the lock down.
|
|
|
- * Using smp_load_acquire() provides a memory barrier that
|
|
|
- * ensures subsequent operations happen after the lock is acquired.
|
|
|
- */
|
|
|
- while (!(smp_load_acquire(&node->locked)))
|
|
|
- arch_mutex_cpu_relax();
|
|
|
-}
|
|
|
-
|
|
|
-static void mspin_unlock(struct mspin_node **lock, struct mspin_node *node)
|
|
|
-{
|
|
|
- struct mspin_node *next = ACCESS_ONCE(node->next);
|
|
|
-
|
|
|
- if (likely(!next)) {
|
|
|
- /*
|
|
|
- * Release the lock by setting it to NULL
|
|
|
- */
|
|
|
- if (cmpxchg(lock, node, NULL) == node)
|
|
|
- return;
|
|
|
- /* Wait until the next pointer is set */
|
|
|
- while (!(next = ACCESS_ONCE(node->next)))
|
|
|
- arch_mutex_cpu_relax();
|
|
|
- }
|
|
|
- /*
|
|
|
- * Pass lock to next waiter.
|
|
|
- * smp_store_release() provides a memory barrier to ensure
|
|
|
- * all operations in the critical section has been completed
|
|
|
- * before unlocking.
|
|
|
- */
|
|
|
- smp_store_release(&next->locked, 1);
|
|
|
-}
|
|
|
|
|
|
/*
|
|
|
* Mutex spinning code migrated from kernel/sched/core.c
|
|
@@ -456,7 +402,7 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass,
|
|
|
|
|
|
for (;;) {
|
|
|
struct task_struct *owner;
|
|
|
- struct mspin_node node;
|
|
|
+ struct mcs_spinlock node;
|
|
|
|
|
|
if (use_ww_ctx && ww_ctx->acquired > 0) {
|
|
|
struct ww_mutex *ww;
|
|
@@ -478,10 +424,10 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass,
|
|
|
* If there's an owner, wait for it to either
|
|
|
* release the lock or go to sleep.
|
|
|
*/
|
|
|
- mspin_lock(MLOCK(lock), &node);
|
|
|
+ mcs_spin_lock(&lock->mcs_lock, &node);
|
|
|
owner = ACCESS_ONCE(lock->owner);
|
|
|
if (owner && !mutex_spin_on_owner(lock, owner)) {
|
|
|
- mspin_unlock(MLOCK(lock), &node);
|
|
|
+ mcs_spin_unlock(&lock->mcs_lock, &node);
|
|
|
goto slowpath;
|
|
|
}
|
|
|
|
|
@@ -496,11 +442,11 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass,
|
|
|
}
|
|
|
|
|
|
mutex_set_owner(lock);
|
|
|
- mspin_unlock(MLOCK(lock), &node);
|
|
|
+ mcs_spin_unlock(&lock->mcs_lock, &node);
|
|
|
preempt_enable();
|
|
|
return 0;
|
|
|
}
|
|
|
- mspin_unlock(MLOCK(lock), &node);
|
|
|
+ mcs_spin_unlock(&lock->mcs_lock, &node);
|
|
|
|
|
|
/*
|
|
|
* When there's no owner, we might have preempted between the
|