* [PATCH 0/4] MCS Lock: MCS lock code cleanup and optimizations
[not found] <cover.1383604526.git.tim.c.chen@linux.intel.com>
@ 2013-11-04 23:36 ` Tim Chen
2013-11-04 23:37 ` [PATCH 1/4] MCS Lock: Restructure the MCS lock defines and locking code into its own file Tim Chen
` (3 subsequent siblings)
4 siblings, 0 replies; 9+ messages in thread
From: Tim Chen @ 2013-11-04 23:36 UTC (permalink / raw)
To: Ingo Molnar, Andrew Morton, Thomas Gleixner
Cc: linux-kernel, linux-mm, linux-arch, Linus Torvalds, Waiman Long,
Andrea Arcangeli, Alex Shi, Andi Kleen, Michel Lespinasse,
Davidlohr Bueso, Matthew R Wilcox, Dave Hansen, Peter Zijlstra,
Rik van Riel, Peter Hurley, Paul E.McKenney, Tim Chen,
Raghavendra K T, George Spelvin, H. Peter Anvin, Arnd Bergmann,
Aswin Chandramouleeswaran, Scott J Norton
In this patch series, we separated out the MCS lock code which was previously embedded in the
mutex.c. This allows for easier reuse of MCS lock in other places like rwsem and qrwlock.
We also did some micro optimizations and barrier cleanup.
This patches were previously part of the rwsem optimization patch series but now we spearate
them out.
Tim Chen
Jason Low (2):
MCS Lock: optimizations and extra comments
MCS Lock: Barrier corrections
Tim Chen (1):
MCS Lock: Restructure the MCS lock defines and locking code into its
own file
Waiman Long (1):
MCS Lock: Make mcs_spinlock.h includable in other files
include/linux/mcs_spinlock.h | 100 ++++++++++++++++++++++++++++++++++++++++++
include/linux/mutex.h | 5 +-
kernel/Makefile | 6 +-
kernel/mcs_spinlock.c | 37 +++++++++++++++
kernel/mutex.c | 60 +++----------------------
5 files changed, 150 insertions(+), 58 deletions(-)
create mode 100644 include/linux/mcs_spinlock.h
create mode 100644 kernel/mcs_spinlock.c
--
1.7.4.4
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply [flat|nested] 9+ messages in thread* [PATCH 1/4] MCS Lock: Restructure the MCS lock defines and locking code into its own file
[not found] <cover.1383604526.git.tim.c.chen@linux.intel.com>
2013-11-04 23:36 ` [PATCH 0/4] MCS Lock: MCS lock code cleanup and optimizations Tim Chen
@ 2013-11-04 23:37 ` Tim Chen
2013-11-04 23:37 ` [PATCH 2/4] MCS Lock: optimizations and extra comments Tim Chen
` (2 subsequent siblings)
4 siblings, 0 replies; 9+ messages in thread
From: Tim Chen @ 2013-11-04 23:37 UTC (permalink / raw)
To: Ingo Molnar, Andrew Morton, Thomas Gleixner
Cc: linux-kernel, linux-mm, linux-arch, Linus Torvalds, Waiman Long,
Andrea Arcangeli, Alex Shi, Andi Kleen, Michel Lespinasse,
Davidlohr Bueso, Matthew R Wilcox, Dave Hansen, Peter Zijlstra,
Rik van Riel, Peter Hurley, Paul E.McKenney, Tim Chen,
Raghavendra K T, George Spelvin, H. Peter Anvin, Arnd Bergmann,
Aswin Chandramouleeswaran, Scott J Norton
We will need the MCS lock code for doing optimistic spinning for rwsem.
Extracting the MCS code from mutex.c and put into its own file allow us
to reuse this code easily for rwsem.
Reviewed-by: Ingo Molnar <mingo@elte.hu>
Reviewed-by: Peter Zijlstra <peterz@infradead.org>
Signed-off-by: Tim Chen <tim.c.chen@linux.intel.com>
Signed-off-by: Davidlohr Bueso <davidlohr@hp.com>
---
include/linux/mcs_spinlock.h | 64 ++++++++++++++++++++++++++++++++++++++++++
include/linux/mutex.h | 5 ++-
kernel/mutex.c | 60 ++++----------------------------------
3 files changed, 74 insertions(+), 55 deletions(-)
create mode 100644 include/linux/mcs_spinlock.h
diff --git a/include/linux/mcs_spinlock.h b/include/linux/mcs_spinlock.h
new file mode 100644
index 0000000..b5de3b0
--- /dev/null
+++ b/include/linux/mcs_spinlock.h
@@ -0,0 +1,64 @@
+/*
+ * MCS lock defines
+ *
+ * This file contains the main data structure and API definitions of MCS lock.
+ *
+ * The MCS lock (proposed by Mellor-Crummey and Scott) is a simple spin-lock
+ * with the desirable properties of being fair, and with each cpu trying
+ * to acquire the lock spinning on a local variable.
+ * It avoids expensive cache bouncings that common test-and-set spin-lock
+ * implementations incur.
+ */
+#ifndef __LINUX_MCS_SPINLOCK_H
+#define __LINUX_MCS_SPINLOCK_H
+
+struct mcs_spinlock {
+ struct mcs_spinlock *next;
+ int locked; /* 1 if lock acquired */
+};
+
+/*
+ * We don't inline mcs_spin_lock() so that perf can correctly account for the
+ * time spent in this lock function.
+ */
+static noinline
+void mcs_spin_lock(struct mcs_spinlock **lock, struct mcs_spinlock *node)
+{
+ struct mcs_spinlock *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;
+ smp_wmb();
+ /* Wait until the lock holder passes the lock down */
+ while (!ACCESS_ONCE(node->locked))
+ arch_mutex_cpu_relax();
+}
+
+static void mcs_spin_unlock(struct mcs_spinlock **lock, struct mcs_spinlock *node)
+{
+ struct mcs_spinlock *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();
+ }
+ ACCESS_ONCE(next->locked) = 1;
+ smp_wmb();
+}
+
+#endif /* __LINUX_MCS_SPINLOCK_H */
diff --git a/include/linux/mutex.h b/include/linux/mutex.h
index ccd4260..e6eaeea 100644
--- a/include/linux/mutex.h
+++ b/include/linux/mutex.h
@@ -46,6 +46,7 @@
* - detects multi-task circular deadlocks and prints out all affected
* locks and tasks (and only those tasks)
*/
+struct mcs_spinlock;
struct mutex {
/* 1: unlocked, 0: locked, negative: locked, possible waiters */
atomic_t count;
@@ -55,7 +56,7 @@ struct mutex {
struct task_struct *owner;
#endif
#ifdef CONFIG_MUTEX_SPIN_ON_OWNER
- void *spin_mlock; /* Spinner MCS lock */
+ struct mcs_spinlock *mcs_lock; /* Spinner MCS lock */
#endif
#ifdef CONFIG_DEBUG_MUTEXES
const char *name;
@@ -179,4 +180,4 @@ extern int atomic_dec_and_mutex_lock(atomic_t *cnt, struct mutex *lock);
#define arch_mutex_cpu_relax() cpu_relax()
#endif
-#endif
+#endif /* __LINUX_MUTEX_H */
diff --git a/kernel/mutex.c b/kernel/mutex.c
index 6d647ae..4640731 100644
--- a/kernel/mutex.c
+++ b/kernel/mutex.c
@@ -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,54 +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;
- smp_wmb();
- /* Wait until the lock holder passes the lock down */
- while (!ACCESS_ONCE(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();
- }
- ACCESS_ONCE(next->locked) = 1;
- smp_wmb();
-}
/*
* Mutex spinning code migrated from kernel/sched/core.c
@@ -448,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 (!__builtin_constant_p(ww_ctx == NULL) && ww_ctx->acquired > 0) {
struct ww_mutex *ww;
@@ -470,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;
}
@@ -488,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
--
1.7.4.4
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply [flat|nested] 9+ messages in thread* [PATCH 2/4] MCS Lock: optimizations and extra comments
[not found] <cover.1383604526.git.tim.c.chen@linux.intel.com>
2013-11-04 23:36 ` [PATCH 0/4] MCS Lock: MCS lock code cleanup and optimizations Tim Chen
2013-11-04 23:37 ` [PATCH 1/4] MCS Lock: Restructure the MCS lock defines and locking code into its own file Tim Chen
@ 2013-11-04 23:37 ` Tim Chen
2013-11-04 23:37 ` [PATCH 3/4] MCS Lock: Barrier corrections Tim Chen
2013-11-04 23:37 ` [PATCH 4/4] MCS Lock: Make mcs_spinlock.h includable in other files Tim Chen
4 siblings, 0 replies; 9+ messages in thread
From: Tim Chen @ 2013-11-04 23:37 UTC (permalink / raw)
To: Ingo Molnar, Andrew Morton, Thomas Gleixner
Cc: linux-kernel, linux-mm, linux-arch, Linus Torvalds, Waiman Long,
Andrea Arcangeli, Alex Shi, Andi Kleen, Michel Lespinasse,
Davidlohr Bueso, Matthew R Wilcox, Dave Hansen, Peter Zijlstra,
Rik van Riel, Peter Hurley, Paul E.McKenney, Tim Chen,
Raghavendra K T, George Spelvin, H. Peter Anvin, Arnd Bergmann,
Aswin Chandramouleeswaran, Scott J Norton
Remove unnecessary operation and make the cmpxchg(lock, node, NULL) == node
check in mcs_spin_unlock() likely() as it is likely that a race did not occur
most of the time.
Also add in more comments describing how the local node is used in MCS locks.
Reviewed-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Reviewed-by: Tim Chen <tim.c.chen@linux.intel.com>
Signed-off-by: Jason Low <jason.low2@hp.com>
---
include/linux/mcs_spinlock.h | 13 +++++++++++--
1 files changed, 11 insertions(+), 2 deletions(-)
diff --git a/include/linux/mcs_spinlock.h b/include/linux/mcs_spinlock.h
index b5de3b0..96f14299 100644
--- a/include/linux/mcs_spinlock.h
+++ b/include/linux/mcs_spinlock.h
@@ -18,6 +18,12 @@ struct mcs_spinlock {
};
/*
+ * In order to acquire the lock, the caller should declare a local node and
+ * pass a reference of the node to this function in addition to the lock.
+ * If the lock has already been acquired, then this will proceed to spin
+ * on this node->locked until the previous lock holder sets the node->locked
+ * in mcs_spin_unlock().
+ *
* We don't inline mcs_spin_lock() so that perf can correctly account for the
* time spent in this lock function.
*/
@@ -33,7 +39,6 @@ void mcs_spin_lock(struct mcs_spinlock **lock, struct mcs_spinlock *node)
prev = xchg(lock, node);
if (likely(prev == NULL)) {
/* Lock acquired */
- node->locked = 1;
return;
}
ACCESS_ONCE(prev->next) = node;
@@ -43,6 +48,10 @@ void mcs_spin_lock(struct mcs_spinlock **lock, struct mcs_spinlock *node)
arch_mutex_cpu_relax();
}
+/*
+ * Releases the lock. The caller should pass in the corresponding node that
+ * was used to acquire the lock.
+ */
static void mcs_spin_unlock(struct mcs_spinlock **lock, struct mcs_spinlock *node)
{
struct mcs_spinlock *next = ACCESS_ONCE(node->next);
@@ -51,7 +60,7 @@ static void mcs_spin_unlock(struct mcs_spinlock **lock, struct mcs_spinlock *nod
/*
* Release the lock by setting it to NULL
*/
- if (cmpxchg(lock, node, NULL) == node)
+ if (likely(cmpxchg(lock, node, NULL) == node))
return;
/* Wait until the next pointer is set */
while (!(next = ACCESS_ONCE(node->next)))
--
1.7.4.4
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply [flat|nested] 9+ messages in thread* [PATCH 3/4] MCS Lock: Barrier corrections
[not found] <cover.1383604526.git.tim.c.chen@linux.intel.com>
` (2 preceding siblings ...)
2013-11-04 23:37 ` [PATCH 2/4] MCS Lock: optimizations and extra comments Tim Chen
@ 2013-11-04 23:37 ` Tim Chen
2013-11-04 23:37 ` [PATCH 4/4] MCS Lock: Make mcs_spinlock.h includable in other files Tim Chen
4 siblings, 0 replies; 9+ messages in thread
From: Tim Chen @ 2013-11-04 23:37 UTC (permalink / raw)
To: Ingo Molnar, Andrew Morton, Thomas Gleixner
Cc: linux-kernel, linux-mm, linux-arch, Linus Torvalds, Waiman Long,
Andrea Arcangeli, Alex Shi, Andi Kleen, Michel Lespinasse,
Davidlohr Bueso, Matthew R Wilcox, Dave Hansen, Peter Zijlstra,
Rik van Riel, Peter Hurley, Paul E.McKenney, Tim Chen,
Raghavendra K T, George Spelvin, H. Peter Anvin, Arnd Bergmann,
Aswin Chandramouleeswaran, Scott J Norton
This patch corrects the way memory barriers are used in the MCS lock
and removes ones that are not needed. Also add comments on all barriers.
Reviewed-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Reviewed-by: Tim Chen <tim.c.chen@linux.intel.com>
Signed-off-by: Jason Low <jason.low2@hp.com>
---
include/linux/mcs_spinlock.h | 13 +++++++++++--
1 files changed, 11 insertions(+), 2 deletions(-)
diff --git a/include/linux/mcs_spinlock.h b/include/linux/mcs_spinlock.h
index 96f14299..93d445d 100644
--- a/include/linux/mcs_spinlock.h
+++ b/include/linux/mcs_spinlock.h
@@ -36,16 +36,19 @@ void mcs_spin_lock(struct mcs_spinlock **lock, struct mcs_spinlock *node)
node->locked = 0;
node->next = NULL;
+ /* xchg() provides a memory barrier */
prev = xchg(lock, node);
if (likely(prev == NULL)) {
/* Lock acquired */
return;
}
ACCESS_ONCE(prev->next) = node;
- smp_wmb();
/* Wait until the lock holder passes the lock down */
while (!ACCESS_ONCE(node->locked))
arch_mutex_cpu_relax();
+
+ /* Make sure subsequent operations happen after the lock is acquired */
+ smp_rmb();
}
/*
@@ -58,6 +61,7 @@ static void mcs_spin_unlock(struct mcs_spinlock **lock, struct mcs_spinlock *nod
if (likely(!next)) {
/*
+ * cmpxchg() provides a memory barrier.
* Release the lock by setting it to NULL
*/
if (likely(cmpxchg(lock, node, NULL) == node))
@@ -65,9 +69,14 @@ static void mcs_spin_unlock(struct mcs_spinlock **lock, struct mcs_spinlock *nod
/* Wait until the next pointer is set */
while (!(next = ACCESS_ONCE(node->next)))
arch_mutex_cpu_relax();
+ } else {
+ /*
+ * Make sure all operations within the critical section
+ * happen before the lock is released.
+ */
+ smp_wmb();
}
ACCESS_ONCE(next->locked) = 1;
- smp_wmb();
}
#endif /* __LINUX_MCS_SPINLOCK_H */
--
1.7.4.4
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply [flat|nested] 9+ messages in thread* [PATCH 4/4] MCS Lock: Make mcs_spinlock.h includable in other files
[not found] <cover.1383604526.git.tim.c.chen@linux.intel.com>
` (3 preceding siblings ...)
2013-11-04 23:37 ` [PATCH 3/4] MCS Lock: Barrier corrections Tim Chen
@ 2013-11-04 23:37 ` Tim Chen
2013-11-05 10:15 ` Will Deacon
2013-11-05 11:14 ` Peter Zijlstra
4 siblings, 2 replies; 9+ messages in thread
From: Tim Chen @ 2013-11-04 23:37 UTC (permalink / raw)
To: Ingo Molnar, Andrew Morton, Thomas Gleixner
Cc: linux-kernel, linux-mm, linux-arch, Linus Torvalds, Waiman Long,
Andrea Arcangeli, Alex Shi, Andi Kleen, Michel Lespinasse,
Davidlohr Bueso, Matthew R Wilcox, Dave Hansen, Peter Zijlstra,
Rik van Riel, Peter Hurley, Paul E.McKenney, Tim Chen,
Raghavendra K T, George Spelvin, H. Peter Anvin, Arnd Bergmann,
Aswin Chandramouleeswaran, Scott J Norton
The following changes are made to enable mcs_spinlock.h file to be
widely included in other files without causing problem:
1) Include a number of prerequisite header files and define
arch_mutex_cpu_relax(), if not previously defined.
2) Separate out mcs_spin_lock() into a mcs_spinlock.c file.
3) Make mcs_spin_unlock() an inlined function.
Signed-off-by: Waiman Long <Waiman.Long@hp.com>
---
include/linux/mcs_spinlock.h | 28 +++++++++++++++++++++++-----
kernel/Makefile | 6 +++---
kernel/mcs_spinlock.c | 37 +++++++++++++++++++++++++++++++++++++
3 files changed, 63 insertions(+), 8 deletions(-)
create mode 100644 kernel/mcs_spinlock.c
diff --git a/include/linux/mcs_spinlock.h b/include/linux/mcs_spinlock.h
index 93d445d..0b36927 100644
--- a/include/linux/mcs_spinlock.h
+++ b/include/linux/mcs_spinlock.h
@@ -12,11 +12,27 @@
#ifndef __LINUX_MCS_SPINLOCK_H
#define __LINUX_MCS_SPINLOCK_H
+/*
+ * asm/processor.h may define arch_mutex_cpu_relax().
+ * If it is not defined, cpu_relax() will be used.
+ */
+#include <asm/barrier.h>
+#include <asm/cmpxchg.h>
+#include <asm/processor.h>
+#include <linux/compiler.h>
+
+#ifndef arch_mutex_cpu_relax
+# define arch_mutex_cpu_relax() cpu_relax()
+#endif
+
struct mcs_spinlock {
struct mcs_spinlock *next;
int locked; /* 1 if lock acquired */
};
+extern
+void mcs_spin_lock(struct mcs_spinlock **lock, struct mcs_spinlock *node);
+
/*
* In order to acquire the lock, the caller should declare a local node and
* pass a reference of the node to this function in addition to the lock.
@@ -24,11 +40,11 @@ struct mcs_spinlock {
* on this node->locked until the previous lock holder sets the node->locked
* in mcs_spin_unlock().
*
- * We don't inline mcs_spin_lock() so that perf can correctly account for the
- * time spent in this lock function.
+ * The _raw_mcs_spin_lock() function should not be called directly. Instead,
+ * users should call mcs_spin_lock().
*/
-static noinline
-void mcs_spin_lock(struct mcs_spinlock **lock, struct mcs_spinlock *node)
+static inline
+void _raw_mcs_spin_lock(struct mcs_spinlock **lock, struct mcs_spinlock *node)
{
struct mcs_spinlock *prev;
@@ -55,7 +71,9 @@ void mcs_spin_lock(struct mcs_spinlock **lock, struct mcs_spinlock *node)
* Releases the lock. The caller should pass in the corresponding node that
* was used to acquire the lock.
*/
-static void mcs_spin_unlock(struct mcs_spinlock **lock, struct mcs_spinlock *node)
+
+static inline
+void mcs_spin_unlock(struct mcs_spinlock **lock, struct mcs_spinlock *node)
{
struct mcs_spinlock *next = ACCESS_ONCE(node->next);
diff --git a/kernel/Makefile b/kernel/Makefile
index 1ce4755..2ad8454 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -50,9 +50,9 @@ obj-$(CONFIG_SMP) += smp.o
ifneq ($(CONFIG_SMP),y)
obj-y += up.o
endif
-obj-$(CONFIG_SMP) += spinlock.o
-obj-$(CONFIG_DEBUG_SPINLOCK) += spinlock.o
-obj-$(CONFIG_PROVE_LOCKING) += spinlock.o
+obj-$(CONFIG_SMP) += spinlock.o mcs_spinlock.o
+obj-$(CONFIG_DEBUG_SPINLOCK) += spinlock.o mcs_spinlock.o
+obj-$(CONFIG_PROVE_LOCKING) += spinlock.o mcs_spinlock.o
obj-$(CONFIG_UID16) += uid16.o
obj-$(CONFIG_MODULES) += module.o
obj-$(CONFIG_MODULE_SIG) += module_signing.o modsign_pubkey.o modsign_certificate.o
diff --git a/kernel/mcs_spinlock.c b/kernel/mcs_spinlock.c
new file mode 100644
index 0000000..6b20324
--- /dev/null
+++ b/kernel/mcs_spinlock.c
@@ -0,0 +1,37 @@
+/*
+ * MCS lock
+ *
+ * The MCS lock (proposed by Mellor-Crummey and Scott) is a simple spin-lock
+ * with the desirable properties of being fair, and with each cpu trying
+ * to acquire the lock spinning on a local variable.
+ * It avoids expensive cache bouncings that common test-and-set spin-lock
+ * implementations incur.
+ */
+#include <linux/mcs_spinlock.h>
+#include <linux/export.h>
+
+/*
+ * We don't inline mcs_spin_lock() so that perf can correctly account for the
+ * time spent in this lock function.
+ */
+void mcs_spin_lock(struct mcs_spinlock **lock, struct mcs_spinlock *node)
+{
+ struct mcs_spinlock *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;
+ smp_wmb();
+ /* Wait until the lock holder passes the lock down */
+ while (!ACCESS_ONCE(node->locked))
+ arch_mutex_cpu_relax();
+}
+EXPORT_SYMBOL(mcs_spin_lock);
--
1.7.4.4
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply [flat|nested] 9+ messages in thread* Re: [PATCH 4/4] MCS Lock: Make mcs_spinlock.h includable in other files
2013-11-04 23:37 ` [PATCH 4/4] MCS Lock: Make mcs_spinlock.h includable in other files Tim Chen
@ 2013-11-05 10:15 ` Will Deacon
2013-11-05 11:22 ` Peter Zijlstra
2013-11-05 11:14 ` Peter Zijlstra
1 sibling, 1 reply; 9+ messages in thread
From: Will Deacon @ 2013-11-05 10:15 UTC (permalink / raw)
To: Tim Chen
Cc: Ingo Molnar, Andrew Morton, Thomas Gleixner, linux-kernel,
linux-mm, linux-arch, Linus Torvalds, Waiman Long,
Andrea Arcangeli, Alex Shi, Andi Kleen, Michel Lespinasse,
Davidlohr Bueso, Matthew R Wilcox, Dave Hansen, Peter Zijlstra,
Rik van Riel, Peter Hurley, Paul E.McKenney, Raghavendra K T,
George Spelvin, H. Peter Anvin, Arnd Bergmann,
Aswin Chandramouleeswaran, Scott J Norton
Hello,
On Mon, Nov 04, 2013 at 11:37:13PM +0000, Tim Chen wrote:
> The following changes are made to enable mcs_spinlock.h file to be
> widely included in other files without causing problem:
>
> 1) Include a number of prerequisite header files and define
> arch_mutex_cpu_relax(), if not previously defined.
> 2) Separate out mcs_spin_lock() into a mcs_spinlock.c file.
> 3) Make mcs_spin_unlock() an inlined function.
[...]
> +void mcs_spin_lock(struct mcs_spinlock **lock, struct mcs_spinlock *node)
> +{
> + struct mcs_spinlock *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;
> + smp_wmb();
> + /* Wait until the lock holder passes the lock down */
> + while (!ACCESS_ONCE(node->locked))
> + arch_mutex_cpu_relax();
> +}
You have the barrier in a different place than the version in the header
file; is this intentional?
Also, why is an smp_wmb() sufficient (as opposed to a full smp_mb()?). Are
there restrictions on the types of access that can occur in the critical
section?
Will
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply [flat|nested] 9+ messages in thread* Re: [PATCH 4/4] MCS Lock: Make mcs_spinlock.h includable in other files
2013-11-05 10:15 ` Will Deacon
@ 2013-11-05 11:22 ` Peter Zijlstra
2013-11-05 17:10 ` Tim Chen
0 siblings, 1 reply; 9+ messages in thread
From: Peter Zijlstra @ 2013-11-05 11:22 UTC (permalink / raw)
To: Will Deacon
Cc: Tim Chen, Ingo Molnar, Andrew Morton, Thomas Gleixner,
linux-kernel, linux-mm, linux-arch, Linus Torvalds, Waiman Long,
Andrea Arcangeli, Alex Shi, Andi Kleen, Michel Lespinasse,
Davidlohr Bueso, Matthew R Wilcox, Dave Hansen, Rik van Riel,
Peter Hurley, Paul E.McKenney, Raghavendra K T, George Spelvin,
H. Peter Anvin, Arnd Bergmann, Aswin Chandramouleeswaran,
Scott J Norton
On Tue, Nov 05, 2013 at 10:15:38AM +0000, Will Deacon wrote:
> Hello,
>
> On Mon, Nov 04, 2013 at 11:37:13PM +0000, Tim Chen wrote:
> > The following changes are made to enable mcs_spinlock.h file to be
> > widely included in other files without causing problem:
> >
> > 1) Include a number of prerequisite header files and define
> > arch_mutex_cpu_relax(), if not previously defined.
> > 2) Separate out mcs_spin_lock() into a mcs_spinlock.c file.
> > 3) Make mcs_spin_unlock() an inlined function.
>
> [...]
>
> > +void mcs_spin_lock(struct mcs_spinlock **lock, struct mcs_spinlock *node)
> > +{
> > + struct mcs_spinlock *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;
> > + smp_wmb();
> > + /* Wait until the lock holder passes the lock down */
> > + while (!ACCESS_ONCE(node->locked))
> > + arch_mutex_cpu_relax();
> > +}
>
> You have the barrier in a different place than the version in the header
> file; is this intentional?
>
> Also, why is an smp_wmb() sufficient (as opposed to a full smp_mb()?). Are
> there restrictions on the types of access that can occur in the critical
> section?
Oh, good spot. I missed it because it doesn't actually remove the one in
the header, why is that?
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply [flat|nested] 9+ messages in thread* Re: [PATCH 4/4] MCS Lock: Make mcs_spinlock.h includable in other files
2013-11-05 11:22 ` Peter Zijlstra
@ 2013-11-05 17:10 ` Tim Chen
0 siblings, 0 replies; 9+ messages in thread
From: Tim Chen @ 2013-11-05 17:10 UTC (permalink / raw)
To: Peter Zijlstra
Cc: Will Deacon, Ingo Molnar, Andrew Morton, Thomas Gleixner,
linux-kernel, linux-mm, linux-arch, Linus Torvalds, Waiman Long,
Andrea Arcangeli, Alex Shi, Andi Kleen, Michel Lespinasse,
Davidlohr Bueso, Matthew R Wilcox, Dave Hansen, Rik van Riel,
Peter Hurley, Paul E.McKenney, Raghavendra K T, George Spelvin,
H. Peter Anvin, Arnd Bergmann, Aswin Chandramouleeswaran,
Scott J Norton
On Tue, 2013-11-05 at 12:22 +0100, Peter Zijlstra wrote:
> On Tue, Nov 05, 2013 at 10:15:38AM +0000, Will Deacon wrote:
> > Hello,
> >
> > On Mon, Nov 04, 2013 at 11:37:13PM +0000, Tim Chen wrote:
> > > The following changes are made to enable mcs_spinlock.h file to be
> > > widely included in other files without causing problem:
> > >
> > > 1) Include a number of prerequisite header files and define
> > > arch_mutex_cpu_relax(), if not previously defined.
> > > 2) Separate out mcs_spin_lock() into a mcs_spinlock.c file.
> > > 3) Make mcs_spin_unlock() an inlined function.
> >
> > [...]
> >
> > > +void mcs_spin_lock(struct mcs_spinlock **lock, struct mcs_spinlock *node)
> > > +{
> > > + struct mcs_spinlock *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;
> > > + smp_wmb();
> > > + /* Wait until the lock holder passes the lock down */
> > > + while (!ACCESS_ONCE(node->locked))
> > > + arch_mutex_cpu_relax();
> > > +}
> >
> > You have the barrier in a different place than the version in the header
> > file; is this intentional?
> >
> > Also, why is an smp_wmb() sufficient (as opposed to a full smp_mb()?). Are
> > there restrictions on the types of access that can occur in the critical
> > section?
>
> Oh, good spot. I missed it because it doesn't actually remove the one in
> the header, why is that?
>
Good catch. I merged an older version of Waiman's patch. I'll correct
this and update with the patch series with the newer one that should
only call the mcs_spin_lock in the header file.
Tim
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH 4/4] MCS Lock: Make mcs_spinlock.h includable in other files
2013-11-04 23:37 ` [PATCH 4/4] MCS Lock: Make mcs_spinlock.h includable in other files Tim Chen
2013-11-05 10:15 ` Will Deacon
@ 2013-11-05 11:14 ` Peter Zijlstra
1 sibling, 0 replies; 9+ messages in thread
From: Peter Zijlstra @ 2013-11-05 11:14 UTC (permalink / raw)
To: Tim Chen
Cc: Ingo Molnar, Andrew Morton, Thomas Gleixner, linux-kernel,
linux-mm, linux-arch, Linus Torvalds, Waiman Long,
Andrea Arcangeli, Alex Shi, Andi Kleen, Michel Lespinasse,
Davidlohr Bueso, Matthew R Wilcox, Dave Hansen, Rik van Riel,
Peter Hurley, Paul E.McKenney, Raghavendra K T, George Spelvin,
H. Peter Anvin, Arnd Bergmann, Aswin Chandramouleeswaran,
Scott J Norton
On Mon, Nov 04, 2013 at 03:37:13PM -0800, Tim Chen wrote:
> +EXPORT_SYMBOL(mcs_spin_lock);
If that can be a GPL, please make it so.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply [flat|nested] 9+ messages in thread