linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH RFC 0/26] Remove spin_unlock_wait()
@ 2017-06-29 23:59 Paul E. McKenney
  2017-06-30  0:01 ` [PATCH RFC 01/26] netfilter: Replace spin_unlock_wait() with lock/unlock pair Paul E. McKenney
                   ` (25 more replies)
  0 siblings, 26 replies; 122+ messages in thread
From: Paul E. McKenney @ 2017-06-29 23:59 UTC (permalink / raw)
  To: linux-kernel
  Cc: netfilter-devel, netdev, oleg, akpm, mingo, dave, manfred, tj,
	arnd, linux-arch, will.deacon, peterz, stern, parri.andrea,
	torvalds

Hello!

There is no agreed-upon definition of spin_unlock_wait()'s semantics,
and it appears that all callers could do just as well with a lock/unlock
pair.  This series therefore removes spin_unlock_wait() and changes
its users to instead use a lock/unlock pair.  The commits are as follows,
in three groups:

1-7.	Change uses of spin_unlock_wait() and raw_spin_unlock_wait()
	to instead use a spin_lock/spin_unlock pair.  These may be
	applied in any order, but must be applied before any later
	commits in this series.  The commit logs state why I believe
	that these commits won't noticeably degrade performance.

8.	Remove core-kernel definitions for spin_unlock_wait() and
	raw_spin_unlock_wait().

9-26.	Remove arch-specific definitions of arch_spin_unlock_wait().

Thoughts?

							Thanx, Paul

------------------------------------------------------------------------

 arch/alpha/include/asm/spinlock.h    |    5 -
 arch/arc/include/asm/spinlock.h      |    5 -
 arch/arm/include/asm/spinlock.h      |   16 ----
 arch/arm64/include/asm/spinlock.h    |   58 +----------------
 arch/blackfin/include/asm/spinlock.h |    5 -
 arch/hexagon/include/asm/spinlock.h  |    5 -
 arch/ia64/include/asm/spinlock.h     |   21 ------
 arch/m32r/include/asm/spinlock.h     |    5 -
 arch/metag/include/asm/spinlock.h    |    5 -
 arch/mips/include/asm/spinlock.h     |   16 ----
 arch/mn10300/include/asm/spinlock.h  |    5 -
 arch/parisc/include/asm/spinlock.h   |    7 --
 arch/powerpc/include/asm/spinlock.h  |   33 ---------
 arch/s390/include/asm/spinlock.h     |    7 --
 arch/sh/include/asm/spinlock-cas.h   |    5 -
 arch/sh/include/asm/spinlock-llsc.h  |    5 -
 arch/sparc/include/asm/spinlock_32.h |    5 -
 arch/sparc/include/asm/spinlock_64.h |    5 -
 arch/tile/include/asm/spinlock_32.h  |    2 
 arch/tile/include/asm/spinlock_64.h  |    2 
 arch/tile/lib/spinlock_32.c          |   23 ------
 arch/tile/lib/spinlock_64.c          |   22 ------
 arch/xtensa/include/asm/spinlock.h   |    5 -
 drivers/ata/libata-eh.c              |    8 --
 include/asm-generic/qspinlock.h      |   14 ----
 include/linux/spinlock.h             |   31 ---------
 include/linux/spinlock_up.h          |    6 -
 ipc/sem.c                            |    3 
 kernel/exit.c                        |    3 
 kernel/locking/qspinlock.c           |  117 -----------------------------------
 kernel/sched/completion.c            |    9 --
 kernel/sched/core.c                  |    3 
 kernel/task_work.c                   |    3 
 net/netfilter/nf_conntrack_core.c    |   26 ++-----
 34 files changed, 26 insertions(+), 464 deletions(-)

^ permalink raw reply	[flat|nested] 122+ messages in thread

* [PATCH RFC 01/26] netfilter: Replace spin_unlock_wait() with lock/unlock pair
  2017-06-29 23:59 [PATCH RFC 0/26] Remove spin_unlock_wait() Paul E. McKenney
@ 2017-06-30  0:01 ` Paul E. McKenney
       [not found]   ` <a6642feb-2f3a-980f-5ed6-2deb79563e6b@colorfullife.com>
  2017-06-30  0:01 ` [PATCH RFC 02/26] task_work: " Paul E. McKenney
                   ` (24 subsequent siblings)
  25 siblings, 1 reply; 122+ messages in thread
From: Paul E. McKenney @ 2017-06-30  0:01 UTC (permalink / raw)
  To: linux-kernel
  Cc: netfilter-devel, netdev, oleg, akpm, mingo, dave, manfred, tj,
	arnd, linux-arch, will.deacon, peterz, stern, parri.andrea,
	torvalds, Paul E. McKenney, Pablo Neira Ayuso, Jozsef Kadlecsik,
	Florian Westphal, David S. Miller, coreteam

There is no agreed-upon definition of spin_unlock_wait()'s semantics,
and it appears that all callers could do just as well with a lock/unlock
pair.  This commit therefore replaces the spin_unlock_wait() calls
in nf_conntrack_lock() and nf_conntrack_all_lock() with spin_lock()
followed immediately by spin_unlock().  These functions do not appear
to be invoked on any fastpaths.

Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Cc: Pablo Neira Ayuso <pablo@netfilter.org>
Cc: Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
Cc: Florian Westphal <fw@strlen.de>
Cc: "David S. Miller" <davem@davemloft.net>
Cc: <netfilter-devel@vger.kernel.org>
Cc: <coreteam@netfilter.org>
Cc: <netdev@vger.kernel.org>
Cc: Will Deacon <will.deacon@arm.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Alan Stern <stern@rowland.harvard.edu>
Cc: Andrea Parri <parri.andrea@gmail.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
---
 net/netfilter/nf_conntrack_core.c | 26 ++++++++------------------
 1 file changed, 8 insertions(+), 18 deletions(-)

diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c
index e847dbaa0c6b..9f997859d160 100644
--- a/net/netfilter/nf_conntrack_core.c
+++ b/net/netfilter/nf_conntrack_core.c
@@ -99,15 +99,11 @@ void nf_conntrack_lock(spinlock_t *lock) __acquires(lock)
 	spin_lock(lock);
 	while (unlikely(nf_conntrack_locks_all)) {
 		spin_unlock(lock);
-
-		/*
-		 * Order the 'nf_conntrack_locks_all' load vs. the
-		 * spin_unlock_wait() loads below, to ensure
-		 * that 'nf_conntrack_locks_all_lock' is indeed held:
-		 */
-		smp_rmb(); /* spin_lock(&nf_conntrack_locks_all_lock) */
-		spin_unlock_wait(&nf_conntrack_locks_all_lock);
+		/* Wait for nf_conntrack_locks_all_lock holder to release ... */
+		spin_lock(&nf_conntrack_locks_all_lock);
+		spin_unlock(&nf_conntrack_locks_all_lock);
 		spin_lock(lock);
+		/* ... and retry. */
 	}
 }
 EXPORT_SYMBOL_GPL(nf_conntrack_lock);
@@ -150,17 +146,11 @@ static void nf_conntrack_all_lock(void)
 
 	spin_lock(&nf_conntrack_locks_all_lock);
 	nf_conntrack_locks_all = true;
-
-	/*
-	 * Order the above store of 'nf_conntrack_locks_all' against
-	 * the spin_unlock_wait() loads below, such that if
-	 * nf_conntrack_lock() observes 'nf_conntrack_locks_all'
-	 * we must observe nf_conntrack_locks[] held:
-	 */
-	smp_mb(); /* spin_lock(&nf_conntrack_locks_all_lock) */
-
 	for (i = 0; i < CONNTRACK_LOCKS; i++) {
-		spin_unlock_wait(&nf_conntrack_locks[i]);
+		/* Wait for any current holder to release lock. */
+		spin_lock(&nf_conntrack_locks[i]);
+		spin_unlock(&nf_conntrack_locks[i]);
+		/* Next acquisition will see nf_conntrack_locks_all == true. */
 	}
 }
 
-- 
2.5.2

^ permalink raw reply related	[flat|nested] 122+ messages in thread

* [PATCH RFC 02/26] task_work: Replace spin_unlock_wait() with lock/unlock pair
  2017-06-29 23:59 [PATCH RFC 0/26] Remove spin_unlock_wait() Paul E. McKenney
  2017-06-30  0:01 ` [PATCH RFC 01/26] netfilter: Replace spin_unlock_wait() with lock/unlock pair Paul E. McKenney
@ 2017-06-30  0:01 ` Paul E. McKenney
  2017-06-30 11:04   ` Oleg Nesterov
  2017-06-30  0:01 ` [PATCH RFC 03/26] sched: " Paul E. McKenney
                   ` (23 subsequent siblings)
  25 siblings, 1 reply; 122+ messages in thread
From: Paul E. McKenney @ 2017-06-30  0:01 UTC (permalink / raw)
  To: linux-kernel
  Cc: netfilter-devel, netdev, oleg, akpm, mingo, dave, manfred, tj,
	arnd, linux-arch, will.deacon, peterz, stern, parri.andrea,
	torvalds, Paul E. McKenney

There is no agreed-upon definition of spin_unlock_wait()'s semantics,
and it appears that all callers could do just as well with a lock/unlock
pair.  This commit therefore replaces the spin_unlock_wait() call in
task_work_run() with spin_lock() followed immediately by spin_unlock().
This should be safe from a performance perspective because calls to the
other side of the race, task_work_cancel(), should be rare.

Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Cc: Oleg Nesterov <oleg@redhat.com>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Will Deacon <will.deacon@arm.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Alan Stern <stern@rowland.harvard.edu>
Cc: Andrea Parri <parri.andrea@gmail.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
---
 kernel/task_work.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/kernel/task_work.c b/kernel/task_work.c
index d513051fcca2..b9b428832229 100644
--- a/kernel/task_work.c
+++ b/kernel/task_work.c
@@ -109,7 +109,8 @@ void task_work_run(void)
 		 * the first entry == work, cmpxchg(task_works) should
 		 * fail, but it can play with *work and other entries.
 		 */
-		raw_spin_unlock_wait(&task->pi_lock);
+		raw_spin_lock(&task->pi_lock);
+		raw_spin_unlock(&task->pi_lock);
 
 		do {
 			next = work->next;
-- 
2.5.2

^ permalink raw reply related	[flat|nested] 122+ messages in thread

* [PATCH RFC 03/26] sched: Replace spin_unlock_wait() with lock/unlock pair
  2017-06-29 23:59 [PATCH RFC 0/26] Remove spin_unlock_wait() Paul E. McKenney
  2017-06-30  0:01 ` [PATCH RFC 01/26] netfilter: Replace spin_unlock_wait() with lock/unlock pair Paul E. McKenney
  2017-06-30  0:01 ` [PATCH RFC 02/26] task_work: " Paul E. McKenney
@ 2017-06-30  0:01 ` Paul E. McKenney
  2017-06-30 10:31   ` Arnd Bergmann
  2017-06-30  0:01 ` [PATCH RFC 04/26] completion: " Paul E. McKenney
                   ` (22 subsequent siblings)
  25 siblings, 1 reply; 122+ messages in thread
From: Paul E. McKenney @ 2017-06-30  0:01 UTC (permalink / raw)
  To: linux-kernel
  Cc: netfilter-devel, netdev, oleg, akpm, mingo, dave, manfred, tj,
	arnd, linux-arch, will.deacon, peterz, stern, parri.andrea,
	torvalds, Paul E. McKenney

There is no agreed-upon definition of spin_unlock_wait()'s semantics,
and it appears that all callers could do just as well with a lock/unlock
pair.  This commit therefore replaces the spin_unlock_wait() call in
do_task_dead() with spin_lock() followed immediately by spin_unlock().
This should be safe from a performance perspective because the lock is
this tasks ->pi_lock, and this is called only after the task exits.

Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Will Deacon <will.deacon@arm.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Alan Stern <stern@rowland.harvard.edu>
Cc: Andrea Parri <parri.andrea@gmail.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
---
 kernel/sched/core.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index e91138fcde86..6dea3d9728c8 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -3461,7 +3461,8 @@ void __noreturn do_task_dead(void)
 	 * is held by try_to_wake_up()
 	 */
 	smp_mb();
-	raw_spin_unlock_wait(&current->pi_lock);
+	raw_spin_lock(&current->pi_lock);
+	raw_spin_unlock(&current->pi_lock);
 
 	/* Causes final put_task_struct in finish_task_switch(): */
 	__set_current_state(TASK_DEAD);
-- 
2.5.2

^ permalink raw reply related	[flat|nested] 122+ messages in thread

* [PATCH RFC 04/26] completion: Replace spin_unlock_wait() with lock/unlock pair
  2017-06-29 23:59 [PATCH RFC 0/26] Remove spin_unlock_wait() Paul E. McKenney
                   ` (2 preceding siblings ...)
  2017-06-30  0:01 ` [PATCH RFC 03/26] sched: " Paul E. McKenney
@ 2017-06-30  0:01 ` Paul E. McKenney
  2017-06-30  0:01 ` [PATCH RFC 05/26] exit: " Paul E. McKenney
                   ` (21 subsequent siblings)
  25 siblings, 0 replies; 122+ messages in thread
From: Paul E. McKenney @ 2017-06-30  0:01 UTC (permalink / raw)
  To: linux-kernel
  Cc: netfilter-devel, netdev, oleg, akpm, mingo, dave, manfred, tj,
	arnd, linux-arch, will.deacon, peterz, stern, parri.andrea,
	torvalds, Paul E. McKenney

There is no agreed-upon definition of spin_unlock_wait()'s semantics,
and it appears that all callers could do just as well with a lock/unlock
pair.  This commit therefore replaces the spin_unlock_wait() call in
completion_done() with spin_lock() followed immediately by spin_unlock().
This should be safe from a performance perspective because the lock
will be held only the wakeup happens really quickly.

Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Will Deacon <will.deacon@arm.com>
Cc: Alan Stern <stern@rowland.harvard.edu>
Cc: Andrea Parri <parri.andrea@gmail.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
---
 kernel/sched/completion.c | 9 ++-------
 1 file changed, 2 insertions(+), 7 deletions(-)

diff --git a/kernel/sched/completion.c b/kernel/sched/completion.c
index 53f9558fa925..d4b89a59629f 100644
--- a/kernel/sched/completion.c
+++ b/kernel/sched/completion.c
@@ -307,14 +307,9 @@ bool completion_done(struct completion *x)
 	 * If ->done, we need to wait for complete() to release ->wait.lock
 	 * otherwise we can end up freeing the completion before complete()
 	 * is done referencing it.
-	 *
-	 * The RMB pairs with complete()'s RELEASE of ->wait.lock and orders
-	 * the loads of ->done and ->wait.lock such that we cannot observe
-	 * the lock before complete() acquires it while observing the ->done
-	 * after it's acquired the lock.
 	 */
-	smp_rmb();
-	spin_unlock_wait(&x->wait.lock);
+	spin_lock(&x->wait.lock);
+	spin_unlock(&x->wait.lock);
 	return true;
 }
 EXPORT_SYMBOL(completion_done);
-- 
2.5.2

^ permalink raw reply related	[flat|nested] 122+ messages in thread

* [PATCH RFC 05/26] exit: Replace spin_unlock_wait() with lock/unlock pair
  2017-06-29 23:59 [PATCH RFC 0/26] Remove spin_unlock_wait() Paul E. McKenney
                   ` (3 preceding siblings ...)
  2017-06-30  0:01 ` [PATCH RFC 04/26] completion: " Paul E. McKenney
@ 2017-06-30  0:01 ` Paul E. McKenney
  2017-06-30  0:01 ` [PATCH RFC 07/26] drivers/ata: " Paul E. McKenney
                   ` (20 subsequent siblings)
  25 siblings, 0 replies; 122+ messages in thread
From: Paul E. McKenney @ 2017-06-30  0:01 UTC (permalink / raw)
  To: linux-kernel
  Cc: netfilter-devel, netdev, oleg, akpm, mingo, dave, manfred, tj,
	arnd, linux-arch, will.deacon, peterz, stern, parri.andrea,
	torvalds, Paul E. McKenney, Ingo Molnar

There is no agreed-upon definition of spin_unlock_wait()'s semantics, and
it appears that all callers could do just as well with a lock/unlock pair.
This commit therefore replaces the spin_unlock_wait() call in do_exit()
with spin_lock() followed immediately by spin_unlock().  This should be
safe from a performance perspective because the lock is a per-task lock,
and this is happening only at task-exit time.

Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Cc: Ingo Molnar <mingo@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Will Deacon <will.deacon@arm.com>
Cc: Alan Stern <stern@rowland.harvard.edu>
Cc: Andrea Parri <parri.andrea@gmail.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
---
 kernel/exit.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/kernel/exit.c b/kernel/exit.c
index 516acdb0e0ec..1a976e47ddd1 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -832,7 +832,8 @@ void __noreturn do_exit(long code)
 	 * Ensure that we must observe the pi_state in exit_mm() ->
 	 * mm_release() -> exit_pi_state_list().
 	 */
-	raw_spin_unlock_wait(&tsk->pi_lock);
+	raw_spin_lock(&tsk->pi_lock);
+	raw_spin_unlock(&tsk->pi_lock);
 
 	if (unlikely(in_atomic())) {
 		pr_info("note: %s[%d] exited with preempt_count %d\n",
-- 
2.5.2

^ permalink raw reply related	[flat|nested] 122+ messages in thread

* [PATCH RFC 07/26] drivers/ata: Replace spin_unlock_wait() with lock/unlock pair
  2017-06-29 23:59 [PATCH RFC 0/26] Remove spin_unlock_wait() Paul E. McKenney
                   ` (4 preceding siblings ...)
  2017-06-30  0:01 ` [PATCH RFC 05/26] exit: " Paul E. McKenney
@ 2017-06-30  0:01 ` Paul E. McKenney
  2017-06-30  0:01 ` [PATCH RFC 08/26] locking: Remove spin_unlock_wait() generic definitions Paul E. McKenney
                   ` (19 subsequent siblings)
  25 siblings, 0 replies; 122+ messages in thread
From: Paul E. McKenney @ 2017-06-30  0:01 UTC (permalink / raw)
  To: linux-kernel
  Cc: netfilter-devel, netdev, oleg, akpm, mingo, dave, manfred, tj,
	arnd, linux-arch, will.deacon, peterz, stern, parri.andrea,
	torvalds, Paul E. McKenney, linux-ide

There is no agreed-upon definition of spin_unlock_wait()'s semantics,
and it appears that all callers could do just as well with a lock/unlock
pair.  This commit therefore eliminates the spin_unlock_wait() call and
associated else-clause and hoists the then-clause's lock and unlock out of
the "if" statement.  This should be safe from a performance perspective
because according to Tejun there should be few if any drivers that don't
set their own error handler.

Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Acked-by: Tejun Heo <tj@kernel.org>
Cc: <linux-ide@vger.kernel.org>
Cc: Will Deacon <will.deacon@arm.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Alan Stern <stern@rowland.harvard.edu>
Cc: Andrea Parri <parri.andrea@gmail.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
---
 drivers/ata/libata-eh.c | 8 +++-----
 1 file changed, 3 insertions(+), 5 deletions(-)

diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c
index ef68232b5222..779f6f18c1f4 100644
--- a/drivers/ata/libata-eh.c
+++ b/drivers/ata/libata-eh.c
@@ -645,12 +645,11 @@ void ata_scsi_cmd_error_handler(struct Scsi_Host *host, struct ata_port *ap,
 	 * completions are honored.  A scmd is determined to have
 	 * timed out iff its associated qc is active and not failed.
 	 */
+	spin_lock_irqsave(ap->lock, flags);
 	if (ap->ops->error_handler) {
 		struct scsi_cmnd *scmd, *tmp;
 		int nr_timedout = 0;
 
-		spin_lock_irqsave(ap->lock, flags);
-
 		/* This must occur under the ap->lock as we don't want
 		   a polled recovery to race the real interrupt handler
 
@@ -700,12 +699,11 @@ void ata_scsi_cmd_error_handler(struct Scsi_Host *host, struct ata_port *ap,
 		if (nr_timedout)
 			__ata_port_freeze(ap);
 
-		spin_unlock_irqrestore(ap->lock, flags);
 
 		/* initialize eh_tries */
 		ap->eh_tries = ATA_EH_MAX_TRIES;
-	} else
-		spin_unlock_wait(ap->lock);
+	}
+	spin_unlock_irqrestore(ap->lock, flags);
 
 }
 EXPORT_SYMBOL(ata_scsi_cmd_error_handler);
-- 
2.5.2

^ permalink raw reply related	[flat|nested] 122+ messages in thread

* [PATCH RFC 08/26] locking: Remove spin_unlock_wait() generic definitions
  2017-06-29 23:59 [PATCH RFC 0/26] Remove spin_unlock_wait() Paul E. McKenney
                   ` (5 preceding siblings ...)
  2017-06-30  0:01 ` [PATCH RFC 07/26] drivers/ata: " Paul E. McKenney
@ 2017-06-30  0:01 ` Paul E. McKenney
  2017-06-30  9:19   ` Will Deacon
  2017-06-30  0:01 ` [PATCH RFC 09/26] alpha: Remove spin_unlock_wait() arch-specific definitions Paul E. McKenney
                   ` (18 subsequent siblings)
  25 siblings, 1 reply; 122+ messages in thread
From: Paul E. McKenney @ 2017-06-30  0:01 UTC (permalink / raw)
  To: linux-kernel
  Cc: netfilter-devel, netdev, oleg, akpm, mingo, dave, manfred, tj,
	arnd, linux-arch, will.deacon, peterz, stern, parri.andrea,
	torvalds, Paul E. McKenney

There is no agreed-upon definition of spin_unlock_wait()'s semantics,
and it appears that all callers could do just as well with a lock/unlock
pair.  This commit therefore removes spin_unlock_wait() and related
definitions from core code.

Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Cc: Arnd Bergmann <arnd@arndb.de>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Will Deacon <will.deacon@arm.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Alan Stern <stern@rowland.harvard.edu>
Cc: Andrea Parri <parri.andrea@gmail.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
---
 include/asm-generic/qspinlock.h |  14 -----
 include/linux/spinlock.h        |  31 -----------
 include/linux/spinlock_up.h     |   6 ---
 kernel/locking/qspinlock.c      | 117 ----------------------------------------
 4 files changed, 168 deletions(-)

diff --git a/include/asm-generic/qspinlock.h b/include/asm-generic/qspinlock.h
index 9f0681bf1e87..66260777d644 100644
--- a/include/asm-generic/qspinlock.h
+++ b/include/asm-generic/qspinlock.h
@@ -22,17 +22,6 @@
 #include <asm-generic/qspinlock_types.h>
 
 /**
- * queued_spin_unlock_wait - wait until the _current_ lock holder releases the lock
- * @lock : Pointer to queued spinlock structure
- *
- * There is a very slight possibility of live-lock if the lockers keep coming
- * and the waiter is just unfortunate enough to not see any unlock state.
- */
-#ifndef queued_spin_unlock_wait
-extern void queued_spin_unlock_wait(struct qspinlock *lock);
-#endif
-
-/**
  * queued_spin_is_locked - is the spinlock locked?
  * @lock: Pointer to queued spinlock structure
  * Return: 1 if it is locked, 0 otherwise
@@ -41,8 +30,6 @@ extern void queued_spin_unlock_wait(struct qspinlock *lock);
 static __always_inline int queued_spin_is_locked(struct qspinlock *lock)
 {
 	/*
-	 * See queued_spin_unlock_wait().
-	 *
 	 * Any !0 state indicates it is locked, even if _Q_LOCKED_VAL
 	 * isn't immediately observable.
 	 */
@@ -135,6 +122,5 @@ static __always_inline bool virt_spin_lock(struct qspinlock *lock)
 #define arch_spin_trylock(l)		queued_spin_trylock(l)
 #define arch_spin_unlock(l)		queued_spin_unlock(l)
 #define arch_spin_lock_flags(l, f)	queued_spin_lock(l)
-#define arch_spin_unlock_wait(l)	queued_spin_unlock_wait(l)
 
 #endif /* __ASM_GENERIC_QSPINLOCK_H */
diff --git a/include/linux/spinlock.h b/include/linux/spinlock.h
index d9510e8522d4..ef018a6e4985 100644
--- a/include/linux/spinlock.h
+++ b/include/linux/spinlock.h
@@ -130,12 +130,6 @@ do {								\
 #define smp_mb__before_spinlock()	smp_wmb()
 #endif
 
-/**
- * raw_spin_unlock_wait - wait until the spinlock gets unlocked
- * @lock: the spinlock in question.
- */
-#define raw_spin_unlock_wait(lock)	arch_spin_unlock_wait(&(lock)->raw_lock)
-
 #ifdef CONFIG_DEBUG_SPINLOCK
  extern void do_raw_spin_lock(raw_spinlock_t *lock) __acquires(lock);
 #define do_raw_spin_lock_flags(lock, flags) do_raw_spin_lock(lock)
@@ -369,31 +363,6 @@ static __always_inline int spin_trylock_irq(spinlock_t *lock)
 	raw_spin_trylock_irqsave(spinlock_check(lock), flags); \
 })
 
-/**
- * spin_unlock_wait - Interpose between successive critical sections
- * @lock: the spinlock whose critical sections are to be interposed.
- *
- * Semantically this is equivalent to a spin_lock() immediately
- * followed by a spin_unlock().  However, most architectures have
- * more efficient implementations in which the spin_unlock_wait()
- * cannot block concurrent lock acquisition, and in some cases
- * where spin_unlock_wait() does not write to the lock variable.
- * Nevertheless, spin_unlock_wait() can have high overhead, so if
- * you feel the need to use it, please check to see if there is
- * a better way to get your job done.
- *
- * The ordering guarantees provided by spin_unlock_wait() are:
- *
- * 1.  All accesses preceding the spin_unlock_wait() happen before
- *     any accesses in later critical sections for this same lock.
- * 2.  All accesses following the spin_unlock_wait() happen after
- *     any accesses in earlier critical sections for this same lock.
- */
-static __always_inline void spin_unlock_wait(spinlock_t *lock)
-{
-	raw_spin_unlock_wait(&lock->rlock);
-}
-
 static __always_inline int spin_is_locked(spinlock_t *lock)
 {
 	return raw_spin_is_locked(&lock->rlock);
diff --git a/include/linux/spinlock_up.h b/include/linux/spinlock_up.h
index 0d9848de677d..612fb530af41 100644
--- a/include/linux/spinlock_up.h
+++ b/include/linux/spinlock_up.h
@@ -26,11 +26,6 @@
 #ifdef CONFIG_DEBUG_SPINLOCK
 #define arch_spin_is_locked(x)		((x)->slock == 0)
 
-static inline void arch_spin_unlock_wait(arch_spinlock_t *lock)
-{
-	smp_cond_load_acquire(&lock->slock, VAL);
-}
-
 static inline void arch_spin_lock(arch_spinlock_t *lock)
 {
 	lock->slock = 0;
@@ -73,7 +68,6 @@ static inline void arch_spin_unlock(arch_spinlock_t *lock)
 
 #else /* DEBUG_SPINLOCK */
 #define arch_spin_is_locked(lock)	((void)(lock), 0)
-#define arch_spin_unlock_wait(lock)	do { barrier(); (void)(lock); } while (0)
 /* for sched/core.c and kernel_lock.c: */
 # define arch_spin_lock(lock)		do { barrier(); (void)(lock); } while (0)
 # define arch_spin_lock_flags(lock, flags)	do { barrier(); (void)(lock); } while (0)
diff --git a/kernel/locking/qspinlock.c b/kernel/locking/qspinlock.c
index b2caec7315af..64a9051e4c2c 100644
--- a/kernel/locking/qspinlock.c
+++ b/kernel/locking/qspinlock.c
@@ -267,123 +267,6 @@ static __always_inline u32  __pv_wait_head_or_lock(struct qspinlock *lock,
 #define queued_spin_lock_slowpath	native_queued_spin_lock_slowpath
 #endif
 
-/*
- * Various notes on spin_is_locked() and spin_unlock_wait(), which are
- * 'interesting' functions:
- *
- * PROBLEM: some architectures have an interesting issue with atomic ACQUIRE
- * operations in that the ACQUIRE applies to the LOAD _not_ the STORE (ARM64,
- * PPC). Also qspinlock has a similar issue per construction, the setting of
- * the locked byte can be unordered acquiring the lock proper.
- *
- * This gets to be 'interesting' in the following cases, where the /should/s
- * end up false because of this issue.
- *
- *
- * CASE 1:
- *
- * So the spin_is_locked() correctness issue comes from something like:
- *
- *   CPU0				CPU1
- *
- *   global_lock();			local_lock(i)
- *     spin_lock(&G)			  spin_lock(&L[i])
- *     for (i)				  if (!spin_is_locked(&G)) {
- *       spin_unlock_wait(&L[i]);	    smp_acquire__after_ctrl_dep();
- *					    return;
- *					  }
- *					  // deal with fail
- *
- * Where it is important CPU1 sees G locked or CPU0 sees L[i] locked such
- * that there is exclusion between the two critical sections.
- *
- * The load from spin_is_locked(&G) /should/ be constrained by the ACQUIRE from
- * spin_lock(&L[i]), and similarly the load(s) from spin_unlock_wait(&L[i])
- * /should/ be constrained by the ACQUIRE from spin_lock(&G).
- *
- * Similarly, later stuff is constrained by the ACQUIRE from CTRL+RMB.
- *
- *
- * CASE 2:
- *
- * For spin_unlock_wait() there is a second correctness issue, namely:
- *
- *   CPU0				CPU1
- *
- *   flag = set;
- *   smp_mb();				spin_lock(&l)
- *   spin_unlock_wait(&l);		if (!flag)
- *					  // add to lockless list
- *					spin_unlock(&l);
- *   // iterate lockless list
- *
- * Which wants to ensure that CPU1 will stop adding bits to the list and CPU0
- * will observe the last entry on the list (if spin_unlock_wait() had ACQUIRE
- * semantics etc..)
- *
- * Where flag /should/ be ordered against the locked store of l.
- */
-
-/*
- * queued_spin_lock_slowpath() can (load-)ACQUIRE the lock before
- * issuing an _unordered_ store to set _Q_LOCKED_VAL.
- *
- * This means that the store can be delayed, but no later than the
- * store-release from the unlock. This means that simply observing
- * _Q_LOCKED_VAL is not sufficient to determine if the lock is acquired.
- *
- * There are two paths that can issue the unordered store:
- *
- *  (1) clear_pending_set_locked():	*,1,0 -> *,0,1
- *
- *  (2) set_locked():			t,0,0 -> t,0,1 ; t != 0
- *      atomic_cmpxchg_relaxed():	t,0,0 -> 0,0,1
- *
- * However, in both cases we have other !0 state we've set before to queue
- * ourseves:
- *
- * For (1) we have the atomic_cmpxchg_acquire() that set _Q_PENDING_VAL, our
- * load is constrained by that ACQUIRE to not pass before that, and thus must
- * observe the store.
- *
- * For (2) we have a more intersting scenario. We enqueue ourselves using
- * xchg_tail(), which ends up being a RELEASE. This in itself is not
- * sufficient, however that is followed by an smp_cond_acquire() on the same
- * word, giving a RELEASE->ACQUIRE ordering. This again constrains our load and
- * guarantees we must observe that store.
- *
- * Therefore both cases have other !0 state that is observable before the
- * unordered locked byte store comes through. This means we can use that to
- * wait for the lock store, and then wait for an unlock.
- */
-#ifndef queued_spin_unlock_wait
-void queued_spin_unlock_wait(struct qspinlock *lock)
-{
-	u32 val;
-
-	for (;;) {
-		val = atomic_read(&lock->val);
-
-		if (!val) /* not locked, we're done */
-			goto done;
-
-		if (val & _Q_LOCKED_MASK) /* locked, go wait for unlock */
-			break;
-
-		/* not locked, but pending, wait until we observe the lock */
-		cpu_relax();
-	}
-
-	/* any unlock is good */
-	while (atomic_read(&lock->val) & _Q_LOCKED_MASK)
-		cpu_relax();
-
-done:
-	smp_acquire__after_ctrl_dep();
-}
-EXPORT_SYMBOL(queued_spin_unlock_wait);
-#endif
-
 #endif /* _GEN_PV_LOCK_SLOWPATH */
 
 /**
-- 
2.5.2

^ permalink raw reply related	[flat|nested] 122+ messages in thread

* [PATCH RFC 09/26] alpha: Remove spin_unlock_wait() arch-specific definitions
  2017-06-29 23:59 [PATCH RFC 0/26] Remove spin_unlock_wait() Paul E. McKenney
                   ` (6 preceding siblings ...)
  2017-06-30  0:01 ` [PATCH RFC 08/26] locking: Remove spin_unlock_wait() generic definitions Paul E. McKenney
@ 2017-06-30  0:01 ` Paul E. McKenney
  2017-06-30  0:01 ` [PATCH RFC 10/26] arc: " Paul E. McKenney
                   ` (17 subsequent siblings)
  25 siblings, 0 replies; 122+ messages in thread
From: Paul E. McKenney @ 2017-06-30  0:01 UTC (permalink / raw)
  To: linux-kernel
  Cc: netfilter-devel, netdev, oleg, akpm, mingo, dave, manfred, tj,
	arnd, linux-arch, will.deacon, peterz, stern, parri.andrea,
	torvalds, Paul E. McKenney, Richard Henderson, Ivan Kokshaysky,
	Matt Turner, linux-alpha

There is no agreed-upon definition of spin_unlock_wait()'s semantics,
and it appears that all callers could do just as well with a lock/unlock
pair.  This commit therefore removes the underlying arch-specific
arch_spin_unlock_wait().

Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Cc: Richard Henderson <rth@twiddle.net>
Cc: Ivan Kokshaysky <ink@jurassic.park.msu.ru>
Cc: Matt Turner <mattst88@gmail.com>
Cc: <linux-alpha@vger.kernel.org>
Cc: Will Deacon <will.deacon@arm.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Alan Stern <stern@rowland.harvard.edu>
Cc: Andrea Parri <parri.andrea@gmail.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
---
 arch/alpha/include/asm/spinlock.h | 5 -----
 1 file changed, 5 deletions(-)

diff --git a/arch/alpha/include/asm/spinlock.h b/arch/alpha/include/asm/spinlock.h
index a40b9fc0c6c3..718ac0b64adf 100644
--- a/arch/alpha/include/asm/spinlock.h
+++ b/arch/alpha/include/asm/spinlock.h
@@ -16,11 +16,6 @@
 #define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock)
 #define arch_spin_is_locked(x)	((x)->lock != 0)
 
-static inline void arch_spin_unlock_wait(arch_spinlock_t *lock)
-{
-	smp_cond_load_acquire(&lock->lock, !VAL);
-}
-
 static inline int arch_spin_value_unlocked(arch_spinlock_t lock)
 {
         return lock.lock == 0;
-- 
2.5.2

^ permalink raw reply related	[flat|nested] 122+ messages in thread

* [PATCH RFC 10/26] arc: Remove spin_unlock_wait() arch-specific definitions
  2017-06-29 23:59 [PATCH RFC 0/26] Remove spin_unlock_wait() Paul E. McKenney
                   ` (7 preceding siblings ...)
  2017-06-30  0:01 ` [PATCH RFC 09/26] alpha: Remove spin_unlock_wait() arch-specific definitions Paul E. McKenney
@ 2017-06-30  0:01 ` Paul E. McKenney
  2017-06-30  0:01 ` [PATCH RFC 11/26] arm: " Paul E. McKenney
                   ` (16 subsequent siblings)
  25 siblings, 0 replies; 122+ messages in thread
From: Paul E. McKenney @ 2017-06-30  0:01 UTC (permalink / raw)
  To: linux-kernel
  Cc: netfilter-devel, netdev, oleg, akpm, mingo, dave, manfred, tj,
	arnd, linux-arch, will.deacon, peterz, stern, parri.andrea,
	torvalds, Paul E. McKenney, Vineet Gupta, linux-snps-arc

There is no agreed-upon definition of spin_unlock_wait()'s semantics,
and it appears that all callers could do just as well with a lock/unlock
pair.  This commit therefore removes the underlying arch-specific
arch_spin_unlock_wait().

Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Cc: Vineet Gupta <vgupta@synopsys.com>
Cc: <linux-snps-arc@lists.infradead.org>
Cc: Will Deacon <will.deacon@arm.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Alan Stern <stern@rowland.harvard.edu>
Cc: Andrea Parri <parri.andrea@gmail.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
---
 arch/arc/include/asm/spinlock.h | 5 -----
 1 file changed, 5 deletions(-)

diff --git a/arch/arc/include/asm/spinlock.h b/arch/arc/include/asm/spinlock.h
index 233d5ffe6ec7..a325e6a36523 100644
--- a/arch/arc/include/asm/spinlock.h
+++ b/arch/arc/include/asm/spinlock.h
@@ -16,11 +16,6 @@
 #define arch_spin_is_locked(x)	((x)->slock != __ARCH_SPIN_LOCK_UNLOCKED__)
 #define arch_spin_lock_flags(lock, flags)	arch_spin_lock(lock)
 
-static inline void arch_spin_unlock_wait(arch_spinlock_t *lock)
-{
-	smp_cond_load_acquire(&lock->slock, !VAL);
-}
-
 #ifdef CONFIG_ARC_HAS_LLSC
 
 static inline void arch_spin_lock(arch_spinlock_t *lock)
-- 
2.5.2

^ permalink raw reply related	[flat|nested] 122+ messages in thread

* [PATCH RFC 11/26] arm: Remove spin_unlock_wait() arch-specific definitions
  2017-06-29 23:59 [PATCH RFC 0/26] Remove spin_unlock_wait() Paul E. McKenney
                   ` (8 preceding siblings ...)
  2017-06-30  0:01 ` [PATCH RFC 10/26] arc: " Paul E. McKenney
@ 2017-06-30  0:01 ` Paul E. McKenney
  2017-06-30  0:01 ` [PATCH RFC 12/26] arm64: " Paul E. McKenney
                   ` (15 subsequent siblings)
  25 siblings, 0 replies; 122+ messages in thread
From: Paul E. McKenney @ 2017-06-30  0:01 UTC (permalink / raw)
  To: linux-kernel
  Cc: netfilter-devel, netdev, oleg, akpm, mingo, dave, manfred, tj,
	arnd, linux-arch, will.deacon, peterz, stern, parri.andrea,
	torvalds, Paul E. McKenney, Russell King, linux-arm-kernel

There is no agreed-upon definition of spin_unlock_wait()'s semantics,
and it appears that all callers could do just as well with a lock/unlock
pair.  This commit therefore removes the underlying arch-specific
arch_spin_unlock_wait().

Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Cc: Russell King <linux@armlinux.org.uk>
Cc: <linux-arm-kernel@lists.infradead.org>
Cc: Will Deacon <will.deacon@arm.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Alan Stern <stern@rowland.harvard.edu>
Cc: Andrea Parri <parri.andrea@gmail.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
---
 arch/arm/include/asm/spinlock.h | 16 ----------------
 1 file changed, 16 deletions(-)

diff --git a/arch/arm/include/asm/spinlock.h b/arch/arm/include/asm/spinlock.h
index 4bec45442072..c030143c18c6 100644
--- a/arch/arm/include/asm/spinlock.h
+++ b/arch/arm/include/asm/spinlock.h
@@ -52,22 +52,6 @@ static inline void dsb_sev(void)
  * memory.
  */
 
-static inline void arch_spin_unlock_wait(arch_spinlock_t *lock)
-{
-	u16 owner = READ_ONCE(lock->tickets.owner);
-
-	for (;;) {
-		arch_spinlock_t tmp = READ_ONCE(*lock);
-
-		if (tmp.tickets.owner == tmp.tickets.next ||
-		    tmp.tickets.owner != owner)
-			break;
-
-		wfe();
-	}
-	smp_acquire__after_ctrl_dep();
-}
-
 #define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock)
 
 static inline void arch_spin_lock(arch_spinlock_t *lock)
-- 
2.5.2

^ permalink raw reply related	[flat|nested] 122+ messages in thread

* [PATCH RFC 12/26] arm64: Remove spin_unlock_wait() arch-specific definitions
  2017-06-29 23:59 [PATCH RFC 0/26] Remove spin_unlock_wait() Paul E. McKenney
                   ` (9 preceding siblings ...)
  2017-06-30  0:01 ` [PATCH RFC 11/26] arm: " Paul E. McKenney
@ 2017-06-30  0:01 ` Paul E. McKenney
  2017-06-30  9:20   ` Will Deacon
  2017-06-30  0:01 ` [PATCH RFC 13/26] blackfin: " Paul E. McKenney
                   ` (14 subsequent siblings)
  25 siblings, 1 reply; 122+ messages in thread
From: Paul E. McKenney @ 2017-06-30  0:01 UTC (permalink / raw)
  To: linux-kernel
  Cc: netfilter-devel, netdev, oleg, akpm, mingo, dave, manfred, tj,
	arnd, linux-arch, will.deacon, peterz, stern, parri.andrea,
	torvalds, Paul E. McKenney, Catalin Marinas, linux-arm-kernel

There is no agreed-upon definition of spin_unlock_wait()'s semantics,
and it appears that all callers could do just as well with a lock/unlock
pair.  This commit therefore removes the underlying arch-specific
arch_spin_unlock_wait().

Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Will Deacon <will.deacon@arm.com>
Cc: <linux-arm-kernel@lists.infradead.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Alan Stern <stern@rowland.harvard.edu>
Cc: Andrea Parri <parri.andrea@gmail.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
---
 arch/arm64/include/asm/spinlock.h | 58 ++++-----------------------------------
 1 file changed, 5 insertions(+), 53 deletions(-)

diff --git a/arch/arm64/include/asm/spinlock.h b/arch/arm64/include/asm/spinlock.h
index cae331d553f8..f445bd7f2b9f 100644
--- a/arch/arm64/include/asm/spinlock.h
+++ b/arch/arm64/include/asm/spinlock.h
@@ -26,58 +26,6 @@
  * The memory barriers are implicit with the load-acquire and store-release
  * instructions.
  */
-static inline void arch_spin_unlock_wait(arch_spinlock_t *lock)
-{
-	unsigned int tmp;
-	arch_spinlock_t lockval;
-	u32 owner;
-
-	/*
-	 * Ensure prior spin_lock operations to other locks have completed
-	 * on this CPU before we test whether "lock" is locked.
-	 */
-	smp_mb();
-	owner = READ_ONCE(lock->owner) << 16;
-
-	asm volatile(
-"	sevl\n"
-"1:	wfe\n"
-"2:	ldaxr	%w0, %2\n"
-	/* Is the lock free? */
-"	eor	%w1, %w0, %w0, ror #16\n"
-"	cbz	%w1, 3f\n"
-	/* Lock taken -- has there been a subsequent unlock->lock transition? */
-"	eor	%w1, %w3, %w0, lsl #16\n"
-"	cbz	%w1, 1b\n"
-	/*
-	 * The owner has been updated, so there was an unlock->lock
-	 * transition that we missed. That means we can rely on the
-	 * store-release of the unlock operation paired with the
-	 * load-acquire of the lock operation to publish any of our
-	 * previous stores to the new lock owner and therefore don't
-	 * need to bother with the writeback below.
-	 */
-"	b	4f\n"
-"3:\n"
-	/*
-	 * Serialise against any concurrent lockers by writing back the
-	 * unlocked lock value
-	 */
-	ARM64_LSE_ATOMIC_INSN(
-	/* LL/SC */
-"	stxr	%w1, %w0, %2\n"
-	__nops(2),
-	/* LSE atomics */
-"	mov	%w1, %w0\n"
-"	cas	%w0, %w0, %2\n"
-"	eor	%w1, %w1, %w0\n")
-	/* Somebody else wrote to the lock, GOTO 10 and reload the value */
-"	cbnz	%w1, 2b\n"
-"4:"
-	: "=&r" (lockval), "=&r" (tmp), "+Q" (*lock)
-	: "r" (owner)
-	: "memory");
-}
 
 #define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock)
 
@@ -176,7 +124,11 @@ static inline int arch_spin_value_unlocked(arch_spinlock_t lock)
 
 static inline int arch_spin_is_locked(arch_spinlock_t *lock)
 {
-	smp_mb(); /* See arch_spin_unlock_wait */
+	/*
+	 * Ensure prior spin_lock operations to other locks have completed
+	 * on this CPU before we test whether "lock" is locked.
+	 */
+	smp_mb(); /* ^^^ */
 	return !arch_spin_value_unlocked(READ_ONCE(*lock));
 }
 
-- 
2.5.2

^ permalink raw reply related	[flat|nested] 122+ messages in thread

* [PATCH RFC 13/26] blackfin: Remove spin_unlock_wait() arch-specific definitions
  2017-06-29 23:59 [PATCH RFC 0/26] Remove spin_unlock_wait() Paul E. McKenney
                   ` (10 preceding siblings ...)
  2017-06-30  0:01 ` [PATCH RFC 12/26] arm64: " Paul E. McKenney
@ 2017-06-30  0:01 ` Paul E. McKenney
  2017-06-30  0:01 ` [PATCH RFC 14/26] hexagon: " Paul E. McKenney
                   ` (13 subsequent siblings)
  25 siblings, 0 replies; 122+ messages in thread
From: Paul E. McKenney @ 2017-06-30  0:01 UTC (permalink / raw)
  To: linux-kernel
  Cc: netfilter-devel, netdev, oleg, akpm, mingo, dave, manfred, tj,
	arnd, linux-arch, will.deacon, peterz, stern, parri.andrea,
	torvalds, Paul E. McKenney, Steven Miao, adi-buildroot-devel

There is no agreed-upon definition of spin_unlock_wait()'s semantics,
and it appears that all callers could do just as well with a lock/unlock
pair.  This commit therefore removes the underlying arch-specific
arch_spin_unlock_wait().

Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Cc: Steven Miao <realmz6@gmail.com>
Cc: <adi-buildroot-devel@lists.sourceforge.net>
Cc: Will Deacon <will.deacon@arm.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Alan Stern <stern@rowland.harvard.edu>
Cc: Andrea Parri <parri.andrea@gmail.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
---
 arch/blackfin/include/asm/spinlock.h | 5 -----
 1 file changed, 5 deletions(-)

diff --git a/arch/blackfin/include/asm/spinlock.h b/arch/blackfin/include/asm/spinlock.h
index c58f4a83ed6f..f6431439d15d 100644
--- a/arch/blackfin/include/asm/spinlock.h
+++ b/arch/blackfin/include/asm/spinlock.h
@@ -48,11 +48,6 @@ static inline void arch_spin_unlock(arch_spinlock_t *lock)
 	__raw_spin_unlock_asm(&lock->lock);
 }
 
-static inline void arch_spin_unlock_wait(arch_spinlock_t *lock)
-{
-	smp_cond_load_acquire(&lock->lock, !VAL);
-}
-
 static inline int arch_read_can_lock(arch_rwlock_t *rw)
 {
 	return __raw_uncached_fetch_asm(&rw->lock) > 0;
-- 
2.5.2

^ permalink raw reply related	[flat|nested] 122+ messages in thread

* [PATCH RFC 14/26] hexagon: Remove spin_unlock_wait() arch-specific definitions
  2017-06-29 23:59 [PATCH RFC 0/26] Remove spin_unlock_wait() Paul E. McKenney
                   ` (11 preceding siblings ...)
  2017-06-30  0:01 ` [PATCH RFC 13/26] blackfin: " Paul E. McKenney
@ 2017-06-30  0:01 ` Paul E. McKenney
  2017-06-30  0:01 ` [PATCH RFC 15/26] ia64: " Paul E. McKenney
                   ` (12 subsequent siblings)
  25 siblings, 0 replies; 122+ messages in thread
From: Paul E. McKenney @ 2017-06-30  0:01 UTC (permalink / raw)
  To: linux-kernel
  Cc: netfilter-devel, netdev, oleg, akpm, mingo, dave, manfred, tj,
	arnd, linux-arch, will.deacon, peterz, stern, parri.andrea,
	torvalds, Paul E. McKenney, Richard Kuo, linux-hexagon

There is no agreed-upon definition of spin_unlock_wait()'s semantics,
and it appears that all callers could do just as well with a lock/unlock
pair.  This commit therefore removes the underlying arch-specific
arch_spin_unlock_wait().

Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Cc: Richard Kuo <rkuo@codeaurora.org>
Cc: <linux-hexagon@vger.kernel.org>
Cc: Will Deacon <will.deacon@arm.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Alan Stern <stern@rowland.harvard.edu>
Cc: Andrea Parri <parri.andrea@gmail.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
---
 arch/hexagon/include/asm/spinlock.h | 5 -----
 1 file changed, 5 deletions(-)

diff --git a/arch/hexagon/include/asm/spinlock.h b/arch/hexagon/include/asm/spinlock.h
index a1c55788c5d6..53a8d5885887 100644
--- a/arch/hexagon/include/asm/spinlock.h
+++ b/arch/hexagon/include/asm/spinlock.h
@@ -179,11 +179,6 @@ static inline unsigned int arch_spin_trylock(arch_spinlock_t *lock)
  */
 #define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock)
 
-static inline void arch_spin_unlock_wait(arch_spinlock_t *lock)
-{
-	smp_cond_load_acquire(&lock->lock, !VAL);
-}
-
 #define arch_spin_is_locked(x) ((x)->lock != 0)
 
 #define arch_read_lock_flags(lock, flags) arch_read_lock(lock)
-- 
2.5.2

^ permalink raw reply related	[flat|nested] 122+ messages in thread

* [PATCH RFC 15/26] ia64: Remove spin_unlock_wait() arch-specific definitions
  2017-06-29 23:59 [PATCH RFC 0/26] Remove spin_unlock_wait() Paul E. McKenney
                   ` (12 preceding siblings ...)
  2017-06-30  0:01 ` [PATCH RFC 14/26] hexagon: " Paul E. McKenney
@ 2017-06-30  0:01 ` Paul E. McKenney
  2017-06-30  0:01 ` [PATCH RFC 16/26] m32r: " Paul E. McKenney
                   ` (11 subsequent siblings)
  25 siblings, 0 replies; 122+ messages in thread
From: Paul E. McKenney @ 2017-06-30  0:01 UTC (permalink / raw)
  To: linux-kernel
  Cc: netfilter-devel, netdev, oleg, akpm, mingo, dave, manfred, tj,
	arnd, linux-arch, will.deacon, peterz, stern, parri.andrea,
	torvalds, Paul E. McKenney, Tony Luck, Fenghua Yu, linux-ia64

There is no agreed-upon definition of spin_unlock_wait()'s semantics,
and it appears that all callers could do just as well with a lock/unlock
pair.  This commit therefore removes the underlying arch-specific
arch_spin_unlock_wait().

Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Cc: Tony Luck <tony.luck@intel.com>
Cc: Fenghua Yu <fenghua.yu@intel.com>
Cc: <linux-ia64@vger.kernel.org>
Cc: Will Deacon <will.deacon@arm.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Alan Stern <stern@rowland.harvard.edu>
Cc: Andrea Parri <parri.andrea@gmail.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
---
 arch/ia64/include/asm/spinlock.h | 21 ---------------------
 1 file changed, 21 deletions(-)

diff --git a/arch/ia64/include/asm/spinlock.h b/arch/ia64/include/asm/spinlock.h
index ca9e76149a4a..df2c121164b8 100644
--- a/arch/ia64/include/asm/spinlock.h
+++ b/arch/ia64/include/asm/spinlock.h
@@ -76,22 +76,6 @@ static __always_inline void __ticket_spin_unlock(arch_spinlock_t *lock)
 	ACCESS_ONCE(*p) = (tmp + 2) & ~1;
 }
 
-static __always_inline void __ticket_spin_unlock_wait(arch_spinlock_t *lock)
-{
-	int	*p = (int *)&lock->lock, ticket;
-
-	ia64_invala();
-
-	for (;;) {
-		asm volatile ("ld4.c.nc %0=[%1]" : "=r"(ticket) : "r"(p) : "memory");
-		if (!(((ticket >> TICKET_SHIFT) ^ ticket) & TICKET_MASK))
-			return;
-		cpu_relax();
-	}
-
-	smp_acquire__after_ctrl_dep();
-}
-
 static inline int __ticket_spin_is_locked(arch_spinlock_t *lock)
 {
 	long tmp = ACCESS_ONCE(lock->lock);
@@ -143,11 +127,6 @@ static __always_inline void arch_spin_lock_flags(arch_spinlock_t *lock,
 	arch_spin_lock(lock);
 }
 
-static inline void arch_spin_unlock_wait(arch_spinlock_t *lock)
-{
-	__ticket_spin_unlock_wait(lock);
-}
-
 #define arch_read_can_lock(rw)		(*(volatile int *)(rw) >= 0)
 #define arch_write_can_lock(rw)	(*(volatile int *)(rw) == 0)
 
-- 
2.5.2

^ permalink raw reply related	[flat|nested] 122+ messages in thread

* [PATCH RFC 16/26] m32r: Remove spin_unlock_wait() arch-specific definitions
  2017-06-29 23:59 [PATCH RFC 0/26] Remove spin_unlock_wait() Paul E. McKenney
                   ` (13 preceding siblings ...)
  2017-06-30  0:01 ` [PATCH RFC 15/26] ia64: " Paul E. McKenney
@ 2017-06-30  0:01 ` Paul E. McKenney
  2017-06-30  0:01 ` [PATCH RFC 18/26] mips: " Paul E. McKenney
                   ` (10 subsequent siblings)
  25 siblings, 0 replies; 122+ messages in thread
From: Paul E. McKenney @ 2017-06-30  0:01 UTC (permalink / raw)
  To: linux-kernel
  Cc: netfilter-devel, netdev, oleg, akpm, mingo, dave, manfred, tj,
	arnd, linux-arch, will.deacon, peterz, stern, parri.andrea,
	torvalds, Paul E. McKenney

There is no agreed-upon definition of spin_unlock_wait()'s semantics,
and it appears that all callers could do just as well with a lock/unlock
pair.  This commit therefore removes the underlying arch-specific
arch_spin_unlock_wait().

Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Cc: Will Deacon <will.deacon@arm.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Alan Stern <stern@rowland.harvard.edu>
Cc: Andrea Parri <parri.andrea@gmail.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
---
 arch/m32r/include/asm/spinlock.h | 5 -----
 1 file changed, 5 deletions(-)

diff --git a/arch/m32r/include/asm/spinlock.h b/arch/m32r/include/asm/spinlock.h
index 323c7fc953cd..a56825592b90 100644
--- a/arch/m32r/include/asm/spinlock.h
+++ b/arch/m32r/include/asm/spinlock.h
@@ -30,11 +30,6 @@
 #define arch_spin_is_locked(x)		(*(volatile int *)(&(x)->slock) <= 0)
 #define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock)
 
-static inline void arch_spin_unlock_wait(arch_spinlock_t *lock)
-{
-	smp_cond_load_acquire(&lock->slock, VAL > 0);
-}
-
 /**
  * arch_spin_trylock - Try spin lock and return a result
  * @lock: Pointer to the lock variable
-- 
2.5.2

^ permalink raw reply related	[flat|nested] 122+ messages in thread

* [PATCH RFC 18/26] mips: Remove spin_unlock_wait() arch-specific definitions
  2017-06-29 23:59 [PATCH RFC 0/26] Remove spin_unlock_wait() Paul E. McKenney
                   ` (14 preceding siblings ...)
  2017-06-30  0:01 ` [PATCH RFC 16/26] m32r: " Paul E. McKenney
@ 2017-06-30  0:01 ` Paul E. McKenney
  2017-06-30  0:01 ` [PATCH RFC 19/26] mn10300: " Paul E. McKenney
                   ` (9 subsequent siblings)
  25 siblings, 0 replies; 122+ messages in thread
From: Paul E. McKenney @ 2017-06-30  0:01 UTC (permalink / raw)
  To: linux-kernel
  Cc: netfilter-devel, netdev, oleg, akpm, mingo, dave, manfred, tj,
	arnd, linux-arch, will.deacon, peterz, stern, parri.andrea,
	torvalds, Paul E. McKenney, Ralf Baechle, linux-mips

There is no agreed-upon definition of spin_unlock_wait()'s semantics,
and it appears that all callers could do just as well with a lock/unlock
pair.  This commit therefore removes the underlying arch-specific
arch_spin_unlock_wait().

Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Cc: Ralf Baechle <ralf@linux-mips.org>
Cc: <linux-mips@linux-mips.org>
Cc: Will Deacon <will.deacon@arm.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Alan Stern <stern@rowland.harvard.edu>
Cc: Andrea Parri <parri.andrea@gmail.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
---
 arch/mips/include/asm/spinlock.h | 16 ----------------
 1 file changed, 16 deletions(-)

diff --git a/arch/mips/include/asm/spinlock.h b/arch/mips/include/asm/spinlock.h
index a8df44d60607..81b4945031ee 100644
--- a/arch/mips/include/asm/spinlock.h
+++ b/arch/mips/include/asm/spinlock.h
@@ -50,22 +50,6 @@ static inline int arch_spin_value_unlocked(arch_spinlock_t lock)
 
 #define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock)
 
-static inline void arch_spin_unlock_wait(arch_spinlock_t *lock)
-{
-	u16 owner = READ_ONCE(lock->h.serving_now);
-	smp_rmb();
-	for (;;) {
-		arch_spinlock_t tmp = READ_ONCE(*lock);
-
-		if (tmp.h.serving_now == tmp.h.ticket ||
-		    tmp.h.serving_now != owner)
-			break;
-
-		cpu_relax();
-	}
-	smp_acquire__after_ctrl_dep();
-}
-
 static inline int arch_spin_is_contended(arch_spinlock_t *lock)
 {
 	u32 counters = ACCESS_ONCE(lock->lock);
-- 
2.5.2

^ permalink raw reply related	[flat|nested] 122+ messages in thread

* [PATCH RFC 19/26] mn10300: Remove spin_unlock_wait() arch-specific definitions
  2017-06-29 23:59 [PATCH RFC 0/26] Remove spin_unlock_wait() Paul E. McKenney
                   ` (15 preceding siblings ...)
  2017-06-30  0:01 ` [PATCH RFC 18/26] mips: " Paul E. McKenney
@ 2017-06-30  0:01 ` Paul E. McKenney
  2017-06-30  0:01 ` [PATCH RFC 20/26] parisc: " Paul E. McKenney
                   ` (8 subsequent siblings)
  25 siblings, 0 replies; 122+ messages in thread
From: Paul E. McKenney @ 2017-06-30  0:01 UTC (permalink / raw)
  To: linux-kernel
  Cc: netfilter-devel, netdev, oleg, akpm, mingo, dave, manfred, tj,
	arnd, linux-arch, will.deacon, peterz, stern, parri.andrea,
	torvalds, Paul E. McKenney, David Howells, linux-am33-list

There is no agreed-upon definition of spin_unlock_wait()'s semantics,
and it appears that all callers could do just as well with a lock/unlock
pair.  This commit therefore removes the underlying arch-specific
arch_spin_unlock_wait().

Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Cc: David Howells <dhowells@redhat.com>
Cc: <linux-am33-list@redhat.com>
Cc: Will Deacon <will.deacon@arm.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Alan Stern <stern@rowland.harvard.edu>
Cc: Andrea Parri <parri.andrea@gmail.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
---
 arch/mn10300/include/asm/spinlock.h | 5 -----
 1 file changed, 5 deletions(-)

diff --git a/arch/mn10300/include/asm/spinlock.h b/arch/mn10300/include/asm/spinlock.h
index 9c7b8f7942d8..fe413b41df6c 100644
--- a/arch/mn10300/include/asm/spinlock.h
+++ b/arch/mn10300/include/asm/spinlock.h
@@ -26,11 +26,6 @@
 
 #define arch_spin_is_locked(x)	(*(volatile signed char *)(&(x)->slock) != 0)
 
-static inline void arch_spin_unlock_wait(arch_spinlock_t *lock)
-{
-	smp_cond_load_acquire(&lock->slock, !VAL);
-}
-
 static inline void arch_spin_unlock(arch_spinlock_t *lock)
 {
 	asm volatile(
-- 
2.5.2

^ permalink raw reply related	[flat|nested] 122+ messages in thread

* [PATCH RFC 20/26] parisc: Remove spin_unlock_wait() arch-specific definitions
  2017-06-29 23:59 [PATCH RFC 0/26] Remove spin_unlock_wait() Paul E. McKenney
                   ` (16 preceding siblings ...)
  2017-06-30  0:01 ` [PATCH RFC 19/26] mn10300: " Paul E. McKenney
@ 2017-06-30  0:01 ` Paul E. McKenney
  2017-06-30  0:01 ` [PATCH RFC 21/26] powerpc: " Paul E. McKenney
                   ` (7 subsequent siblings)
  25 siblings, 0 replies; 122+ messages in thread
From: Paul E. McKenney @ 2017-06-30  0:01 UTC (permalink / raw)
  To: linux-kernel
  Cc: netfilter-devel, netdev, oleg, akpm, mingo, dave, manfred, tj,
	arnd, linux-arch, will.deacon, peterz, stern, parri.andrea,
	torvalds, Paul E. McKenney, James E.J. Bottomley, Helge Deller,
	linux-parisc

There is no agreed-upon definition of spin_unlock_wait()'s semantics,
and it appears that all callers could do just as well with a lock/unlock
pair.  This commit therefore removes the underlying arch-specific
arch_spin_unlock_wait().

Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Cc: "James E.J. Bottomley" <jejb@parisc-linux.org>
Cc: Helge Deller <deller@gmx.de>
Cc: <linux-parisc@vger.kernel.org>
Cc: Will Deacon <will.deacon@arm.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Alan Stern <stern@rowland.harvard.edu>
Cc: Andrea Parri <parri.andrea@gmail.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
---
 arch/parisc/include/asm/spinlock.h | 7 -------
 1 file changed, 7 deletions(-)

diff --git a/arch/parisc/include/asm/spinlock.h b/arch/parisc/include/asm/spinlock.h
index e32936cd7f10..55bfe4affca3 100644
--- a/arch/parisc/include/asm/spinlock.h
+++ b/arch/parisc/include/asm/spinlock.h
@@ -14,13 +14,6 @@ static inline int arch_spin_is_locked(arch_spinlock_t *x)
 
 #define arch_spin_lock(lock) arch_spin_lock_flags(lock, 0)
 
-static inline void arch_spin_unlock_wait(arch_spinlock_t *x)
-{
-	volatile unsigned int *a = __ldcw_align(x);
-
-	smp_cond_load_acquire(a, VAL);
-}
-
 static inline void arch_spin_lock_flags(arch_spinlock_t *x,
 					 unsigned long flags)
 {
-- 
2.5.2

^ permalink raw reply related	[flat|nested] 122+ messages in thread

* [PATCH RFC 21/26] powerpc: Remove spin_unlock_wait() arch-specific definitions
  2017-06-29 23:59 [PATCH RFC 0/26] Remove spin_unlock_wait() Paul E. McKenney
                   ` (17 preceding siblings ...)
  2017-06-30  0:01 ` [PATCH RFC 20/26] parisc: " Paul E. McKenney
@ 2017-06-30  0:01 ` Paul E. McKenney
  2017-07-02  3:58   ` Boqun Feng
  2017-06-30  0:01 ` [PATCH RFC 22/26] s390: " Paul E. McKenney
                   ` (6 subsequent siblings)
  25 siblings, 1 reply; 122+ messages in thread
From: Paul E. McKenney @ 2017-06-30  0:01 UTC (permalink / raw)
  To: linux-kernel
  Cc: netfilter-devel, netdev, oleg, akpm, mingo, dave, manfred, tj,
	arnd, linux-arch, will.deacon, peterz, stern, parri.andrea,
	torvalds, Paul E. McKenney, Benjamin Herrenschmidt,
	Paul Mackerras, Michael Ellerman, linuxppc-dev

There is no agreed-upon definition of spin_unlock_wait()'s semantics,
and it appears that all callers could do just as well with a lock/unlock
pair.  This commit therefore removes the underlying arch-specific
arch_spin_unlock_wait().

Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Michael Ellerman <mpe@ellerman.id.au>
Cc: <linuxppc-dev@lists.ozlabs.org>
Cc: Will Deacon <will.deacon@arm.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Alan Stern <stern@rowland.harvard.edu>
Cc: Andrea Parri <parri.andrea@gmail.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
---
 arch/powerpc/include/asm/spinlock.h | 33 ---------------------------------
 1 file changed, 33 deletions(-)

diff --git a/arch/powerpc/include/asm/spinlock.h b/arch/powerpc/include/asm/spinlock.h
index 8c1b913de6d7..d256e448ea49 100644
--- a/arch/powerpc/include/asm/spinlock.h
+++ b/arch/powerpc/include/asm/spinlock.h
@@ -170,39 +170,6 @@ static inline void arch_spin_unlock(arch_spinlock_t *lock)
 	lock->slock = 0;
 }
 
-static inline void arch_spin_unlock_wait(arch_spinlock_t *lock)
-{
-	arch_spinlock_t lock_val;
-
-	smp_mb();
-
-	/*
-	 * Atomically load and store back the lock value (unchanged). This
-	 * ensures that our observation of the lock value is ordered with
-	 * respect to other lock operations.
-	 */
-	__asm__ __volatile__(
-"1:	" PPC_LWARX(%0, 0, %2, 0) "\n"
-"	stwcx. %0, 0, %2\n"
-"	bne- 1b\n"
-	: "=&r" (lock_val), "+m" (*lock)
-	: "r" (lock)
-	: "cr0", "xer");
-
-	if (arch_spin_value_unlocked(lock_val))
-		goto out;
-
-	while (lock->slock) {
-		HMT_low();
-		if (SHARED_PROCESSOR)
-			__spin_yield(lock);
-	}
-	HMT_medium();
-
-out:
-	smp_mb();
-}
-
 /*
  * Read-write spinlocks, allowing multiple readers
  * but only one writer.
-- 
2.5.2

^ permalink raw reply related	[flat|nested] 122+ messages in thread

* [PATCH RFC 22/26] s390: Remove spin_unlock_wait() arch-specific definitions
  2017-06-29 23:59 [PATCH RFC 0/26] Remove spin_unlock_wait() Paul E. McKenney
                   ` (18 preceding siblings ...)
  2017-06-30  0:01 ` [PATCH RFC 21/26] powerpc: " Paul E. McKenney
@ 2017-06-30  0:01 ` Paul E. McKenney
  2017-06-30  0:01 ` [PATCH RFC 23/26] sh: " Paul E. McKenney
                   ` (5 subsequent siblings)
  25 siblings, 0 replies; 122+ messages in thread
From: Paul E. McKenney @ 2017-06-30  0:01 UTC (permalink / raw)
  To: linux-kernel
  Cc: netfilter-devel, netdev, oleg, akpm, mingo, dave, manfred, tj,
	arnd, linux-arch, will.deacon, peterz, stern, parri.andrea,
	torvalds, Paul E. McKenney, Martin Schwidefsky, Heiko Carstens,
	linux-s390

There is no agreed-upon definition of spin_unlock_wait()'s semantics,
and it appears that all callers could do just as well with a lock/unlock
pair.  This commit therefore removes the underlying arch-specific
arch_spin_unlock_wait().

Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Cc: Martin Schwidefsky <schwidefsky@de.ibm.com>
Cc: Heiko Carstens <heiko.carstens@de.ibm.com>
Cc: <linux-s390@vger.kernel.org>
Cc: Will Deacon <will.deacon@arm.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Alan Stern <stern@rowland.harvard.edu>
Cc: Andrea Parri <parri.andrea@gmail.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
---
 arch/s390/include/asm/spinlock.h | 7 -------
 1 file changed, 7 deletions(-)

diff --git a/arch/s390/include/asm/spinlock.h b/arch/s390/include/asm/spinlock.h
index f7838ecd83c6..217ee5210c32 100644
--- a/arch/s390/include/asm/spinlock.h
+++ b/arch/s390/include/asm/spinlock.h
@@ -98,13 +98,6 @@ static inline void arch_spin_unlock(arch_spinlock_t *lp)
 		: "cc", "memory");
 }
 
-static inline void arch_spin_unlock_wait(arch_spinlock_t *lock)
-{
-	while (arch_spin_is_locked(lock))
-		arch_spin_relax(lock);
-	smp_acquire__after_ctrl_dep();
-}
-
 /*
  * Read-write spinlocks, allowing multiple readers
  * but only one writer.
-- 
2.5.2

^ permalink raw reply related	[flat|nested] 122+ messages in thread

* [PATCH RFC 23/26] sh: Remove spin_unlock_wait() arch-specific definitions
  2017-06-29 23:59 [PATCH RFC 0/26] Remove spin_unlock_wait() Paul E. McKenney
                   ` (19 preceding siblings ...)
  2017-06-30  0:01 ` [PATCH RFC 22/26] s390: " Paul E. McKenney
@ 2017-06-30  0:01 ` Paul E. McKenney
  2017-06-30  0:01 ` [PATCH RFC 24/26] sparc: " Paul E. McKenney
                   ` (4 subsequent siblings)
  25 siblings, 0 replies; 122+ messages in thread
From: Paul E. McKenney @ 2017-06-30  0:01 UTC (permalink / raw)
  To: linux-kernel
  Cc: netfilter-devel, netdev, oleg, akpm, mingo, dave, manfred, tj,
	arnd, linux-arch, will.deacon, peterz, stern, parri.andrea,
	torvalds, Paul E. McKenney, Yoshinori Sato, Rich Felker,
	linux-sh

There is no agreed-upon definition of spin_unlock_wait()'s semantics,
and it appears that all callers could do just as well with a lock/unlock
pair.  This commit therefore removes the underlying arch-specific
arch_spin_unlock_wait().

Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Cc: Yoshinori Sato <ysato@users.sourceforge.jp>
Cc: Rich Felker <dalias@libc.org>
Cc: <linux-sh@vger.kernel.org>
Cc: Will Deacon <will.deacon@arm.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Alan Stern <stern@rowland.harvard.edu>
Cc: Andrea Parri <parri.andrea@gmail.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
---
 arch/sh/include/asm/spinlock-cas.h  | 5 -----
 arch/sh/include/asm/spinlock-llsc.h | 5 -----
 2 files changed, 10 deletions(-)

diff --git a/arch/sh/include/asm/spinlock-cas.h b/arch/sh/include/asm/spinlock-cas.h
index c46e8cc7b515..5ed7dbbd94ff 100644
--- a/arch/sh/include/asm/spinlock-cas.h
+++ b/arch/sh/include/asm/spinlock-cas.h
@@ -29,11 +29,6 @@ static inline unsigned __sl_cas(volatile unsigned *p, unsigned old, unsigned new
 #define arch_spin_is_locked(x)		((x)->lock <= 0)
 #define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock)
 
-static inline void arch_spin_unlock_wait(arch_spinlock_t *lock)
-{
-	smp_cond_load_acquire(&lock->lock, VAL > 0);
-}
-
 static inline void arch_spin_lock(arch_spinlock_t *lock)
 {
 	while (!__sl_cas(&lock->lock, 1, 0));
diff --git a/arch/sh/include/asm/spinlock-llsc.h b/arch/sh/include/asm/spinlock-llsc.h
index cec78143fa83..f77263aae760 100644
--- a/arch/sh/include/asm/spinlock-llsc.h
+++ b/arch/sh/include/asm/spinlock-llsc.h
@@ -21,11 +21,6 @@
 #define arch_spin_is_locked(x)		((x)->lock <= 0)
 #define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock)
 
-static inline void arch_spin_unlock_wait(arch_spinlock_t *lock)
-{
-	smp_cond_load_acquire(&lock->lock, VAL > 0);
-}
-
 /*
  * Simple spin lock operations.  There are two variants, one clears IRQ's
  * on the local processor, one does not.
-- 
2.5.2

^ permalink raw reply related	[flat|nested] 122+ messages in thread

* [PATCH RFC 24/26] sparc: Remove spin_unlock_wait() arch-specific definitions
  2017-06-29 23:59 [PATCH RFC 0/26] Remove spin_unlock_wait() Paul E. McKenney
                   ` (20 preceding siblings ...)
  2017-06-30  0:01 ` [PATCH RFC 23/26] sh: " Paul E. McKenney
@ 2017-06-30  0:01 ` Paul E. McKenney
  2017-06-30  0:01 ` [PATCH RFC 25/26] tile: " Paul E. McKenney
                   ` (3 subsequent siblings)
  25 siblings, 0 replies; 122+ messages in thread
From: Paul E. McKenney @ 2017-06-30  0:01 UTC (permalink / raw)
  To: linux-kernel
  Cc: netfilter-devel, netdev, oleg, akpm, mingo, dave, manfred, tj,
	arnd, linux-arch, will.deacon, peterz, stern, parri.andrea,
	torvalds, Paul E. McKenney, David S. Miller, sparclinux

There is no agreed-upon definition of spin_unlock_wait()'s semantics,
and it appears that all callers could do just as well with a lock/unlock
pair.  This commit therefore removes the underlying arch-specific
arch_spin_unlock_wait().

Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Cc: "David S. Miller" <davem@davemloft.net>
Cc: <sparclinux@vger.kernel.org>
Cc: Will Deacon <will.deacon@arm.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Alan Stern <stern@rowland.harvard.edu>
Cc: Andrea Parri <parri.andrea@gmail.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
---
 arch/sparc/include/asm/spinlock_32.h | 5 -----
 arch/sparc/include/asm/spinlock_64.h | 5 -----
 2 files changed, 10 deletions(-)

diff --git a/arch/sparc/include/asm/spinlock_32.h b/arch/sparc/include/asm/spinlock_32.h
index 8011e79f59c9..67345b2dc408 100644
--- a/arch/sparc/include/asm/spinlock_32.h
+++ b/arch/sparc/include/asm/spinlock_32.h
@@ -14,11 +14,6 @@
 
 #define arch_spin_is_locked(lock) (*((volatile unsigned char *)(lock)) != 0)
 
-static inline void arch_spin_unlock_wait(arch_spinlock_t *lock)
-{
-	smp_cond_load_acquire(&lock->lock, !VAL);
-}
-
 static inline void arch_spin_lock(arch_spinlock_t *lock)
 {
 	__asm__ __volatile__(
diff --git a/arch/sparc/include/asm/spinlock_64.h b/arch/sparc/include/asm/spinlock_64.h
index 07c9f2e9bf57..923d57f9b79d 100644
--- a/arch/sparc/include/asm/spinlock_64.h
+++ b/arch/sparc/include/asm/spinlock_64.h
@@ -26,11 +26,6 @@
 
 #define arch_spin_is_locked(lp)	((lp)->lock != 0)
 
-static inline void arch_spin_unlock_wait(arch_spinlock_t *lock)
-{
-	smp_cond_load_acquire(&lock->lock, !VAL);
-}
-
 static inline void arch_spin_lock(arch_spinlock_t *lock)
 {
 	unsigned long tmp;
-- 
2.5.2

^ permalink raw reply related	[flat|nested] 122+ messages in thread

* [PATCH RFC 25/26] tile: Remove spin_unlock_wait() arch-specific definitions
  2017-06-29 23:59 [PATCH RFC 0/26] Remove spin_unlock_wait() Paul E. McKenney
                   ` (21 preceding siblings ...)
  2017-06-30  0:01 ` [PATCH RFC 24/26] sparc: " Paul E. McKenney
@ 2017-06-30  0:01 ` Paul E. McKenney
  2017-06-30  0:06   ` Linus Torvalds
  2017-06-30  0:01 ` [PATCH RFC 26/26] xtensa: " Paul E. McKenney
                   ` (2 subsequent siblings)
  25 siblings, 1 reply; 122+ messages in thread
From: Paul E. McKenney @ 2017-06-30  0:01 UTC (permalink / raw)
  To: linux-kernel
  Cc: netfilter-devel, netdev, oleg, akpm, mingo, dave, manfred, tj,
	arnd, linux-arch, will.deacon, peterz, stern, parri.andrea,
	torvalds, Paul E. McKenney, Chris Metcalf

There is no agreed-upon definition of spin_unlock_wait()'s semantics,
and it appears that all callers could do just as well with a lock/unlock
pair.  This commit therefore removes the underlying arch-specific
arch_spin_unlock_wait().

Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Cc: Chris Metcalf <cmetcalf@mellanox.com>
Cc: Will Deacon <will.deacon@arm.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Alan Stern <stern@rowland.harvard.edu>
Cc: Andrea Parri <parri.andrea@gmail.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
---
 arch/tile/include/asm/spinlock_32.h |  2 --
 arch/tile/include/asm/spinlock_64.h |  2 --
 arch/tile/lib/spinlock_32.c         | 23 -----------------------
 arch/tile/lib/spinlock_64.c         | 22 ----------------------
 4 files changed, 49 deletions(-)

diff --git a/arch/tile/include/asm/spinlock_32.h b/arch/tile/include/asm/spinlock_32.h
index b14b1ba5bf9c..cba8ba9b8da6 100644
--- a/arch/tile/include/asm/spinlock_32.h
+++ b/arch/tile/include/asm/spinlock_32.h
@@ -64,8 +64,6 @@ static inline void arch_spin_unlock(arch_spinlock_t *lock)
 	lock->current_ticket = old_ticket + TICKET_QUANTUM;
 }
 
-void arch_spin_unlock_wait(arch_spinlock_t *lock);
-
 /*
  * Read-write spinlocks, allowing multiple readers
  * but only one writer.
diff --git a/arch/tile/include/asm/spinlock_64.h b/arch/tile/include/asm/spinlock_64.h
index b9718fb4e74a..9a2c2d605752 100644
--- a/arch/tile/include/asm/spinlock_64.h
+++ b/arch/tile/include/asm/spinlock_64.h
@@ -58,8 +58,6 @@ static inline void arch_spin_unlock(arch_spinlock_t *lock)
 	__insn_fetchadd4(&lock->lock, 1U << __ARCH_SPIN_CURRENT_SHIFT);
 }
 
-void arch_spin_unlock_wait(arch_spinlock_t *lock);
-
 void arch_spin_lock_slow(arch_spinlock_t *lock, u32 val);
 
 /* Grab the "next" ticket number and bump it atomically.
diff --git a/arch/tile/lib/spinlock_32.c b/arch/tile/lib/spinlock_32.c
index 076c6cc43113..db9333f2447c 100644
--- a/arch/tile/lib/spinlock_32.c
+++ b/arch/tile/lib/spinlock_32.c
@@ -62,29 +62,6 @@ int arch_spin_trylock(arch_spinlock_t *lock)
 }
 EXPORT_SYMBOL(arch_spin_trylock);
 
-void arch_spin_unlock_wait(arch_spinlock_t *lock)
-{
-	u32 iterations = 0;
-	int curr = READ_ONCE(lock->current_ticket);
-	int next = READ_ONCE(lock->next_ticket);
-
-	/* Return immediately if unlocked. */
-	if (next == curr)
-		return;
-
-	/* Wait until the current locker has released the lock. */
-	do {
-		delay_backoff(iterations++);
-	} while (READ_ONCE(lock->current_ticket) == curr);
-
-	/*
-	 * The TILE architecture doesn't do read speculation; therefore
-	 * a control dependency guarantees a LOAD->{LOAD,STORE} order.
-	 */
-	barrier();
-}
-EXPORT_SYMBOL(arch_spin_unlock_wait);
-
 /*
  * The low byte is always reserved to be the marker for a "tns" operation
  * since the low bit is set to "1" by a tns.  The next seven bits are
diff --git a/arch/tile/lib/spinlock_64.c b/arch/tile/lib/spinlock_64.c
index a4b5b2cbce93..de414c22892f 100644
--- a/arch/tile/lib/spinlock_64.c
+++ b/arch/tile/lib/spinlock_64.c
@@ -62,28 +62,6 @@ int arch_spin_trylock(arch_spinlock_t *lock)
 }
 EXPORT_SYMBOL(arch_spin_trylock);
 
-void arch_spin_unlock_wait(arch_spinlock_t *lock)
-{
-	u32 iterations = 0;
-	u32 val = READ_ONCE(lock->lock);
-	u32 curr = arch_spin_current(val);
-
-	/* Return immediately if unlocked. */
-	if (arch_spin_next(val) == curr)
-		return;
-
-	/* Wait until the current locker has released the lock. */
-	do {
-		delay_backoff(iterations++);
-	} while (arch_spin_current(READ_ONCE(lock->lock)) == curr);
-
-	/*
-	 * The TILE architecture doesn't do read speculation; therefore
-	 * a control dependency guarantees a LOAD->{LOAD,STORE} order.
-	 */
-	barrier();
-}
-EXPORT_SYMBOL(arch_spin_unlock_wait);
 
 /*
  * If the read lock fails due to a writer, we retry periodically
-- 
2.5.2

^ permalink raw reply related	[flat|nested] 122+ messages in thread

* [PATCH RFC 26/26] xtensa: Remove spin_unlock_wait() arch-specific definitions
  2017-06-29 23:59 [PATCH RFC 0/26] Remove spin_unlock_wait() Paul E. McKenney
                   ` (22 preceding siblings ...)
  2017-06-30  0:01 ` [PATCH RFC 25/26] tile: " Paul E. McKenney
@ 2017-06-30  0:01 ` Paul E. McKenney
       [not found] ` <1498780894-8253-6-git-send-email-paulmck@linux.vnet.ibm.com>
  2017-07-05 23:29 ` [PATCH v2 0/9] Remove spin_unlock_wait() Paul E. McKenney
  25 siblings, 0 replies; 122+ messages in thread
From: Paul E. McKenney @ 2017-06-30  0:01 UTC (permalink / raw)
  To: linux-kernel
  Cc: netfilter-devel, netdev, oleg, akpm, mingo, dave, manfred, tj,
	arnd, linux-arch, will.deacon, peterz, stern, parri.andrea,
	torvalds, Paul E. McKenney, Chris Zankel, Max Filippov,
	linux-xtensa

There is no agreed-upon definition of spin_unlock_wait()'s semantics,
and it appears that all callers could do just as well with a lock/unlock
pair.  This commit therefore removes the underlying arch-specific
arch_spin_unlock_wait().

Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Cc: Chris Zankel <chris@zankel.net>
Cc: Max Filippov <jcmvbkbc@gmail.com>
Cc: <linux-xtensa@linux-xtensa.org>
---
 arch/xtensa/include/asm/spinlock.h | 5 -----
 1 file changed, 5 deletions(-)

diff --git a/arch/xtensa/include/asm/spinlock.h b/arch/xtensa/include/asm/spinlock.h
index a36221cf6363..3bb49681ee24 100644
--- a/arch/xtensa/include/asm/spinlock.h
+++ b/arch/xtensa/include/asm/spinlock.h
@@ -33,11 +33,6 @@
 
 #define arch_spin_is_locked(x) ((x)->slock != 0)
 
-static inline void arch_spin_unlock_wait(arch_spinlock_t *lock)
-{
-	smp_cond_load_acquire(&lock->slock, !VAL);
-}
-
 #define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock)
 
 static inline void arch_spin_lock(arch_spinlock_t *lock)
-- 
2.5.2

^ permalink raw reply related	[flat|nested] 122+ messages in thread

* Re: [PATCH RFC 25/26] tile: Remove spin_unlock_wait() arch-specific definitions
  2017-06-30  0:01 ` [PATCH RFC 25/26] tile: " Paul E. McKenney
@ 2017-06-30  0:06   ` Linus Torvalds
  2017-06-30  0:09     ` Paul E. McKenney
  2017-06-30  0:10     ` Linus Torvalds
  0 siblings, 2 replies; 122+ messages in thread
From: Linus Torvalds @ 2017-06-30  0:06 UTC (permalink / raw)
  To: Paul E. McKenney
  Cc: Linux Kernel Mailing List, NetFilter, Network Development,
	Oleg Nesterov, Andrew Morton, Ingo Molnar, Davidlohr Bueso,
	Manfred Spraul, Tejun Heo, Arnd Bergmann, linux-arch,
	Will Deacon, Peter Zijlstra, Alan Stern, Andrea Parri,
	Chris Metcalf

On Thu, Jun 29, 2017 at 5:01 PM, Paul E. McKenney
<paulmck@linux.vnet.ibm.com> wrote:
> There is no agreed-upon definition of spin_unlock_wait()'s semantics,
> and it appears that all callers could do just as well with a lock/unlock
> pair.  This commit therefore removes the underlying arch-specific
> arch_spin_unlock_wait().

Please don't make this one commit fopr every architecture.

Once something gets removed, it gets removed. There's no point in
"remove it from architecture X". If there are no more users, we're
done with it, and making it be 25 patches with the same commit message
instead of just one doesn't help anybody.

               Linus

^ permalink raw reply	[flat|nested] 122+ messages in thread

* Re: [PATCH RFC 25/26] tile: Remove spin_unlock_wait() arch-specific definitions
  2017-06-30  0:06   ` Linus Torvalds
@ 2017-06-30  0:09     ` Paul E. McKenney
  2017-06-30  0:14       ` Paul E. McKenney
  2017-06-30  0:10     ` Linus Torvalds
  1 sibling, 1 reply; 122+ messages in thread
From: Paul E. McKenney @ 2017-06-30  0:09 UTC (permalink / raw)
  To: Linus Torvalds
  Cc: Linux Kernel Mailing List, NetFilter, Network Development,
	Oleg Nesterov, Andrew Morton, Ingo Molnar, Davidlohr Bueso,
	Manfred Spraul, Tejun Heo, Arnd Bergmann, linux-arch,
	Will Deacon, Peter Zijlstra, Alan Stern, Andrea Parri,
	Chris Metcalf

On Thu, Jun 29, 2017 at 05:06:16PM -0700, Linus Torvalds wrote:
> On Thu, Jun 29, 2017 at 5:01 PM, Paul E. McKenney
> <paulmck@linux.vnet.ibm.com> wrote:
> > There is no agreed-upon definition of spin_unlock_wait()'s semantics,
> > and it appears that all callers could do just as well with a lock/unlock
> > pair.  This commit therefore removes the underlying arch-specific
> > arch_spin_unlock_wait().
> 
> Please don't make this one commit fopr every architecture.
> 
> Once something gets removed, it gets removed. There's no point in
> "remove it from architecture X". If there are no more users, we're
> done with it, and making it be 25 patches with the same commit message
> instead of just one doesn't help anybody.

Apologies, I will merge them.

							Thanx, Paul

^ permalink raw reply	[flat|nested] 122+ messages in thread

* Re: [PATCH RFC 25/26] tile: Remove spin_unlock_wait() arch-specific definitions
  2017-06-30  0:06   ` Linus Torvalds
  2017-06-30  0:09     ` Paul E. McKenney
@ 2017-06-30  0:10     ` Linus Torvalds
  2017-06-30  0:24       ` Paul E. McKenney
  1 sibling, 1 reply; 122+ messages in thread
From: Linus Torvalds @ 2017-06-30  0:10 UTC (permalink / raw)
  To: Paul E. McKenney
  Cc: Linux Kernel Mailing List, NetFilter, Network Development,
	Oleg Nesterov, Andrew Morton, Ingo Molnar, Davidlohr Bueso,
	Manfred Spraul, Tejun Heo, Arnd Bergmann, linux-arch,
	Will Deacon, Peter Zijlstra, Alan Stern, Andrea Parri,
	Chris Metcalf

On Thu, Jun 29, 2017 at 5:06 PM, Linus Torvalds
<torvalds@linux-foundation.org> wrote:
>
> Please don't make this one commit fopr every architecture.
>
> Once something gets removed, it gets removed. There's no point in
> "remove it from architecture X". If there are no more users, we're
> done with it, and making it be 25 patches with the same commit message
> instead of just one doesn't help anybody.

Just to clarify: I think the actual *users* are worth doing one by
one, particularly if there are user-specific explanations of what that
particular code wanted, and why spin_unlock_wait() doesn't really
help.

And I think that you actually have those per-user insights by now,
after looking at the long thread.

So I'm not saying "do one patch for the whole series". One patch per
removal of use is fine - in fact preferred.

But once there are no actual more users, just remove all the
architecture definitions in one go, because explaining the same thing
several times doesn't actually help anything.

In fact, *if* we end up ever resurrecting that thing, it's good if we
can resurrect it in one go. Then we can resurrect the one or two users
that turned out to matter after all and could come up with why some
particular ordering was ok too.

                   Linus

^ permalink raw reply	[flat|nested] 122+ messages in thread

* Re: [PATCH RFC 25/26] tile: Remove spin_unlock_wait() arch-specific definitions
  2017-06-30  0:09     ` Paul E. McKenney
@ 2017-06-30  0:14       ` Paul E. McKenney
  0 siblings, 0 replies; 122+ messages in thread
From: Paul E. McKenney @ 2017-06-30  0:14 UTC (permalink / raw)
  To: Linus Torvalds
  Cc: Linux Kernel Mailing List, NetFilter, Network Development,
	Oleg Nesterov, Andrew Morton, Ingo Molnar, Davidlohr Bueso,
	Manfred Spraul, Tejun Heo, Arnd Bergmann, linux-arch,
	Will Deacon, Peter Zijlstra, Alan Stern, Andrea Parri,
	Chris Metcalf

On Thu, Jun 29, 2017 at 05:09:56PM -0700, Paul E. McKenney wrote:
> On Thu, Jun 29, 2017 at 05:06:16PM -0700, Linus Torvalds wrote:
> > On Thu, Jun 29, 2017 at 5:01 PM, Paul E. McKenney
> > <paulmck@linux.vnet.ibm.com> wrote:
> > > There is no agreed-upon definition of spin_unlock_wait()'s semantics,
> > > and it appears that all callers could do just as well with a lock/unlock
> > > pair.  This commit therefore removes the underlying arch-specific
> > > arch_spin_unlock_wait().
> > 
> > Please don't make this one commit fopr every architecture.
> > 
> > Once something gets removed, it gets removed. There's no point in
> > "remove it from architecture X". If there are no more users, we're
> > done with it, and making it be 25 patches with the same commit message
> > instead of just one doesn't help anybody.
> 
> Apologies, I will merge them.

I suppose that I could have sent the merged patch...  Please see below.

							Thanx, Paul

------------------------------------------------------------------------

commit e81efa4219e9b07e476448572aafe8f9c4ad28c8
Author: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Date:   Thu Jun 29 15:53:02 2017 -0700

    arch: Remove spin_unlock_wait() arch-specific definitions
    
    There is no agreed-upon definition of spin_unlock_wait()'s semantics,
    and it appears that all callers could do just as well with a lock/unlock
    pair.  This commit therefore removes the underlying arch-specific
    arch_spin_unlock_wait() for all architectures providing them.
    
    Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
    Cc: <linux-arch@vger.kernel.org>
    Cc: Will Deacon <will.deacon@arm.com>
    Cc: Peter Zijlstra <peterz@infradead.org>
    Cc: Alan Stern <stern@rowland.harvard.edu>
    Cc: Andrea Parri <parri.andrea@gmail.com>
    Cc: Linus Torvalds <torvalds@linux-foundation.org>

diff --git a/arch/alpha/include/asm/spinlock.h b/arch/alpha/include/asm/spinlock.h
index a40b9fc0c6c3..718ac0b64adf 100644
--- a/arch/alpha/include/asm/spinlock.h
+++ b/arch/alpha/include/asm/spinlock.h
@@ -16,11 +16,6 @@
 #define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock)
 #define arch_spin_is_locked(x)	((x)->lock != 0)
 
-static inline void arch_spin_unlock_wait(arch_spinlock_t *lock)
-{
-	smp_cond_load_acquire(&lock->lock, !VAL);
-}
-
 static inline int arch_spin_value_unlocked(arch_spinlock_t lock)
 {
         return lock.lock == 0;
diff --git a/arch/arc/include/asm/spinlock.h b/arch/arc/include/asm/spinlock.h
index 233d5ffe6ec7..a325e6a36523 100644
--- a/arch/arc/include/asm/spinlock.h
+++ b/arch/arc/include/asm/spinlock.h
@@ -16,11 +16,6 @@
 #define arch_spin_is_locked(x)	((x)->slock != __ARCH_SPIN_LOCK_UNLOCKED__)
 #define arch_spin_lock_flags(lock, flags)	arch_spin_lock(lock)
 
-static inline void arch_spin_unlock_wait(arch_spinlock_t *lock)
-{
-	smp_cond_load_acquire(&lock->slock, !VAL);
-}
-
 #ifdef CONFIG_ARC_HAS_LLSC
 
 static inline void arch_spin_lock(arch_spinlock_t *lock)
diff --git a/arch/arm/include/asm/spinlock.h b/arch/arm/include/asm/spinlock.h
index 4bec45442072..c030143c18c6 100644
--- a/arch/arm/include/asm/spinlock.h
+++ b/arch/arm/include/asm/spinlock.h
@@ -52,22 +52,6 @@ static inline void dsb_sev(void)
  * memory.
  */
 
-static inline void arch_spin_unlock_wait(arch_spinlock_t *lock)
-{
-	u16 owner = READ_ONCE(lock->tickets.owner);
-
-	for (;;) {
-		arch_spinlock_t tmp = READ_ONCE(*lock);
-
-		if (tmp.tickets.owner == tmp.tickets.next ||
-		    tmp.tickets.owner != owner)
-			break;
-
-		wfe();
-	}
-	smp_acquire__after_ctrl_dep();
-}
-
 #define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock)
 
 static inline void arch_spin_lock(arch_spinlock_t *lock)
diff --git a/arch/arm64/include/asm/spinlock.h b/arch/arm64/include/asm/spinlock.h
index cae331d553f8..f445bd7f2b9f 100644
--- a/arch/arm64/include/asm/spinlock.h
+++ b/arch/arm64/include/asm/spinlock.h
@@ -26,58 +26,6 @@
  * The memory barriers are implicit with the load-acquire and store-release
  * instructions.
  */
-static inline void arch_spin_unlock_wait(arch_spinlock_t *lock)
-{
-	unsigned int tmp;
-	arch_spinlock_t lockval;
-	u32 owner;
-
-	/*
-	 * Ensure prior spin_lock operations to other locks have completed
-	 * on this CPU before we test whether "lock" is locked.
-	 */
-	smp_mb();
-	owner = READ_ONCE(lock->owner) << 16;
-
-	asm volatile(
-"	sevl\n"
-"1:	wfe\n"
-"2:	ldaxr	%w0, %2\n"
-	/* Is the lock free? */
-"	eor	%w1, %w0, %w0, ror #16\n"
-"	cbz	%w1, 3f\n"
-	/* Lock taken -- has there been a subsequent unlock->lock transition? */
-"	eor	%w1, %w3, %w0, lsl #16\n"
-"	cbz	%w1, 1b\n"
-	/*
-	 * The owner has been updated, so there was an unlock->lock
-	 * transition that we missed. That means we can rely on the
-	 * store-release of the unlock operation paired with the
-	 * load-acquire of the lock operation to publish any of our
-	 * previous stores to the new lock owner and therefore don't
-	 * need to bother with the writeback below.
-	 */
-"	b	4f\n"
-"3:\n"
-	/*
-	 * Serialise against any concurrent lockers by writing back the
-	 * unlocked lock value
-	 */
-	ARM64_LSE_ATOMIC_INSN(
-	/* LL/SC */
-"	stxr	%w1, %w0, %2\n"
-	__nops(2),
-	/* LSE atomics */
-"	mov	%w1, %w0\n"
-"	cas	%w0, %w0, %2\n"
-"	eor	%w1, %w1, %w0\n")
-	/* Somebody else wrote to the lock, GOTO 10 and reload the value */
-"	cbnz	%w1, 2b\n"
-"4:"
-	: "=&r" (lockval), "=&r" (tmp), "+Q" (*lock)
-	: "r" (owner)
-	: "memory");
-}
 
 #define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock)
 
@@ -176,7 +124,11 @@ static inline int arch_spin_value_unlocked(arch_spinlock_t lock)
 
 static inline int arch_spin_is_locked(arch_spinlock_t *lock)
 {
-	smp_mb(); /* See arch_spin_unlock_wait */
+	/*
+	 * Ensure prior spin_lock operations to other locks have completed
+	 * on this CPU before we test whether "lock" is locked.
+	 */
+	smp_mb(); /* ^^^ */
 	return !arch_spin_value_unlocked(READ_ONCE(*lock));
 }
 
diff --git a/arch/blackfin/include/asm/spinlock.h b/arch/blackfin/include/asm/spinlock.h
index c58f4a83ed6f..f6431439d15d 100644
--- a/arch/blackfin/include/asm/spinlock.h
+++ b/arch/blackfin/include/asm/spinlock.h
@@ -48,11 +48,6 @@ static inline void arch_spin_unlock(arch_spinlock_t *lock)
 	__raw_spin_unlock_asm(&lock->lock);
 }
 
-static inline void arch_spin_unlock_wait(arch_spinlock_t *lock)
-{
-	smp_cond_load_acquire(&lock->lock, !VAL);
-}
-
 static inline int arch_read_can_lock(arch_rwlock_t *rw)
 {
 	return __raw_uncached_fetch_asm(&rw->lock) > 0;
diff --git a/arch/hexagon/include/asm/spinlock.h b/arch/hexagon/include/asm/spinlock.h
index a1c55788c5d6..53a8d5885887 100644
--- a/arch/hexagon/include/asm/spinlock.h
+++ b/arch/hexagon/include/asm/spinlock.h
@@ -179,11 +179,6 @@ static inline unsigned int arch_spin_trylock(arch_spinlock_t *lock)
  */
 #define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock)
 
-static inline void arch_spin_unlock_wait(arch_spinlock_t *lock)
-{
-	smp_cond_load_acquire(&lock->lock, !VAL);
-}
-
 #define arch_spin_is_locked(x) ((x)->lock != 0)
 
 #define arch_read_lock_flags(lock, flags) arch_read_lock(lock)
diff --git a/arch/ia64/include/asm/spinlock.h b/arch/ia64/include/asm/spinlock.h
index ca9e76149a4a..df2c121164b8 100644
--- a/arch/ia64/include/asm/spinlock.h
+++ b/arch/ia64/include/asm/spinlock.h
@@ -76,22 +76,6 @@ static __always_inline void __ticket_spin_unlock(arch_spinlock_t *lock)
 	ACCESS_ONCE(*p) = (tmp + 2) & ~1;
 }
 
-static __always_inline void __ticket_spin_unlock_wait(arch_spinlock_t *lock)
-{
-	int	*p = (int *)&lock->lock, ticket;
-
-	ia64_invala();
-
-	for (;;) {
-		asm volatile ("ld4.c.nc %0=[%1]" : "=r"(ticket) : "r"(p) : "memory");
-		if (!(((ticket >> TICKET_SHIFT) ^ ticket) & TICKET_MASK))
-			return;
-		cpu_relax();
-	}
-
-	smp_acquire__after_ctrl_dep();
-}
-
 static inline int __ticket_spin_is_locked(arch_spinlock_t *lock)
 {
 	long tmp = ACCESS_ONCE(lock->lock);
@@ -143,11 +127,6 @@ static __always_inline void arch_spin_lock_flags(arch_spinlock_t *lock,
 	arch_spin_lock(lock);
 }
 
-static inline void arch_spin_unlock_wait(arch_spinlock_t *lock)
-{
-	__ticket_spin_unlock_wait(lock);
-}
-
 #define arch_read_can_lock(rw)		(*(volatile int *)(rw) >= 0)
 #define arch_write_can_lock(rw)	(*(volatile int *)(rw) == 0)
 
diff --git a/arch/m32r/include/asm/spinlock.h b/arch/m32r/include/asm/spinlock.h
index 323c7fc953cd..a56825592b90 100644
--- a/arch/m32r/include/asm/spinlock.h
+++ b/arch/m32r/include/asm/spinlock.h
@@ -30,11 +30,6 @@
 #define arch_spin_is_locked(x)		(*(volatile int *)(&(x)->slock) <= 0)
 #define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock)
 
-static inline void arch_spin_unlock_wait(arch_spinlock_t *lock)
-{
-	smp_cond_load_acquire(&lock->slock, VAL > 0);
-}
-
 /**
  * arch_spin_trylock - Try spin lock and return a result
  * @lock: Pointer to the lock variable
diff --git a/arch/metag/include/asm/spinlock.h b/arch/metag/include/asm/spinlock.h
index c0c7a22be1ae..ddf7fe5708a6 100644
--- a/arch/metag/include/asm/spinlock.h
+++ b/arch/metag/include/asm/spinlock.h
@@ -15,11 +15,6 @@
  * locked.
  */
 
-static inline void arch_spin_unlock_wait(arch_spinlock_t *lock)
-{
-	smp_cond_load_acquire(&lock->lock, !VAL);
-}
-
 #define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock)
 
 #define	arch_read_lock_flags(lock, flags) arch_read_lock(lock)
diff --git a/arch/mips/include/asm/spinlock.h b/arch/mips/include/asm/spinlock.h
index a8df44d60607..81b4945031ee 100644
--- a/arch/mips/include/asm/spinlock.h
+++ b/arch/mips/include/asm/spinlock.h
@@ -50,22 +50,6 @@ static inline int arch_spin_value_unlocked(arch_spinlock_t lock)
 
 #define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock)
 
-static inline void arch_spin_unlock_wait(arch_spinlock_t *lock)
-{
-	u16 owner = READ_ONCE(lock->h.serving_now);
-	smp_rmb();
-	for (;;) {
-		arch_spinlock_t tmp = READ_ONCE(*lock);
-
-		if (tmp.h.serving_now == tmp.h.ticket ||
-		    tmp.h.serving_now != owner)
-			break;
-
-		cpu_relax();
-	}
-	smp_acquire__after_ctrl_dep();
-}
-
 static inline int arch_spin_is_contended(arch_spinlock_t *lock)
 {
 	u32 counters = ACCESS_ONCE(lock->lock);
diff --git a/arch/mn10300/include/asm/spinlock.h b/arch/mn10300/include/asm/spinlock.h
index 9c7b8f7942d8..fe413b41df6c 100644
--- a/arch/mn10300/include/asm/spinlock.h
+++ b/arch/mn10300/include/asm/spinlock.h
@@ -26,11 +26,6 @@
 
 #define arch_spin_is_locked(x)	(*(volatile signed char *)(&(x)->slock) != 0)
 
-static inline void arch_spin_unlock_wait(arch_spinlock_t *lock)
-{
-	smp_cond_load_acquire(&lock->slock, !VAL);
-}
-
 static inline void arch_spin_unlock(arch_spinlock_t *lock)
 {
 	asm volatile(
diff --git a/arch/parisc/include/asm/spinlock.h b/arch/parisc/include/asm/spinlock.h
index e32936cd7f10..55bfe4affca3 100644
--- a/arch/parisc/include/asm/spinlock.h
+++ b/arch/parisc/include/asm/spinlock.h
@@ -14,13 +14,6 @@ static inline int arch_spin_is_locked(arch_spinlock_t *x)
 
 #define arch_spin_lock(lock) arch_spin_lock_flags(lock, 0)
 
-static inline void arch_spin_unlock_wait(arch_spinlock_t *x)
-{
-	volatile unsigned int *a = __ldcw_align(x);
-
-	smp_cond_load_acquire(a, VAL);
-}
-
 static inline void arch_spin_lock_flags(arch_spinlock_t *x,
 					 unsigned long flags)
 {
diff --git a/arch/powerpc/include/asm/spinlock.h b/arch/powerpc/include/asm/spinlock.h
index 8c1b913de6d7..d256e448ea49 100644
--- a/arch/powerpc/include/asm/spinlock.h
+++ b/arch/powerpc/include/asm/spinlock.h
@@ -170,39 +170,6 @@ static inline void arch_spin_unlock(arch_spinlock_t *lock)
 	lock->slock = 0;
 }
 
-static inline void arch_spin_unlock_wait(arch_spinlock_t *lock)
-{
-	arch_spinlock_t lock_val;
-
-	smp_mb();
-
-	/*
-	 * Atomically load and store back the lock value (unchanged). This
-	 * ensures that our observation of the lock value is ordered with
-	 * respect to other lock operations.
-	 */
-	__asm__ __volatile__(
-"1:	" PPC_LWARX(%0, 0, %2, 0) "\n"
-"	stwcx. %0, 0, %2\n"
-"	bne- 1b\n"
-	: "=&r" (lock_val), "+m" (*lock)
-	: "r" (lock)
-	: "cr0", "xer");
-
-	if (arch_spin_value_unlocked(lock_val))
-		goto out;
-
-	while (lock->slock) {
-		HMT_low();
-		if (SHARED_PROCESSOR)
-			__spin_yield(lock);
-	}
-	HMT_medium();
-
-out:
-	smp_mb();
-}
-
 /*
  * Read-write spinlocks, allowing multiple readers
  * but only one writer.
diff --git a/arch/s390/include/asm/spinlock.h b/arch/s390/include/asm/spinlock.h
index f7838ecd83c6..217ee5210c32 100644
--- a/arch/s390/include/asm/spinlock.h
+++ b/arch/s390/include/asm/spinlock.h
@@ -98,13 +98,6 @@ static inline void arch_spin_unlock(arch_spinlock_t *lp)
 		: "cc", "memory");
 }
 
-static inline void arch_spin_unlock_wait(arch_spinlock_t *lock)
-{
-	while (arch_spin_is_locked(lock))
-		arch_spin_relax(lock);
-	smp_acquire__after_ctrl_dep();
-}
-
 /*
  * Read-write spinlocks, allowing multiple readers
  * but only one writer.
diff --git a/arch/sh/include/asm/spinlock-cas.h b/arch/sh/include/asm/spinlock-cas.h
index c46e8cc7b515..5ed7dbbd94ff 100644
--- a/arch/sh/include/asm/spinlock-cas.h
+++ b/arch/sh/include/asm/spinlock-cas.h
@@ -29,11 +29,6 @@ static inline unsigned __sl_cas(volatile unsigned *p, unsigned old, unsigned new
 #define arch_spin_is_locked(x)		((x)->lock <= 0)
 #define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock)
 
-static inline void arch_spin_unlock_wait(arch_spinlock_t *lock)
-{
-	smp_cond_load_acquire(&lock->lock, VAL > 0);
-}
-
 static inline void arch_spin_lock(arch_spinlock_t *lock)
 {
 	while (!__sl_cas(&lock->lock, 1, 0));
diff --git a/arch/sh/include/asm/spinlock-llsc.h b/arch/sh/include/asm/spinlock-llsc.h
index cec78143fa83..f77263aae760 100644
--- a/arch/sh/include/asm/spinlock-llsc.h
+++ b/arch/sh/include/asm/spinlock-llsc.h
@@ -21,11 +21,6 @@
 #define arch_spin_is_locked(x)		((x)->lock <= 0)
 #define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock)
 
-static inline void arch_spin_unlock_wait(arch_spinlock_t *lock)
-{
-	smp_cond_load_acquire(&lock->lock, VAL > 0);
-}
-
 /*
  * Simple spin lock operations.  There are two variants, one clears IRQ's
  * on the local processor, one does not.
diff --git a/arch/sparc/include/asm/spinlock_32.h b/arch/sparc/include/asm/spinlock_32.h
index 8011e79f59c9..67345b2dc408 100644
--- a/arch/sparc/include/asm/spinlock_32.h
+++ b/arch/sparc/include/asm/spinlock_32.h
@@ -14,11 +14,6 @@
 
 #define arch_spin_is_locked(lock) (*((volatile unsigned char *)(lock)) != 0)
 
-static inline void arch_spin_unlock_wait(arch_spinlock_t *lock)
-{
-	smp_cond_load_acquire(&lock->lock, !VAL);
-}
-
 static inline void arch_spin_lock(arch_spinlock_t *lock)
 {
 	__asm__ __volatile__(
diff --git a/arch/sparc/include/asm/spinlock_64.h b/arch/sparc/include/asm/spinlock_64.h
index 07c9f2e9bf57..923d57f9b79d 100644
--- a/arch/sparc/include/asm/spinlock_64.h
+++ b/arch/sparc/include/asm/spinlock_64.h
@@ -26,11 +26,6 @@
 
 #define arch_spin_is_locked(lp)	((lp)->lock != 0)
 
-static inline void arch_spin_unlock_wait(arch_spinlock_t *lock)
-{
-	smp_cond_load_acquire(&lock->lock, !VAL);
-}
-
 static inline void arch_spin_lock(arch_spinlock_t *lock)
 {
 	unsigned long tmp;
diff --git a/arch/tile/include/asm/spinlock_32.h b/arch/tile/include/asm/spinlock_32.h
index b14b1ba5bf9c..cba8ba9b8da6 100644
--- a/arch/tile/include/asm/spinlock_32.h
+++ b/arch/tile/include/asm/spinlock_32.h
@@ -64,8 +64,6 @@ static inline void arch_spin_unlock(arch_spinlock_t *lock)
 	lock->current_ticket = old_ticket + TICKET_QUANTUM;
 }
 
-void arch_spin_unlock_wait(arch_spinlock_t *lock);
-
 /*
  * Read-write spinlocks, allowing multiple readers
  * but only one writer.
diff --git a/arch/tile/include/asm/spinlock_64.h b/arch/tile/include/asm/spinlock_64.h
index b9718fb4e74a..9a2c2d605752 100644
--- a/arch/tile/include/asm/spinlock_64.h
+++ b/arch/tile/include/asm/spinlock_64.h
@@ -58,8 +58,6 @@ static inline void arch_spin_unlock(arch_spinlock_t *lock)
 	__insn_fetchadd4(&lock->lock, 1U << __ARCH_SPIN_CURRENT_SHIFT);
 }
 
-void arch_spin_unlock_wait(arch_spinlock_t *lock);
-
 void arch_spin_lock_slow(arch_spinlock_t *lock, u32 val);
 
 /* Grab the "next" ticket number and bump it atomically.
diff --git a/arch/tile/lib/spinlock_32.c b/arch/tile/lib/spinlock_32.c
index 076c6cc43113..db9333f2447c 100644
--- a/arch/tile/lib/spinlock_32.c
+++ b/arch/tile/lib/spinlock_32.c
@@ -62,29 +62,6 @@ int arch_spin_trylock(arch_spinlock_t *lock)
 }
 EXPORT_SYMBOL(arch_spin_trylock);
 
-void arch_spin_unlock_wait(arch_spinlock_t *lock)
-{
-	u32 iterations = 0;
-	int curr = READ_ONCE(lock->current_ticket);
-	int next = READ_ONCE(lock->next_ticket);
-
-	/* Return immediately if unlocked. */
-	if (next == curr)
-		return;
-
-	/* Wait until the current locker has released the lock. */
-	do {
-		delay_backoff(iterations++);
-	} while (READ_ONCE(lock->current_ticket) == curr);
-
-	/*
-	 * The TILE architecture doesn't do read speculation; therefore
-	 * a control dependency guarantees a LOAD->{LOAD,STORE} order.
-	 */
-	barrier();
-}
-EXPORT_SYMBOL(arch_spin_unlock_wait);
-
 /*
  * The low byte is always reserved to be the marker for a "tns" operation
  * since the low bit is set to "1" by a tns.  The next seven bits are
diff --git a/arch/tile/lib/spinlock_64.c b/arch/tile/lib/spinlock_64.c
index a4b5b2cbce93..de414c22892f 100644
--- a/arch/tile/lib/spinlock_64.c
+++ b/arch/tile/lib/spinlock_64.c
@@ -62,28 +62,6 @@ int arch_spin_trylock(arch_spinlock_t *lock)
 }
 EXPORT_SYMBOL(arch_spin_trylock);
 
-void arch_spin_unlock_wait(arch_spinlock_t *lock)
-{
-	u32 iterations = 0;
-	u32 val = READ_ONCE(lock->lock);
-	u32 curr = arch_spin_current(val);
-
-	/* Return immediately if unlocked. */
-	if (arch_spin_next(val) == curr)
-		return;
-
-	/* Wait until the current locker has released the lock. */
-	do {
-		delay_backoff(iterations++);
-	} while (arch_spin_current(READ_ONCE(lock->lock)) == curr);
-
-	/*
-	 * The TILE architecture doesn't do read speculation; therefore
-	 * a control dependency guarantees a LOAD->{LOAD,STORE} order.
-	 */
-	barrier();
-}
-EXPORT_SYMBOL(arch_spin_unlock_wait);
 
 /*
  * If the read lock fails due to a writer, we retry periodically
diff --git a/arch/xtensa/include/asm/spinlock.h b/arch/xtensa/include/asm/spinlock.h
index a36221cf6363..3bb49681ee24 100644
--- a/arch/xtensa/include/asm/spinlock.h
+++ b/arch/xtensa/include/asm/spinlock.h
@@ -33,11 +33,6 @@
 
 #define arch_spin_is_locked(x) ((x)->slock != 0)
 
-static inline void arch_spin_unlock_wait(arch_spinlock_t *lock)
-{
-	smp_cond_load_acquire(&lock->slock, !VAL);
-}
-
 #define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock)
 
 static inline void arch_spin_lock(arch_spinlock_t *lock)

^ permalink raw reply related	[flat|nested] 122+ messages in thread

* Re: [PATCH RFC 25/26] tile: Remove spin_unlock_wait() arch-specific definitions
  2017-06-30  0:10     ` Linus Torvalds
@ 2017-06-30  0:24       ` Paul E. McKenney
  0 siblings, 0 replies; 122+ messages in thread
From: Paul E. McKenney @ 2017-06-30  0:24 UTC (permalink / raw)
  To: Linus Torvalds
  Cc: Linux Kernel Mailing List, NetFilter, Network Development,
	Oleg Nesterov, Andrew Morton, Ingo Molnar, Davidlohr Bueso,
	Manfred Spraul, Tejun Heo, Arnd Bergmann, linux-arch,
	Will Deacon, Peter Zijlstra, Alan Stern, Andrea Parri,
	Chris Metcalf

On Thu, Jun 29, 2017 at 05:10:41PM -0700, Linus Torvalds wrote:
> On Thu, Jun 29, 2017 at 5:06 PM, Linus Torvalds
> <torvalds@linux-foundation.org> wrote:
> >
> > Please don't make this one commit fopr every architecture.
> >
> > Once something gets removed, it gets removed. There's no point in
> > "remove it from architecture X". If there are no more users, we're
> > done with it, and making it be 25 patches with the same commit message
> > instead of just one doesn't help anybody.
> 
> Just to clarify: I think the actual *users* are worth doing one by
> one, particularly if there are user-specific explanations of what that
> particular code wanted, and why spin_unlock_wait() doesn't really
> help.

Got it, and I did merge -only- the arch-specific definition removals
into one commit.  Should I also merge the core-code definition removals
into that same commit, or is it OK to remove the core-code definitions
with one commit and the arch-specific definitions with another.

(My guess is that you would prefer I removed -all- definitions with one
commit, including the core-kernel definitions, but at this point I figure
I should just ask.)

> And I think that you actually have those per-user insights by now,
> after looking at the long thread.

One Acked-by thus far, so some progress!

> So I'm not saying "do one patch for the whole series". One patch per
> removal of use is fine - in fact preferred.

Got it.  It allows the developers and maintainers to tell me where my
analysis is wrong, for one thing.  ;-)

> But once there are no actual more users, just remove all the
> architecture definitions in one go, because explaining the same thing
> several times doesn't actually help anything.
> 
> In fact, *if* we end up ever resurrecting that thing, it's good if we
> can resurrect it in one go. Then we can resurrect the one or two users
> that turned out to matter after all and could come up with why some
> particular ordering was ok too.

Understood!

							Thanx, Paul

^ permalink raw reply	[flat|nested] 122+ messages in thread

* Re: [PATCH RFC 08/26] locking: Remove spin_unlock_wait() generic definitions
  2017-06-30  0:01 ` [PATCH RFC 08/26] locking: Remove spin_unlock_wait() generic definitions Paul E. McKenney
@ 2017-06-30  9:19   ` Will Deacon
  2017-06-30 12:38     ` Paul E. McKenney
  0 siblings, 1 reply; 122+ messages in thread
From: Will Deacon @ 2017-06-30  9:19 UTC (permalink / raw)
  To: Paul E. McKenney
  Cc: linux-kernel, netfilter-devel, netdev, oleg, akpm, mingo, dave,
	manfred, tj, arnd, linux-arch, peterz, stern, parri.andrea,
	torvalds

On Thu, Jun 29, 2017 at 05:01:16PM -0700, Paul E. McKenney wrote:
> There is no agreed-upon definition of spin_unlock_wait()'s semantics,
> and it appears that all callers could do just as well with a lock/unlock
> pair.  This commit therefore removes spin_unlock_wait() and related
> definitions from core code.
> 
> Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
> Cc: Arnd Bergmann <arnd@arndb.de>
> Cc: Ingo Molnar <mingo@redhat.com>
> Cc: Will Deacon <will.deacon@arm.com>
> Cc: Peter Zijlstra <peterz@infradead.org>
> Cc: Alan Stern <stern@rowland.harvard.edu>
> Cc: Andrea Parri <parri.andrea@gmail.com>
> Cc: Linus Torvalds <torvalds@linux-foundation.org>
> ---
>  include/asm-generic/qspinlock.h |  14 -----
>  include/linux/spinlock.h        |  31 -----------
>  include/linux/spinlock_up.h     |   6 ---
>  kernel/locking/qspinlock.c      | 117 ----------------------------------------
>  4 files changed, 168 deletions(-)

[...]

> diff --git a/kernel/locking/qspinlock.c b/kernel/locking/qspinlock.c
> index b2caec7315af..64a9051e4c2c 100644
> --- a/kernel/locking/qspinlock.c
> +++ b/kernel/locking/qspinlock.c
> @@ -267,123 +267,6 @@ static __always_inline u32  __pv_wait_head_or_lock(struct qspinlock *lock,
>  #define queued_spin_lock_slowpath	native_queued_spin_lock_slowpath
>  #endif
>  
> -/*
> - * Various notes on spin_is_locked() and spin_unlock_wait(), which are
> - * 'interesting' functions:
> - *
> - * PROBLEM: some architectures have an interesting issue with atomic ACQUIRE
> - * operations in that the ACQUIRE applies to the LOAD _not_ the STORE (ARM64,
> - * PPC). Also qspinlock has a similar issue per construction, the setting of
> - * the locked byte can be unordered acquiring the lock proper.
> - *
> - * This gets to be 'interesting' in the following cases, where the /should/s
> - * end up false because of this issue.
> - *
> - *
> - * CASE 1:
> - *
> - * So the spin_is_locked() correctness issue comes from something like:
> - *
> - *   CPU0				CPU1
> - *
> - *   global_lock();			local_lock(i)
> - *     spin_lock(&G)			  spin_lock(&L[i])
> - *     for (i)				  if (!spin_is_locked(&G)) {
> - *       spin_unlock_wait(&L[i]);	    smp_acquire__after_ctrl_dep();
> - *					    return;
> - *					  }
> - *					  // deal with fail
> - *
> - * Where it is important CPU1 sees G locked or CPU0 sees L[i] locked such
> - * that there is exclusion between the two critical sections.
> - *
> - * The load from spin_is_locked(&G) /should/ be constrained by the ACQUIRE from
> - * spin_lock(&L[i]), and similarly the load(s) from spin_unlock_wait(&L[i])
> - * /should/ be constrained by the ACQUIRE from spin_lock(&G).
> - *
> - * Similarly, later stuff is constrained by the ACQUIRE from CTRL+RMB.

Might be worth keeping this comment about spin_is_locked, since we're not
removing that guy just yet!

Will

^ permalink raw reply	[flat|nested] 122+ messages in thread

* Re: [PATCH RFC 12/26] arm64: Remove spin_unlock_wait() arch-specific definitions
  2017-06-30  0:01 ` [PATCH RFC 12/26] arm64: " Paul E. McKenney
@ 2017-06-30  9:20   ` Will Deacon
  2017-06-30 17:29     ` Paul E. McKenney
  0 siblings, 1 reply; 122+ messages in thread
From: Will Deacon @ 2017-06-30  9:20 UTC (permalink / raw)
  To: Paul E. McKenney
  Cc: linux-kernel, netfilter-devel, netdev, oleg, akpm, mingo, dave,
	manfred, tj, arnd, linux-arch, peterz, stern, parri.andrea,
	torvalds, Catalin Marinas, linux-arm-kernel

On Thu, Jun 29, 2017 at 05:01:20PM -0700, Paul E. McKenney wrote:
> There is no agreed-upon definition of spin_unlock_wait()'s semantics,
> and it appears that all callers could do just as well with a lock/unlock
> pair.  This commit therefore removes the underlying arch-specific
> arch_spin_unlock_wait().
> 
> Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
> Cc: Catalin Marinas <catalin.marinas@arm.com>
> Cc: Will Deacon <will.deacon@arm.com>
> Cc: <linux-arm-kernel@lists.infradead.org>
> Cc: Peter Zijlstra <peterz@infradead.org>
> Cc: Alan Stern <stern@rowland.harvard.edu>
> Cc: Andrea Parri <parri.andrea@gmail.com>
> Cc: Linus Torvalds <torvalds@linux-foundation.org>
> ---
>  arch/arm64/include/asm/spinlock.h | 58 ++++-----------------------------------
>  1 file changed, 5 insertions(+), 53 deletions(-)

I'm going to miss this code.

Acked-by: Will Deacon <will.deacon@arm.com>

Will

^ permalink raw reply	[flat|nested] 122+ messages in thread

* Re: [PATCH RFC 03/26] sched: Replace spin_unlock_wait() with lock/unlock pair
  2017-06-30  0:01 ` [PATCH RFC 03/26] sched: " Paul E. McKenney
@ 2017-06-30 10:31   ` Arnd Bergmann
  2017-06-30 12:35     ` Paul E. McKenney
  0 siblings, 1 reply; 122+ messages in thread
From: Arnd Bergmann @ 2017-06-30 10:31 UTC (permalink / raw)
  To: Paul E. McKenney
  Cc: Linux Kernel Mailing List, netfilter-devel, Networking,
	Oleg Nesterov, Andrew Morton, Ingo Molnar, dave, manfred,
	Tejun Heo, linux-arch, Will Deacon, Peter Zijlstra, Alan Stern,
	parri.andrea, Linus Torvalds

On Fri, Jun 30, 2017 at 2:01 AM, Paul E. McKenney
<paulmck@linux.vnet.ibm.com> wrote:
> There is no agreed-upon definition of spin_unlock_wait()'s semantics,
> and it appears that all callers could do just as well with a lock/unlock
> pair.  This commit therefore replaces the spin_unlock_wait() call in
> do_task_dead() with spin_lock() followed immediately by spin_unlock().
> This should be safe from a performance perspective because the lock is
> this tasks ->pi_lock, and this is called only after the task exits.
>
> diff --git a/kernel/sched/core.c b/kernel/sched/core.c
> index e91138fcde86..6dea3d9728c8 100644
> --- a/kernel/sched/core.c
> +++ b/kernel/sched/core.c
> @@ -3461,7 +3461,8 @@ void __noreturn do_task_dead(void)
>          * is held by try_to_wake_up()
>          */
>         smp_mb();
> -       raw_spin_unlock_wait(&current->pi_lock);
> +       raw_spin_lock(&current->pi_lock);
> +       raw_spin_unlock(&current->pi_lock);

Does the raw_spin_lock()/raw_spin_unlock() imply an smp_mb() or stronger?
Maybe it would be clearer to remove the extra barrier if so.

     Arnd

^ permalink raw reply	[flat|nested] 122+ messages in thread

* Re: [PATCH RFC 02/26] task_work: Replace spin_unlock_wait() with lock/unlock pair
  2017-06-30  0:01 ` [PATCH RFC 02/26] task_work: " Paul E. McKenney
@ 2017-06-30 11:04   ` Oleg Nesterov
  2017-06-30 12:50     ` Paul E. McKenney
  0 siblings, 1 reply; 122+ messages in thread
From: Oleg Nesterov @ 2017-06-30 11:04 UTC (permalink / raw)
  To: Paul E. McKenney
  Cc: linux-kernel, netfilter-devel, netdev, akpm, mingo, dave,
	manfred, tj, arnd, linux-arch, will.deacon, peterz, stern,
	parri.andrea, torvalds

On 06/29, Paul E. McKenney wrote:
>
> --- a/kernel/task_work.c
> +++ b/kernel/task_work.c
> @@ -109,7 +109,8 @@ void task_work_run(void)
>  		 * the first entry == work, cmpxchg(task_works) should
>  		 * fail, but it can play with *work and other entries.
>  		 */
> -		raw_spin_unlock_wait(&task->pi_lock);
> +		raw_spin_lock(&task->pi_lock);
> +		raw_spin_unlock(&task->pi_lock);

Well, bit the you need spin_lock_irq(). And this is one of the reasons
why I personally think unlock_wait have some sense...

Oleg.

^ permalink raw reply	[flat|nested] 122+ messages in thread

* Re: [PATCH RFC 03/26] sched: Replace spin_unlock_wait() with lock/unlock pair
  2017-06-30 10:31   ` Arnd Bergmann
@ 2017-06-30 12:35     ` Paul E. McKenney
  0 siblings, 0 replies; 122+ messages in thread
From: Paul E. McKenney @ 2017-06-30 12:35 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: Linux Kernel Mailing List, netfilter-devel, Networking,
	Oleg Nesterov, Andrew Morton, Ingo Molnar, dave, manfred,
	Tejun Heo, linux-arch, Will Deacon, Peter Zijlstra, Alan Stern,
	parri.andrea, Linus Torvalds

On Fri, Jun 30, 2017 at 12:31:50PM +0200, Arnd Bergmann wrote:
> On Fri, Jun 30, 2017 at 2:01 AM, Paul E. McKenney
> <paulmck@linux.vnet.ibm.com> wrote:
> > There is no agreed-upon definition of spin_unlock_wait()'s semantics,
> > and it appears that all callers could do just as well with a lock/unlock
> > pair.  This commit therefore replaces the spin_unlock_wait() call in
> > do_task_dead() with spin_lock() followed immediately by spin_unlock().
> > This should be safe from a performance perspective because the lock is
> > this tasks ->pi_lock, and this is called only after the task exits.
> >
> > diff --git a/kernel/sched/core.c b/kernel/sched/core.c
> > index e91138fcde86..6dea3d9728c8 100644
> > --- a/kernel/sched/core.c
> > +++ b/kernel/sched/core.c
> > @@ -3461,7 +3461,8 @@ void __noreturn do_task_dead(void)
> >          * is held by try_to_wake_up()
> >          */
> >         smp_mb();
> > -       raw_spin_unlock_wait(&current->pi_lock);
> > +       raw_spin_lock(&current->pi_lock);
> > +       raw_spin_unlock(&current->pi_lock);
> 
> Does the raw_spin_lock()/raw_spin_unlock() imply an smp_mb() or stronger?
> Maybe it would be clearer to remove the extra barrier if so.

No, it does not in general, but it does on most architectures, and
there are ways to allow those architectures to gain the benefit of their
stronger locks.  For example, would this work?  

> >          * is held by try_to_wake_up()
> >          */
> > -       smp_mb();
> > -       raw_spin_unlock_wait(&current->pi_lock);
> > +       smp_mb__before_spinlock();
> > +       raw_spin_lock(&current->pi_lock);
> > +       raw_spin_unlock(&current->pi_lock);

							Thanx, Paul

^ permalink raw reply	[flat|nested] 122+ messages in thread

* Re: [PATCH RFC 08/26] locking: Remove spin_unlock_wait() generic definitions
  2017-06-30  9:19   ` Will Deacon
@ 2017-06-30 12:38     ` Paul E. McKenney
  2017-06-30 13:13       ` Will Deacon
  0 siblings, 1 reply; 122+ messages in thread
From: Paul E. McKenney @ 2017-06-30 12:38 UTC (permalink / raw)
  To: Will Deacon
  Cc: linux-kernel, netfilter-devel, netdev, oleg, akpm, mingo, dave,
	manfred, tj, arnd, linux-arch, peterz, stern, parri.andrea,
	torvalds

On Fri, Jun 30, 2017 at 10:19:29AM +0100, Will Deacon wrote:
> On Thu, Jun 29, 2017 at 05:01:16PM -0700, Paul E. McKenney wrote:
> > There is no agreed-upon definition of spin_unlock_wait()'s semantics,
> > and it appears that all callers could do just as well with a lock/unlock
> > pair.  This commit therefore removes spin_unlock_wait() and related
> > definitions from core code.
> > 
> > Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
> > Cc: Arnd Bergmann <arnd@arndb.de>
> > Cc: Ingo Molnar <mingo@redhat.com>
> > Cc: Will Deacon <will.deacon@arm.com>
> > Cc: Peter Zijlstra <peterz@infradead.org>
> > Cc: Alan Stern <stern@rowland.harvard.edu>
> > Cc: Andrea Parri <parri.andrea@gmail.com>
> > Cc: Linus Torvalds <torvalds@linux-foundation.org>
> > ---
> >  include/asm-generic/qspinlock.h |  14 -----
> >  include/linux/spinlock.h        |  31 -----------
> >  include/linux/spinlock_up.h     |   6 ---
> >  kernel/locking/qspinlock.c      | 117 ----------------------------------------
> >  4 files changed, 168 deletions(-)
> 
> [...]
> 
> > diff --git a/kernel/locking/qspinlock.c b/kernel/locking/qspinlock.c
> > index b2caec7315af..64a9051e4c2c 100644
> > --- a/kernel/locking/qspinlock.c
> > +++ b/kernel/locking/qspinlock.c
> > @@ -267,123 +267,6 @@ static __always_inline u32  __pv_wait_head_or_lock(struct qspinlock *lock,
> >  #define queued_spin_lock_slowpath	native_queued_spin_lock_slowpath
> >  #endif
> >  
> > -/*
> > - * Various notes on spin_is_locked() and spin_unlock_wait(), which are
> > - * 'interesting' functions:
> > - *
> > - * PROBLEM: some architectures have an interesting issue with atomic ACQUIRE
> > - * operations in that the ACQUIRE applies to the LOAD _not_ the STORE (ARM64,
> > - * PPC). Also qspinlock has a similar issue per construction, the setting of
> > - * the locked byte can be unordered acquiring the lock proper.
> > - *
> > - * This gets to be 'interesting' in the following cases, where the /should/s
> > - * end up false because of this issue.
> > - *
> > - *
> > - * CASE 1:
> > - *
> > - * So the spin_is_locked() correctness issue comes from something like:
> > - *
> > - *   CPU0				CPU1
> > - *
> > - *   global_lock();			local_lock(i)
> > - *     spin_lock(&G)			  spin_lock(&L[i])
> > - *     for (i)				  if (!spin_is_locked(&G)) {
> > - *       spin_unlock_wait(&L[i]);	    smp_acquire__after_ctrl_dep();
> > - *					    return;
> > - *					  }
> > - *					  // deal with fail
> > - *
> > - * Where it is important CPU1 sees G locked or CPU0 sees L[i] locked such
> > - * that there is exclusion between the two critical sections.
> > - *
> > - * The load from spin_is_locked(&G) /should/ be constrained by the ACQUIRE from
> > - * spin_lock(&L[i]), and similarly the load(s) from spin_unlock_wait(&L[i])
> > - * /should/ be constrained by the ACQUIRE from spin_lock(&G).
> > - *
> > - * Similarly, later stuff is constrained by the ACQUIRE from CTRL+RMB.
> 
> Might be worth keeping this comment about spin_is_locked, since we're not
> removing that guy just yet!

Ah, all the examples had spin_unlock_wait() in them.  So what I need to
do is to create a spin_unlock_wait()-free example to illustrate the
text starting with "The load from spin_is_locked(", correct?

I also need to check all uses of spin_is_locked().  There might no
longer be any that rely on any particular ordering...

								Thanx, Paul

^ permalink raw reply	[flat|nested] 122+ messages in thread

* Re: [PATCH RFC 02/26] task_work: Replace spin_unlock_wait() with lock/unlock pair
  2017-06-30 11:04   ` Oleg Nesterov
@ 2017-06-30 12:50     ` Paul E. McKenney
  2017-06-30 15:20       ` Oleg Nesterov
  0 siblings, 1 reply; 122+ messages in thread
From: Paul E. McKenney @ 2017-06-30 12:50 UTC (permalink / raw)
  To: Oleg Nesterov
  Cc: linux-kernel, netfilter-devel, netdev, akpm, mingo, dave,
	manfred, tj, arnd, linux-arch, will.deacon, peterz, stern,
	parri.andrea, torvalds

On Fri, Jun 30, 2017 at 01:04:45PM +0200, Oleg Nesterov wrote:
> On 06/29, Paul E. McKenney wrote:
> >
> > --- a/kernel/task_work.c
> > +++ b/kernel/task_work.c
> > @@ -109,7 +109,8 @@ void task_work_run(void)
> >  		 * the first entry == work, cmpxchg(task_works) should
> >  		 * fail, but it can play with *work and other entries.
> >  		 */
> > -		raw_spin_unlock_wait(&task->pi_lock);
> > +		raw_spin_lock(&task->pi_lock);
> > +		raw_spin_unlock(&task->pi_lock);
> 
> Well, bit the you need spin_lock_irq(). And this is one of the reasons
> why I personally think unlock_wait have some sense...

Good catch, and I clearly need to double-check the other commits for
any need to disable interrupts.  Anyway, like this, with the addition
of a flags variable, correct?

> > +		raw_spin_lock_irq(&task->pi_lock);
> > +		raw_spin_unlock_irq(&task->pi_lock);

I agree that the spin_unlock_wait() implementations would avoid the
deadlock with an acquisition from an interrupt handler, while also
avoiding the need to momentarily disable interrupts.  The ->pi_lock is
a per-task lock, so I am assuming (perhaps naively) that contention is
not a problem.  So is the overhead of interrupt disabling likely to be
noticeable here?

							Thanx, Paul

^ permalink raw reply	[flat|nested] 122+ messages in thread

* Re: [PATCH RFC 08/26] locking: Remove spin_unlock_wait() generic definitions
  2017-06-30 12:38     ` Paul E. McKenney
@ 2017-06-30 13:13       ` Will Deacon
  2017-06-30 22:18         ` Paul E. McKenney
  0 siblings, 1 reply; 122+ messages in thread
From: Will Deacon @ 2017-06-30 13:13 UTC (permalink / raw)
  To: Paul E. McKenney
  Cc: linux-kernel, netfilter-devel, netdev, oleg, akpm, mingo, dave,
	manfred, tj, arnd, linux-arch, peterz, stern, parri.andrea,
	torvalds

On Fri, Jun 30, 2017 at 05:38:15AM -0700, Paul E. McKenney wrote:
> On Fri, Jun 30, 2017 at 10:19:29AM +0100, Will Deacon wrote:
> > On Thu, Jun 29, 2017 at 05:01:16PM -0700, Paul E. McKenney wrote:
> > > There is no agreed-upon definition of spin_unlock_wait()'s semantics,
> > > and it appears that all callers could do just as well with a lock/unlock
> > > pair.  This commit therefore removes spin_unlock_wait() and related
> > > definitions from core code.
> > > 
> > > Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
> > > Cc: Arnd Bergmann <arnd@arndb.de>
> > > Cc: Ingo Molnar <mingo@redhat.com>
> > > Cc: Will Deacon <will.deacon@arm.com>
> > > Cc: Peter Zijlstra <peterz@infradead.org>
> > > Cc: Alan Stern <stern@rowland.harvard.edu>
> > > Cc: Andrea Parri <parri.andrea@gmail.com>
> > > Cc: Linus Torvalds <torvalds@linux-foundation.org>
> > > ---
> > >  include/asm-generic/qspinlock.h |  14 -----
> > >  include/linux/spinlock.h        |  31 -----------
> > >  include/linux/spinlock_up.h     |   6 ---
> > >  kernel/locking/qspinlock.c      | 117 ----------------------------------------
> > >  4 files changed, 168 deletions(-)
> > 
> > [...]
> > 
> > > diff --git a/kernel/locking/qspinlock.c b/kernel/locking/qspinlock.c
> > > index b2caec7315af..64a9051e4c2c 100644
> > > --- a/kernel/locking/qspinlock.c
> > > +++ b/kernel/locking/qspinlock.c
> > > @@ -267,123 +267,6 @@ static __always_inline u32  __pv_wait_head_or_lock(struct qspinlock *lock,
> > >  #define queued_spin_lock_slowpath	native_queued_spin_lock_slowpath
> > >  #endif
> > >  
> > > -/*
> > > - * Various notes on spin_is_locked() and spin_unlock_wait(), which are
> > > - * 'interesting' functions:
> > > - *
> > > - * PROBLEM: some architectures have an interesting issue with atomic ACQUIRE
> > > - * operations in that the ACQUIRE applies to the LOAD _not_ the STORE (ARM64,
> > > - * PPC). Also qspinlock has a similar issue per construction, the setting of
> > > - * the locked byte can be unordered acquiring the lock proper.
> > > - *
> > > - * This gets to be 'interesting' in the following cases, where the /should/s
> > > - * end up false because of this issue.
> > > - *
> > > - *
> > > - * CASE 1:
> > > - *
> > > - * So the spin_is_locked() correctness issue comes from something like:
> > > - *
> > > - *   CPU0				CPU1
> > > - *
> > > - *   global_lock();			local_lock(i)
> > > - *     spin_lock(&G)			  spin_lock(&L[i])
> > > - *     for (i)				  if (!spin_is_locked(&G)) {
> > > - *       spin_unlock_wait(&L[i]);	    smp_acquire__after_ctrl_dep();
> > > - *					    return;
> > > - *					  }
> > > - *					  // deal with fail
> > > - *
> > > - * Where it is important CPU1 sees G locked or CPU0 sees L[i] locked such
> > > - * that there is exclusion between the two critical sections.
> > > - *
> > > - * The load from spin_is_locked(&G) /should/ be constrained by the ACQUIRE from
> > > - * spin_lock(&L[i]), and similarly the load(s) from spin_unlock_wait(&L[i])
> > > - * /should/ be constrained by the ACQUIRE from spin_lock(&G).
> > > - *
> > > - * Similarly, later stuff is constrained by the ACQUIRE from CTRL+RMB.
> > 
> > Might be worth keeping this comment about spin_is_locked, since we're not
> > removing that guy just yet!
> 
> Ah, all the examples had spin_unlock_wait() in them.  So what I need to
> do is to create a spin_unlock_wait()-free example to illustrate the
> text starting with "The load from spin_is_locked(", correct?

Yeah, I think so.

> I also need to check all uses of spin_is_locked().  There might no
> longer be any that rely on any particular ordering...

Right. I think we're looking for the "insane case" as per 38b850a73034
(which was apparently used by ipc/sem.c at the time, but no longer).

There's a usage in kernel/debug/debug_core.c, but it doesn't fill me with
joy.

Will

^ permalink raw reply	[flat|nested] 122+ messages in thread

* Re: [PATCH RFC 02/26] task_work: Replace spin_unlock_wait() with lock/unlock pair
  2017-06-30 12:50     ` Paul E. McKenney
@ 2017-06-30 15:20       ` Oleg Nesterov
  2017-06-30 16:16         ` Paul E. McKenney
  0 siblings, 1 reply; 122+ messages in thread
From: Oleg Nesterov @ 2017-06-30 15:20 UTC (permalink / raw)
  To: Paul E. McKenney
  Cc: linux-kernel, netfilter-devel, netdev, akpm, mingo, dave,
	manfred, tj, arnd, linux-arch, will.deacon, peterz, stern,
	parri.andrea, torvalds

On 06/30, Paul E. McKenney wrote:
>
> > > +		raw_spin_lock_irq(&task->pi_lock);
> > > +		raw_spin_unlock_irq(&task->pi_lock);
>
> I agree that the spin_unlock_wait() implementations would avoid the
> deadlock with an acquisition from an interrupt handler, while also
> avoiding the need to momentarily disable interrupts.  The ->pi_lock is
> a per-task lock, so I am assuming (perhaps naively) that contention is
> not a problem.  So is the overhead of interrupt disabling likely to be
> noticeable here?

I do not think the overhead will be noticeable in this particular case.

But I am not sure I understand why do we want to unlock_wait. Yes I agree,
it has some problems, but still...

The code above looks strange for me. If we are going to repeat this pattern
the perhaps we should add a helper for lock+unlock and name it unlock_wait2 ;)

If not, we should probably change this code more:

--- a/kernel/task_work.c
+++ b/kernel/task_work.c
@@ -96,20 +96,16 @@ void task_work_run(void)
 		 * work->func() can do task_work_add(), do not set
 		 * work_exited unless the list is empty.
 		 */
+		raw_spin_lock_irq(&task->pi_lock);
 		do {
 			work = READ_ONCE(task->task_works);
 			head = !work && (task->flags & PF_EXITING) ?
 				&work_exited : NULL;
 		} while (cmpxchg(&task->task_works, work, head) != work);
+		raw_spin_unlock_irq(&task->pi_lock);
 
 		if (!work)
 			break;
-		/*
-		 * Synchronize with task_work_cancel(). It can't remove
-		 * the first entry == work, cmpxchg(task_works) should
-		 * fail, but it can play with *work and other entries.
-		 */
-		raw_spin_unlock_wait(&task->pi_lock);
 
 		do {
 			next = work->next;

performance-wise this is almost the same, and if we do not really care about
overhead we can simplify the code: this way it is obvious that we can't race
with task_work_cancel().

Oleg.

^ permalink raw reply	[flat|nested] 122+ messages in thread

* Re: [PATCH RFC 02/26] task_work: Replace spin_unlock_wait() with lock/unlock pair
  2017-06-30 15:20       ` Oleg Nesterov
@ 2017-06-30 16:16         ` Paul E. McKenney
  2017-06-30 17:21           ` Paul E. McKenney
  2017-06-30 19:21           ` Oleg Nesterov
  0 siblings, 2 replies; 122+ messages in thread
From: Paul E. McKenney @ 2017-06-30 16:16 UTC (permalink / raw)
  To: Oleg Nesterov
  Cc: linux-kernel, netfilter-devel, netdev, akpm, mingo, dave,
	manfred, tj, arnd, linux-arch, will.deacon, peterz, stern,
	parri.andrea, torvalds

On Fri, Jun 30, 2017 at 05:20:10PM +0200, Oleg Nesterov wrote:
> On 06/30, Paul E. McKenney wrote:
> >
> > > > +		raw_spin_lock_irq(&task->pi_lock);
> > > > +		raw_spin_unlock_irq(&task->pi_lock);
> >
> > I agree that the spin_unlock_wait() implementations would avoid the
> > deadlock with an acquisition from an interrupt handler, while also
> > avoiding the need to momentarily disable interrupts.  The ->pi_lock is
> > a per-task lock, so I am assuming (perhaps naively) that contention is
> > not a problem.  So is the overhead of interrupt disabling likely to be
> > noticeable here?
> 
> I do not think the overhead will be noticeable in this particular case.
> 
> But I am not sure I understand why do we want to unlock_wait. Yes I agree,
> it has some problems, but still...
> 
> The code above looks strange for me. If we are going to repeat this pattern
> the perhaps we should add a helper for lock+unlock and name it unlock_wait2 ;)
> 
> If not, we should probably change this code more:

This looks -much- better than my patch!  May I have your Signed-off-by?

							Thanx, Paul

> --- a/kernel/task_work.c
> +++ b/kernel/task_work.c
> @@ -96,20 +96,16 @@ void task_work_run(void)
>  		 * work->func() can do task_work_add(), do not set
>  		 * work_exited unless the list is empty.
>  		 */
> +		raw_spin_lock_irq(&task->pi_lock);
>  		do {
>  			work = READ_ONCE(task->task_works);
>  			head = !work && (task->flags & PF_EXITING) ?
>  				&work_exited : NULL;
>  		} while (cmpxchg(&task->task_works, work, head) != work);
> +		raw_spin_unlock_irq(&task->pi_lock);
> 
>  		if (!work)
>  			break;
> -		/*
> -		 * Synchronize with task_work_cancel(). It can't remove
> -		 * the first entry == work, cmpxchg(task_works) should
> -		 * fail, but it can play with *work and other entries.
> -		 */
> -		raw_spin_unlock_wait(&task->pi_lock);
> 
>  		do {
>  			next = work->next;
> 
> performance-wise this is almost the same, and if we do not really care about
> overhead we can simplify the code: this way it is obvious that we can't race
> with task_work_cancel().
> 
> Oleg.
> 

^ permalink raw reply	[flat|nested] 122+ messages in thread

* Re: [PATCH RFC 02/26] task_work: Replace spin_unlock_wait() with lock/unlock pair
  2017-06-30 16:16         ` Paul E. McKenney
@ 2017-06-30 17:21           ` Paul E. McKenney
  2017-06-30 19:21           ` Oleg Nesterov
  1 sibling, 0 replies; 122+ messages in thread
From: Paul E. McKenney @ 2017-06-30 17:21 UTC (permalink / raw)
  To: Oleg Nesterov
  Cc: linux-kernel, netfilter-devel, netdev, akpm, mingo, dave,
	manfred, tj, arnd, linux-arch, will.deacon, peterz, stern,
	parri.andrea, torvalds

On Fri, Jun 30, 2017 at 09:16:07AM -0700, Paul E. McKenney wrote:
> On Fri, Jun 30, 2017 at 05:20:10PM +0200, Oleg Nesterov wrote:
> > On 06/30, Paul E. McKenney wrote:
> > >
> > > > > +		raw_spin_lock_irq(&task->pi_lock);
> > > > > +		raw_spin_unlock_irq(&task->pi_lock);
> > >
> > > I agree that the spin_unlock_wait() implementations would avoid the
> > > deadlock with an acquisition from an interrupt handler, while also
> > > avoiding the need to momentarily disable interrupts.  The ->pi_lock is
> > > a per-task lock, so I am assuming (perhaps naively) that contention is
> > > not a problem.  So is the overhead of interrupt disabling likely to be
> > > noticeable here?
> > 
> > I do not think the overhead will be noticeable in this particular case.
> > 
> > But I am not sure I understand why do we want to unlock_wait. Yes I agree,
> > it has some problems, but still...

Well, I tried documenting exactly what it did and did not do, which got
an ack from Peter.

	https://marc.info/?l=linux-kernel&m=149575078313105

However, my later pull request spawned a bit of discussion:

	https://marc.info/?l=linux-kernel&m=149730349001044

This discussion led me to propose strengthening spin_unlock_wait()
to act as a lock/unlock pair.  This can be implemented on x86 as
an smp_mb() followed by a read-only spinloop, as shown on branch
spin_unlock_wait.2017.06.23a on my -rcu tree.

Linus was not amused, and said that if we were going to make
spin_unlock_wait() have the semantics of lock+unlock, we should just
open-code that, especially given that there are way more definitions
of spin_unlock_wait() than there are uses.  He also suggested making
spin_unlock_wait() have only acquire semantics (x86 spin loop with
no memory-barrier instructions) and add explicit barriers where
required.

	https://marc.info/?l=linux-kernel&m=149860012913036

I did a series for this which may be found on branch
spin_unlock_wait.2017.06.27a on my -rcu tree.

This approach was not loved by others (see later on the above thread), and
Linus's reply (which reiterated his opposition to lock+unlock semantics)
suggested the possibility of removing spin_unlock_wait() entirely.

	https://marc.info/?l=linux-kernel&m=149869476911620

So I figured, in for a penny, in for a pound, and therefore did the series
that includes this patch.  The most recent update (which does not yet
include your improved version) is on branch spin_unlock_wait.2017.06.30b
of my -rcu tree.

Hey, you asked!  ;-)

							Thanx, Paul

> > The code above looks strange for me. If we are going to repeat this pattern
> > the perhaps we should add a helper for lock+unlock and name it unlock_wait2 ;)
> > 
> > If not, we should probably change this code more:
> 
> This looks -much- better than my patch!  May I have your Signed-off-by?
> 
> 							Thanx, Paul
> 
> > --- a/kernel/task_work.c
> > +++ b/kernel/task_work.c
> > @@ -96,20 +96,16 @@ void task_work_run(void)
> >  		 * work->func() can do task_work_add(), do not set
> >  		 * work_exited unless the list is empty.
> >  		 */
> > +		raw_spin_lock_irq(&task->pi_lock);
> >  		do {
> >  			work = READ_ONCE(task->task_works);
> >  			head = !work && (task->flags & PF_EXITING) ?
> >  				&work_exited : NULL;
> >  		} while (cmpxchg(&task->task_works, work, head) != work);
> > +		raw_spin_unlock_irq(&task->pi_lock);
> > 
> >  		if (!work)
> >  			break;
> > -		/*
> > -		 * Synchronize with task_work_cancel(). It can't remove
> > -		 * the first entry == work, cmpxchg(task_works) should
> > -		 * fail, but it can play with *work and other entries.
> > -		 */
> > -		raw_spin_unlock_wait(&task->pi_lock);
> > 
> >  		do {
> >  			next = work->next;
> > 
> > performance-wise this is almost the same, and if we do not really care about
> > overhead we can simplify the code: this way it is obvious that we can't race
> > with task_work_cancel().
> > 
> > Oleg.
> > 

^ permalink raw reply	[flat|nested] 122+ messages in thread

* Re: [PATCH RFC 12/26] arm64: Remove spin_unlock_wait() arch-specific definitions
  2017-06-30  9:20   ` Will Deacon
@ 2017-06-30 17:29     ` Paul E. McKenney
  0 siblings, 0 replies; 122+ messages in thread
From: Paul E. McKenney @ 2017-06-30 17:29 UTC (permalink / raw)
  To: Will Deacon
  Cc: linux-kernel, netfilter-devel, netdev, oleg, akpm, mingo, dave,
	manfred, tj, arnd, linux-arch, peterz, stern, parri.andrea,
	torvalds, Catalin Marinas, linux-arm-kernel

On Fri, Jun 30, 2017 at 10:20:57AM +0100, Will Deacon wrote:
> On Thu, Jun 29, 2017 at 05:01:20PM -0700, Paul E. McKenney wrote:
> > There is no agreed-upon definition of spin_unlock_wait()'s semantics,
> > and it appears that all callers could do just as well with a lock/unlock
> > pair.  This commit therefore removes the underlying arch-specific
> > arch_spin_unlock_wait().
> > 
> > Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
> > Cc: Catalin Marinas <catalin.marinas@arm.com>
> > Cc: Will Deacon <will.deacon@arm.com>
> > Cc: <linux-arm-kernel@lists.infradead.org>
> > Cc: Peter Zijlstra <peterz@infradead.org>
> > Cc: Alan Stern <stern@rowland.harvard.edu>
> > Cc: Andrea Parri <parri.andrea@gmail.com>
> > Cc: Linus Torvalds <torvalds@linux-foundation.org>
> > ---
> >  arch/arm64/include/asm/spinlock.h | 58 ++++-----------------------------------
> >  1 file changed, 5 insertions(+), 53 deletions(-)
> 
> I'm going to miss this code.

;-) ;-) ;-)

> Acked-by: Will Deacon <will.deacon@arm.com>

Applied, thank you!

							Thanx, Paul

^ permalink raw reply	[flat|nested] 122+ messages in thread

* Re: [PATCH RFC 02/26] task_work: Replace spin_unlock_wait() with lock/unlock pair
  2017-06-30 16:16         ` Paul E. McKenney
  2017-06-30 17:21           ` Paul E. McKenney
@ 2017-06-30 19:21           ` Oleg Nesterov
  2017-06-30 19:50             ` Alan Stern
  2017-06-30 20:02             ` Paul E. McKenney
  1 sibling, 2 replies; 122+ messages in thread
From: Oleg Nesterov @ 2017-06-30 19:21 UTC (permalink / raw)
  To: Paul E. McKenney
  Cc: linux-kernel, netfilter-devel, netdev, akpm, mingo, dave,
	manfred, tj, arnd, linux-arch, will.deacon, peterz, stern,
	parri.andrea, torvalds

On 06/30, Paul E. McKenney wrote:
>
> On Fri, Jun 30, 2017 at 05:20:10PM +0200, Oleg Nesterov wrote:
> >
> > I do not think the overhead will be noticeable in this particular case.
> >
> > But I am not sure I understand why do we want to unlock_wait. Yes I agree,
                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

if it was not clear, I tried to say "why do we want to _remove_ unlock_wait".

> > it has some problems, but still...
> >
> > The code above looks strange for me. If we are going to repeat this pattern
> > the perhaps we should add a helper for lock+unlock and name it unlock_wait2 ;)
> >
> > If not, we should probably change this code more:
>
> This looks -much- better than my patch!  May I have your Signed-off-by?

Only if you promise to replace all RCU flavors with a single simple implementation
based on rwlock ;)

Seriously, of course I won't argue, and it seems that nobody except me likes
this primitive, but to me spin_unlock_wait() looks like synchronize_rcu(() and
sometimes it makes sense.

Including this particular case. task_work_run() is going to flush/destroy the
->task_works list, so it needs to wait until all currently executing "readers"
(task_work_cancel()'s which have started before ->task_works was updated) have
completed.

Oleg.

^ permalink raw reply	[flat|nested] 122+ messages in thread

* Re: [PATCH RFC 02/26] task_work: Replace spin_unlock_wait() with lock/unlock pair
  2017-06-30 19:21           ` Oleg Nesterov
@ 2017-06-30 19:50             ` Alan Stern
  2017-06-30 20:04               ` Paul E. McKenney
  2017-06-30 20:02             ` Paul E. McKenney
  1 sibling, 1 reply; 122+ messages in thread
From: Alan Stern @ 2017-06-30 19:50 UTC (permalink / raw)
  To: Oleg Nesterov
  Cc: Paul E. McKenney, linux-kernel, netfilter-devel, netdev, akpm,
	mingo, dave, manfred, tj, arnd, linux-arch, will.deacon, peterz,
	parri.andrea, torvalds

On Fri, 30 Jun 2017, Oleg Nesterov wrote:

> On 06/30, Paul E. McKenney wrote:
> >
> > On Fri, Jun 30, 2017 at 05:20:10PM +0200, Oleg Nesterov wrote:
> > >
> > > I do not think the overhead will be noticeable in this particular case.
> > >
> > > But I am not sure I understand why do we want to unlock_wait. Yes I agree,
>                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> 
> if it was not clear, I tried to say "why do we want to _remove_ unlock_wait".
> 
> > > it has some problems, but still...
> > >
> > > The code above looks strange for me. If we are going to repeat this pattern
> > > the perhaps we should add a helper for lock+unlock and name it unlock_wait2 ;)
> > >
> > > If not, we should probably change this code more:
> >
> > This looks -much- better than my patch!  May I have your Signed-off-by?
> 
> Only if you promise to replace all RCU flavors with a single simple implementation
> based on rwlock ;)
> 
> Seriously, of course I won't argue, and it seems that nobody except me likes
> this primitive, but to me spin_unlock_wait() looks like synchronize_rcu(() and
> sometimes it makes sense.

If it looks like synchronize_rcu(), why not actually use 
synchronize_rcu()?

Alan Stern

> Including this particular case. task_work_run() is going to flush/destroy the
> ->task_works list, so it needs to wait until all currently executing "readers"
> (task_work_cancel()'s which have started before ->task_works was updated) have
> completed.

^ permalink raw reply	[flat|nested] 122+ messages in thread

* Re: [PATCH RFC 02/26] task_work: Replace spin_unlock_wait() with lock/unlock pair
  2017-06-30 19:21           ` Oleg Nesterov
  2017-06-30 19:50             ` Alan Stern
@ 2017-06-30 20:02             ` Paul E. McKenney
  2017-06-30 20:19               ` Paul E. McKenney
  1 sibling, 1 reply; 122+ messages in thread
From: Paul E. McKenney @ 2017-06-30 20:02 UTC (permalink / raw)
  To: Oleg Nesterov
  Cc: linux-kernel, netfilter-devel, netdev, akpm, mingo, dave,
	manfred, tj, arnd, linux-arch, will.deacon, peterz, stern,
	parri.andrea, torvalds

On Fri, Jun 30, 2017 at 09:21:23PM +0200, Oleg Nesterov wrote:
> On 06/30, Paul E. McKenney wrote:
> >
> > On Fri, Jun 30, 2017 at 05:20:10PM +0200, Oleg Nesterov wrote:
> > >
> > > I do not think the overhead will be noticeable in this particular case.
> > >
> > > But I am not sure I understand why do we want to unlock_wait. Yes I agree,
>                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> 
> if it was not clear, I tried to say "why do we want to _remove_ unlock_wait".
> 
> > > it has some problems, but still...
> > >
> > > The code above looks strange for me. If we are going to repeat this pattern
> > > the perhaps we should add a helper for lock+unlock and name it unlock_wait2 ;)
> > >
> > > If not, we should probably change this code more:
> >
> > This looks -much- better than my patch!  May I have your Signed-off-by?
> 
> Only if you promise to replace all RCU flavors with a single simple implementation
> based on rwlock ;)

;-) ;-) ;-)

Here you go:

https://github.com/pramalhe/ConcurrencyFreaks/blob/master/papers/poormanurcu-2015.pdf

> Seriously, of course I won't argue, and it seems that nobody except me likes
> this primitive, but to me spin_unlock_wait() looks like synchronize_rcu(() and
> sometimes it makes sense.

Well, that analogy was what led me to propose that its semantics be
defined as spin_lock() immediately followed by spin_unlock().  But that
didn't go over well.

> Including this particular case. task_work_run() is going to flush/destroy the
> ->task_works list, so it needs to wait until all currently executing "readers"
> (task_work_cancel()'s which have started before ->task_works was updated) have
> completed.

Understood!

							Thanx, Paul

^ permalink raw reply	[flat|nested] 122+ messages in thread

* Re: [PATCH RFC 02/26] task_work: Replace spin_unlock_wait() with lock/unlock pair
  2017-06-30 19:50             ` Alan Stern
@ 2017-06-30 20:04               ` Paul E. McKenney
  0 siblings, 0 replies; 122+ messages in thread
From: Paul E. McKenney @ 2017-06-30 20:04 UTC (permalink / raw)
  To: Alan Stern
  Cc: Oleg Nesterov, linux-kernel, netfilter-devel, netdev, akpm,
	mingo, dave, manfred, tj, arnd, linux-arch, will.deacon, peterz,
	parri.andrea, torvalds

On Fri, Jun 30, 2017 at 03:50:33PM -0400, Alan Stern wrote:
> On Fri, 30 Jun 2017, Oleg Nesterov wrote:
> 
> > On 06/30, Paul E. McKenney wrote:
> > >
> > > On Fri, Jun 30, 2017 at 05:20:10PM +0200, Oleg Nesterov wrote:
> > > >
> > > > I do not think the overhead will be noticeable in this particular case.
> > > >
> > > > But I am not sure I understand why do we want to unlock_wait. Yes I agree,
> >                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> > 
> > if it was not clear, I tried to say "why do we want to _remove_ unlock_wait".
> > 
> > > > it has some problems, but still...
> > > >
> > > > The code above looks strange for me. If we are going to repeat this pattern
> > > > the perhaps we should add a helper for lock+unlock and name it unlock_wait2 ;)
> > > >
> > > > If not, we should probably change this code more:
> > >
> > > This looks -much- better than my patch!  May I have your Signed-off-by?
> > 
> > Only if you promise to replace all RCU flavors with a single simple implementation
> > based on rwlock ;)
> > 
> > Seriously, of course I won't argue, and it seems that nobody except me likes
> > this primitive, but to me spin_unlock_wait() looks like synchronize_rcu(() and
> > sometimes it makes sense.
> 
> If it looks like synchronize_rcu(), why not actually use 
> synchronize_rcu()?

My guess is that the latencies of synchronize_rcu() don't suit his needs.
When the lock is not held, spin_unlock_wait() is quite fast, even
compared to expedited grace periods.

							Thanx, Paul

> Alan Stern
> 
> > Including this particular case. task_work_run() is going to flush/destroy the
> > ->task_works list, so it needs to wait until all currently executing "readers"
> > (task_work_cancel()'s which have started before ->task_works was updated) have
> > completed.
> 

^ permalink raw reply	[flat|nested] 122+ messages in thread

* Re: [PATCH RFC 02/26] task_work: Replace spin_unlock_wait() with lock/unlock pair
  2017-06-30 20:02             ` Paul E. McKenney
@ 2017-06-30 20:19               ` Paul E. McKenney
  0 siblings, 0 replies; 122+ messages in thread
From: Paul E. McKenney @ 2017-06-30 20:19 UTC (permalink / raw)
  To: Oleg Nesterov
  Cc: linux-kernel, netfilter-devel, netdev, akpm, mingo, dave,
	manfred, tj, arnd, linux-arch, will.deacon, peterz, stern,
	parri.andrea, torvalds

On Fri, Jun 30, 2017 at 01:02:48PM -0700, Paul E. McKenney wrote:
> On Fri, Jun 30, 2017 at 09:21:23PM +0200, Oleg Nesterov wrote:
> > On 06/30, Paul E. McKenney wrote:
> > >
> > > On Fri, Jun 30, 2017 at 05:20:10PM +0200, Oleg Nesterov wrote:
> > > >
> > > > I do not think the overhead will be noticeable in this particular case.
> > > >
> > > > But I am not sure I understand why do we want to unlock_wait. Yes I agree,
> >                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> > 
> > if it was not clear, I tried to say "why do we want to _remove_ unlock_wait".
> > 
> > > > it has some problems, but still...
> > > >
> > > > The code above looks strange for me. If we are going to repeat this pattern
> > > > the perhaps we should add a helper for lock+unlock and name it unlock_wait2 ;)
> > > >
> > > > If not, we should probably change this code more:
> > >
> > > This looks -much- better than my patch!  May I have your Signed-off-by?
> > 
> > Only if you promise to replace all RCU flavors with a single simple implementation
> > based on rwlock ;)
> 
> ;-) ;-) ;-)
> 
> Here you go:
> 
> https://github.com/pramalhe/ConcurrencyFreaks/blob/master/papers/poormanurcu-2015.pdf
> 
> > Seriously, of course I won't argue, and it seems that nobody except me likes
> > this primitive, but to me spin_unlock_wait() looks like synchronize_rcu(() and
> > sometimes it makes sense.
> 
> Well, that analogy was what led me to propose that its semantics be
> defined as spin_lock() immediately followed by spin_unlock().  But that
> didn't go over well.
> 
> > Including this particular case. task_work_run() is going to flush/destroy the
> > ->task_works list, so it needs to wait until all currently executing "readers"
> > (task_work_cancel()'s which have started before ->task_works was updated) have
> > completed.
> 
> Understood!

And please see below for the resulting patch and commit log.  Please let
me know if I broke something.

							Thanx, Paul

------------------------------------------------------------------------

commit 6c0801c9ab19fc2f4c1e2436eb1b72e0af9a317b
Author: Oleg Nesterov <oleg@redhat.com>
Date:   Fri Jun 30 13:13:59 2017 -0700

    task_work: Replace spin_unlock_wait() with lock/unlock pair
    
    There is no agreed-upon definition of spin_unlock_wait()'s semantics,
    and it appears that all callers could do just as well with a lock/unlock
    pair.  This commit therefore replaces the spin_unlock_wait() call in
    task_work_run() with a spin_lock_irq() and a spin_unlock_irq() aruond
    the cmpxchg() dequeue loop.  This should be safe from a performance
    perspective because ->pi_lock is local to the task and because calls to
    the other side of the race, task_work_cancel(), should be rare.
    
    Signed-off-by: Oleg Nesterov <oleg@redhat.com>
    Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>

diff --git a/kernel/task_work.c b/kernel/task_work.c
index d513051fcca2..836a72a66fba 100644
--- a/kernel/task_work.c
+++ b/kernel/task_work.c
@@ -96,20 +96,16 @@ void task_work_run(void)
 		 * work->func() can do task_work_add(), do not set
 		 * work_exited unless the list is empty.
 		 */
+		raw_spin_lock_irq(&task->pi_lock);
 		do {
 			work = READ_ONCE(task->task_works);
 			head = !work && (task->flags & PF_EXITING) ?
 				&work_exited : NULL;
 		} while (cmpxchg(&task->task_works, work, head) != work);
+		raw_spin_unlock_irq(&task->pi_lock);
 
 		if (!work)
 			break;
-		/*
-		 * Synchronize with task_work_cancel(). It can't remove
-		 * the first entry == work, cmpxchg(task_works) should
-		 * fail, but it can play with *work and other entries.
-		 */
-		raw_spin_unlock_wait(&task->pi_lock);
 
 		do {
 			next = work->next;

^ permalink raw reply related	[flat|nested] 122+ messages in thread

* Re: [PATCH RFC 08/26] locking: Remove spin_unlock_wait() generic definitions
  2017-06-30 13:13       ` Will Deacon
@ 2017-06-30 22:18         ` Paul E. McKenney
  2017-07-03 13:15           ` Will Deacon
  0 siblings, 1 reply; 122+ messages in thread
From: Paul E. McKenney @ 2017-06-30 22:18 UTC (permalink / raw)
  To: Will Deacon
  Cc: linux-kernel, netfilter-devel, netdev, oleg, akpm, mingo, dave,
	manfred, tj, arnd, linux-arch, peterz, stern, parri.andrea,
	torvalds

On Fri, Jun 30, 2017 at 02:13:39PM +0100, Will Deacon wrote:
> On Fri, Jun 30, 2017 at 05:38:15AM -0700, Paul E. McKenney wrote:
> > On Fri, Jun 30, 2017 at 10:19:29AM +0100, Will Deacon wrote:
> > > On Thu, Jun 29, 2017 at 05:01:16PM -0700, Paul E. McKenney wrote:
> > > > There is no agreed-upon definition of spin_unlock_wait()'s semantics,
> > > > and it appears that all callers could do just as well with a lock/unlock
> > > > pair.  This commit therefore removes spin_unlock_wait() and related
> > > > definitions from core code.
> > > > 
> > > > Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
> > > > Cc: Arnd Bergmann <arnd@arndb.de>
> > > > Cc: Ingo Molnar <mingo@redhat.com>
> > > > Cc: Will Deacon <will.deacon@arm.com>
> > > > Cc: Peter Zijlstra <peterz@infradead.org>
> > > > Cc: Alan Stern <stern@rowland.harvard.edu>
> > > > Cc: Andrea Parri <parri.andrea@gmail.com>
> > > > Cc: Linus Torvalds <torvalds@linux-foundation.org>
> > > > ---
> > > >  include/asm-generic/qspinlock.h |  14 -----
> > > >  include/linux/spinlock.h        |  31 -----------
> > > >  include/linux/spinlock_up.h     |   6 ---
> > > >  kernel/locking/qspinlock.c      | 117 ----------------------------------------
> > > >  4 files changed, 168 deletions(-)
> > > 
> > > [...]
> > > 
> > > > diff --git a/kernel/locking/qspinlock.c b/kernel/locking/qspinlock.c
> > > > index b2caec7315af..64a9051e4c2c 100644
> > > > --- a/kernel/locking/qspinlock.c
> > > > +++ b/kernel/locking/qspinlock.c
> > > > @@ -267,123 +267,6 @@ static __always_inline u32  __pv_wait_head_or_lock(struct qspinlock *lock,
> > > >  #define queued_spin_lock_slowpath	native_queued_spin_lock_slowpath
> > > >  #endif
> > > >  
> > > > -/*
> > > > - * Various notes on spin_is_locked() and spin_unlock_wait(), which are
> > > > - * 'interesting' functions:
> > > > - *
> > > > - * PROBLEM: some architectures have an interesting issue with atomic ACQUIRE
> > > > - * operations in that the ACQUIRE applies to the LOAD _not_ the STORE (ARM64,
> > > > - * PPC). Also qspinlock has a similar issue per construction, the setting of
> > > > - * the locked byte can be unordered acquiring the lock proper.
> > > > - *
> > > > - * This gets to be 'interesting' in the following cases, where the /should/s
> > > > - * end up false because of this issue.
> > > > - *
> > > > - *
> > > > - * CASE 1:
> > > > - *
> > > > - * So the spin_is_locked() correctness issue comes from something like:
> > > > - *
> > > > - *   CPU0				CPU1
> > > > - *
> > > > - *   global_lock();			local_lock(i)
> > > > - *     spin_lock(&G)			  spin_lock(&L[i])
> > > > - *     for (i)				  if (!spin_is_locked(&G)) {
> > > > - *       spin_unlock_wait(&L[i]);	    smp_acquire__after_ctrl_dep();
> > > > - *					    return;
> > > > - *					  }
> > > > - *					  // deal with fail
> > > > - *
> > > > - * Where it is important CPU1 sees G locked or CPU0 sees L[i] locked such
> > > > - * that there is exclusion between the two critical sections.
> > > > - *
> > > > - * The load from spin_is_locked(&G) /should/ be constrained by the ACQUIRE from
> > > > - * spin_lock(&L[i]), and similarly the load(s) from spin_unlock_wait(&L[i])
> > > > - * /should/ be constrained by the ACQUIRE from spin_lock(&G).
> > > > - *
> > > > - * Similarly, later stuff is constrained by the ACQUIRE from CTRL+RMB.
> > > 
> > > Might be worth keeping this comment about spin_is_locked, since we're not
> > > removing that guy just yet!
> > 
> > Ah, all the examples had spin_unlock_wait() in them.  So what I need to
> > do is to create a spin_unlock_wait()-free example to illustrate the
> > text starting with "The load from spin_is_locked(", correct?
> 
> Yeah, I think so.
> 
> > I also need to check all uses of spin_is_locked().  There might no
> > longer be any that rely on any particular ordering...
> 
> Right. I think we're looking for the "insane case" as per 38b850a73034
> (which was apparently used by ipc/sem.c at the time, but no longer).
> 
> There's a usage in kernel/debug/debug_core.c, but it doesn't fill me with
> joy.

That is indeed an interesting one...  But my first round will be what
semantics the implementations seem to provide:

Acquire courtesy of TSO: s390, sparc, x86.
Acquire: ia64 (in reality fully ordered).
Control dependency: alpha, arc, arm, blackfin, hexagon, m32r, mn10300, tile,
	xtensa.
Control dependency plus leading full barrier: arm64, powerpc.
UP-only: c6x, cris, frv, h8300, m68k, microblaze nios2, openrisc, um, unicore32.

Special cases:
	metag: Acquire if !CONFIG_METAG_SMP_WRITE_REORDERING.
	       Otherwise control dependency?
	mips: Control dependency, acquire if CONFIG_CPU_CAVIUM_OCTEON.
	parisc: Acquire courtesy of TSO, but why barrier in smp_load_acquire?
	sh: Acquire if one of SH4A, SH5, or J2, otherwise acquire?  UP-only?

Are these correct, or am I missing something with any of them?

							Thanx, Paul

^ permalink raw reply	[flat|nested] 122+ messages in thread

* Re: [PATCH RFC 06/26] ipc: Replace spin_unlock_wait() with lock/unlock pair
       [not found] ` <1498780894-8253-6-git-send-email-paulmck@linux.vnet.ibm.com>
@ 2017-07-01 19:23   ` Manfred Spraul
  2017-07-02  3:16     ` Paul E. McKenney
  0 siblings, 1 reply; 122+ messages in thread
From: Manfred Spraul @ 2017-07-01 19:23 UTC (permalink / raw)
  To: Paul E. McKenney, linux-kernel
  Cc: netfilter-devel, netdev, oleg, akpm, mingo, dave, tj, arnd,
	linux-arch, will.deacon, peterz, stern, parri.andrea, torvalds

On 06/30/2017 02:01 AM, Paul E. McKenney wrote:
> There is no agreed-upon definition of spin_unlock_wait()'s semantics,
> and it appears that all callers could do just as well with a lock/unlock
> pair.  This commit therefore replaces the spin_unlock_wait() call in
> exit_sem() with spin_lock() followed immediately by spin_unlock().
> This should be safe from a performance perspective because exit_sem()
> is rarely invoked in production.
>
> Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
> Cc: Andrew Morton <akpm@linux-foundation.org>
> Cc: Davidlohr Bueso <dave@stgolabs.net>
> Cc: Manfred Spraul <manfred@colorfullife.com>
> Cc: Will Deacon <will.deacon@arm.com>
> Cc: Peter Zijlstra <peterz@infradead.org>
> Cc: Alan Stern <stern@rowland.harvard.edu>
> Cc: Andrea Parri <parri.andrea@gmail.com>
> Cc: Linus Torvalds <torvalds@linux-foundation.org>
Acked-by: Manfred Spraul <manfred@colorfullife.com>
> ---
>   ipc/sem.c | 3 ++-
>   1 file changed, 2 insertions(+), 1 deletion(-)
>
> diff --git a/ipc/sem.c b/ipc/sem.c
> index 947dc2348271..e88d0749a929 100644
> --- a/ipc/sem.c
> +++ b/ipc/sem.c
> @@ -2096,7 +2096,8 @@ void exit_sem(struct task_struct *tsk)
>   			 * possibility where we exit while freeary() didn't
>   			 * finish unlocking sem_undo_list.
>   			 */
> -			spin_unlock_wait(&ulp->lock);
> +			spin_lock(&ulp->lock);
> +			spin_unlock(&ulp->lock);
>   			rcu_read_unlock();
>   			break;
>   		}

^ permalink raw reply	[flat|nested] 122+ messages in thread

* Re: [PATCH RFC 01/26] netfilter: Replace spin_unlock_wait() with lock/unlock pair
       [not found]   ` <a6642feb-2f3a-980f-5ed6-2deb79563e6b@colorfullife.com>
@ 2017-07-02  2:00     ` Paul E. McKenney
  2017-07-03 14:39     ` Alan Stern
  1 sibling, 0 replies; 122+ messages in thread
From: Paul E. McKenney @ 2017-07-02  2:00 UTC (permalink / raw)
  To: Manfred Spraul
  Cc: linux-kernel, netfilter-devel, netdev, oleg, akpm, mingo, dave,
	tj, arnd, linux-arch, will.deacon, peterz, stern, parri.andrea,
	torvalds, Pablo Neira Ayuso, Jozsef Kadlecsik, Florian Westphal,
	David S. Miller, coreteam

On Sat, Jul 01, 2017 at 09:44:12PM +0200, Manfred Spraul wrote:
> Hi Paul,
> 
> On 06/30/2017 02:01 AM, Paul E. McKenney wrote:
> >There is no agreed-upon definition of spin_unlock_wait()'s semantics,
> >and it appears that all callers could do just as well with a lock/unlock
> >pair.  This commit therefore replaces the spin_unlock_wait() calls
> >in nf_conntrack_lock() and nf_conntrack_all_lock() with spin_lock()
> >followed immediately by spin_unlock().  These functions do not appear
> >to be invoked on any fastpaths.
> >
> >Signed-off-by: Paul E. McKenney<paulmck@linux.vnet.ibm.com>
> >Cc: Pablo Neira Ayuso<pablo@netfilter.org>
> >Cc: Jozsef Kadlecsik<kadlec@blackhole.kfki.hu>
> >Cc: Florian Westphal<fw@strlen.de>
> >Cc: "David S. Miller"<davem@davemloft.net>
> >Cc:<netfilter-devel@vger.kernel.org>
> >Cc:<coreteam@netfilter.org>
> >Cc:<netdev@vger.kernel.org>
> >Cc: Will Deacon<will.deacon@arm.com>
> >Cc: Peter Zijlstra<peterz@infradead.org>
> >Cc: Alan Stern<stern@rowland.harvard.edu>
> >Cc: Andrea Parri<parri.andrea@gmail.com>
> >Cc: Linus Torvalds<torvalds@linux-foundation.org>
> >---
> >  net/netfilter/nf_conntrack_core.c | 26 ++++++++------------------
> >  1 file changed, 8 insertions(+), 18 deletions(-)
> >
> >diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c
> >index e847dbaa0c6b..9f997859d160 100644
> >--- a/net/netfilter/nf_conntrack_core.c
> >+++ b/net/netfilter/nf_conntrack_core.c
> >@@ -99,15 +99,11 @@ void nf_conntrack_lock(spinlock_t *lock) __acquires(lock)
> >  	spin_lock(lock);
> >  	while (unlikely(nf_conntrack_locks_all)) {
> I think here an ACQUIRE is missing.
> >  		spin_unlock(lock);
> >-
> >-		/*
> >-		 * Order the 'nf_conntrack_locks_all' load vs. the
> >-		 * spin_unlock_wait() loads below, to ensure
> >-		 * that 'nf_conntrack_locks_all_lock' is indeed held:
> >-		 */
> >-		smp_rmb(); /* spin_lock(&nf_conntrack_locks_all_lock) */
> >-		spin_unlock_wait(&nf_conntrack_locks_all_lock);
> >+		/* Wait for nf_conntrack_locks_all_lock holder to release ... */
> >+		spin_lock(&nf_conntrack_locks_all_lock);
> >+		spin_unlock(&nf_conntrack_locks_all_lock);
> >  		spin_lock(lock);
> >+		/* ... and retry. */
> >  	}
> >  }
> As far as I see, nf_conntrack_locks[] nests inside
> nf_conntrack_lock_all_lock.
> So
>    spin_lock(&nf_conntrack_locks_all_lock);
>    spin_lock(lock);
>    spin_unlock(&nf_conntrack_locks_all_lock);
> 
> can replace the retry logic.
> 
> Correct? Then what about the attached patch?

At first glance, it looks correct to me, thank you!  I have replaced my
patch with this one for testing and further review.

							Thanx, Paul

> --
>     Manfred
> 
> 

> >From 453e7a77f3756d939c754031b092cbdfbd149559 Mon Sep 17 00:00:00 2001
> From: Manfred Spraul <manfred@colorfullife.com>
> Date: Sun, 21 Aug 2016 07:17:55 +0200
> Subject: [PATCH] net/netfilter/nf_conntrack_core: Fix net_conntrack_lock()
> 
> As we want to remove spin_unlock_wait() and replace it with explicit
> spin_lock()/spin_unlock() calls, we can use this to simplify the
> locking.
> 
> In addition:
> - Reading nf_conntrack_locks_all needs ACQUIRE memory ordering.
> - The new code avoids the backwards loop.
> 
> Only slightly tested, I did not manage to trigger calls to
> nf_conntrack_all_lock().
> 
> Fixes: b16c29191dc8
> Signed-off-by: Manfred Spraul <manfred@colorfullife.com>
> Cc: <stable@vger.kernel.org>
> Cc: Sasha Levin <sasha.levin@oracle.com>
> Cc: Pablo Neira Ayuso <pablo@netfilter.org>
> Cc: netfilter-devel@vger.kernel.org
> ---
>  net/netfilter/nf_conntrack_core.c | 44 +++++++++++++++++++++------------------
>  1 file changed, 24 insertions(+), 20 deletions(-)
> 
> diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c
> index e847dba..1193565 100644
> --- a/net/netfilter/nf_conntrack_core.c
> +++ b/net/netfilter/nf_conntrack_core.c
> @@ -96,19 +96,24 @@ static struct conntrack_gc_work conntrack_gc_work;
> 
>  void nf_conntrack_lock(spinlock_t *lock) __acquires(lock)
>  {
> +	/* 1) Acquire the lock */
>  	spin_lock(lock);
> -	while (unlikely(nf_conntrack_locks_all)) {
> -		spin_unlock(lock);
> 
> -		/*
> -		 * Order the 'nf_conntrack_locks_all' load vs. the
> -		 * spin_unlock_wait() loads below, to ensure
> -		 * that 'nf_conntrack_locks_all_lock' is indeed held:
> -		 */
> -		smp_rmb(); /* spin_lock(&nf_conntrack_locks_all_lock) */
> -		spin_unlock_wait(&nf_conntrack_locks_all_lock);
> -		spin_lock(lock);
> -	}
> +	/* 2) read nf_conntrack_locks_all, with ACQUIRE semantics */
> +	if (likely(smp_load_acquire(&nf_conntrack_locks_all) == false))
> +		return;
> +
> +	/* fast path failed, unlock */
> +	spin_unlock(lock);
> +
> +	/* Slow path 1) get global lock */
> +	spin_lock(&nf_conntrack_locks_all_lock);
> +
> +	/* Slow path 2) get the lock we want */
> +	spin_lock(lock);
> +
> +	/* Slow path 3) release the global lock */
> +	spin_unlock(&nf_conntrack_locks_all_lock);
>  }
>  EXPORT_SYMBOL_GPL(nf_conntrack_lock);
> 
> @@ -149,18 +154,17 @@ static void nf_conntrack_all_lock(void)
>  	int i;
> 
>  	spin_lock(&nf_conntrack_locks_all_lock);
> -	nf_conntrack_locks_all = true;
> 
> -	/*
> -	 * Order the above store of 'nf_conntrack_locks_all' against
> -	 * the spin_unlock_wait() loads below, such that if
> -	 * nf_conntrack_lock() observes 'nf_conntrack_locks_all'
> -	 * we must observe nf_conntrack_locks[] held:
> -	 */
> -	smp_mb(); /* spin_lock(&nf_conntrack_locks_all_lock) */
> +	nf_conntrack_locks_all = true;
> 
>  	for (i = 0; i < CONNTRACK_LOCKS; i++) {
> -		spin_unlock_wait(&nf_conntrack_locks[i]);
> +		spin_lock(&nf_conntrack_locks[i]);
> +
> +		/* This spin_unlock provides the "release" to ensure that
> +		 * nf_conntrack_locks_all==true is visible to everyone that
> +		 * acquired spin_lock(&nf_conntrack_locks[]).
> +		 */
> +		spin_unlock(&nf_conntrack_locks[i]);
>  	}
>  }
> 
> -- 
> 2.9.4
> 

^ permalink raw reply	[flat|nested] 122+ messages in thread

* Re: [PATCH RFC 06/26] ipc: Replace spin_unlock_wait() with lock/unlock pair
  2017-07-01 19:23   ` [PATCH RFC 06/26] ipc: Replace spin_unlock_wait() with lock/unlock pair Manfred Spraul
@ 2017-07-02  3:16     ` Paul E. McKenney
  0 siblings, 0 replies; 122+ messages in thread
From: Paul E. McKenney @ 2017-07-02  3:16 UTC (permalink / raw)
  To: Manfred Spraul
  Cc: linux-kernel, netfilter-devel, netdev, oleg, akpm, mingo, dave,
	tj, arnd, linux-arch, will.deacon, peterz, stern, parri.andrea,
	torvalds

On Sat, Jul 01, 2017 at 09:23:03PM +0200, Manfred Spraul wrote:
> On 06/30/2017 02:01 AM, Paul E. McKenney wrote:
> >There is no agreed-upon definition of spin_unlock_wait()'s semantics,
> >and it appears that all callers could do just as well with a lock/unlock
> >pair.  This commit therefore replaces the spin_unlock_wait() call in
> >exit_sem() with spin_lock() followed immediately by spin_unlock().
> >This should be safe from a performance perspective because exit_sem()
> >is rarely invoked in production.
> >
> >Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
> >Cc: Andrew Morton <akpm@linux-foundation.org>
> >Cc: Davidlohr Bueso <dave@stgolabs.net>
> >Cc: Manfred Spraul <manfred@colorfullife.com>
> >Cc: Will Deacon <will.deacon@arm.com>
> >Cc: Peter Zijlstra <peterz@infradead.org>
> >Cc: Alan Stern <stern@rowland.harvard.edu>
> >Cc: Andrea Parri <parri.andrea@gmail.com>
> >Cc: Linus Torvalds <torvalds@linux-foundation.org>
> Acked-by: Manfred Spraul <manfred@colorfullife.com>

Applied, thank you!

							Thanx, Paul

> >---
> >  ipc/sem.c | 3 ++-
> >  1 file changed, 2 insertions(+), 1 deletion(-)
> >
> >diff --git a/ipc/sem.c b/ipc/sem.c
> >index 947dc2348271..e88d0749a929 100644
> >--- a/ipc/sem.c
> >+++ b/ipc/sem.c
> >@@ -2096,7 +2096,8 @@ void exit_sem(struct task_struct *tsk)
> >  			 * possibility where we exit while freeary() didn't
> >  			 * finish unlocking sem_undo_list.
> >  			 */
> >-			spin_unlock_wait(&ulp->lock);
> >+			spin_lock(&ulp->lock);
> >+			spin_unlock(&ulp->lock);
> >  			rcu_read_unlock();
> >  			break;
> >  		}
> 
> 

^ permalink raw reply	[flat|nested] 122+ messages in thread

* Re: [PATCH RFC 21/26] powerpc: Remove spin_unlock_wait() arch-specific definitions
  2017-06-30  0:01 ` [PATCH RFC 21/26] powerpc: " Paul E. McKenney
@ 2017-07-02  3:58   ` Boqun Feng
  2017-07-05 23:57     ` Paul E. McKenney
  0 siblings, 1 reply; 122+ messages in thread
From: Boqun Feng @ 2017-07-02  3:58 UTC (permalink / raw)
  To: Paul E. McKenney
  Cc: linux-kernel, linux-arch, parri.andrea, dave, manfred, arnd,
	peterz, netdev, linuxppc-dev, will.deacon, oleg, mingo,
	netfilter-devel, tj, stern, akpm, torvalds, Paul Mackerras

[-- Attachment #1: Type: text/plain, Size: 2192 bytes --]

On Thu, Jun 29, 2017 at 05:01:29PM -0700, Paul E. McKenney wrote:
> There is no agreed-upon definition of spin_unlock_wait()'s semantics,
> and it appears that all callers could do just as well with a lock/unlock
> pair.  This commit therefore removes the underlying arch-specific
> arch_spin_unlock_wait().
> 
> Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
> Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
> Cc: Paul Mackerras <paulus@samba.org>
> Cc: Michael Ellerman <mpe@ellerman.id.au>
> Cc: <linuxppc-dev@lists.ozlabs.org>
> Cc: Will Deacon <will.deacon@arm.com>
> Cc: Peter Zijlstra <peterz@infradead.org>
> Cc: Alan Stern <stern@rowland.harvard.edu>
> Cc: Andrea Parri <parri.andrea@gmail.com>
> Cc: Linus Torvalds <torvalds@linux-foundation.org>

Acked-by: Boqun Feng <boqun.feng@gmail.com>

Regards,
Boqun

> ---
>  arch/powerpc/include/asm/spinlock.h | 33 ---------------------------------
>  1 file changed, 33 deletions(-)
> 
> diff --git a/arch/powerpc/include/asm/spinlock.h b/arch/powerpc/include/asm/spinlock.h
> index 8c1b913de6d7..d256e448ea49 100644
> --- a/arch/powerpc/include/asm/spinlock.h
> +++ b/arch/powerpc/include/asm/spinlock.h
> @@ -170,39 +170,6 @@ static inline void arch_spin_unlock(arch_spinlock_t *lock)
>  	lock->slock = 0;
>  }
>  
> -static inline void arch_spin_unlock_wait(arch_spinlock_t *lock)
> -{
> -	arch_spinlock_t lock_val;
> -
> -	smp_mb();
> -
> -	/*
> -	 * Atomically load and store back the lock value (unchanged). This
> -	 * ensures that our observation of the lock value is ordered with
> -	 * respect to other lock operations.
> -	 */
> -	__asm__ __volatile__(
> -"1:	" PPC_LWARX(%0, 0, %2, 0) "\n"
> -"	stwcx. %0, 0, %2\n"
> -"	bne- 1b\n"
> -	: "=&r" (lock_val), "+m" (*lock)
> -	: "r" (lock)
> -	: "cr0", "xer");
> -
> -	if (arch_spin_value_unlocked(lock_val))
> -		goto out;
> -
> -	while (lock->slock) {
> -		HMT_low();
> -		if (SHARED_PROCESSOR)
> -			__spin_yield(lock);
> -	}
> -	HMT_medium();
> -
> -out:
> -	smp_mb();
> -}
> -
>  /*
>   * Read-write spinlocks, allowing multiple readers
>   * but only one writer.
> -- 
> 2.5.2
> 

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 122+ messages in thread

* Re: [PATCH RFC 08/26] locking: Remove spin_unlock_wait() generic definitions
  2017-06-30 22:18         ` Paul E. McKenney
@ 2017-07-03 13:15           ` Will Deacon
  2017-07-03 16:18             ` Paul E. McKenney
  0 siblings, 1 reply; 122+ messages in thread
From: Will Deacon @ 2017-07-03 13:15 UTC (permalink / raw)
  To: Paul E. McKenney
  Cc: linux-kernel, netfilter-devel, netdev, oleg, akpm, mingo, dave,
	manfred, tj, arnd, linux-arch, peterz, stern, parri.andrea,
	torvalds

On Fri, Jun 30, 2017 at 03:18:40PM -0700, Paul E. McKenney wrote:
> On Fri, Jun 30, 2017 at 02:13:39PM +0100, Will Deacon wrote:
> > On Fri, Jun 30, 2017 at 05:38:15AM -0700, Paul E. McKenney wrote:
> > > I also need to check all uses of spin_is_locked().  There might no
> > > longer be any that rely on any particular ordering...
> > 
> > Right. I think we're looking for the "insane case" as per 38b850a73034
> > (which was apparently used by ipc/sem.c at the time, but no longer).
> > 
> > There's a usage in kernel/debug/debug_core.c, but it doesn't fill me with
> > joy.
> 
> That is indeed an interesting one...  But my first round will be what
> semantics the implementations seem to provide:
> 
> Acquire courtesy of TSO: s390, sparc, x86.
> Acquire: ia64 (in reality fully ordered).
> Control dependency: alpha, arc, arm, blackfin, hexagon, m32r, mn10300, tile,
> 	xtensa.
> Control dependency plus leading full barrier: arm64, powerpc.
> UP-only: c6x, cris, frv, h8300, m68k, microblaze nios2, openrisc, um, unicore32.
> 
> Special cases:
> 	metag: Acquire if !CONFIG_METAG_SMP_WRITE_REORDERING.
> 	       Otherwise control dependency?
> 	mips: Control dependency, acquire if CONFIG_CPU_CAVIUM_OCTEON.
> 	parisc: Acquire courtesy of TSO, but why barrier in smp_load_acquire?
> 	sh: Acquire if one of SH4A, SH5, or J2, otherwise acquire?  UP-only?
> 
> Are these correct, or am I missing something with any of them?

That looks about right but, at least on ARM, I think we have to consider
the semantics of spin_is_locked with respect to the other spin_* functions,
rather than in isolation.

For example, ARM only has a control dependency, but spin_lock has a trailing
smp_mb() and spin_unlock has both leading and trailing smp_mb().

Will

^ permalink raw reply	[flat|nested] 122+ messages in thread

* Re: [PATCH RFC 01/26] netfilter: Replace spin_unlock_wait() with lock/unlock pair
       [not found]   ` <a6642feb-2f3a-980f-5ed6-2deb79563e6b@colorfullife.com>
  2017-07-02  2:00     ` Paul E. McKenney
@ 2017-07-03 14:39     ` Alan Stern
  2017-07-03 17:14       ` Paul E. McKenney
  1 sibling, 1 reply; 122+ messages in thread
From: Alan Stern @ 2017-07-03 14:39 UTC (permalink / raw)
  To: Manfred Spraul
  Cc: Paul E. McKenney, linux-kernel, netfilter-devel, netdev, oleg,
	akpm, mingo, dave, tj, arnd, linux-arch, will.deacon, peterz,
	parri.andrea, torvalds, Pablo Neira Ayuso, Jozsef Kadlecsik,
	Florian Westphal, David S. Miller, coreteam

On Sat, 1 Jul 2017, Manfred Spraul wrote:

> As we want to remove spin_unlock_wait() and replace it with explicit
> spin_lock()/spin_unlock() calls, we can use this to simplify the
> locking.
> 
> In addition:
> - Reading nf_conntrack_locks_all needs ACQUIRE memory ordering.
> - The new code avoids the backwards loop.
> 
> Only slightly tested, I did not manage to trigger calls to
> nf_conntrack_all_lock().
> 
> Fixes: b16c29191dc8
> Signed-off-by: Manfred Spraul <manfred@colorfullife.com>
> Cc: <stable@vger.kernel.org>
> Cc: Sasha Levin <sasha.levin@oracle.com>
> Cc: Pablo Neira Ayuso <pablo@netfilter.org>
> Cc: netfilter-devel@vger.kernel.org
> ---
>  net/netfilter/nf_conntrack_core.c | 44 +++++++++++++++++++++------------------
>  1 file changed, 24 insertions(+), 20 deletions(-)
> 
> diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c
> index e847dba..1193565 100644
> --- a/net/netfilter/nf_conntrack_core.c
> +++ b/net/netfilter/nf_conntrack_core.c
> @@ -96,19 +96,24 @@ static struct conntrack_gc_work conntrack_gc_work;
>  
>  void nf_conntrack_lock(spinlock_t *lock) __acquires(lock)
>  {
> +	/* 1) Acquire the lock */
>  	spin_lock(lock);
> -	while (unlikely(nf_conntrack_locks_all)) {
> -		spin_unlock(lock);
>  
> -		/*
> -		 * Order the 'nf_conntrack_locks_all' load vs. the
> -		 * spin_unlock_wait() loads below, to ensure
> -		 * that 'nf_conntrack_locks_all_lock' is indeed held:
> -		 */
> -		smp_rmb(); /* spin_lock(&nf_conntrack_locks_all_lock) */
> -		spin_unlock_wait(&nf_conntrack_locks_all_lock);
> -		spin_lock(lock);
> -	}
> +	/* 2) read nf_conntrack_locks_all, with ACQUIRE semantics */
> +	if (likely(smp_load_acquire(&nf_conntrack_locks_all) == false))
> +		return;

As far as I can tell, this read does not need to have ACQUIRE
semantics.

You need to guarantee that two things can never happen:

    (1) We read nf_conntrack_locks_all == false, and this routine's
	critical section for nf_conntrack_locks[i] runs after the
	(empty) critical section for that lock in 
	nf_conntrack_all_lock().

    (2) We read nf_conntrack_locks_all == true, and this routine's 
	critical section for nf_conntrack_locks_all_lock runs before 
	the critical section in nf_conntrack_all_lock().

In fact, neither one can happen even if smp_load_acquire() is replaced
with READ_ONCE().  The reason is simple enough, using this property of
spinlocks:

	If critical section CS1 runs before critical section CS2 (for 
	the same lock) then: (a) every write coming before CS1's
	spin_unlock() will be visible to any read coming after CS2's
	spin_lock(), and (b) no write coming after CS2's spin_lock()
	will be visible to any read coming before CS1's spin_unlock().

Thus for (1), assuming the critical sections run in the order mentioned
above, since nf_conntrack_all_lock() writes to nf_conntrack_locks_all
before releasing nf_conntrack_locks[i], and since nf_conntrack_lock()
acquires nf_conntrack_locks[i] before reading nf_conntrack_locks_all,
by (a) the read will always see the write.

Similarly for (2), since nf_conntrack_all_lock() acquires 
nf_conntrack_locks_all_lock before writing to nf_conntrack_locks_all, 
and since nf_conntrack_lock() reads nf_conntrack_locks_all before 
releasing nf_conntrack_locks_all_lock, by (b) the read cannot see the 
write.

Alan Stern

> +
> +	/* fast path failed, unlock */
> +	spin_unlock(lock);
> +
> +	/* Slow path 1) get global lock */
> +	spin_lock(&nf_conntrack_locks_all_lock);
> +
> +	/* Slow path 2) get the lock we want */
> +	spin_lock(lock);
> +
> +	/* Slow path 3) release the global lock */
> +	spin_unlock(&nf_conntrack_locks_all_lock);
>  }
>  EXPORT_SYMBOL_GPL(nf_conntrack_lock);
>  
> @@ -149,18 +154,17 @@ static void nf_conntrack_all_lock(void)
>  	int i;
>  
>  	spin_lock(&nf_conntrack_locks_all_lock);
> -	nf_conntrack_locks_all = true;
>  
> -	/*
> -	 * Order the above store of 'nf_conntrack_locks_all' against
> -	 * the spin_unlock_wait() loads below, such that if
> -	 * nf_conntrack_lock() observes 'nf_conntrack_locks_all'
> -	 * we must observe nf_conntrack_locks[] held:
> -	 */
> -	smp_mb(); /* spin_lock(&nf_conntrack_locks_all_lock) */
> +	nf_conntrack_locks_all = true;
>  
>  	for (i = 0; i < CONNTRACK_LOCKS; i++) {
> -		spin_unlock_wait(&nf_conntrack_locks[i]);
> +		spin_lock(&nf_conntrack_locks[i]);
> +
> +		/* This spin_unlock provides the "release" to ensure that
> +		 * nf_conntrack_locks_all==true is visible to everyone that
> +		 * acquired spin_lock(&nf_conntrack_locks[]).
> +		 */
> +		spin_unlock(&nf_conntrack_locks[i]);
>  	}
>  }

^ permalink raw reply	[flat|nested] 122+ messages in thread

* Re: [PATCH RFC 08/26] locking: Remove spin_unlock_wait() generic definitions
  2017-07-03 13:15           ` Will Deacon
@ 2017-07-03 16:18             ` Paul E. McKenney
  2017-07-03 16:40               ` Linus Torvalds
  0 siblings, 1 reply; 122+ messages in thread
From: Paul E. McKenney @ 2017-07-03 16:18 UTC (permalink / raw)
  To: Will Deacon
  Cc: linux-kernel, netfilter-devel, netdev, oleg, akpm, mingo, dave,
	manfred, tj, arnd, linux-arch, peterz, stern, parri.andrea,
	torvalds

On Mon, Jul 03, 2017 at 02:15:14PM +0100, Will Deacon wrote:
> On Fri, Jun 30, 2017 at 03:18:40PM -0700, Paul E. McKenney wrote:
> > On Fri, Jun 30, 2017 at 02:13:39PM +0100, Will Deacon wrote:
> > > On Fri, Jun 30, 2017 at 05:38:15AM -0700, Paul E. McKenney wrote:
> > > > I also need to check all uses of spin_is_locked().  There might no
> > > > longer be any that rely on any particular ordering...
> > > 
> > > Right. I think we're looking for the "insane case" as per 38b850a73034
> > > (which was apparently used by ipc/sem.c at the time, but no longer).
> > > 
> > > There's a usage in kernel/debug/debug_core.c, but it doesn't fill me with
> > > joy.
> > 
> > That is indeed an interesting one...  But my first round will be what
> > semantics the implementations seem to provide:
> > 
> > Acquire courtesy of TSO: s390, sparc, x86.
> > Acquire: ia64 (in reality fully ordered).
> > Control dependency: alpha, arc, arm, blackfin, hexagon, m32r, mn10300, tile,
> > 	xtensa.
> > Control dependency plus leading full barrier: arm64, powerpc.
> > UP-only: c6x, cris, frv, h8300, m68k, microblaze nios2, openrisc, um, unicore32.
> > 
> > Special cases:
> > 	metag: Acquire if !CONFIG_METAG_SMP_WRITE_REORDERING.
> > 	       Otherwise control dependency?
> > 	mips: Control dependency, acquire if CONFIG_CPU_CAVIUM_OCTEON.
> > 	parisc: Acquire courtesy of TSO, but why barrier in smp_load_acquire?
> > 	sh: Acquire if one of SH4A, SH5, or J2, otherwise acquire?  UP-only?
> > 
> > Are these correct, or am I missing something with any of them?
> 
> That looks about right but, at least on ARM, I think we have to consider
> the semantics of spin_is_locked with respect to the other spin_* functions,
> rather than in isolation.
> 
> For example, ARM only has a control dependency, but spin_lock has a trailing
> smp_mb() and spin_unlock has both leading and trailing smp_mb().

Agreed, and my next step is to look at spin_lock() followed by
spin_is_locked(), not necessarily the same lock.

							Thanx, Paul

^ permalink raw reply	[flat|nested] 122+ messages in thread

* Re: [PATCH RFC 08/26] locking: Remove spin_unlock_wait() generic definitions
  2017-07-03 16:18             ` Paul E. McKenney
@ 2017-07-03 16:40               ` Linus Torvalds
  2017-07-03 17:13                 ` Will Deacon
  2017-07-03 21:10                 ` Paul E. McKenney
  0 siblings, 2 replies; 122+ messages in thread
From: Linus Torvalds @ 2017-07-03 16:40 UTC (permalink / raw)
  To: Paul McKenney
  Cc: Will Deacon, Linux Kernel Mailing List, NetFilter,
	Network Development, Oleg Nesterov, Andrew Morton, Ingo Molnar,
	Davidlohr Bueso, Manfred Spraul, Tejun Heo, Arnd Bergmann,
	linux-arch, Peter Zijlstra, Alan Stern, Andrea Parri

On Mon, Jul 3, 2017 at 9:18 AM, Paul E. McKenney
<paulmck@linux.vnet.ibm.com> wrote:
>
> Agreed, and my next step is to look at spin_lock() followed by
> spin_is_locked(), not necessarily the same lock.

Hmm. Most (all?) "spin_is_locked()" really should be about the same
thread that took the lock (ie it's about asserts and lock debugging).

The optimistic ABBA avoidance pattern for spinlocks *should* be

    spin_lock(inner)
    ...
    if (!try_lock(outer)) {
           spin_unlock(inner);
           .. do them in the right order ..

so I don't think spin_is_locked() should have any memory barriers.

In fact, the core function for spin_is_locked() is arguably
arch_spin_value_unlocked() which doesn't even do the access itself.

                       Linus

^ permalink raw reply	[flat|nested] 122+ messages in thread

* Re: [PATCH RFC 08/26] locking: Remove spin_unlock_wait() generic definitions
  2017-07-03 16:40               ` Linus Torvalds
@ 2017-07-03 17:13                 ` Will Deacon
  2017-07-03 22:30                   ` Paul E. McKenney
  2017-07-03 21:10                 ` Paul E. McKenney
  1 sibling, 1 reply; 122+ messages in thread
From: Will Deacon @ 2017-07-03 17:13 UTC (permalink / raw)
  To: Linus Torvalds
  Cc: Paul McKenney, Linux Kernel Mailing List, NetFilter,
	Network Development, Oleg Nesterov, Andrew Morton, Ingo Molnar,
	Davidlohr Bueso, Manfred Spraul, Tejun Heo, Arnd Bergmann,
	linux-arch, Peter Zijlstra, Alan Stern, Andrea Parri

On Mon, Jul 03, 2017 at 09:40:22AM -0700, Linus Torvalds wrote:
> On Mon, Jul 3, 2017 at 9:18 AM, Paul E. McKenney
> <paulmck@linux.vnet.ibm.com> wrote:
> >
> > Agreed, and my next step is to look at spin_lock() followed by
> > spin_is_locked(), not necessarily the same lock.
> 
> Hmm. Most (all?) "spin_is_locked()" really should be about the same
> thread that took the lock (ie it's about asserts and lock debugging).
> 
> The optimistic ABBA avoidance pattern for spinlocks *should* be
> 
>     spin_lock(inner)
>     ...
>     if (!try_lock(outer)) {
>            spin_unlock(inner);
>            .. do them in the right order ..
> 
> so I don't think spin_is_locked() should have any memory barriers.
> 
> In fact, the core function for spin_is_locked() is arguably
> arch_spin_value_unlocked() which doesn't even do the access itself.

Yeah, but there's some spaced-out stuff going on in kgdb_cpu_enter where
it looks to me like raw_spin_is_locked is used for synchronization. My
eyes are hurting looking at it, though.

Will

^ permalink raw reply	[flat|nested] 122+ messages in thread

* Re: [PATCH RFC 01/26] netfilter: Replace spin_unlock_wait() with lock/unlock pair
  2017-07-03 14:39     ` Alan Stern
@ 2017-07-03 17:14       ` Paul E. McKenney
  2017-07-03 19:01         ` Manfred Spraul
  2017-07-03 20:04         ` Alan Stern
  0 siblings, 2 replies; 122+ messages in thread
From: Paul E. McKenney @ 2017-07-03 17:14 UTC (permalink / raw)
  To: Alan Stern
  Cc: Manfred Spraul, linux-kernel, netfilter-devel, netdev, oleg,
	akpm, mingo, dave, tj, arnd, linux-arch, will.deacon, peterz,
	parri.andrea, torvalds, Pablo Neira Ayuso, Jozsef Kadlecsik,
	Florian Westphal, David S. Miller, coreteam

On Mon, Jul 03, 2017 at 10:39:49AM -0400, Alan Stern wrote:
> On Sat, 1 Jul 2017, Manfred Spraul wrote:
> 
> > As we want to remove spin_unlock_wait() and replace it with explicit
> > spin_lock()/spin_unlock() calls, we can use this to simplify the
> > locking.
> > 
> > In addition:
> > - Reading nf_conntrack_locks_all needs ACQUIRE memory ordering.
> > - The new code avoids the backwards loop.
> > 
> > Only slightly tested, I did not manage to trigger calls to
> > nf_conntrack_all_lock().
> > 
> > Fixes: b16c29191dc8
> > Signed-off-by: Manfred Spraul <manfred@colorfullife.com>
> > Cc: <stable@vger.kernel.org>
> > Cc: Sasha Levin <sasha.levin@oracle.com>
> > Cc: Pablo Neira Ayuso <pablo@netfilter.org>
> > Cc: netfilter-devel@vger.kernel.org
> > ---
> >  net/netfilter/nf_conntrack_core.c | 44 +++++++++++++++++++++------------------
> >  1 file changed, 24 insertions(+), 20 deletions(-)
> > 
> > diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c
> > index e847dba..1193565 100644
> > --- a/net/netfilter/nf_conntrack_core.c
> > +++ b/net/netfilter/nf_conntrack_core.c
> > @@ -96,19 +96,24 @@ static struct conntrack_gc_work conntrack_gc_work;
> >  
> >  void nf_conntrack_lock(spinlock_t *lock) __acquires(lock)
> >  {
> > +	/* 1) Acquire the lock */
> >  	spin_lock(lock);
> > -	while (unlikely(nf_conntrack_locks_all)) {
> > -		spin_unlock(lock);
> >  
> > -		/*
> > -		 * Order the 'nf_conntrack_locks_all' load vs. the
> > -		 * spin_unlock_wait() loads below, to ensure
> > -		 * that 'nf_conntrack_locks_all_lock' is indeed held:
> > -		 */
> > -		smp_rmb(); /* spin_lock(&nf_conntrack_locks_all_lock) */
> > -		spin_unlock_wait(&nf_conntrack_locks_all_lock);
> > -		spin_lock(lock);
> > -	}
> > +	/* 2) read nf_conntrack_locks_all, with ACQUIRE semantics */
> > +	if (likely(smp_load_acquire(&nf_conntrack_locks_all) == false))
> > +		return;
> 
> As far as I can tell, this read does not need to have ACQUIRE
> semantics.
> 
> You need to guarantee that two things can never happen:
> 
>     (1) We read nf_conntrack_locks_all == false, and this routine's
> 	critical section for nf_conntrack_locks[i] runs after the
> 	(empty) critical section for that lock in 
> 	nf_conntrack_all_lock().
> 
>     (2) We read nf_conntrack_locks_all == true, and this routine's 
> 	critical section for nf_conntrack_locks_all_lock runs before 
> 	the critical section in nf_conntrack_all_lock().
> 
> In fact, neither one can happen even if smp_load_acquire() is replaced
> with READ_ONCE().  The reason is simple enough, using this property of
> spinlocks:
> 
> 	If critical section CS1 runs before critical section CS2 (for 
> 	the same lock) then: (a) every write coming before CS1's
> 	spin_unlock() will be visible to any read coming after CS2's
> 	spin_lock(), and (b) no write coming after CS2's spin_lock()
> 	will be visible to any read coming before CS1's spin_unlock().
> 
> Thus for (1), assuming the critical sections run in the order mentioned
> above, since nf_conntrack_all_lock() writes to nf_conntrack_locks_all
> before releasing nf_conntrack_locks[i], and since nf_conntrack_lock()
> acquires nf_conntrack_locks[i] before reading nf_conntrack_locks_all,
> by (a) the read will always see the write.
> 
> Similarly for (2), since nf_conntrack_all_lock() acquires 
> nf_conntrack_locks_all_lock before writing to nf_conntrack_locks_all, 
> and since nf_conntrack_lock() reads nf_conntrack_locks_all before 
> releasing nf_conntrack_locks_all_lock, by (b) the read cannot see the 
> write.

And the Linux kernel memory model (https://lwn.net/Articles/718628/
and https://lwn.net/Articles/720550/) agrees with Alan.  Here is
a litmus test, which emulates spin_lock() with xchg_acquire() and
spin_unlock() with smp_store_release():

------------------------------------------------------------------------

C C-ManfredSpraul-L1G1xchgnr.litmus

(* Expected result: Never.  *)

{
}

P0(int *nfcla, spinlock_t *gbl, int *gbl_held, spinlock_t *lcl, int *lcl_held)
{
	/* Acquire local lock. */
	r10 = xchg_acquire(lcl, 1);
	r1 = READ_ONCE(*nfcla);
	if (r1) {
		smp_store_release(lcl, 0);
		r11 = xchg_acquire(gbl, 1);
		r12 = xchg_acquire(lcl, 1);
		smp_store_release(gbl, 0);
	}
	r2 = READ_ONCE(*gbl_held);
	WRITE_ONCE(*lcl_held, 1);
	WRITE_ONCE(*lcl_held, 0);
	smp_store_release(lcl, 0);
}

P1(int *nfcla, spinlock_t *gbl, int *gbl_held, spinlock_t *lcl, int *lcl_held)
{
	/* Acquire global lock. */
	r10 = xchg_acquire(gbl, 1);
	WRITE_ONCE(*nfcla, 1);
	r11 = xchg_acquire(lcl, 1);
	smp_store_release(lcl, 0);
	r2 = READ_ONCE(*lcl_held);
	WRITE_ONCE(*gbl_held, 1);
	WRITE_ONCE(*gbl_held, 0);
	smp_store_release(gbl, 0);
}

exists
((0:r2=1 \/ 1:r2=1) /\ 0:r10=0 /\ 0:r11=0 /\ 0:r12=0 /\ 1:r10=0 /\ 1:r11=0)

------------------------------------------------------------------------

The memory model says that the forbidden state does not happen:

------------------------------------------------------------------------

States 25
0:r10=0; 0:r11=0; 0:r12=0; 0:r2=0; 1:r10=0; 1:r11=0; 1:r2=0;
0:r10=0; 0:r11=0; 0:r12=0; 0:r2=0; 1:r10=0; 1:r11=1; 1:r2=0;
0:r10=0; 0:r11=0; 0:r12=0; 0:r2=0; 1:r10=0; 1:r11=1; 1:r2=1;
0:r10=0; 0:r11=0; 0:r12=0; 0:r2=1; 1:r10=0; 1:r11=1; 1:r2=0;
0:r10=0; 0:r11=0; 0:r12=0; 0:r2=1; 1:r10=0; 1:r11=1; 1:r2=1;
0:r10=0; 0:r11=1; 0:r12=0; 0:r2=0; 1:r10=0; 1:r11=0; 1:r2=0;
0:r10=0; 0:r11=1; 0:r12=0; 0:r2=0; 1:r10=0; 1:r11=0; 1:r2=1;
0:r10=0; 0:r11=1; 0:r12=0; 0:r2=0; 1:r10=0; 1:r11=1; 1:r2=0;
0:r10=0; 0:r11=1; 0:r12=0; 0:r2=0; 1:r10=0; 1:r11=1; 1:r2=1;
0:r10=0; 0:r11=1; 0:r12=0; 0:r2=1; 1:r10=0; 1:r11=0; 1:r2=0;
0:r10=0; 0:r11=1; 0:r12=0; 0:r2=1; 1:r10=0; 1:r11=0; 1:r2=1;
0:r10=0; 0:r11=1; 0:r12=0; 0:r2=1; 1:r10=0; 1:r11=1; 1:r2=0;
0:r10=0; 0:r11=1; 0:r12=0; 0:r2=1; 1:r10=0; 1:r11=1; 1:r2=1;
0:r10=0; 0:r11=1; 0:r12=1; 0:r2=0; 1:r10=0; 1:r11=0; 1:r2=0;
0:r10=0; 0:r11=1; 0:r12=1; 0:r2=0; 1:r10=0; 1:r11=0; 1:r2=1;
0:r10=0; 0:r11=1; 0:r12=1; 0:r2=1; 1:r10=0; 1:r11=0; 1:r2=0;
0:r10=0; 0:r11=1; 0:r12=1; 0:r2=1; 1:r10=0; 1:r11=0; 1:r2=1;
0:r10=1; 0:r11=0; 0:r12=0; 0:r2=0; 1:r10=0; 1:r11=0; 1:r2=0;
0:r10=1; 0:r11=0; 0:r12=0; 0:r2=0; 1:r10=0; 1:r11=0; 1:r2=1;
0:r10=1; 0:r11=0; 0:r12=0; 0:r2=1; 1:r10=0; 1:r11=0; 1:r2=0;
0:r10=1; 0:r11=0; 0:r12=0; 0:r2=1; 1:r10=0; 1:r11=0; 1:r2=1;
0:r10=1; 0:r11=1; 0:r12=0; 0:r2=0; 1:r10=0; 1:r11=0; 1:r2=0;
0:r10=1; 0:r11=1; 0:r12=0; 0:r2=0; 1:r10=0; 1:r11=0; 1:r2=1;
0:r10=1; 0:r11=1; 0:r12=0; 0:r2=1; 1:r10=0; 1:r11=0; 1:r2=0;
0:r10=1; 0:r11=1; 0:r12=0; 0:r2=1; 1:r10=0; 1:r11=0; 1:r2=1;
No
Witnesses
Positive: 0 Negative: 260
Condition exists ((0:r2=1 \/ 1:r2=1) /\ 0:r10=0 /\ 0:r11=0 /\ 0:r12=0 /\ 1:r10=0 /\ 1:r11=0)
Observation C-ManfredSpraul-L1G1xchgnr Never 0 260

------------------------------------------------------------------------

(Note the line "Positive: 0 Negative: 260", in other words, there
were no scenarios that matched the "exists" clause and 260 that did
not match.)

Of course, testing is also required.  ;-)

Manfred, any objections to my changing your patch as Alan suggests?

							Thanx, Paul

^ permalink raw reply	[flat|nested] 122+ messages in thread

* Re: [PATCH RFC 01/26] netfilter: Replace spin_unlock_wait() with lock/unlock pair
  2017-07-03 17:14       ` Paul E. McKenney
@ 2017-07-03 19:01         ` Manfred Spraul
  2017-07-03 19:57           ` Alan Stern
  2017-07-03 20:04         ` Alan Stern
  1 sibling, 1 reply; 122+ messages in thread
From: Manfred Spraul @ 2017-07-03 19:01 UTC (permalink / raw)
  To: paulmck, Alan Stern
  Cc: linux-kernel, netfilter-devel, netdev, oleg, akpm, mingo, dave,
	tj, arnd, linux-arch, will.deacon, peterz, parri.andrea,
	torvalds, Pablo Neira Ayuso, Jozsef Kadlecsik, Florian Westphal,
	David S. Miller, coreteam, 1vier1

On 07/03/2017 07:14 PM, Paul E. McKenney wrote:
> On Mon, Jul 03, 2017 at 10:39:49AM -0400, Alan Stern wrote:
>> On Sat, 1 Jul 2017, Manfred Spraul wrote:
>>
>>> As we want to remove spin_unlock_wait() and replace it with explicit
>>> spin_lock()/spin_unlock() calls, we can use this to simplify the
>>> locking.
>>>
>>> In addition:
>>> - Reading nf_conntrack_locks_all needs ACQUIRE memory ordering.
>>> - The new code avoids the backwards loop.
>>>
>>> Only slightly tested, I did not manage to trigger calls to
>>> nf_conntrack_all_lock().
>>>
>>> Fixes: b16c29191dc8
>>> Signed-off-by: Manfred Spraul <manfred@colorfullife.com>
>>> Cc: <stable@vger.kernel.org>
>>> Cc: Sasha Levin <sasha.levin@oracle.com>
>>> Cc: Pablo Neira Ayuso <pablo@netfilter.org>
>>> Cc: netfilter-devel@vger.kernel.org
>>> ---
>>>   net/netfilter/nf_conntrack_core.c | 44 +++++++++++++++++++++------------------
>>>   1 file changed, 24 insertions(+), 20 deletions(-)
>>>
>>> diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c
>>> index e847dba..1193565 100644
>>> --- a/net/netfilter/nf_conntrack_core.c
>>> +++ b/net/netfilter/nf_conntrack_core.c
>>> @@ -96,19 +96,24 @@ static struct conntrack_gc_work conntrack_gc_work;
>>>   
>>>   void nf_conntrack_lock(spinlock_t *lock) __acquires(lock)
>>>   {
>>> +	/* 1) Acquire the lock */
>>>   	spin_lock(lock);
>>> -	while (unlikely(nf_conntrack_locks_all)) {
>>> -		spin_unlock(lock);
>>>   
>>> -		/*
>>> -		 * Order the 'nf_conntrack_locks_all' load vs. the
>>> -		 * spin_unlock_wait() loads below, to ensure
>>> -		 * that 'nf_conntrack_locks_all_lock' is indeed held:
>>> -		 */
>>> -		smp_rmb(); /* spin_lock(&nf_conntrack_locks_all_lock) */
>>> -		spin_unlock_wait(&nf_conntrack_locks_all_lock);
>>> -		spin_lock(lock);
>>> -	}
>>> +	/* 2) read nf_conntrack_locks_all, with ACQUIRE semantics */
>>> +	if (likely(smp_load_acquire(&nf_conntrack_locks_all) == false))
>>> +		return;
>> As far as I can tell, this read does not need to have ACQUIRE
>> semantics.
>>
>> You need to guarantee that two things can never happen:
>>
>>      (1) We read nf_conntrack_locks_all == false, and this routine's
>> 	critical section for nf_conntrack_locks[i] runs after the
>> 	(empty) critical section for that lock in
>> 	nf_conntrack_all_lock().
>>
>>      (2) We read nf_conntrack_locks_all == true, and this routine's
>> 	critical section for nf_conntrack_locks_all_lock runs before
>> 	the critical section in nf_conntrack_all_lock().
I was looking at nf_conntrack_all_unlock:
There is a smp_store_release() - which memory barrier does this pair with?

nf_conntrack_all_unlock()
     <arbitrary writes>
     smp_store_release(a, false)
     spin_unlock(b);

nf_conntrack_lock()
     spin_lock(c);
     xx=read_once(a)
     if (xx==false)
         return
     <arbitrary read>

>> In fact, neither one can happen even if smp_load_acquire() is replaced
>> with READ_ONCE().  The reason is simple enough, using this property of
>> spinlocks:
>>
>> 	If critical section CS1 runs before critical section CS2 (for
>> 	the same lock) then: (a) every write coming before CS1's
>> 	spin_unlock() will be visible to any read coming after CS2's
>> 	spin_lock(), and (b) no write coming after CS2's spin_lock()
>> 	will be visible to any read coming before CS1's spin_unlock().
Does this apply? The locks are different.
>> Thus for (1), assuming the critical sections run in the order mentioned
>> above, since nf_conntrack_all_lock() writes to nf_conntrack_locks_all
>> before releasing nf_conntrack_locks[i], and since nf_conntrack_lock()
>> acquires nf_conntrack_locks[i] before reading nf_conntrack_locks_all,
>> by (a) the read will always see the write.
>>
>> Similarly for (2), since nf_conntrack_all_lock() acquires
>> nf_conntrack_locks_all_lock before writing to nf_conntrack_locks_all,
>> and since nf_conntrack_lock() reads nf_conntrack_locks_all before
>> releasing nf_conntrack_locks_all_lock, by (b) the read cannot see the
>> write.
> And the Linux kernel memory model (https://lwn.net/Articles/718628/
> and https://lwn.net/Articles/720550/) agrees with Alan.  Here is
> a litmus test, which emulates spin_lock() with xchg_acquire() and
> spin_unlock() with smp_store_release():
>
> ------------------------------------------------------------------------
>
> C C-ManfredSpraul-L1G1xchgnr.litmus
>
> (* Expected result: Never.  *)
>
> {
> }
>
> P0(int *nfcla, spinlock_t *gbl, int *gbl_held, spinlock_t *lcl, int *lcl_held)
> {
> 	/* Acquire local lock. */
> 	r10 = xchg_acquire(lcl, 1);
> 	r1 = READ_ONCE(*nfcla);
> 	if (r1) {
> 		smp_store_release(lcl, 0);
> 		r11 = xchg_acquire(gbl, 1);
> 		r12 = xchg_acquire(lcl, 1);
> 		smp_store_release(gbl, 0);
> 	}
> 	r2 = READ_ONCE(*gbl_held);
> 	WRITE_ONCE(*lcl_held, 1);
> 	WRITE_ONCE(*lcl_held, 0);
> 	smp_store_release(lcl, 0);
> }
>
> P1(int *nfcla, spinlock_t *gbl, int *gbl_held, spinlock_t *lcl, int *lcl_held)
> {
> 	/* Acquire global lock. */
> 	r10 = xchg_acquire(gbl, 1);
> 	WRITE_ONCE(*nfcla, 1);
> 	r11 = xchg_acquire(lcl, 1);
> 	smp_store_release(lcl, 0);
> 	r2 = READ_ONCE(*lcl_held);
> 	WRITE_ONCE(*gbl_held, 1);
> 	WRITE_ONCE(*gbl_held, 0);
Where is the write that resets nfcla=0?
> 	smp_store_release(gbl, 0);
> }
>
> exists
> ((0:r2=1 \/ 1:r2=1) /\ 0:r10=0 /\ 0:r11=0 /\ 0:r12=0 /\ 1:r10=0 /\ 1:r11=0)
>
> ------------------------------------------------------------------------
>
> The memory model says that the forbidden state does not happen:
[...]
> Manfred, any objections to my changing your patch as Alan suggests?
I tried to pair the memory barriers:
nf_conntrack_all_unlock() contains a smp_store_release().
What does that pair with?

--
     Manfred

^ permalink raw reply	[flat|nested] 122+ messages in thread

* Re: [PATCH RFC 01/26] netfilter: Replace spin_unlock_wait() with lock/unlock pair
  2017-07-03 19:01         ` Manfred Spraul
@ 2017-07-03 19:57           ` Alan Stern
  2017-07-06 18:43             ` Manfred Spraul
  0 siblings, 1 reply; 122+ messages in thread
From: Alan Stern @ 2017-07-03 19:57 UTC (permalink / raw)
  To: Manfred Spraul
  Cc: paulmck, linux-kernel, netfilter-devel, netdev, oleg, akpm,
	mingo, dave, tj, arnd, linux-arch, will.deacon, peterz,
	parri.andrea, torvalds, Pablo Neira Ayuso, Jozsef Kadlecsik,
	Florian Westphal, David S. Miller, coreteam, 1vier1

On Mon, 3 Jul 2017, Manfred Spraul wrote:

> >>> +	/* 2) read nf_conntrack_locks_all, with ACQUIRE semantics */
> >>> +	if (likely(smp_load_acquire(&nf_conntrack_locks_all) == false))
> >>> +		return;
> >> As far as I can tell, this read does not need to have ACQUIRE
> >> semantics.
> >>
> >> You need to guarantee that two things can never happen:
> >>
> >>      (1) We read nf_conntrack_locks_all == false, and this routine's
> >> 	critical section for nf_conntrack_locks[i] runs after the
> >> 	(empty) critical section for that lock in
> >> 	nf_conntrack_all_lock().
> >>
> >>      (2) We read nf_conntrack_locks_all == true, and this routine's
> >> 	critical section for nf_conntrack_locks_all_lock runs before
> >> 	the critical section in nf_conntrack_all_lock().
> I was looking at nf_conntrack_all_unlock:
> There is a smp_store_release() - which memory barrier does this pair with?
> 
> nf_conntrack_all_unlock()
>      <arbitrary writes>
>      smp_store_release(a, false)
>      spin_unlock(b);
> 
> nf_conntrack_lock()
>      spin_lock(c);
>      xx=read_once(a)
>      if (xx==false)
>          return
>      <arbitrary read>

Ah, I see your point.  Yes, I did wonder about what would happen when
nf_conntrack_locks_all was set back to false.  But I didn't think about
it any further, because the relevant code wasn't in your patch.

> I tried to pair the memory barriers:
> nf_conntrack_all_unlock() contains a smp_store_release().
> What does that pair with?

You are right, this does need to be smp_load_acquire() after all.  
Perhaps the preceding comment should mention that it pairs with the 
smp_store_release() from an earlier invocation of 
nf_conntrack_all_unlock().

(Alternatively, you could make nf_conntrack_all_unlock() do a
lock+unlock on all the locks in the array, just like
nf_conntrack_all_lock().  But of course, that would be a lot less
efficient.)

Alan Stern

^ permalink raw reply	[flat|nested] 122+ messages in thread

* Re: [PATCH RFC 01/26] netfilter: Replace spin_unlock_wait() with lock/unlock pair
  2017-07-03 17:14       ` Paul E. McKenney
  2017-07-03 19:01         ` Manfred Spraul
@ 2017-07-03 20:04         ` Alan Stern
  2017-07-03 20:53           ` Paul E. McKenney
  1 sibling, 1 reply; 122+ messages in thread
From: Alan Stern @ 2017-07-03 20:04 UTC (permalink / raw)
  To: Paul E. McKenney
  Cc: Manfred Spraul, linux-kernel, netfilter-devel, netdev, oleg,
	akpm, mingo, dave, tj, arnd, linux-arch, will.deacon, peterz,
	parri.andrea, torvalds, Pablo Neira Ayuso, Jozsef Kadlecsik,
	Florian Westphal, David S. Miller, coreteam

On Mon, 3 Jul 2017, Paul E. McKenney wrote:

> On Mon, Jul 03, 2017 at 10:39:49AM -0400, Alan Stern wrote:
> > On Sat, 1 Jul 2017, Manfred Spraul wrote:
> > 
> > > As we want to remove spin_unlock_wait() and replace it with explicit
> > > spin_lock()/spin_unlock() calls, we can use this to simplify the
> > > locking.
> > > 
> > > In addition:
> > > - Reading nf_conntrack_locks_all needs ACQUIRE memory ordering.
> > > - The new code avoids the backwards loop.
> > > 
> > > Only slightly tested, I did not manage to trigger calls to
> > > nf_conntrack_all_lock().
> > > 
> > > Fixes: b16c29191dc8
> > > Signed-off-by: Manfred Spraul <manfred@colorfullife.com>
> > > Cc: <stable@vger.kernel.org>
> > > Cc: Sasha Levin <sasha.levin@oracle.com>
> > > Cc: Pablo Neira Ayuso <pablo@netfilter.org>
> > > Cc: netfilter-devel@vger.kernel.org
> > > ---
> > >  net/netfilter/nf_conntrack_core.c | 44 +++++++++++++++++++++------------------
> > >  1 file changed, 24 insertions(+), 20 deletions(-)
> > > 
> > > diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c
> > > index e847dba..1193565 100644
> > > --- a/net/netfilter/nf_conntrack_core.c
> > > +++ b/net/netfilter/nf_conntrack_core.c
> > > @@ -96,19 +96,24 @@ static struct conntrack_gc_work conntrack_gc_work;
> > >  
> > >  void nf_conntrack_lock(spinlock_t *lock) __acquires(lock)
> > >  {
> > > +	/* 1) Acquire the lock */
> > >  	spin_lock(lock);
> > > -	while (unlikely(nf_conntrack_locks_all)) {
> > > -		spin_unlock(lock);
> > >  
> > > -		/*
> > > -		 * Order the 'nf_conntrack_locks_all' load vs. the
> > > -		 * spin_unlock_wait() loads below, to ensure
> > > -		 * that 'nf_conntrack_locks_all_lock' is indeed held:
> > > -		 */
> > > -		smp_rmb(); /* spin_lock(&nf_conntrack_locks_all_lock) */
> > > -		spin_unlock_wait(&nf_conntrack_locks_all_lock);
> > > -		spin_lock(lock);
> > > -	}
> > > +	/* 2) read nf_conntrack_locks_all, with ACQUIRE semantics */
> > > +	if (likely(smp_load_acquire(&nf_conntrack_locks_all) == false))
> > > +		return;
> > 
> > As far as I can tell, this read does not need to have ACQUIRE
> > semantics.
> > 
> > You need to guarantee that two things can never happen:
> > 
> >     (1) We read nf_conntrack_locks_all == false, and this routine's
> > 	critical section for nf_conntrack_locks[i] runs after the
> > 	(empty) critical section for that lock in 
> > 	nf_conntrack_all_lock().
> > 
> >     (2) We read nf_conntrack_locks_all == true, and this routine's 
> > 	critical section for nf_conntrack_locks_all_lock runs before 
> > 	the critical section in nf_conntrack_all_lock().
> > 
> > In fact, neither one can happen even if smp_load_acquire() is replaced
> > with READ_ONCE().  The reason is simple enough, using this property of
> > spinlocks:
> > 
> > 	If critical section CS1 runs before critical section CS2 (for 
> > 	the same lock) then: (a) every write coming before CS1's
> > 	spin_unlock() will be visible to any read coming after CS2's
> > 	spin_lock(), and (b) no write coming after CS2's spin_lock()
> > 	will be visible to any read coming before CS1's spin_unlock().
> > 
> > Thus for (1), assuming the critical sections run in the order mentioned
> > above, since nf_conntrack_all_lock() writes to nf_conntrack_locks_all
> > before releasing nf_conntrack_locks[i], and since nf_conntrack_lock()
> > acquires nf_conntrack_locks[i] before reading nf_conntrack_locks_all,
> > by (a) the read will always see the write.
> > 
> > Similarly for (2), since nf_conntrack_all_lock() acquires 
> > nf_conntrack_locks_all_lock before writing to nf_conntrack_locks_all, 
> > and since nf_conntrack_lock() reads nf_conntrack_locks_all before 
> > releasing nf_conntrack_locks_all_lock, by (b) the read cannot see the 
> > write.
> 
> And the Linux kernel memory model (https://lwn.net/Articles/718628/
> and https://lwn.net/Articles/720550/) agrees with Alan.  Here is
> a litmus test, which emulates spin_lock() with xchg_acquire() and
> spin_unlock() with smp_store_release():
> 
> ------------------------------------------------------------------------
> 
> C C-ManfredSpraul-L1G1xchgnr.litmus
> 
> (* Expected result: Never.  *)
> 
> {
> }
> 
> P0(int *nfcla, spinlock_t *gbl, int *gbl_held, spinlock_t *lcl, int *lcl_held)
> {
> 	/* Acquire local lock. */
> 	r10 = xchg_acquire(lcl, 1);
> 	r1 = READ_ONCE(*nfcla);
> 	if (r1) {
> 		smp_store_release(lcl, 0);
> 		r11 = xchg_acquire(gbl, 1);
> 		r12 = xchg_acquire(lcl, 1);
> 		smp_store_release(gbl, 0);
> 	}
> 	r2 = READ_ONCE(*gbl_held);
> 	WRITE_ONCE(*lcl_held, 1);
> 	WRITE_ONCE(*lcl_held, 0);
> 	smp_store_release(lcl, 0);
> }
> 
> P1(int *nfcla, spinlock_t *gbl, int *gbl_held, spinlock_t *lcl, int *lcl_held)
> {
> 	/* Acquire global lock. */
> 	r10 = xchg_acquire(gbl, 1);
> 	WRITE_ONCE(*nfcla, 1);
> 	r11 = xchg_acquire(lcl, 1);
> 	smp_store_release(lcl, 0);
> 	r2 = READ_ONCE(*lcl_held);
> 	WRITE_ONCE(*gbl_held, 1);

This litmus test is incomplete, because it omits the assignment setting
nf_conntrack_locks_all back to false when the global lock is released.  
You should insert

	smp_store_release(*nfcla, 0);

right here.

> 	WRITE_ONCE(*gbl_held, 0);
> 	smp_store_release(gbl, 0);
> }
> 
> exists
> ((0:r2=1 \/ 1:r2=1) /\ 0:r10=0 /\ 0:r11=0 /\ 0:r12=0 /\ 1:r10=0 /\ 1:r11=0)

With that addition, the litmus test fails unless the read of nfcla in 
P0 is an smp_load_acquire.  So Manfred's patch should not be changed.

Alan Stern

^ permalink raw reply	[flat|nested] 122+ messages in thread

* Re: [PATCH RFC 01/26] netfilter: Replace spin_unlock_wait() with lock/unlock pair
  2017-07-03 20:04         ` Alan Stern
@ 2017-07-03 20:53           ` Paul E. McKenney
  0 siblings, 0 replies; 122+ messages in thread
From: Paul E. McKenney @ 2017-07-03 20:53 UTC (permalink / raw)
  To: Alan Stern
  Cc: Manfred Spraul, linux-kernel, netfilter-devel, netdev, oleg,
	akpm, mingo, dave, tj, arnd, linux-arch, will.deacon, peterz,
	parri.andrea, torvalds, Pablo Neira Ayuso, Jozsef Kadlecsik,
	Florian Westphal, David S. Miller, coreteam

On Mon, Jul 03, 2017 at 04:04:14PM -0400, Alan Stern wrote:
> On Mon, 3 Jul 2017, Paul E. McKenney wrote:
> 
> > On Mon, Jul 03, 2017 at 10:39:49AM -0400, Alan Stern wrote:
> > > On Sat, 1 Jul 2017, Manfred Spraul wrote:
> > > 
> > > > As we want to remove spin_unlock_wait() and replace it with explicit
> > > > spin_lock()/spin_unlock() calls, we can use this to simplify the
> > > > locking.
> > > > 
> > > > In addition:
> > > > - Reading nf_conntrack_locks_all needs ACQUIRE memory ordering.
> > > > - The new code avoids the backwards loop.
> > > > 
> > > > Only slightly tested, I did not manage to trigger calls to
> > > > nf_conntrack_all_lock().
> > > > 
> > > > Fixes: b16c29191dc8
> > > > Signed-off-by: Manfred Spraul <manfred@colorfullife.com>
> > > > Cc: <stable@vger.kernel.org>
> > > > Cc: Sasha Levin <sasha.levin@oracle.com>
> > > > Cc: Pablo Neira Ayuso <pablo@netfilter.org>
> > > > Cc: netfilter-devel@vger.kernel.org
> > > > ---
> > > >  net/netfilter/nf_conntrack_core.c | 44 +++++++++++++++++++++------------------
> > > >  1 file changed, 24 insertions(+), 20 deletions(-)
> > > > 
> > > > diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c
> > > > index e847dba..1193565 100644
> > > > --- a/net/netfilter/nf_conntrack_core.c
> > > > +++ b/net/netfilter/nf_conntrack_core.c
> > > > @@ -96,19 +96,24 @@ static struct conntrack_gc_work conntrack_gc_work;
> > > >  
> > > >  void nf_conntrack_lock(spinlock_t *lock) __acquires(lock)
> > > >  {
> > > > +	/* 1) Acquire the lock */
> > > >  	spin_lock(lock);
> > > > -	while (unlikely(nf_conntrack_locks_all)) {
> > > > -		spin_unlock(lock);
> > > >  
> > > > -		/*
> > > > -		 * Order the 'nf_conntrack_locks_all' load vs. the
> > > > -		 * spin_unlock_wait() loads below, to ensure
> > > > -		 * that 'nf_conntrack_locks_all_lock' is indeed held:
> > > > -		 */
> > > > -		smp_rmb(); /* spin_lock(&nf_conntrack_locks_all_lock) */
> > > > -		spin_unlock_wait(&nf_conntrack_locks_all_lock);
> > > > -		spin_lock(lock);
> > > > -	}
> > > > +	/* 2) read nf_conntrack_locks_all, with ACQUIRE semantics */
> > > > +	if (likely(smp_load_acquire(&nf_conntrack_locks_all) == false))
> > > > +		return;
> > > 
> > > As far as I can tell, this read does not need to have ACQUIRE
> > > semantics.
> > > 
> > > You need to guarantee that two things can never happen:
> > > 
> > >     (1) We read nf_conntrack_locks_all == false, and this routine's
> > > 	critical section for nf_conntrack_locks[i] runs after the
> > > 	(empty) critical section for that lock in 
> > > 	nf_conntrack_all_lock().
> > > 
> > >     (2) We read nf_conntrack_locks_all == true, and this routine's 
> > > 	critical section for nf_conntrack_locks_all_lock runs before 
> > > 	the critical section in nf_conntrack_all_lock().
> > > 
> > > In fact, neither one can happen even if smp_load_acquire() is replaced
> > > with READ_ONCE().  The reason is simple enough, using this property of
> > > spinlocks:
> > > 
> > > 	If critical section CS1 runs before critical section CS2 (for 
> > > 	the same lock) then: (a) every write coming before CS1's
> > > 	spin_unlock() will be visible to any read coming after CS2's
> > > 	spin_lock(), and (b) no write coming after CS2's spin_lock()
> > > 	will be visible to any read coming before CS1's spin_unlock().
> > > 
> > > Thus for (1), assuming the critical sections run in the order mentioned
> > > above, since nf_conntrack_all_lock() writes to nf_conntrack_locks_all
> > > before releasing nf_conntrack_locks[i], and since nf_conntrack_lock()
> > > acquires nf_conntrack_locks[i] before reading nf_conntrack_locks_all,
> > > by (a) the read will always see the write.
> > > 
> > > Similarly for (2), since nf_conntrack_all_lock() acquires 
> > > nf_conntrack_locks_all_lock before writing to nf_conntrack_locks_all, 
> > > and since nf_conntrack_lock() reads nf_conntrack_locks_all before 
> > > releasing nf_conntrack_locks_all_lock, by (b) the read cannot see the 
> > > write.
> > 
> > And the Linux kernel memory model (https://lwn.net/Articles/718628/
> > and https://lwn.net/Articles/720550/) agrees with Alan.  Here is
> > a litmus test, which emulates spin_lock() with xchg_acquire() and
> > spin_unlock() with smp_store_release():
> > 
> > ------------------------------------------------------------------------
> > 
> > C C-ManfredSpraul-L1G1xchgnr.litmus
> > 
> > (* Expected result: Never.  *)
> > 
> > {
> > }
> > 
> > P0(int *nfcla, spinlock_t *gbl, int *gbl_held, spinlock_t *lcl, int *lcl_held)
> > {
> > 	/* Acquire local lock. */
> > 	r10 = xchg_acquire(lcl, 1);
> > 	r1 = READ_ONCE(*nfcla);
> > 	if (r1) {
> > 		smp_store_release(lcl, 0);
> > 		r11 = xchg_acquire(gbl, 1);
> > 		r12 = xchg_acquire(lcl, 1);
> > 		smp_store_release(gbl, 0);
> > 	}
> > 	r2 = READ_ONCE(*gbl_held);
> > 	WRITE_ONCE(*lcl_held, 1);
> > 	WRITE_ONCE(*lcl_held, 0);
> > 	smp_store_release(lcl, 0);
> > }
> > 
> > P1(int *nfcla, spinlock_t *gbl, int *gbl_held, spinlock_t *lcl, int *lcl_held)
> > {
> > 	/* Acquire global lock. */
> > 	r10 = xchg_acquire(gbl, 1);
> > 	WRITE_ONCE(*nfcla, 1);
> > 	r11 = xchg_acquire(lcl, 1);
> > 	smp_store_release(lcl, 0);
> > 	r2 = READ_ONCE(*lcl_held);
> > 	WRITE_ONCE(*gbl_held, 1);
> 
> This litmus test is incomplete, because it omits the assignment setting
> nf_conntrack_locks_all back to false when the global lock is released.  
> You should insert
> 
> 	smp_store_release(*nfcla, 0);
> 
> right here.
> 
> > 	WRITE_ONCE(*gbl_held, 0);
> > 	smp_store_release(gbl, 0);
> > }
> > 
> > exists
> > ((0:r2=1 \/ 1:r2=1) /\ 0:r10=0 /\ 0:r11=0 /\ 0:r12=0 /\ 1:r10=0 /\ 1:r11=0)
> 
> With that addition, the litmus test fails unless the read of nfcla in 
> P0 is an smp_load_acquire.  So Manfred's patch should not be changed.

Very good!  Aside from updating litmus tests, my work is done!  ;-)

							Thanx, Paul

^ permalink raw reply	[flat|nested] 122+ messages in thread

* Re: [PATCH RFC 08/26] locking: Remove spin_unlock_wait() generic definitions
  2017-07-03 16:40               ` Linus Torvalds
  2017-07-03 17:13                 ` Will Deacon
@ 2017-07-03 21:10                 ` Paul E. McKenney
  1 sibling, 0 replies; 122+ messages in thread
From: Paul E. McKenney @ 2017-07-03 21:10 UTC (permalink / raw)
  To: Linus Torvalds
  Cc: Will Deacon, Linux Kernel Mailing List, NetFilter,
	Network Development, Oleg Nesterov, Andrew Morton, Ingo Molnar,
	Davidlohr Bueso, Manfred Spraul, Tejun Heo, Arnd Bergmann,
	linux-arch, Peter Zijlstra, Alan Stern, Andrea Parri

On Mon, Jul 03, 2017 at 09:40:22AM -0700, Linus Torvalds wrote:
> On Mon, Jul 3, 2017 at 9:18 AM, Paul E. McKenney
> <paulmck@linux.vnet.ibm.com> wrote:
> >
> > Agreed, and my next step is to look at spin_lock() followed by
> > spin_is_locked(), not necessarily the same lock.
> 
> Hmm. Most (all?) "spin_is_locked()" really should be about the same
> thread that took the lock (ie it's about asserts and lock debugging).

Good to know, that does make things easier.  ;-)

I am not certain that it is feasible to automatically recognize
non-assert/non-debugging use cases of spin_is_locked(), but there is
aways manual inspection.

> The optimistic ABBA avoidance pattern for spinlocks *should* be
> 
>     spin_lock(inner)
>     ...
>     if (!try_lock(outer)) {
>            spin_unlock(inner);
>            .. do them in the right order ..
> 
> so I don't think spin_is_locked() should have any memory barriers.
> 
> In fact, the core function for spin_is_locked() is arguably
> arch_spin_value_unlocked() which doesn't even do the access itself.

OK, so we should rework any cases where people are relying on acquisition
of one spin_lock() being ordered with a later spin_is_locked() on some
other lock by that same thread.

							Thanx, Paul

^ permalink raw reply	[flat|nested] 122+ messages in thread

* Re: [PATCH RFC 08/26] locking: Remove spin_unlock_wait() generic definitions
  2017-07-03 17:13                 ` Will Deacon
@ 2017-07-03 22:30                   ` Paul E. McKenney
  2017-07-03 22:49                     ` Linus Torvalds
  0 siblings, 1 reply; 122+ messages in thread
From: Paul E. McKenney @ 2017-07-03 22:30 UTC (permalink / raw)
  To: Will Deacon
  Cc: Linus Torvalds, Linux Kernel Mailing List, NetFilter,
	Network Development, Oleg Nesterov, Andrew Morton, Ingo Molnar,
	Davidlohr Bueso, Manfred Spraul, Tejun Heo, Arnd Bergmann,
	linux-arch, Peter Zijlstra, Alan Stern, Andrea Parri

On Mon, Jul 03, 2017 at 06:13:38PM +0100, Will Deacon wrote:
> On Mon, Jul 03, 2017 at 09:40:22AM -0700, Linus Torvalds wrote:
> > On Mon, Jul 3, 2017 at 9:18 AM, Paul E. McKenney
> > <paulmck@linux.vnet.ibm.com> wrote:
> > >
> > > Agreed, and my next step is to look at spin_lock() followed by
> > > spin_is_locked(), not necessarily the same lock.
> > 
> > Hmm. Most (all?) "spin_is_locked()" really should be about the same
> > thread that took the lock (ie it's about asserts and lock debugging).
> > 
> > The optimistic ABBA avoidance pattern for spinlocks *should* be
> > 
> >     spin_lock(inner)
> >     ...
> >     if (!try_lock(outer)) {
> >            spin_unlock(inner);
> >            .. do them in the right order ..
> > 
> > so I don't think spin_is_locked() should have any memory barriers.
> > 
> > In fact, the core function for spin_is_locked() is arguably
> > arch_spin_value_unlocked() which doesn't even do the access itself.
> 
> Yeah, but there's some spaced-out stuff going on in kgdb_cpu_enter where
> it looks to me like raw_spin_is_locked is used for synchronization. My
> eyes are hurting looking at it, though.

That certainly is one interesting function, isn't it?  I wonder what
happens if you replace the raw_spin_is_locked() calls with an
unlock under a trylock check?  ;-)

							Thanx, Paul

^ permalink raw reply	[flat|nested] 122+ messages in thread

* Re: [PATCH RFC 08/26] locking: Remove spin_unlock_wait() generic definitions
  2017-07-03 22:30                   ` Paul E. McKenney
@ 2017-07-03 22:49                     ` Linus Torvalds
  2017-07-04  0:39                       ` Paul E. McKenney
  0 siblings, 1 reply; 122+ messages in thread
From: Linus Torvalds @ 2017-07-03 22:49 UTC (permalink / raw)
  To: Paul McKenney
  Cc: Will Deacon, Linux Kernel Mailing List, NetFilter,
	Network Development, Oleg Nesterov, Andrew Morton, Ingo Molnar,
	Davidlohr Bueso, Manfred Spraul, Tejun Heo, Arnd Bergmann,
	linux-arch, Peter Zijlstra, Alan Stern, Andrea Parri

On Mon, Jul 3, 2017 at 3:30 PM, Paul E. McKenney
<paulmck@linux.vnet.ibm.com> wrote:
>
> That certainly is one interesting function, isn't it?  I wonder what
> happens if you replace the raw_spin_is_locked() calls with an
> unlock under a trylock check?  ;-)

Deadlock due to interrupts again?

Didn't your spin_unlock_wait() patches teach you anything? Checking
state is fundamentally different from taking the lock. Even a trylock.

I guess you could try with the irqsave versions. But no, we're not doing that.

                Linus

^ permalink raw reply	[flat|nested] 122+ messages in thread

* Re: [PATCH RFC 08/26] locking: Remove spin_unlock_wait() generic definitions
  2017-07-03 22:49                     ` Linus Torvalds
@ 2017-07-04  0:39                       ` Paul E. McKenney
  2017-07-04  0:54                         ` Paul E. McKenney
  0 siblings, 1 reply; 122+ messages in thread
From: Paul E. McKenney @ 2017-07-04  0:39 UTC (permalink / raw)
  To: Linus Torvalds
  Cc: Will Deacon, Linux Kernel Mailing List, NetFilter,
	Network Development, Oleg Nesterov, Andrew Morton, Ingo Molnar,
	Davidlohr Bueso, Manfred Spraul, Tejun Heo, Arnd Bergmann,
	linux-arch, Peter Zijlstra, Alan Stern, Andrea Parri

On Mon, Jul 03, 2017 at 03:49:42PM -0700, Linus Torvalds wrote:
> On Mon, Jul 3, 2017 at 3:30 PM, Paul E. McKenney
> <paulmck@linux.vnet.ibm.com> wrote:
> >
> > That certainly is one interesting function, isn't it?  I wonder what
> > happens if you replace the raw_spin_is_locked() calls with an
> > unlock under a trylock check?  ;-)
> 
> Deadlock due to interrupts again?

Unless I am missing something subtle, the kgdb_cpu_enter() function in
question has a local_irq_save() over the "interesting" portion of its
workings, so interrupt-handler self-deadlock should not happen.

> Didn't your spin_unlock_wait() patches teach you anything? Checking
> state is fundamentally different from taking the lock. Even a trylock.

That was an embarrassing bug, no two ways about it.  :-/

> I guess you could try with the irqsave versions. But no, we're not doing that.

Again, no need in this case.

But I agree with Will's assessment of this function...

The raw_spin_is_locked() looks to be asking if -any- CPU holds the
dbg_slave_lock, and the answer could of course change immediately
on return from raw_spin_is_locked().  Perhaps the theory is that
if other CPU holds the lock, this CPU is supposed to be subjected to
kgdb_roundup_cpus().  Except that the CPU that held dbg_slave_lock might
be just about to release that lock.  Odd.

Seems like there should be a get_online_cpus() somewhere, but maybe
that constraint is to be manually enforced.

							Thanx, Paul

^ permalink raw reply	[flat|nested] 122+ messages in thread

* Re: [PATCH RFC 08/26] locking: Remove spin_unlock_wait() generic definitions
  2017-07-04  0:39                       ` Paul E. McKenney
@ 2017-07-04  0:54                         ` Paul E. McKenney
  0 siblings, 0 replies; 122+ messages in thread
From: Paul E. McKenney @ 2017-07-04  0:54 UTC (permalink / raw)
  To: Linus Torvalds
  Cc: Will Deacon, Linux Kernel Mailing List, NetFilter,
	Network Development, Oleg Nesterov, Andrew Morton, Ingo Molnar,
	Davidlohr Bueso, Manfred Spraul, Tejun Heo, Arnd Bergmann,
	linux-arch, Peter Zijlstra, Alan Stern, Andrea Parri

On Mon, Jul 03, 2017 at 05:39:36PM -0700, Paul E. McKenney wrote:
> On Mon, Jul 03, 2017 at 03:49:42PM -0700, Linus Torvalds wrote:
> > On Mon, Jul 3, 2017 at 3:30 PM, Paul E. McKenney
> > <paulmck@linux.vnet.ibm.com> wrote:
> > >
> > > That certainly is one interesting function, isn't it?  I wonder what
> > > happens if you replace the raw_spin_is_locked() calls with an
> > > unlock under a trylock check?  ;-)
> > 
> > Deadlock due to interrupts again?
> 
> Unless I am missing something subtle, the kgdb_cpu_enter() function in
> question has a local_irq_save() over the "interesting" portion of its
> workings, so interrupt-handler self-deadlock should not happen.
> 
> > Didn't your spin_unlock_wait() patches teach you anything? Checking
> > state is fundamentally different from taking the lock. Even a trylock.
> 
> That was an embarrassing bug, no two ways about it.  :-/
> 
> > I guess you could try with the irqsave versions. But no, we're not doing that.
> 
> Again, no need in this case.
> 
> But I agree with Will's assessment of this function...
> 
> The raw_spin_is_locked() looks to be asking if -any- CPU holds the
> dbg_slave_lock, and the answer could of course change immediately
> on return from raw_spin_is_locked().  Perhaps the theory is that
> if other CPU holds the lock, this CPU is supposed to be subjected to
> kgdb_roundup_cpus().  Except that the CPU that held dbg_slave_lock might
> be just about to release that lock.  Odd.
> 
> Seems like there should be a get_online_cpus() somewhere, but maybe
> that constraint is to be manually enforced.

Except that invoking get_online_cpus() from an exception handler would
be of course be a spectacularly bad idea.  I would feel better if the
num_online_cpus() was under the local_irq_save(), but perhaps this code
is relying on the stop_machine().  Except that it appears we could
deadlock with offline waiting for stop_machine() to complete and kdbg
waiting for all CPUs to report, including those in stop_machine().

Looks like the current situation is "Don't use kdbg if there is any
possibility of CPU-hotplug operations."  Not necessarily an unreasonable
restriction.

But I need to let me eyes heal a bit before looking at this more.

							Thanx, Paul

^ permalink raw reply	[flat|nested] 122+ messages in thread

* [PATCH v2 0/9] Remove spin_unlock_wait()
  2017-06-29 23:59 [PATCH RFC 0/26] Remove spin_unlock_wait() Paul E. McKenney
                   ` (24 preceding siblings ...)
       [not found] ` <1498780894-8253-6-git-send-email-paulmck@linux.vnet.ibm.com>
@ 2017-07-05 23:29 ` Paul E. McKenney
  2017-07-05 23:31   ` [PATCH v2 1/9] net/netfilter/nf_conntrack_core: Fix net_conntrack_lock() Paul E. McKenney
                     ` (10 more replies)
  25 siblings, 11 replies; 122+ messages in thread
From: Paul E. McKenney @ 2017-07-05 23:29 UTC (permalink / raw)
  To: linux-kernel
  Cc: netfilter-devel, netdev, oleg, akpm, mingo, dave, manfred, tj,
	arnd, linux-arch, will.deacon, peterz, stern, parri.andrea,
	torvalds

Hello!

There is no agreed-upon definition of spin_unlock_wait()'s semantics,
and it appears that all callers could do just as well with a lock/unlock
pair.  This series therefore removes spin_unlock_wait() and changes
its users to instead use a lock/unlock pair.  The commits are as follows,
in three groups:

1-7.	Change uses of spin_unlock_wait() and raw_spin_unlock_wait()
	to instead use a spin_lock/spin_unlock pair.  These may be
	applied in any order, but must be applied before any later
	commits in this series.  The commit logs state why I believe
	that these commits won't noticeably degrade performance.

8.	Remove core-kernel definitions for spin_unlock_wait() and
	raw_spin_unlock_wait().

9.	Remove arch-specific definitions of arch_spin_unlock_wait().

Changes since v1:

o	Disable interrupts where needed, thus avoiding embarrassing
	interrupt-based self-deadlocks.

o	Substitute Manfred's patch for contrack_lock (#1 above).

o	Substitute Oleg's patch for task_work (#2 above).

o	Use more efficient barrier based on Arnd Bergmann feedback.

							Thanx, Paul

------------------------------------------------------------------------

 arch/alpha/include/asm/spinlock.h    |    5 -
 arch/arc/include/asm/spinlock.h      |    5 -
 arch/arm/include/asm/spinlock.h      |   16 ----
 arch/arm64/include/asm/spinlock.h    |   58 +----------------
 arch/blackfin/include/asm/spinlock.h |    5 -
 arch/hexagon/include/asm/spinlock.h  |    5 -
 arch/ia64/include/asm/spinlock.h     |   21 ------
 arch/m32r/include/asm/spinlock.h     |    5 -
 arch/metag/include/asm/spinlock.h    |    5 -
 arch/mips/include/asm/spinlock.h     |   16 ----
 arch/mn10300/include/asm/spinlock.h  |    5 -
 arch/parisc/include/asm/spinlock.h   |    7 --
 arch/powerpc/include/asm/spinlock.h  |   33 ---------
 arch/s390/include/asm/spinlock.h     |    7 --
 arch/sh/include/asm/spinlock-cas.h   |    5 -
 arch/sh/include/asm/spinlock-llsc.h  |    5 -
 arch/sparc/include/asm/spinlock_32.h |    5 -
 arch/sparc/include/asm/spinlock_64.h |    5 -
 arch/tile/include/asm/spinlock_32.h  |    2 
 arch/tile/include/asm/spinlock_64.h  |    2 
 arch/tile/lib/spinlock_32.c          |   23 ------
 arch/tile/lib/spinlock_64.c          |   22 ------
 arch/xtensa/include/asm/spinlock.h   |    5 -
 drivers/ata/libata-eh.c              |    8 --
 include/asm-generic/qspinlock.h      |   14 ----
 include/linux/spinlock.h             |   31 ---------
 include/linux/spinlock_up.h          |    6 -
 ipc/sem.c                            |    3 
 kernel/exit.c                        |    3 
 kernel/locking/qspinlock.c           |  117 -----------------------------------
 kernel/sched/completion.c            |    9 --
 kernel/sched/core.c                  |    5 -
 kernel/task_work.c                   |    8 --
 net/netfilter/nf_conntrack_core.c    |   44 +++++++------
 34 files changed, 43 insertions(+), 472 deletions(-)

^ permalink raw reply	[flat|nested] 122+ messages in thread

* [PATCH v2 1/9] net/netfilter/nf_conntrack_core: Fix net_conntrack_lock()
  2017-07-05 23:29 ` [PATCH v2 0/9] Remove spin_unlock_wait() Paul E. McKenney
@ 2017-07-05 23:31   ` Paul E. McKenney
  2017-07-06 18:45     ` Manfred Spraul
  2017-07-05 23:31   ` [PATCH v2 2/9] task_work: Replace spin_unlock_wait() with lock/unlock pair Paul E. McKenney
                     ` (9 subsequent siblings)
  10 siblings, 1 reply; 122+ messages in thread
From: Paul E. McKenney @ 2017-07-05 23:31 UTC (permalink / raw)
  To: linux-kernel
  Cc: netfilter-devel, netdev, oleg, akpm, mingo, dave, manfred, tj,
	arnd, linux-arch, will.deacon, peterz, stern, parri.andrea,
	torvalds, stable, Sasha Levin, Pablo Neira Ayuso,
	Paul E. McKenney

From: Manfred Spraul <manfred@colorfullife.com>

As we want to remove spin_unlock_wait() and replace it with explicit
spin_lock()/spin_unlock() calls, we can use this to simplify the
locking.

In addition:
- Reading nf_conntrack_locks_all needs ACQUIRE memory ordering.
- The new code avoids the backwards loop.

Only slightly tested, I did not manage to trigger calls to
nf_conntrack_all_lock().

Fixes: b16c29191dc8
Signed-off-by: Manfred Spraul <manfred@colorfullife.com>
Cc: <stable@vger.kernel.org>
Cc: Sasha Levin <sasha.levin@oracle.com>
Cc: Pablo Neira Ayuso <pablo@netfilter.org>
Cc: netfilter-devel@vger.kernel.org
Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
---
 net/netfilter/nf_conntrack_core.c | 44 +++++++++++++++++++++------------------
 1 file changed, 24 insertions(+), 20 deletions(-)

diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c
index e847dbaa0c6b..1193565c38ae 100644
--- a/net/netfilter/nf_conntrack_core.c
+++ b/net/netfilter/nf_conntrack_core.c
@@ -96,19 +96,24 @@ static struct conntrack_gc_work conntrack_gc_work;
 
 void nf_conntrack_lock(spinlock_t *lock) __acquires(lock)
 {
+	/* 1) Acquire the lock */
 	spin_lock(lock);
-	while (unlikely(nf_conntrack_locks_all)) {
-		spin_unlock(lock);
 
-		/*
-		 * Order the 'nf_conntrack_locks_all' load vs. the
-		 * spin_unlock_wait() loads below, to ensure
-		 * that 'nf_conntrack_locks_all_lock' is indeed held:
-		 */
-		smp_rmb(); /* spin_lock(&nf_conntrack_locks_all_lock) */
-		spin_unlock_wait(&nf_conntrack_locks_all_lock);
-		spin_lock(lock);
-	}
+	/* 2) read nf_conntrack_locks_all, with ACQUIRE semantics */
+	if (likely(smp_load_acquire(&nf_conntrack_locks_all) == false))
+		return;
+
+	/* fast path failed, unlock */
+	spin_unlock(lock);
+
+	/* Slow path 1) get global lock */
+	spin_lock(&nf_conntrack_locks_all_lock);
+
+	/* Slow path 2) get the lock we want */
+	spin_lock(lock);
+
+	/* Slow path 3) release the global lock */
+	spin_unlock(&nf_conntrack_locks_all_lock);
 }
 EXPORT_SYMBOL_GPL(nf_conntrack_lock);
 
@@ -149,18 +154,17 @@ static void nf_conntrack_all_lock(void)
 	int i;
 
 	spin_lock(&nf_conntrack_locks_all_lock);
-	nf_conntrack_locks_all = true;
 
-	/*
-	 * Order the above store of 'nf_conntrack_locks_all' against
-	 * the spin_unlock_wait() loads below, such that if
-	 * nf_conntrack_lock() observes 'nf_conntrack_locks_all'
-	 * we must observe nf_conntrack_locks[] held:
-	 */
-	smp_mb(); /* spin_lock(&nf_conntrack_locks_all_lock) */
+	nf_conntrack_locks_all = true;
 
 	for (i = 0; i < CONNTRACK_LOCKS; i++) {
-		spin_unlock_wait(&nf_conntrack_locks[i]);
+		spin_lock(&nf_conntrack_locks[i]);
+
+		/* This spin_unlock provides the "release" to ensure that
+		 * nf_conntrack_locks_all==true is visible to everyone that
+		 * acquired spin_lock(&nf_conntrack_locks[]).
+		 */
+		spin_unlock(&nf_conntrack_locks[i]);
 	}
 }
 
-- 
2.5.2

^ permalink raw reply related	[flat|nested] 122+ messages in thread

* [PATCH v2 2/9] task_work: Replace spin_unlock_wait() with lock/unlock pair
  2017-07-05 23:29 ` [PATCH v2 0/9] Remove spin_unlock_wait() Paul E. McKenney
  2017-07-05 23:31   ` [PATCH v2 1/9] net/netfilter/nf_conntrack_core: Fix net_conntrack_lock() Paul E. McKenney
@ 2017-07-05 23:31   ` Paul E. McKenney
  2017-07-05 23:31   ` [PATCH v2 3/9] sched: " Paul E. McKenney
                     ` (8 subsequent siblings)
  10 siblings, 0 replies; 122+ messages in thread
From: Paul E. McKenney @ 2017-07-05 23:31 UTC (permalink / raw)
  To: linux-kernel
  Cc: netfilter-devel, netdev, oleg, akpm, mingo, dave, manfred, tj,
	arnd, linux-arch, will.deacon, peterz, stern, parri.andrea,
	torvalds, Paul E. McKenney

From: Oleg Nesterov <oleg@redhat.com>

There is no agreed-upon definition of spin_unlock_wait()'s semantics,
and it appears that all callers could do just as well with a lock/unlock
pair.  This commit therefore replaces the spin_unlock_wait() call in
task_work_run() with a spin_lock_irq() and a spin_unlock_irq() aruond
the cmpxchg() dequeue loop.  This should be safe from a performance
perspective because ->pi_lock is local to the task and because calls to
the other side of the race, task_work_cancel(), should be rare.

Signed-off-by: Oleg Nesterov <oleg@redhat.com>
Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
---
 kernel/task_work.c | 8 ++------
 1 file changed, 2 insertions(+), 6 deletions(-)

diff --git a/kernel/task_work.c b/kernel/task_work.c
index d513051fcca2..836a72a66fba 100644
--- a/kernel/task_work.c
+++ b/kernel/task_work.c
@@ -96,20 +96,16 @@ void task_work_run(void)
 		 * work->func() can do task_work_add(), do not set
 		 * work_exited unless the list is empty.
 		 */
+		raw_spin_lock_irq(&task->pi_lock);
 		do {
 			work = READ_ONCE(task->task_works);
 			head = !work && (task->flags & PF_EXITING) ?
 				&work_exited : NULL;
 		} while (cmpxchg(&task->task_works, work, head) != work);
+		raw_spin_unlock_irq(&task->pi_lock);
 
 		if (!work)
 			break;
-		/*
-		 * Synchronize with task_work_cancel(). It can't remove
-		 * the first entry == work, cmpxchg(task_works) should
-		 * fail, but it can play with *work and other entries.
-		 */
-		raw_spin_unlock_wait(&task->pi_lock);
 
 		do {
 			next = work->next;
-- 
2.5.2

^ permalink raw reply related	[flat|nested] 122+ messages in thread

* [PATCH v2 3/9] sched: Replace spin_unlock_wait() with lock/unlock pair
  2017-07-05 23:29 ` [PATCH v2 0/9] Remove spin_unlock_wait() Paul E. McKenney
  2017-07-05 23:31   ` [PATCH v2 1/9] net/netfilter/nf_conntrack_core: Fix net_conntrack_lock() Paul E. McKenney
  2017-07-05 23:31   ` [PATCH v2 2/9] task_work: Replace spin_unlock_wait() with lock/unlock pair Paul E. McKenney
@ 2017-07-05 23:31   ` Paul E. McKenney
  2017-07-05 23:31   ` [PATCH v2 4/9] completion: " Paul E. McKenney
                     ` (7 subsequent siblings)
  10 siblings, 0 replies; 122+ messages in thread
From: Paul E. McKenney @ 2017-07-05 23:31 UTC (permalink / raw)
  To: linux-kernel
  Cc: netfilter-devel, netdev, oleg, akpm, mingo, dave, manfred, tj,
	arnd, linux-arch, will.deacon, peterz, stern, parri.andrea,
	torvalds, Paul E. McKenney

There is no agreed-upon definition of spin_unlock_wait()'s semantics,
and it appears that all callers could do just as well with a lock/unlock
pair.  This commit therefore replaces the spin_unlock_wait() call in
do_task_dead() with spin_lock() followed immediately by spin_unlock().
This should be safe from a performance perspective because the lock is
this tasks ->pi_lock, and this is called only after the task exits.

Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Will Deacon <will.deacon@arm.com>
Cc: Alan Stern <stern@rowland.harvard.edu>
Cc: Andrea Parri <parri.andrea@gmail.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
[ paulmck: Replace leading smp_mb() with smp_mb__before_spinlock(),
  courtesy of Arnd Bergmann's noting its odd location. ]
---
 kernel/sched/core.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index e91138fcde86..48a8760fedf4 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -3460,8 +3460,9 @@ void __noreturn do_task_dead(void)
 	 * To avoid it, we have to wait for releasing tsk->pi_lock which
 	 * is held by try_to_wake_up()
 	 */
-	smp_mb();
-	raw_spin_unlock_wait(&current->pi_lock);
+	smp_mb__before_spinlock();
+	raw_spin_lock_irq(&current->pi_lock);
+	raw_spin_unlock_irq(&current->pi_lock);
 
 	/* Causes final put_task_struct in finish_task_switch(): */
 	__set_current_state(TASK_DEAD);
-- 
2.5.2

^ permalink raw reply related	[flat|nested] 122+ messages in thread

* [PATCH v2 4/9] completion: Replace spin_unlock_wait() with lock/unlock pair
  2017-07-05 23:29 ` [PATCH v2 0/9] Remove spin_unlock_wait() Paul E. McKenney
                     ` (2 preceding siblings ...)
  2017-07-05 23:31   ` [PATCH v2 3/9] sched: " Paul E. McKenney
@ 2017-07-05 23:31   ` Paul E. McKenney
  2017-07-05 23:31   ` [PATCH v2 5/9] exit: " Paul E. McKenney
                     ` (6 subsequent siblings)
  10 siblings, 0 replies; 122+ messages in thread
From: Paul E. McKenney @ 2017-07-05 23:31 UTC (permalink / raw)
  To: linux-kernel
  Cc: netfilter-devel, netdev, oleg, akpm, mingo, dave, manfred, tj,
	arnd, linux-arch, will.deacon, peterz, stern, parri.andrea,
	torvalds, Paul E. McKenney

There is no agreed-upon definition of spin_unlock_wait()'s semantics,
and it appears that all callers could do just as well with a lock/unlock
pair.  This commit therefore replaces the spin_unlock_wait() call in
completion_done() with spin_lock() followed immediately by spin_unlock().
This should be safe from a performance perspective because the lock
will be held only the wakeup happens really quickly.

Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Will Deacon <will.deacon@arm.com>
Cc: Alan Stern <stern@rowland.harvard.edu>
Cc: Andrea Parri <parri.andrea@gmail.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
---
 kernel/sched/completion.c | 9 ++-------
 1 file changed, 2 insertions(+), 7 deletions(-)

diff --git a/kernel/sched/completion.c b/kernel/sched/completion.c
index 53f9558fa925..3e66712e1964 100644
--- a/kernel/sched/completion.c
+++ b/kernel/sched/completion.c
@@ -307,14 +307,9 @@ bool completion_done(struct completion *x)
 	 * If ->done, we need to wait for complete() to release ->wait.lock
 	 * otherwise we can end up freeing the completion before complete()
 	 * is done referencing it.
-	 *
-	 * The RMB pairs with complete()'s RELEASE of ->wait.lock and orders
-	 * the loads of ->done and ->wait.lock such that we cannot observe
-	 * the lock before complete() acquires it while observing the ->done
-	 * after it's acquired the lock.
 	 */
-	smp_rmb();
-	spin_unlock_wait(&x->wait.lock);
+	spin_lock_irq(&x->wait.lock);
+	spin_unlock_irq(&x->wait.lock);
 	return true;
 }
 EXPORT_SYMBOL(completion_done);
-- 
2.5.2

^ permalink raw reply related	[flat|nested] 122+ messages in thread

* [PATCH v2 5/9] exit: Replace spin_unlock_wait() with lock/unlock pair
  2017-07-05 23:29 ` [PATCH v2 0/9] Remove spin_unlock_wait() Paul E. McKenney
                     ` (3 preceding siblings ...)
  2017-07-05 23:31   ` [PATCH v2 4/9] completion: " Paul E. McKenney
@ 2017-07-05 23:31   ` Paul E. McKenney
  2017-07-05 23:31   ` [PATCH v2 6/9] ipc: " Paul E. McKenney
                     ` (5 subsequent siblings)
  10 siblings, 0 replies; 122+ messages in thread
From: Paul E. McKenney @ 2017-07-05 23:31 UTC (permalink / raw)
  To: linux-kernel
  Cc: netfilter-devel, netdev, oleg, akpm, mingo, dave, manfred, tj,
	arnd, linux-arch, will.deacon, peterz, stern, parri.andrea,
	torvalds, Paul E. McKenney, Ingo Molnar

There is no agreed-upon definition of spin_unlock_wait()'s semantics, and
it appears that all callers could do just as well with a lock/unlock pair.
This commit therefore replaces the spin_unlock_wait() call in do_exit()
with spin_lock() followed immediately by spin_unlock().  This should be
safe from a performance perspective because the lock is a per-task lock,
and this is happening only at task-exit time.

Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Cc: Ingo Molnar <mingo@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Will Deacon <will.deacon@arm.com>
Cc: Alan Stern <stern@rowland.harvard.edu>
Cc: Andrea Parri <parri.andrea@gmail.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
---
 kernel/exit.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/kernel/exit.c b/kernel/exit.c
index 516acdb0e0ec..6d19c9090d43 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -832,7 +832,8 @@ void __noreturn do_exit(long code)
 	 * Ensure that we must observe the pi_state in exit_mm() ->
 	 * mm_release() -> exit_pi_state_list().
 	 */
-	raw_spin_unlock_wait(&tsk->pi_lock);
+	raw_spin_lock_irq(&tsk->pi_lock);
+	raw_spin_unlock_irq(&tsk->pi_lock);
 
 	if (unlikely(in_atomic())) {
 		pr_info("note: %s[%d] exited with preempt_count %d\n",
-- 
2.5.2

^ permalink raw reply related	[flat|nested] 122+ messages in thread

* [PATCH v2 6/9] ipc: Replace spin_unlock_wait() with lock/unlock pair
  2017-07-05 23:29 ` [PATCH v2 0/9] Remove spin_unlock_wait() Paul E. McKenney
                     ` (4 preceding siblings ...)
  2017-07-05 23:31   ` [PATCH v2 5/9] exit: " Paul E. McKenney
@ 2017-07-05 23:31   ` Paul E. McKenney
  2017-07-05 23:31   ` [PATCH v2 7/9] drivers/ata: " Paul E. McKenney
                     ` (4 subsequent siblings)
  10 siblings, 0 replies; 122+ messages in thread
From: Paul E. McKenney @ 2017-07-05 23:31 UTC (permalink / raw)
  To: linux-kernel
  Cc: netfilter-devel, netdev, oleg, akpm, mingo, dave, manfred, tj,
	arnd, linux-arch, will.deacon, peterz, stern, parri.andrea,
	torvalds, Paul E. McKenney

There is no agreed-upon definition of spin_unlock_wait()'s semantics,
and it appears that all callers could do just as well with a lock/unlock
pair.  This commit therefore replaces the spin_unlock_wait() call in
exit_sem() with spin_lock() followed immediately by spin_unlock().
This should be safe from a performance perspective because exit_sem()
is rarely invoked in production.

Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Davidlohr Bueso <dave@stgolabs.net>
Cc: Will Deacon <will.deacon@arm.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Alan Stern <stern@rowland.harvard.edu>
Cc: Andrea Parri <parri.andrea@gmail.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Acked-by: Manfred Spraul <manfred@colorfullife.com>
---
 ipc/sem.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/ipc/sem.c b/ipc/sem.c
index 947dc2348271..e88d0749a929 100644
--- a/ipc/sem.c
+++ b/ipc/sem.c
@@ -2096,7 +2096,8 @@ void exit_sem(struct task_struct *tsk)
 			 * possibility where we exit while freeary() didn't
 			 * finish unlocking sem_undo_list.
 			 */
-			spin_unlock_wait(&ulp->lock);
+			spin_lock(&ulp->lock);
+			spin_unlock(&ulp->lock);
 			rcu_read_unlock();
 			break;
 		}
-- 
2.5.2

^ permalink raw reply related	[flat|nested] 122+ messages in thread

* [PATCH v2 7/9] drivers/ata: Replace spin_unlock_wait() with lock/unlock pair
  2017-07-05 23:29 ` [PATCH v2 0/9] Remove spin_unlock_wait() Paul E. McKenney
                     ` (5 preceding siblings ...)
  2017-07-05 23:31   ` [PATCH v2 6/9] ipc: " Paul E. McKenney
@ 2017-07-05 23:31   ` Paul E. McKenney
  2017-07-05 23:31   ` [PATCH v2 8/9] locking: Remove spin_unlock_wait() generic definitions Paul E. McKenney
                     ` (3 subsequent siblings)
  10 siblings, 0 replies; 122+ messages in thread
From: Paul E. McKenney @ 2017-07-05 23:31 UTC (permalink / raw)
  To: linux-kernel
  Cc: netfilter-devel, netdev, oleg, akpm, mingo, dave, manfred, tj,
	arnd, linux-arch, will.deacon, peterz, stern, parri.andrea,
	torvalds, Paul E. McKenney, linux-ide

There is no agreed-upon definition of spin_unlock_wait()'s semantics,
and it appears that all callers could do just as well with a lock/unlock
pair.  This commit therefore eliminates the spin_unlock_wait() call and
associated else-clause and hoists the then-clause's lock and unlock out of
the "if" statement.  This should be safe from a performance perspective
because according to Tejun there should be few if any drivers that don't
set their own error handler.

Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Acked-by: Tejun Heo <tj@kernel.org>
Cc: <linux-ide@vger.kernel.org>
Cc: Will Deacon <will.deacon@arm.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Alan Stern <stern@rowland.harvard.edu>
Cc: Andrea Parri <parri.andrea@gmail.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
---
 drivers/ata/libata-eh.c | 8 +++-----
 1 file changed, 3 insertions(+), 5 deletions(-)

diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c
index ef68232b5222..779f6f18c1f4 100644
--- a/drivers/ata/libata-eh.c
+++ b/drivers/ata/libata-eh.c
@@ -645,12 +645,11 @@ void ata_scsi_cmd_error_handler(struct Scsi_Host *host, struct ata_port *ap,
 	 * completions are honored.  A scmd is determined to have
 	 * timed out iff its associated qc is active and not failed.
 	 */
+	spin_lock_irqsave(ap->lock, flags);
 	if (ap->ops->error_handler) {
 		struct scsi_cmnd *scmd, *tmp;
 		int nr_timedout = 0;
 
-		spin_lock_irqsave(ap->lock, flags);
-
 		/* This must occur under the ap->lock as we don't want
 		   a polled recovery to race the real interrupt handler
 
@@ -700,12 +699,11 @@ void ata_scsi_cmd_error_handler(struct Scsi_Host *host, struct ata_port *ap,
 		if (nr_timedout)
 			__ata_port_freeze(ap);
 
-		spin_unlock_irqrestore(ap->lock, flags);
 
 		/* initialize eh_tries */
 		ap->eh_tries = ATA_EH_MAX_TRIES;
-	} else
-		spin_unlock_wait(ap->lock);
+	}
+	spin_unlock_irqrestore(ap->lock, flags);
 
 }
 EXPORT_SYMBOL(ata_scsi_cmd_error_handler);
-- 
2.5.2

^ permalink raw reply related	[flat|nested] 122+ messages in thread

* [PATCH v2 8/9] locking: Remove spin_unlock_wait() generic definitions
  2017-07-05 23:29 ` [PATCH v2 0/9] Remove spin_unlock_wait() Paul E. McKenney
                     ` (6 preceding siblings ...)
  2017-07-05 23:31   ` [PATCH v2 7/9] drivers/ata: " Paul E. McKenney
@ 2017-07-05 23:31   ` Paul E. McKenney
  2017-07-05 23:31   ` [PATCH v2 9/9] arch: Remove spin_unlock_wait() arch-specific definitions Paul E. McKenney
                     ` (2 subsequent siblings)
  10 siblings, 0 replies; 122+ messages in thread
From: Paul E. McKenney @ 2017-07-05 23:31 UTC (permalink / raw)
  To: linux-kernel
  Cc: netfilter-devel, netdev, oleg, akpm, mingo, dave, manfred, tj,
	arnd, linux-arch, will.deacon, peterz, stern, parri.andrea,
	torvalds, Paul E. McKenney

There is no agreed-upon definition of spin_unlock_wait()'s semantics,
and it appears that all callers could do just as well with a lock/unlock
pair.  This commit therefore removes spin_unlock_wait() and related
definitions from core code.

Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Cc: Arnd Bergmann <arnd@arndb.de>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Will Deacon <will.deacon@arm.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Alan Stern <stern@rowland.harvard.edu>
Cc: Andrea Parri <parri.andrea@gmail.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
---
 include/asm-generic/qspinlock.h |  14 -----
 include/linux/spinlock.h        |  31 -----------
 include/linux/spinlock_up.h     |   6 ---
 kernel/locking/qspinlock.c      | 117 ----------------------------------------
 4 files changed, 168 deletions(-)

diff --git a/include/asm-generic/qspinlock.h b/include/asm-generic/qspinlock.h
index 9f0681bf1e87..66260777d644 100644
--- a/include/asm-generic/qspinlock.h
+++ b/include/asm-generic/qspinlock.h
@@ -22,17 +22,6 @@
 #include <asm-generic/qspinlock_types.h>
 
 /**
- * queued_spin_unlock_wait - wait until the _current_ lock holder releases the lock
- * @lock : Pointer to queued spinlock structure
- *
- * There is a very slight possibility of live-lock if the lockers keep coming
- * and the waiter is just unfortunate enough to not see any unlock state.
- */
-#ifndef queued_spin_unlock_wait
-extern void queued_spin_unlock_wait(struct qspinlock *lock);
-#endif
-
-/**
  * queued_spin_is_locked - is the spinlock locked?
  * @lock: Pointer to queued spinlock structure
  * Return: 1 if it is locked, 0 otherwise
@@ -41,8 +30,6 @@ extern void queued_spin_unlock_wait(struct qspinlock *lock);
 static __always_inline int queued_spin_is_locked(struct qspinlock *lock)
 {
 	/*
-	 * See queued_spin_unlock_wait().
-	 *
 	 * Any !0 state indicates it is locked, even if _Q_LOCKED_VAL
 	 * isn't immediately observable.
 	 */
@@ -135,6 +122,5 @@ static __always_inline bool virt_spin_lock(struct qspinlock *lock)
 #define arch_spin_trylock(l)		queued_spin_trylock(l)
 #define arch_spin_unlock(l)		queued_spin_unlock(l)
 #define arch_spin_lock_flags(l, f)	queued_spin_lock(l)
-#define arch_spin_unlock_wait(l)	queued_spin_unlock_wait(l)
 
 #endif /* __ASM_GENERIC_QSPINLOCK_H */
diff --git a/include/linux/spinlock.h b/include/linux/spinlock.h
index d9510e8522d4..ef018a6e4985 100644
--- a/include/linux/spinlock.h
+++ b/include/linux/spinlock.h
@@ -130,12 +130,6 @@ do {								\
 #define smp_mb__before_spinlock()	smp_wmb()
 #endif
 
-/**
- * raw_spin_unlock_wait - wait until the spinlock gets unlocked
- * @lock: the spinlock in question.
- */
-#define raw_spin_unlock_wait(lock)	arch_spin_unlock_wait(&(lock)->raw_lock)
-
 #ifdef CONFIG_DEBUG_SPINLOCK
  extern void do_raw_spin_lock(raw_spinlock_t *lock) __acquires(lock);
 #define do_raw_spin_lock_flags(lock, flags) do_raw_spin_lock(lock)
@@ -369,31 +363,6 @@ static __always_inline int spin_trylock_irq(spinlock_t *lock)
 	raw_spin_trylock_irqsave(spinlock_check(lock), flags); \
 })
 
-/**
- * spin_unlock_wait - Interpose between successive critical sections
- * @lock: the spinlock whose critical sections are to be interposed.
- *
- * Semantically this is equivalent to a spin_lock() immediately
- * followed by a spin_unlock().  However, most architectures have
- * more efficient implementations in which the spin_unlock_wait()
- * cannot block concurrent lock acquisition, and in some cases
- * where spin_unlock_wait() does not write to the lock variable.
- * Nevertheless, spin_unlock_wait() can have high overhead, so if
- * you feel the need to use it, please check to see if there is
- * a better way to get your job done.
- *
- * The ordering guarantees provided by spin_unlock_wait() are:
- *
- * 1.  All accesses preceding the spin_unlock_wait() happen before
- *     any accesses in later critical sections for this same lock.
- * 2.  All accesses following the spin_unlock_wait() happen after
- *     any accesses in earlier critical sections for this same lock.
- */
-static __always_inline void spin_unlock_wait(spinlock_t *lock)
-{
-	raw_spin_unlock_wait(&lock->rlock);
-}
-
 static __always_inline int spin_is_locked(spinlock_t *lock)
 {
 	return raw_spin_is_locked(&lock->rlock);
diff --git a/include/linux/spinlock_up.h b/include/linux/spinlock_up.h
index 0d9848de677d..612fb530af41 100644
--- a/include/linux/spinlock_up.h
+++ b/include/linux/spinlock_up.h
@@ -26,11 +26,6 @@
 #ifdef CONFIG_DEBUG_SPINLOCK
 #define arch_spin_is_locked(x)		((x)->slock == 0)
 
-static inline void arch_spin_unlock_wait(arch_spinlock_t *lock)
-{
-	smp_cond_load_acquire(&lock->slock, VAL);
-}
-
 static inline void arch_spin_lock(arch_spinlock_t *lock)
 {
 	lock->slock = 0;
@@ -73,7 +68,6 @@ static inline void arch_spin_unlock(arch_spinlock_t *lock)
 
 #else /* DEBUG_SPINLOCK */
 #define arch_spin_is_locked(lock)	((void)(lock), 0)
-#define arch_spin_unlock_wait(lock)	do { barrier(); (void)(lock); } while (0)
 /* for sched/core.c and kernel_lock.c: */
 # define arch_spin_lock(lock)		do { barrier(); (void)(lock); } while (0)
 # define arch_spin_lock_flags(lock, flags)	do { barrier(); (void)(lock); } while (0)
diff --git a/kernel/locking/qspinlock.c b/kernel/locking/qspinlock.c
index b2caec7315af..64a9051e4c2c 100644
--- a/kernel/locking/qspinlock.c
+++ b/kernel/locking/qspinlock.c
@@ -267,123 +267,6 @@ static __always_inline u32  __pv_wait_head_or_lock(struct qspinlock *lock,
 #define queued_spin_lock_slowpath	native_queued_spin_lock_slowpath
 #endif
 
-/*
- * Various notes on spin_is_locked() and spin_unlock_wait(), which are
- * 'interesting' functions:
- *
- * PROBLEM: some architectures have an interesting issue with atomic ACQUIRE
- * operations in that the ACQUIRE applies to the LOAD _not_ the STORE (ARM64,
- * PPC). Also qspinlock has a similar issue per construction, the setting of
- * the locked byte can be unordered acquiring the lock proper.
- *
- * This gets to be 'interesting' in the following cases, where the /should/s
- * end up false because of this issue.
- *
- *
- * CASE 1:
- *
- * So the spin_is_locked() correctness issue comes from something like:
- *
- *   CPU0				CPU1
- *
- *   global_lock();			local_lock(i)
- *     spin_lock(&G)			  spin_lock(&L[i])
- *     for (i)				  if (!spin_is_locked(&G)) {
- *       spin_unlock_wait(&L[i]);	    smp_acquire__after_ctrl_dep();
- *					    return;
- *					  }
- *					  // deal with fail
- *
- * Where it is important CPU1 sees G locked or CPU0 sees L[i] locked such
- * that there is exclusion between the two critical sections.
- *
- * The load from spin_is_locked(&G) /should/ be constrained by the ACQUIRE from
- * spin_lock(&L[i]), and similarly the load(s) from spin_unlock_wait(&L[i])
- * /should/ be constrained by the ACQUIRE from spin_lock(&G).
- *
- * Similarly, later stuff is constrained by the ACQUIRE from CTRL+RMB.
- *
- *
- * CASE 2:
- *
- * For spin_unlock_wait() there is a second correctness issue, namely:
- *
- *   CPU0				CPU1
- *
- *   flag = set;
- *   smp_mb();				spin_lock(&l)
- *   spin_unlock_wait(&l);		if (!flag)
- *					  // add to lockless list
- *					spin_unlock(&l);
- *   // iterate lockless list
- *
- * Which wants to ensure that CPU1 will stop adding bits to the list and CPU0
- * will observe the last entry on the list (if spin_unlock_wait() had ACQUIRE
- * semantics etc..)
- *
- * Where flag /should/ be ordered against the locked store of l.
- */
-
-/*
- * queued_spin_lock_slowpath() can (load-)ACQUIRE the lock before
- * issuing an _unordered_ store to set _Q_LOCKED_VAL.
- *
- * This means that the store can be delayed, but no later than the
- * store-release from the unlock. This means that simply observing
- * _Q_LOCKED_VAL is not sufficient to determine if the lock is acquired.
- *
- * There are two paths that can issue the unordered store:
- *
- *  (1) clear_pending_set_locked():	*,1,0 -> *,0,1
- *
- *  (2) set_locked():			t,0,0 -> t,0,1 ; t != 0
- *      atomic_cmpxchg_relaxed():	t,0,0 -> 0,0,1
- *
- * However, in both cases we have other !0 state we've set before to queue
- * ourseves:
- *
- * For (1) we have the atomic_cmpxchg_acquire() that set _Q_PENDING_VAL, our
- * load is constrained by that ACQUIRE to not pass before that, and thus must
- * observe the store.
- *
- * For (2) we have a more intersting scenario. We enqueue ourselves using
- * xchg_tail(), which ends up being a RELEASE. This in itself is not
- * sufficient, however that is followed by an smp_cond_acquire() on the same
- * word, giving a RELEASE->ACQUIRE ordering. This again constrains our load and
- * guarantees we must observe that store.
- *
- * Therefore both cases have other !0 state that is observable before the
- * unordered locked byte store comes through. This means we can use that to
- * wait for the lock store, and then wait for an unlock.
- */
-#ifndef queued_spin_unlock_wait
-void queued_spin_unlock_wait(struct qspinlock *lock)
-{
-	u32 val;
-
-	for (;;) {
-		val = atomic_read(&lock->val);
-
-		if (!val) /* not locked, we're done */
-			goto done;
-
-		if (val & _Q_LOCKED_MASK) /* locked, go wait for unlock */
-			break;
-
-		/* not locked, but pending, wait until we observe the lock */
-		cpu_relax();
-	}
-
-	/* any unlock is good */
-	while (atomic_read(&lock->val) & _Q_LOCKED_MASK)
-		cpu_relax();
-
-done:
-	smp_acquire__after_ctrl_dep();
-}
-EXPORT_SYMBOL(queued_spin_unlock_wait);
-#endif
-
 #endif /* _GEN_PV_LOCK_SLOWPATH */
 
 /**
-- 
2.5.2

^ permalink raw reply related	[flat|nested] 122+ messages in thread

* [PATCH v2 9/9] arch: Remove spin_unlock_wait() arch-specific definitions
  2017-07-05 23:29 ` [PATCH v2 0/9] Remove spin_unlock_wait() Paul E. McKenney
                     ` (7 preceding siblings ...)
  2017-07-05 23:31   ` [PATCH v2 8/9] locking: Remove spin_unlock_wait() generic definitions Paul E. McKenney
@ 2017-07-05 23:31   ` Paul E. McKenney
  2017-07-06 14:12   ` [PATCH v2 0/9] Remove spin_unlock_wait() David Laight
  2017-07-07 19:27   ` [PATCH v3 " Paul E. McKenney
  10 siblings, 0 replies; 122+ messages in thread
From: Paul E. McKenney @ 2017-07-05 23:31 UTC (permalink / raw)
  To: linux-kernel
  Cc: netfilter-devel, netdev, oleg, akpm, mingo, dave, manfred, tj,
	arnd, linux-arch, will.deacon, peterz, stern, parri.andrea,
	torvalds, Paul E. McKenney

There is no agreed-upon definition of spin_unlock_wait()'s semantics,
and it appears that all callers could do just as well with a lock/unlock
pair.  This commit therefore removes the underlying arch-specific
arch_spin_unlock_wait() for all architectures providing them.

Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Cc: <linux-arch@vger.kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Alan Stern <stern@rowland.harvard.edu>
Cc: Andrea Parri <parri.andrea@gmail.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Acked-by: Will Deacon <will.deacon@arm.com>
Acked-by: Boqun Feng <boqun.feng@gmail.com>
---
 arch/alpha/include/asm/spinlock.h    |  5 ----
 arch/arc/include/asm/spinlock.h      |  5 ----
 arch/arm/include/asm/spinlock.h      | 16 ----------
 arch/arm64/include/asm/spinlock.h    | 58 ++++--------------------------------
 arch/blackfin/include/asm/spinlock.h |  5 ----
 arch/hexagon/include/asm/spinlock.h  |  5 ----
 arch/ia64/include/asm/spinlock.h     | 21 -------------
 arch/m32r/include/asm/spinlock.h     |  5 ----
 arch/metag/include/asm/spinlock.h    |  5 ----
 arch/mips/include/asm/spinlock.h     | 16 ----------
 arch/mn10300/include/asm/spinlock.h  |  5 ----
 arch/parisc/include/asm/spinlock.h   |  7 -----
 arch/powerpc/include/asm/spinlock.h  | 33 --------------------
 arch/s390/include/asm/spinlock.h     |  7 -----
 arch/sh/include/asm/spinlock-cas.h   |  5 ----
 arch/sh/include/asm/spinlock-llsc.h  |  5 ----
 arch/sparc/include/asm/spinlock_32.h |  5 ----
 arch/sparc/include/asm/spinlock_64.h |  5 ----
 arch/tile/include/asm/spinlock_32.h  |  2 --
 arch/tile/include/asm/spinlock_64.h  |  2 --
 arch/tile/lib/spinlock_32.c          | 23 --------------
 arch/tile/lib/spinlock_64.c          | 22 --------------
 arch/xtensa/include/asm/spinlock.h   |  5 ----
 23 files changed, 5 insertions(+), 262 deletions(-)

diff --git a/arch/alpha/include/asm/spinlock.h b/arch/alpha/include/asm/spinlock.h
index a40b9fc0c6c3..718ac0b64adf 100644
--- a/arch/alpha/include/asm/spinlock.h
+++ b/arch/alpha/include/asm/spinlock.h
@@ -16,11 +16,6 @@
 #define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock)
 #define arch_spin_is_locked(x)	((x)->lock != 0)
 
-static inline void arch_spin_unlock_wait(arch_spinlock_t *lock)
-{
-	smp_cond_load_acquire(&lock->lock, !VAL);
-}
-
 static inline int arch_spin_value_unlocked(arch_spinlock_t lock)
 {
         return lock.lock == 0;
diff --git a/arch/arc/include/asm/spinlock.h b/arch/arc/include/asm/spinlock.h
index 233d5ffe6ec7..a325e6a36523 100644
--- a/arch/arc/include/asm/spinlock.h
+++ b/arch/arc/include/asm/spinlock.h
@@ -16,11 +16,6 @@
 #define arch_spin_is_locked(x)	((x)->slock != __ARCH_SPIN_LOCK_UNLOCKED__)
 #define arch_spin_lock_flags(lock, flags)	arch_spin_lock(lock)
 
-static inline void arch_spin_unlock_wait(arch_spinlock_t *lock)
-{
-	smp_cond_load_acquire(&lock->slock, !VAL);
-}
-
 #ifdef CONFIG_ARC_HAS_LLSC
 
 static inline void arch_spin_lock(arch_spinlock_t *lock)
diff --git a/arch/arm/include/asm/spinlock.h b/arch/arm/include/asm/spinlock.h
index 4bec45442072..c030143c18c6 100644
--- a/arch/arm/include/asm/spinlock.h
+++ b/arch/arm/include/asm/spinlock.h
@@ -52,22 +52,6 @@ static inline void dsb_sev(void)
  * memory.
  */
 
-static inline void arch_spin_unlock_wait(arch_spinlock_t *lock)
-{
-	u16 owner = READ_ONCE(lock->tickets.owner);
-
-	for (;;) {
-		arch_spinlock_t tmp = READ_ONCE(*lock);
-
-		if (tmp.tickets.owner == tmp.tickets.next ||
-		    tmp.tickets.owner != owner)
-			break;
-
-		wfe();
-	}
-	smp_acquire__after_ctrl_dep();
-}
-
 #define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock)
 
 static inline void arch_spin_lock(arch_spinlock_t *lock)
diff --git a/arch/arm64/include/asm/spinlock.h b/arch/arm64/include/asm/spinlock.h
index cae331d553f8..f445bd7f2b9f 100644
--- a/arch/arm64/include/asm/spinlock.h
+++ b/arch/arm64/include/asm/spinlock.h
@@ -26,58 +26,6 @@
  * The memory barriers are implicit with the load-acquire and store-release
  * instructions.
  */
-static inline void arch_spin_unlock_wait(arch_spinlock_t *lock)
-{
-	unsigned int tmp;
-	arch_spinlock_t lockval;
-	u32 owner;
-
-	/*
-	 * Ensure prior spin_lock operations to other locks have completed
-	 * on this CPU before we test whether "lock" is locked.
-	 */
-	smp_mb();
-	owner = READ_ONCE(lock->owner) << 16;
-
-	asm volatile(
-"	sevl\n"
-"1:	wfe\n"
-"2:	ldaxr	%w0, %2\n"
-	/* Is the lock free? */
-"	eor	%w1, %w0, %w0, ror #16\n"
-"	cbz	%w1, 3f\n"
-	/* Lock taken -- has there been a subsequent unlock->lock transition? */
-"	eor	%w1, %w3, %w0, lsl #16\n"
-"	cbz	%w1, 1b\n"
-	/*
-	 * The owner has been updated, so there was an unlock->lock
-	 * transition that we missed. That means we can rely on the
-	 * store-release of the unlock operation paired with the
-	 * load-acquire of the lock operation to publish any of our
-	 * previous stores to the new lock owner and therefore don't
-	 * need to bother with the writeback below.
-	 */
-"	b	4f\n"
-"3:\n"
-	/*
-	 * Serialise against any concurrent lockers by writing back the
-	 * unlocked lock value
-	 */
-	ARM64_LSE_ATOMIC_INSN(
-	/* LL/SC */
-"	stxr	%w1, %w0, %2\n"
-	__nops(2),
-	/* LSE atomics */
-"	mov	%w1, %w0\n"
-"	cas	%w0, %w0, %2\n"
-"	eor	%w1, %w1, %w0\n")
-	/* Somebody else wrote to the lock, GOTO 10 and reload the value */
-"	cbnz	%w1, 2b\n"
-"4:"
-	: "=&r" (lockval), "=&r" (tmp), "+Q" (*lock)
-	: "r" (owner)
-	: "memory");
-}
 
 #define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock)
 
@@ -176,7 +124,11 @@ static inline int arch_spin_value_unlocked(arch_spinlock_t lock)
 
 static inline int arch_spin_is_locked(arch_spinlock_t *lock)
 {
-	smp_mb(); /* See arch_spin_unlock_wait */
+	/*
+	 * Ensure prior spin_lock operations to other locks have completed
+	 * on this CPU before we test whether "lock" is locked.
+	 */
+	smp_mb(); /* ^^^ */
 	return !arch_spin_value_unlocked(READ_ONCE(*lock));
 }
 
diff --git a/arch/blackfin/include/asm/spinlock.h b/arch/blackfin/include/asm/spinlock.h
index c58f4a83ed6f..f6431439d15d 100644
--- a/arch/blackfin/include/asm/spinlock.h
+++ b/arch/blackfin/include/asm/spinlock.h
@@ -48,11 +48,6 @@ static inline void arch_spin_unlock(arch_spinlock_t *lock)
 	__raw_spin_unlock_asm(&lock->lock);
 }
 
-static inline void arch_spin_unlock_wait(arch_spinlock_t *lock)
-{
-	smp_cond_load_acquire(&lock->lock, !VAL);
-}
-
 static inline int arch_read_can_lock(arch_rwlock_t *rw)
 {
 	return __raw_uncached_fetch_asm(&rw->lock) > 0;
diff --git a/arch/hexagon/include/asm/spinlock.h b/arch/hexagon/include/asm/spinlock.h
index a1c55788c5d6..53a8d5885887 100644
--- a/arch/hexagon/include/asm/spinlock.h
+++ b/arch/hexagon/include/asm/spinlock.h
@@ -179,11 +179,6 @@ static inline unsigned int arch_spin_trylock(arch_spinlock_t *lock)
  */
 #define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock)
 
-static inline void arch_spin_unlock_wait(arch_spinlock_t *lock)
-{
-	smp_cond_load_acquire(&lock->lock, !VAL);
-}
-
 #define arch_spin_is_locked(x) ((x)->lock != 0)
 
 #define arch_read_lock_flags(lock, flags) arch_read_lock(lock)
diff --git a/arch/ia64/include/asm/spinlock.h b/arch/ia64/include/asm/spinlock.h
index ca9e76149a4a..df2c121164b8 100644
--- a/arch/ia64/include/asm/spinlock.h
+++ b/arch/ia64/include/asm/spinlock.h
@@ -76,22 +76,6 @@ static __always_inline void __ticket_spin_unlock(arch_spinlock_t *lock)
 	ACCESS_ONCE(*p) = (tmp + 2) & ~1;
 }
 
-static __always_inline void __ticket_spin_unlock_wait(arch_spinlock_t *lock)
-{
-	int	*p = (int *)&lock->lock, ticket;
-
-	ia64_invala();
-
-	for (;;) {
-		asm volatile ("ld4.c.nc %0=[%1]" : "=r"(ticket) : "r"(p) : "memory");
-		if (!(((ticket >> TICKET_SHIFT) ^ ticket) & TICKET_MASK))
-			return;
-		cpu_relax();
-	}
-
-	smp_acquire__after_ctrl_dep();
-}
-
 static inline int __ticket_spin_is_locked(arch_spinlock_t *lock)
 {
 	long tmp = ACCESS_ONCE(lock->lock);
@@ -143,11 +127,6 @@ static __always_inline void arch_spin_lock_flags(arch_spinlock_t *lock,
 	arch_spin_lock(lock);
 }
 
-static inline void arch_spin_unlock_wait(arch_spinlock_t *lock)
-{
-	__ticket_spin_unlock_wait(lock);
-}
-
 #define arch_read_can_lock(rw)		(*(volatile int *)(rw) >= 0)
 #define arch_write_can_lock(rw)	(*(volatile int *)(rw) == 0)
 
diff --git a/arch/m32r/include/asm/spinlock.h b/arch/m32r/include/asm/spinlock.h
index 323c7fc953cd..a56825592b90 100644
--- a/arch/m32r/include/asm/spinlock.h
+++ b/arch/m32r/include/asm/spinlock.h
@@ -30,11 +30,6 @@
 #define arch_spin_is_locked(x)		(*(volatile int *)(&(x)->slock) <= 0)
 #define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock)
 
-static inline void arch_spin_unlock_wait(arch_spinlock_t *lock)
-{
-	smp_cond_load_acquire(&lock->slock, VAL > 0);
-}
-
 /**
  * arch_spin_trylock - Try spin lock and return a result
  * @lock: Pointer to the lock variable
diff --git a/arch/metag/include/asm/spinlock.h b/arch/metag/include/asm/spinlock.h
index c0c7a22be1ae..ddf7fe5708a6 100644
--- a/arch/metag/include/asm/spinlock.h
+++ b/arch/metag/include/asm/spinlock.h
@@ -15,11 +15,6 @@
  * locked.
  */
 
-static inline void arch_spin_unlock_wait(arch_spinlock_t *lock)
-{
-	smp_cond_load_acquire(&lock->lock, !VAL);
-}
-
 #define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock)
 
 #define	arch_read_lock_flags(lock, flags) arch_read_lock(lock)
diff --git a/arch/mips/include/asm/spinlock.h b/arch/mips/include/asm/spinlock.h
index a8df44d60607..81b4945031ee 100644
--- a/arch/mips/include/asm/spinlock.h
+++ b/arch/mips/include/asm/spinlock.h
@@ -50,22 +50,6 @@ static inline int arch_spin_value_unlocked(arch_spinlock_t lock)
 
 #define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock)
 
-static inline void arch_spin_unlock_wait(arch_spinlock_t *lock)
-{
-	u16 owner = READ_ONCE(lock->h.serving_now);
-	smp_rmb();
-	for (;;) {
-		arch_spinlock_t tmp = READ_ONCE(*lock);
-
-		if (tmp.h.serving_now == tmp.h.ticket ||
-		    tmp.h.serving_now != owner)
-			break;
-
-		cpu_relax();
-	}
-	smp_acquire__after_ctrl_dep();
-}
-
 static inline int arch_spin_is_contended(arch_spinlock_t *lock)
 {
 	u32 counters = ACCESS_ONCE(lock->lock);
diff --git a/arch/mn10300/include/asm/spinlock.h b/arch/mn10300/include/asm/spinlock.h
index 9c7b8f7942d8..fe413b41df6c 100644
--- a/arch/mn10300/include/asm/spinlock.h
+++ b/arch/mn10300/include/asm/spinlock.h
@@ -26,11 +26,6 @@
 
 #define arch_spin_is_locked(x)	(*(volatile signed char *)(&(x)->slock) != 0)
 
-static inline void arch_spin_unlock_wait(arch_spinlock_t *lock)
-{
-	smp_cond_load_acquire(&lock->slock, !VAL);
-}
-
 static inline void arch_spin_unlock(arch_spinlock_t *lock)
 {
 	asm volatile(
diff --git a/arch/parisc/include/asm/spinlock.h b/arch/parisc/include/asm/spinlock.h
index e32936cd7f10..55bfe4affca3 100644
--- a/arch/parisc/include/asm/spinlock.h
+++ b/arch/parisc/include/asm/spinlock.h
@@ -14,13 +14,6 @@ static inline int arch_spin_is_locked(arch_spinlock_t *x)
 
 #define arch_spin_lock(lock) arch_spin_lock_flags(lock, 0)
 
-static inline void arch_spin_unlock_wait(arch_spinlock_t *x)
-{
-	volatile unsigned int *a = __ldcw_align(x);
-
-	smp_cond_load_acquire(a, VAL);
-}
-
 static inline void arch_spin_lock_flags(arch_spinlock_t *x,
 					 unsigned long flags)
 {
diff --git a/arch/powerpc/include/asm/spinlock.h b/arch/powerpc/include/asm/spinlock.h
index 8c1b913de6d7..d256e448ea49 100644
--- a/arch/powerpc/include/asm/spinlock.h
+++ b/arch/powerpc/include/asm/spinlock.h
@@ -170,39 +170,6 @@ static inline void arch_spin_unlock(arch_spinlock_t *lock)
 	lock->slock = 0;
 }
 
-static inline void arch_spin_unlock_wait(arch_spinlock_t *lock)
-{
-	arch_spinlock_t lock_val;
-
-	smp_mb();
-
-	/*
-	 * Atomically load and store back the lock value (unchanged). This
-	 * ensures that our observation of the lock value is ordered with
-	 * respect to other lock operations.
-	 */
-	__asm__ __volatile__(
-"1:	" PPC_LWARX(%0, 0, %2, 0) "\n"
-"	stwcx. %0, 0, %2\n"
-"	bne- 1b\n"
-	: "=&r" (lock_val), "+m" (*lock)
-	: "r" (lock)
-	: "cr0", "xer");
-
-	if (arch_spin_value_unlocked(lock_val))
-		goto out;
-
-	while (lock->slock) {
-		HMT_low();
-		if (SHARED_PROCESSOR)
-			__spin_yield(lock);
-	}
-	HMT_medium();
-
-out:
-	smp_mb();
-}
-
 /*
  * Read-write spinlocks, allowing multiple readers
  * but only one writer.
diff --git a/arch/s390/include/asm/spinlock.h b/arch/s390/include/asm/spinlock.h
index f7838ecd83c6..217ee5210c32 100644
--- a/arch/s390/include/asm/spinlock.h
+++ b/arch/s390/include/asm/spinlock.h
@@ -98,13 +98,6 @@ static inline void arch_spin_unlock(arch_spinlock_t *lp)
 		: "cc", "memory");
 }
 
-static inline void arch_spin_unlock_wait(arch_spinlock_t *lock)
-{
-	while (arch_spin_is_locked(lock))
-		arch_spin_relax(lock);
-	smp_acquire__after_ctrl_dep();
-}
-
 /*
  * Read-write spinlocks, allowing multiple readers
  * but only one writer.
diff --git a/arch/sh/include/asm/spinlock-cas.h b/arch/sh/include/asm/spinlock-cas.h
index c46e8cc7b515..5ed7dbbd94ff 100644
--- a/arch/sh/include/asm/spinlock-cas.h
+++ b/arch/sh/include/asm/spinlock-cas.h
@@ -29,11 +29,6 @@ static inline unsigned __sl_cas(volatile unsigned *p, unsigned old, unsigned new
 #define arch_spin_is_locked(x)		((x)->lock <= 0)
 #define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock)
 
-static inline void arch_spin_unlock_wait(arch_spinlock_t *lock)
-{
-	smp_cond_load_acquire(&lock->lock, VAL > 0);
-}
-
 static inline void arch_spin_lock(arch_spinlock_t *lock)
 {
 	while (!__sl_cas(&lock->lock, 1, 0));
diff --git a/arch/sh/include/asm/spinlock-llsc.h b/arch/sh/include/asm/spinlock-llsc.h
index cec78143fa83..f77263aae760 100644
--- a/arch/sh/include/asm/spinlock-llsc.h
+++ b/arch/sh/include/asm/spinlock-llsc.h
@@ -21,11 +21,6 @@
 #define arch_spin_is_locked(x)		((x)->lock <= 0)
 #define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock)
 
-static inline void arch_spin_unlock_wait(arch_spinlock_t *lock)
-{
-	smp_cond_load_acquire(&lock->lock, VAL > 0);
-}
-
 /*
  * Simple spin lock operations.  There are two variants, one clears IRQ's
  * on the local processor, one does not.
diff --git a/arch/sparc/include/asm/spinlock_32.h b/arch/sparc/include/asm/spinlock_32.h
index 8011e79f59c9..67345b2dc408 100644
--- a/arch/sparc/include/asm/spinlock_32.h
+++ b/arch/sparc/include/asm/spinlock_32.h
@@ -14,11 +14,6 @@
 
 #define arch_spin_is_locked(lock) (*((volatile unsigned char *)(lock)) != 0)
 
-static inline void arch_spin_unlock_wait(arch_spinlock_t *lock)
-{
-	smp_cond_load_acquire(&lock->lock, !VAL);
-}
-
 static inline void arch_spin_lock(arch_spinlock_t *lock)
 {
 	__asm__ __volatile__(
diff --git a/arch/sparc/include/asm/spinlock_64.h b/arch/sparc/include/asm/spinlock_64.h
index 07c9f2e9bf57..923d57f9b79d 100644
--- a/arch/sparc/include/asm/spinlock_64.h
+++ b/arch/sparc/include/asm/spinlock_64.h
@@ -26,11 +26,6 @@
 
 #define arch_spin_is_locked(lp)	((lp)->lock != 0)
 
-static inline void arch_spin_unlock_wait(arch_spinlock_t *lock)
-{
-	smp_cond_load_acquire(&lock->lock, !VAL);
-}
-
 static inline void arch_spin_lock(arch_spinlock_t *lock)
 {
 	unsigned long tmp;
diff --git a/arch/tile/include/asm/spinlock_32.h b/arch/tile/include/asm/spinlock_32.h
index b14b1ba5bf9c..cba8ba9b8da6 100644
--- a/arch/tile/include/asm/spinlock_32.h
+++ b/arch/tile/include/asm/spinlock_32.h
@@ -64,8 +64,6 @@ static inline void arch_spin_unlock(arch_spinlock_t *lock)
 	lock->current_ticket = old_ticket + TICKET_QUANTUM;
 }
 
-void arch_spin_unlock_wait(arch_spinlock_t *lock);
-
 /*
  * Read-write spinlocks, allowing multiple readers
  * but only one writer.
diff --git a/arch/tile/include/asm/spinlock_64.h b/arch/tile/include/asm/spinlock_64.h
index b9718fb4e74a..9a2c2d605752 100644
--- a/arch/tile/include/asm/spinlock_64.h
+++ b/arch/tile/include/asm/spinlock_64.h
@@ -58,8 +58,6 @@ static inline void arch_spin_unlock(arch_spinlock_t *lock)
 	__insn_fetchadd4(&lock->lock, 1U << __ARCH_SPIN_CURRENT_SHIFT);
 }
 
-void arch_spin_unlock_wait(arch_spinlock_t *lock);
-
 void arch_spin_lock_slow(arch_spinlock_t *lock, u32 val);
 
 /* Grab the "next" ticket number and bump it atomically.
diff --git a/arch/tile/lib/spinlock_32.c b/arch/tile/lib/spinlock_32.c
index 076c6cc43113..db9333f2447c 100644
--- a/arch/tile/lib/spinlock_32.c
+++ b/arch/tile/lib/spinlock_32.c
@@ -62,29 +62,6 @@ int arch_spin_trylock(arch_spinlock_t *lock)
 }
 EXPORT_SYMBOL(arch_spin_trylock);
 
-void arch_spin_unlock_wait(arch_spinlock_t *lock)
-{
-	u32 iterations = 0;
-	int curr = READ_ONCE(lock->current_ticket);
-	int next = READ_ONCE(lock->next_ticket);
-
-	/* Return immediately if unlocked. */
-	if (next == curr)
-		return;
-
-	/* Wait until the current locker has released the lock. */
-	do {
-		delay_backoff(iterations++);
-	} while (READ_ONCE(lock->current_ticket) == curr);
-
-	/*
-	 * The TILE architecture doesn't do read speculation; therefore
-	 * a control dependency guarantees a LOAD->{LOAD,STORE} order.
-	 */
-	barrier();
-}
-EXPORT_SYMBOL(arch_spin_unlock_wait);
-
 /*
  * The low byte is always reserved to be the marker for a "tns" operation
  * since the low bit is set to "1" by a tns.  The next seven bits are
diff --git a/arch/tile/lib/spinlock_64.c b/arch/tile/lib/spinlock_64.c
index a4b5b2cbce93..de414c22892f 100644
--- a/arch/tile/lib/spinlock_64.c
+++ b/arch/tile/lib/spinlock_64.c
@@ -62,28 +62,6 @@ int arch_spin_trylock(arch_spinlock_t *lock)
 }
 EXPORT_SYMBOL(arch_spin_trylock);
 
-void arch_spin_unlock_wait(arch_spinlock_t *lock)
-{
-	u32 iterations = 0;
-	u32 val = READ_ONCE(lock->lock);
-	u32 curr = arch_spin_current(val);
-
-	/* Return immediately if unlocked. */
-	if (arch_spin_next(val) == curr)
-		return;
-
-	/* Wait until the current locker has released the lock. */
-	do {
-		delay_backoff(iterations++);
-	} while (arch_spin_current(READ_ONCE(lock->lock)) == curr);
-
-	/*
-	 * The TILE architecture doesn't do read speculation; therefore
-	 * a control dependency guarantees a LOAD->{LOAD,STORE} order.
-	 */
-	barrier();
-}
-EXPORT_SYMBOL(arch_spin_unlock_wait);
 
 /*
  * If the read lock fails due to a writer, we retry periodically
diff --git a/arch/xtensa/include/asm/spinlock.h b/arch/xtensa/include/asm/spinlock.h
index a36221cf6363..3bb49681ee24 100644
--- a/arch/xtensa/include/asm/spinlock.h
+++ b/arch/xtensa/include/asm/spinlock.h
@@ -33,11 +33,6 @@
 
 #define arch_spin_is_locked(x) ((x)->slock != 0)
 
-static inline void arch_spin_unlock_wait(arch_spinlock_t *lock)
-{
-	smp_cond_load_acquire(&lock->slock, !VAL);
-}
-
 #define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock)
 
 static inline void arch_spin_lock(arch_spinlock_t *lock)
-- 
2.5.2

^ permalink raw reply related	[flat|nested] 122+ messages in thread

* Re: [PATCH RFC 21/26] powerpc: Remove spin_unlock_wait() arch-specific definitions
  2017-07-02  3:58   ` Boqun Feng
@ 2017-07-05 23:57     ` Paul E. McKenney
  0 siblings, 0 replies; 122+ messages in thread
From: Paul E. McKenney @ 2017-07-05 23:57 UTC (permalink / raw)
  To: Boqun Feng
  Cc: linux-kernel, linux-arch, parri.andrea, dave, manfred, arnd,
	peterz, netdev, linuxppc-dev, will.deacon, oleg, mingo,
	netfilter-devel, tj, stern, akpm, torvalds, Paul Mackerras

On Sun, Jul 02, 2017 at 11:58:07AM +0800, Boqun Feng wrote:
> On Thu, Jun 29, 2017 at 05:01:29PM -0700, Paul E. McKenney wrote:
> > There is no agreed-upon definition of spin_unlock_wait()'s semantics,
> > and it appears that all callers could do just as well with a lock/unlock
> > pair.  This commit therefore removes the underlying arch-specific
> > arch_spin_unlock_wait().
> > 
> > Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
> > Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
> > Cc: Paul Mackerras <paulus@samba.org>
> > Cc: Michael Ellerman <mpe@ellerman.id.au>
> > Cc: <linuxppc-dev@lists.ozlabs.org>
> > Cc: Will Deacon <will.deacon@arm.com>
> > Cc: Peter Zijlstra <peterz@infradead.org>
> > Cc: Alan Stern <stern@rowland.harvard.edu>
> > Cc: Andrea Parri <parri.andrea@gmail.com>
> > Cc: Linus Torvalds <torvalds@linux-foundation.org>
> 
> Acked-by: Boqun Feng <boqun.feng@gmail.com>

And finally applied in preparation for v2 of the patch series.

Thank you!!!

							Thanx, Paul

> Regards,
> Boqun
> 
> > ---
> >  arch/powerpc/include/asm/spinlock.h | 33 ---------------------------------
> >  1 file changed, 33 deletions(-)
> > 
> > diff --git a/arch/powerpc/include/asm/spinlock.h b/arch/powerpc/include/asm/spinlock.h
> > index 8c1b913de6d7..d256e448ea49 100644
> > --- a/arch/powerpc/include/asm/spinlock.h
> > +++ b/arch/powerpc/include/asm/spinlock.h
> > @@ -170,39 +170,6 @@ static inline void arch_spin_unlock(arch_spinlock_t *lock)
> >  	lock->slock = 0;
> >  }
> >  
> > -static inline void arch_spin_unlock_wait(arch_spinlock_t *lock)
> > -{
> > -	arch_spinlock_t lock_val;
> > -
> > -	smp_mb();
> > -
> > -	/*
> > -	 * Atomically load and store back the lock value (unchanged). This
> > -	 * ensures that our observation of the lock value is ordered with
> > -	 * respect to other lock operations.
> > -	 */
> > -	__asm__ __volatile__(
> > -"1:	" PPC_LWARX(%0, 0, %2, 0) "\n"
> > -"	stwcx. %0, 0, %2\n"
> > -"	bne- 1b\n"
> > -	: "=&r" (lock_val), "+m" (*lock)
> > -	: "r" (lock)
> > -	: "cr0", "xer");
> > -
> > -	if (arch_spin_value_unlocked(lock_val))
> > -		goto out;
> > -
> > -	while (lock->slock) {
> > -		HMT_low();
> > -		if (SHARED_PROCESSOR)
> > -			__spin_yield(lock);
> > -	}
> > -	HMT_medium();
> > -
> > -out:
> > -	smp_mb();
> > -}
> > -
> >  /*
> >   * Read-write spinlocks, allowing multiple readers
> >   * but only one writer.
> > -- 
> > 2.5.2
> > 

^ permalink raw reply	[flat|nested] 122+ messages in thread

* RE: [PATCH v2 0/9] Remove spin_unlock_wait()
  2017-07-05 23:29 ` [PATCH v2 0/9] Remove spin_unlock_wait() Paul E. McKenney
                     ` (8 preceding siblings ...)
  2017-07-05 23:31   ` [PATCH v2 9/9] arch: Remove spin_unlock_wait() arch-specific definitions Paul E. McKenney
@ 2017-07-06 14:12   ` David Laight
  2017-07-06 15:21     ` Paul E. McKenney
  2017-07-06 16:05     ` Peter Zijlstra
  2017-07-07 19:27   ` [PATCH v3 " Paul E. McKenney
  10 siblings, 2 replies; 122+ messages in thread
From: David Laight @ 2017-07-06 14:12 UTC (permalink / raw)
  To: 'paulmck@linux.vnet.ibm.com', linux-kernel
  Cc: netfilter-devel, netdev, oleg, akpm, mingo, dave, manfred, tj,
	arnd, linux-arch, will.deacon, peterz, stern, parri.andrea,
	torvalds

From: Paul E. McKenney
> Sent: 06 July 2017 00:30
> There is no agreed-upon definition of spin_unlock_wait()'s semantics,
> and it appears that all callers could do just as well with a lock/unlock
> pair.  This series therefore removes spin_unlock_wait() and changes
> its users to instead use a lock/unlock pair.  The commits are as follows,
> in three groups:
> 
> 1-7.	Change uses of spin_unlock_wait() and raw_spin_unlock_wait()
> 	to instead use a spin_lock/spin_unlock pair.  These may be
> 	applied in any order, but must be applied before any later
> 	commits in this series.  The commit logs state why I believe
> 	that these commits won't noticeably degrade performance.

I can't help feeling that it might be better to have a spin_lock_sync()
call that is equivalent to a spin_lock/spin_unlock pair.
The default implementation being an inline function that does exactly that.
This would let an architecture implement a more efficient version.

It might even be that this is the defined semantics of spin_unlock_wait().

Note that it can only be useful to do a spin_lock/unlock pair if it is
impossible for another code path to try to acquire the lock.
(Or, at least, the code can't care if the lock is acquired just after.)
So if it can de determined that the lock isn't held (a READ_ONCE()
might be enough) the lock itself need not be acquired (with the
associated slow bus cycles).

	David

^ permalink raw reply	[flat|nested] 122+ messages in thread

* Re: [PATCH v2 0/9] Remove spin_unlock_wait()
  2017-07-06 14:12   ` [PATCH v2 0/9] Remove spin_unlock_wait() David Laight
@ 2017-07-06 15:21     ` Paul E. McKenney
  2017-07-06 16:10       ` Peter Zijlstra
  2017-07-06 16:05     ` Peter Zijlstra
  1 sibling, 1 reply; 122+ messages in thread
From: Paul E. McKenney @ 2017-07-06 15:21 UTC (permalink / raw)
  To: David Laight
  Cc: linux-kernel, netfilter-devel, netdev, oleg, akpm, mingo, dave,
	manfred, tj, arnd, linux-arch, will.deacon, peterz, stern,
	parri.andrea, torvalds

On Thu, Jul 06, 2017 at 02:12:24PM +0000, David Laight wrote:
> From: Paul E. McKenney
> > Sent: 06 July 2017 00:30
> > There is no agreed-upon definition of spin_unlock_wait()'s semantics,
> > and it appears that all callers could do just as well with a lock/unlock
> > pair.  This series therefore removes spin_unlock_wait() and changes
> > its users to instead use a lock/unlock pair.  The commits are as follows,
> > in three groups:
> > 
> > 1-7.	Change uses of spin_unlock_wait() and raw_spin_unlock_wait()
> > 	to instead use a spin_lock/spin_unlock pair.  These may be
> > 	applied in any order, but must be applied before any later
> > 	commits in this series.  The commit logs state why I believe
> > 	that these commits won't noticeably degrade performance.
> 
> I can't help feeling that it might be better to have a spin_lock_sync()
> call that is equivalent to a spin_lock/spin_unlock pair.
> The default implementation being an inline function that does exactly that.
> This would let an architecture implement a more efficient version.
> 
> It might even be that this is the defined semantics of spin_unlock_wait().

That was in fact my first proposal, see the comment header in current
mainline for spin_unlock_wait() in include/linux/spinlock.h.  But Linus
quite rightly pointed out that if spin_unlock_wait() was to be defined in
this way, we should get rid of spin_unlock_wait() entirely, especially
given that there are not very many calls to spin_unlock_wait() and
also given that none of them are particularly performance critical.
Hence the current patch set, which does just that.

> Note that it can only be useful to do a spin_lock/unlock pair if it is
> impossible for another code path to try to acquire the lock.
> (Or, at least, the code can't care if the lock is acquired just after.)

Indeed!  As Oleg Nesterov pointed out, a spin_lock()/spin_unlock() pair
is sort of like synchronize_rcu() for a given lock, where that lock's
critical sections play the role of RCU read-side critical sections.
So anything before the pair is visible to later critical sections, and
anything in prior critical sections is visible to anything after the pair.
But again, as Linus pointed out, if we are going to have these semantics,
just do spin_lock() immediately followed by spin_unlock().

> So if it can de determined that the lock isn't held (a READ_ONCE()
> might be enough) the lock itself need not be acquired (with the
> associated slow bus cycles).

If you want the full semantics of a spin_lock()/spin_unlock() pair,
you need a full memory barrier before the READ_ONCE(), even on x86.
Without that memory barrier, you don't get the effect of the release
implicit in spin_unlock().

For weaker architectures, such as PowerPC and ARM, a READ_ONCE()
does -not- suffice, not at all, even with smp_mb() before and after.
I encourage you to take a look at arch_spin_unlock_wait() in arm64
and powerpc if youi are interested.  There were also some lengthy LKML
threads discussing this about 18 months ago that could be illuminating.

And yes, there are architecture-specific optimizations for an
empty spin_lock()/spin_unlock() critical section, and the current
arch_spin_unlock_wait() implementations show some of these optimizations.
But I expect that performance benefits would need to be demonstrated at
the system level.

							Thanx, Paul

^ permalink raw reply	[flat|nested] 122+ messages in thread

* Re: [PATCH v2 0/9] Remove spin_unlock_wait()
  2017-07-06 14:12   ` [PATCH v2 0/9] Remove spin_unlock_wait() David Laight
  2017-07-06 15:21     ` Paul E. McKenney
@ 2017-07-06 16:05     ` Peter Zijlstra
  2017-07-06 16:20       ` Paul E. McKenney
  2017-07-07  8:06       ` Ingo Molnar
  1 sibling, 2 replies; 122+ messages in thread
From: Peter Zijlstra @ 2017-07-06 16:05 UTC (permalink / raw)
  To: David Laight
  Cc: 'paulmck@linux.vnet.ibm.com',
	linux-kernel, netfilter-devel, netdev, oleg, akpm, mingo, dave,
	manfred, tj, arnd, linux-arch, will.deacon, stern, parri.andrea,
	torvalds

On Thu, Jul 06, 2017 at 02:12:24PM +0000, David Laight wrote:
> From: Paul E. McKenney
> > Sent: 06 July 2017 00:30
> > There is no agreed-upon definition of spin_unlock_wait()'s semantics,
> > and it appears that all callers could do just as well with a lock/unlock
> > pair.  This series therefore removes spin_unlock_wait() and changes
> > its users to instead use a lock/unlock pair.  The commits are as follows,
> > in three groups:
> > 
> > 1-7.	Change uses of spin_unlock_wait() and raw_spin_unlock_wait()
> > 	to instead use a spin_lock/spin_unlock pair.  These may be
> > 	applied in any order, but must be applied before any later
> > 	commits in this series.  The commit logs state why I believe
> > 	that these commits won't noticeably degrade performance.
> 
> I can't help feeling that it might be better to have a spin_lock_sync()
> call that is equivalent to a spin_lock/spin_unlock pair.
> The default implementation being an inline function that does exactly that.
> This would let an architecture implement a more efficient version.

So that has the IRQ inversion issue found earlier in this patch-set. Not
actually doing the acquire though breaks other guarantees. See later.

> It might even be that this is the defined semantics of spin_unlock_wait().

As is, spin_unlock_wait() is somewhat ill defined. IIRC it grew from an
optimization by Oleg and subsequently got used elsewhere. And it being
the subtle bugger it is, there were bugs.

But part of the problem with that definition is fairness. For fair locks,
spin_lock()+spin_unlock() partakes in the fairness protocol. Many of the
things that would make spin_lock_sync() cheaper preclude it doing that.

(with the exception of ticket locks, those could actually do this).

But I think we can argue we don't in fact want that, all we really need
is to ensure the completion of the _current_ lock. But then you've
violated that equivalent thing.

As is, this is all a bit up in the air -- some of the ticket lock
variants are fair or minimal, the qspinlock on is prone to starvation
(although I think I can in fact fix that for qspinlock).

> Note that it can only be useful to do a spin_lock/unlock pair if it is
> impossible for another code path to try to acquire the lock.
> (Or, at least, the code can't care if the lock is acquired just after.)
> So if it can de determined that the lock isn't held (a READ_ONCE()
> might be enough) the lock itself need not be acquired (with the
> associated slow bus cycles).

Now look at the ARM64/PPC implementations that do explicit stores.

READ_ONCE() can only ever be sufficient on strongly ordered
architectures, but given many performance critical architectures are in
fact weakly ordered, you've opened up the exact can of worms we want to
get rid of the thing for.


So given:

(1)

  spin_lock()
  spin_unlock()

does not in fact provide memory ordering. Any prior/subsequent
load/stores can leak into the section and cross there.

What the thing does do however is serialize against other critical
sections in that:

(2)

  CPU0			CPU1

			spin_lock()
  spin_lock()
			X = 5
			spin_unlock()
  spin_unlock()
  r = X;

we must have r == 5 (due to address dependency on the lock; CPU1 does
the store to X, then a store-release to the lock. CPU0 then does a
load-acquire on the lock and that fully orders the subsequent load of X
to the prior store of X).


The other way around is more difficult though:

(3)

  CPU0			CPU1

  X=5
  spin_lock()
			spin_lock()
  spin_unlock()
			r = X;
			spin_unlock()

Where the above will in fact observe r == 5, this will be very difficult
to achieve with anything that will not let CPU1 wait. Which was the
entire premise of the original optimization by Oleg.

One of the later fixes we did to spin_unlock_wait() is to give it
ACQUIRE semantics to deal with (2) but even that got massively tricky,
see for example the ARM64 / PPC implementations.



In short, I doubt there is any real optimization possible if you want to
retain exact lock+unlock semantics.

Now on the one hand I feel like Oleg that it would be a shame to loose
the optimization, OTOH this thing is really really tricky to use,
and has lead to a number of bugs already.

^ permalink raw reply	[flat|nested] 122+ messages in thread

* Re: [PATCH v2 0/9] Remove spin_unlock_wait()
  2017-07-06 15:21     ` Paul E. McKenney
@ 2017-07-06 16:10       ` Peter Zijlstra
  2017-07-06 16:24         ` Paul E. McKenney
  0 siblings, 1 reply; 122+ messages in thread
From: Peter Zijlstra @ 2017-07-06 16:10 UTC (permalink / raw)
  To: Paul E. McKenney
  Cc: David Laight, linux-kernel, netfilter-devel, netdev, oleg, akpm,
	mingo, dave, manfred, tj, arnd, linux-arch, will.deacon, stern,
	parri.andrea, torvalds

On Thu, Jul 06, 2017 at 08:21:10AM -0700, Paul E. McKenney wrote:
> And yes, there are architecture-specific optimizations for an
> empty spin_lock()/spin_unlock() critical section, and the current
> arch_spin_unlock_wait() implementations show some of these optimizations.
> But I expect that performance benefits would need to be demonstrated at
> the system level.

I do in fact contended there are any optimizations for the exact
lock+unlock semantics.

The current spin_unlock_wait() is weaker. Most notably it will not (with
exception of ARM64/PPC for other reasons) cause waits on other CPUs.

^ permalink raw reply	[flat|nested] 122+ messages in thread

* Re: [PATCH v2 0/9] Remove spin_unlock_wait()
  2017-07-06 16:05     ` Peter Zijlstra
@ 2017-07-06 16:20       ` Paul E. McKenney
  2017-07-06 16:50         ` Peter Zijlstra
  2017-07-07  8:06       ` Ingo Molnar
  1 sibling, 1 reply; 122+ messages in thread
From: Paul E. McKenney @ 2017-07-06 16:20 UTC (permalink / raw)
  To: Peter Zijlstra
  Cc: David Laight, linux-kernel, netfilter-devel, netdev, oleg, akpm,
	mingo, dave, manfred, tj, arnd, linux-arch, will.deacon, stern,
	parri.andrea, torvalds

On Thu, Jul 06, 2017 at 06:05:55PM +0200, Peter Zijlstra wrote:
> On Thu, Jul 06, 2017 at 02:12:24PM +0000, David Laight wrote:
> > From: Paul E. McKenney

[ . . . ]

> Now on the one hand I feel like Oleg that it would be a shame to loose
> the optimization, OTOH this thing is really really tricky to use,
> and has lead to a number of bugs already.

I do agree, it is a bit sad to see these optimizations go.  So, should
this make mainline, I will be tagging the commits that spin_unlock_wait()
so that they can be easily reverted should someone come up with good
semantics and a compelling use case with compelling performance benefits.

							Thanx, Paul

^ permalink raw reply	[flat|nested] 122+ messages in thread

* Re: [PATCH v2 0/9] Remove spin_unlock_wait()
  2017-07-06 16:10       ` Peter Zijlstra
@ 2017-07-06 16:24         ` Paul E. McKenney
  2017-07-06 16:41           ` Peter Zijlstra
  2017-07-06 16:49           ` Alan Stern
  0 siblings, 2 replies; 122+ messages in thread
From: Paul E. McKenney @ 2017-07-06 16:24 UTC (permalink / raw)
  To: Peter Zijlstra
  Cc: David Laight, linux-kernel, netfilter-devel, netdev, oleg, akpm,
	mingo, dave, manfred, tj, arnd, linux-arch, will.deacon, stern,
	parri.andrea, torvalds

On Thu, Jul 06, 2017 at 06:10:47PM +0200, Peter Zijlstra wrote:
> On Thu, Jul 06, 2017 at 08:21:10AM -0700, Paul E. McKenney wrote:
> > And yes, there are architecture-specific optimizations for an
> > empty spin_lock()/spin_unlock() critical section, and the current
> > arch_spin_unlock_wait() implementations show some of these optimizations.
> > But I expect that performance benefits would need to be demonstrated at
> > the system level.
> 
> I do in fact contended there are any optimizations for the exact
> lock+unlock semantics.

You lost me on this one.

> The current spin_unlock_wait() is weaker. Most notably it will not (with
> exception of ARM64/PPC for other reasons) cause waits on other CPUs.

Agreed, weaker semantics allow more optimizations.  So use cases needing
only the weaker semantics should more readily show performance benefits.
But either way, we need compelling use cases, and I do not believe that
any of the existing spin_unlock_wait() calls are compelling.  Perhaps I
am confused, but I am not seeing it for any of them.

							Thanx, Paul

^ permalink raw reply	[flat|nested] 122+ messages in thread

* Re: [PATCH v2 0/9] Remove spin_unlock_wait()
  2017-07-06 16:24         ` Paul E. McKenney
@ 2017-07-06 16:41           ` Peter Zijlstra
  2017-07-06 17:03             ` Paul E. McKenney
  2017-07-06 16:49           ` Alan Stern
  1 sibling, 1 reply; 122+ messages in thread
From: Peter Zijlstra @ 2017-07-06 16:41 UTC (permalink / raw)
  To: Paul E. McKenney
  Cc: David Laight, linux-kernel, netfilter-devel, netdev, oleg, akpm,
	mingo, dave, manfred, tj, arnd, linux-arch, will.deacon, stern,
	parri.andrea, torvalds

On Thu, Jul 06, 2017 at 09:24:12AM -0700, Paul E. McKenney wrote:
> On Thu, Jul 06, 2017 at 06:10:47PM +0200, Peter Zijlstra wrote:
> > On Thu, Jul 06, 2017 at 08:21:10AM -0700, Paul E. McKenney wrote:
> > > And yes, there are architecture-specific optimizations for an
> > > empty spin_lock()/spin_unlock() critical section, and the current
> > > arch_spin_unlock_wait() implementations show some of these optimizations.
> > > But I expect that performance benefits would need to be demonstrated at
> > > the system level.
> > 
> > I do in fact contended there are any optimizations for the exact
> > lock+unlock semantics.
> 
> You lost me on this one.

For the exact semantics you'd have to fully participate in the fairness
protocol. You have to in fact acquire the lock in order to have the
other contending CPUs wait (otherwise my earlier case 3 will fail).

At that point I'm not sure there is much actual code you can leave out.

What actual optimization is there left at that point?

^ permalink raw reply	[flat|nested] 122+ messages in thread

* Re: [PATCH v2 0/9] Remove spin_unlock_wait()
  2017-07-06 16:24         ` Paul E. McKenney
  2017-07-06 16:41           ` Peter Zijlstra
@ 2017-07-06 16:49           ` Alan Stern
  2017-07-06 16:54             ` Peter Zijlstra
  1 sibling, 1 reply; 122+ messages in thread
From: Alan Stern @ 2017-07-06 16:49 UTC (permalink / raw)
  To: Paul E. McKenney
  Cc: Peter Zijlstra, David Laight, linux-kernel, netfilter-devel,
	netdev, oleg, akpm, mingo, dave, manfred, tj, arnd, linux-arch,
	will.deacon, parri.andrea, torvalds

On Thu, 6 Jul 2017, Paul E. McKenney wrote:

> On Thu, Jul 06, 2017 at 06:10:47PM +0200, Peter Zijlstra wrote:
> > On Thu, Jul 06, 2017 at 08:21:10AM -0700, Paul E. McKenney wrote:
> > > And yes, there are architecture-specific optimizations for an
> > > empty spin_lock()/spin_unlock() critical section, and the current
> > > arch_spin_unlock_wait() implementations show some of these optimizations.
> > > But I expect that performance benefits would need to be demonstrated at
> > > the system level.
> > 
> > I do in fact contended there are any optimizations for the exact
> > lock+unlock semantics.
> 
> You lost me on this one.
> 
> > The current spin_unlock_wait() is weaker. Most notably it will not (with
> > exception of ARM64/PPC for other reasons) cause waits on other CPUs.
> 
> Agreed, weaker semantics allow more optimizations.  So use cases needing
> only the weaker semantics should more readily show performance benefits.
> But either way, we need compelling use cases, and I do not believe that
> any of the existing spin_unlock_wait() calls are compelling.  Perhaps I
> am confused, but I am not seeing it for any of them.

If somebody really wants the full spin_unlock_wait semantics and
doesn't want to interfere with other CPUs, wouldn't synchronize_sched()
or something similar do the job?  It wouldn't be as efficient as
lock+unlock, but it also wouldn't affect other CPUs.

Alan Stern

^ permalink raw reply	[flat|nested] 122+ messages in thread

* Re: [PATCH v2 0/9] Remove spin_unlock_wait()
  2017-07-06 16:20       ` Paul E. McKenney
@ 2017-07-06 16:50         ` Peter Zijlstra
  2017-07-06 17:08           ` Will Deacon
                             ` (2 more replies)
  0 siblings, 3 replies; 122+ messages in thread
From: Peter Zijlstra @ 2017-07-06 16:50 UTC (permalink / raw)
  To: Paul E. McKenney
  Cc: David Laight, linux-kernel, netfilter-devel, netdev, oleg, akpm,
	mingo, dave, manfred, tj, arnd, linux-arch, will.deacon, stern,
	parri.andrea, torvalds

On Thu, Jul 06, 2017 at 09:20:24AM -0700, Paul E. McKenney wrote:
> On Thu, Jul 06, 2017 at 06:05:55PM +0200, Peter Zijlstra wrote:
> > On Thu, Jul 06, 2017 at 02:12:24PM +0000, David Laight wrote:
> > > From: Paul E. McKenney
> 
> [ . . . ]
> 
> > Now on the one hand I feel like Oleg that it would be a shame to loose
> > the optimization, OTOH this thing is really really tricky to use,
> > and has lead to a number of bugs already.
> 
> I do agree, it is a bit sad to see these optimizations go.  So, should
> this make mainline, I will be tagging the commits that spin_unlock_wait()
> so that they can be easily reverted should someone come up with good
> semantics and a compelling use case with compelling performance benefits.

Ha!, but what would constitute 'good semantics' ?

The current thing is something along the lines of:

  "Waits for the currently observed critical section
   to complete with ACQUIRE ordering such that it will observe
   whatever state was left by said critical section."

With the 'obvious' benefit of limited interference on those actually
wanting to acquire the lock, and a shorter wait time on our side too,
since we only need to wait for completion of the current section, and
not for however many contender are before us.

Not sure I have an actual (micro) benchmark that shows a difference
though.



Is this all good enough to retain the thing, I dunno. Like I said, I'm
conflicted on the whole thing. On the one hand its a nice optimization,
on the other hand I don't want to have to keep fixing these bugs.

^ permalink raw reply	[flat|nested] 122+ messages in thread

* Re: [PATCH v2 0/9] Remove spin_unlock_wait()
  2017-07-06 16:49           ` Alan Stern
@ 2017-07-06 16:54             ` Peter Zijlstra
  2017-07-06 19:37               ` Alan Stern
  0 siblings, 1 reply; 122+ messages in thread
From: Peter Zijlstra @ 2017-07-06 16:54 UTC (permalink / raw)
  To: Alan Stern
  Cc: Paul E. McKenney, David Laight, linux-kernel, netfilter-devel,
	netdev, oleg, akpm, mingo, dave, manfred, tj, arnd, linux-arch,
	will.deacon, parri.andrea, torvalds

On Thu, Jul 06, 2017 at 12:49:12PM -0400, Alan Stern wrote:
> On Thu, 6 Jul 2017, Paul E. McKenney wrote:
> 
> > On Thu, Jul 06, 2017 at 06:10:47PM +0200, Peter Zijlstra wrote:
> > > On Thu, Jul 06, 2017 at 08:21:10AM -0700, Paul E. McKenney wrote:
> > > > And yes, there are architecture-specific optimizations for an
> > > > empty spin_lock()/spin_unlock() critical section, and the current
> > > > arch_spin_unlock_wait() implementations show some of these optimizations.
> > > > But I expect that performance benefits would need to be demonstrated at
> > > > the system level.
> > > 
> > > I do in fact contended there are any optimizations for the exact
> > > lock+unlock semantics.
> > 
> > You lost me on this one.
> > 
> > > The current spin_unlock_wait() is weaker. Most notably it will not (with
> > > exception of ARM64/PPC for other reasons) cause waits on other CPUs.
> > 
> > Agreed, weaker semantics allow more optimizations.  So use cases needing
> > only the weaker semantics should more readily show performance benefits.
> > But either way, we need compelling use cases, and I do not believe that
> > any of the existing spin_unlock_wait() calls are compelling.  Perhaps I
> > am confused, but I am not seeing it for any of them.
> 
> If somebody really wants the full spin_unlock_wait semantics and
> doesn't want to interfere with other CPUs, wouldn't synchronize_sched()
> or something similar do the job?  It wouldn't be as efficient as
> lock+unlock, but it also wouldn't affect other CPUs.

So please don't do that. That'll create massive pain for RT. Also I
don't think it works. The whole point was that spin_unlock_wait() is
_cheaper_ than lock()+unlock(). If it gets to be more expensive there is
absolutely no point in using it.

^ permalink raw reply	[flat|nested] 122+ messages in thread

* Re: [PATCH v2 0/9] Remove spin_unlock_wait()
  2017-07-06 16:41           ` Peter Zijlstra
@ 2017-07-06 17:03             ` Paul E. McKenney
  0 siblings, 0 replies; 122+ messages in thread
From: Paul E. McKenney @ 2017-07-06 17:03 UTC (permalink / raw)
  To: Peter Zijlstra
  Cc: David Laight, linux-kernel, netfilter-devel, netdev, oleg, akpm,
	mingo, dave, manfred, tj, arnd, linux-arch, will.deacon, stern,
	parri.andrea, torvalds

On Thu, Jul 06, 2017 at 06:41:34PM +0200, Peter Zijlstra wrote:
> On Thu, Jul 06, 2017 at 09:24:12AM -0700, Paul E. McKenney wrote:
> > On Thu, Jul 06, 2017 at 06:10:47PM +0200, Peter Zijlstra wrote:
> > > On Thu, Jul 06, 2017 at 08:21:10AM -0700, Paul E. McKenney wrote:
> > > > And yes, there are architecture-specific optimizations for an
> > > > empty spin_lock()/spin_unlock() critical section, and the current
> > > > arch_spin_unlock_wait() implementations show some of these optimizations.
> > > > But I expect that performance benefits would need to be demonstrated at
> > > > the system level.
> > > 
> > > I do in fact contended there are any optimizations for the exact
> > > lock+unlock semantics.
> > 
> > You lost me on this one.
> 
> For the exact semantics you'd have to fully participate in the fairness
> protocol. You have to in fact acquire the lock in order to have the
> other contending CPUs wait (otherwise my earlier case 3 will fail).
> 
> At that point I'm not sure there is much actual code you can leave out.
> 
> What actual optimization is there left at that point?

Got it.  It was just that I was having a hard time parsing your sentence.
You were contending that there are no optimizations for all implementations
for the full semantics.

							Thanx, Paul

^ permalink raw reply	[flat|nested] 122+ messages in thread

* Re: [PATCH v2 0/9] Remove spin_unlock_wait()
  2017-07-06 16:50         ` Peter Zijlstra
@ 2017-07-06 17:08           ` Will Deacon
  2017-07-06 17:29             ` Paul E. McKenney
  2017-07-06 17:18           ` Paul E. McKenney
  2017-07-07  8:31           ` Ingo Molnar
  2 siblings, 1 reply; 122+ messages in thread
From: Will Deacon @ 2017-07-06 17:08 UTC (permalink / raw)
  To: Peter Zijlstra
  Cc: Paul E. McKenney, David Laight, linux-kernel, netfilter-devel,
	netdev, oleg, akpm, mingo, dave, manfred, tj, arnd, linux-arch,
	stern, parri.andrea, torvalds

On Thu, Jul 06, 2017 at 06:50:36PM +0200, Peter Zijlstra wrote:
> On Thu, Jul 06, 2017 at 09:20:24AM -0700, Paul E. McKenney wrote:
> > On Thu, Jul 06, 2017 at 06:05:55PM +0200, Peter Zijlstra wrote:
> > > On Thu, Jul 06, 2017 at 02:12:24PM +0000, David Laight wrote:
> > > > From: Paul E. McKenney
> > 
> > [ . . . ]
> > 
> > > Now on the one hand I feel like Oleg that it would be a shame to loose
> > > the optimization, OTOH this thing is really really tricky to use,
> > > and has lead to a number of bugs already.
> > 
> > I do agree, it is a bit sad to see these optimizations go.  So, should
> > this make mainline, I will be tagging the commits that spin_unlock_wait()
> > so that they can be easily reverted should someone come up with good
> > semantics and a compelling use case with compelling performance benefits.
> 
> Ha!, but what would constitute 'good semantics' ?
> 
> The current thing is something along the lines of:
> 
>   "Waits for the currently observed critical section
>    to complete with ACQUIRE ordering such that it will observe
>    whatever state was left by said critical section."
> 
> With the 'obvious' benefit of limited interference on those actually
> wanting to acquire the lock, and a shorter wait time on our side too,
> since we only need to wait for completion of the current section, and
> not for however many contender are before us.
> 
> Not sure I have an actual (micro) benchmark that shows a difference
> though.
> 
> 
> 
> Is this all good enough to retain the thing, I dunno. Like I said, I'm
> conflicted on the whole thing. On the one hand its a nice optimization,
> on the other hand I don't want to have to keep fixing these bugs.

As I've said, I'd be keen to see us drop this and bring it back if/when we
get a compelling use-case along with performance numbers. At that point,
we'd be in a better position to define the semantics anyway, knowing what
exactly is expected by the use-case.

Will

^ permalink raw reply	[flat|nested] 122+ messages in thread

* Re: [PATCH v2 0/9] Remove spin_unlock_wait()
  2017-07-06 16:50         ` Peter Zijlstra
  2017-07-06 17:08           ` Will Deacon
@ 2017-07-06 17:18           ` Paul E. McKenney
  2017-07-07  8:31           ` Ingo Molnar
  2 siblings, 0 replies; 122+ messages in thread
From: Paul E. McKenney @ 2017-07-06 17:18 UTC (permalink / raw)
  To: Peter Zijlstra
  Cc: David Laight, linux-kernel, netfilter-devel, netdev, oleg, akpm,
	mingo, dave, manfred, tj, arnd, linux-arch, will.deacon, stern,
	parri.andrea, torvalds

On Thu, Jul 06, 2017 at 06:50:36PM +0200, Peter Zijlstra wrote:
> On Thu, Jul 06, 2017 at 09:20:24AM -0700, Paul E. McKenney wrote:
> > On Thu, Jul 06, 2017 at 06:05:55PM +0200, Peter Zijlstra wrote:
> > > On Thu, Jul 06, 2017 at 02:12:24PM +0000, David Laight wrote:
> > > > From: Paul E. McKenney
> > 
> > [ . . . ]
> > 
> > > Now on the one hand I feel like Oleg that it would be a shame to loose
> > > the optimization, OTOH this thing is really really tricky to use,
> > > and has lead to a number of bugs already.
> > 
> > I do agree, it is a bit sad to see these optimizations go.  So, should
> > this make mainline, I will be tagging the commits that spin_unlock_wait()
> > so that they can be easily reverted should someone come up with good
> > semantics and a compelling use case with compelling performance benefits.
> 
> Ha!, but what would constitute 'good semantics' ?

At this point, it beats the heck out of me!  ;-)

> The current thing is something along the lines of:
> 
>   "Waits for the currently observed critical section
>    to complete with ACQUIRE ordering such that it will observe
>    whatever state was left by said critical section."
> 
> With the 'obvious' benefit of limited interference on those actually
> wanting to acquire the lock, and a shorter wait time on our side too,
> since we only need to wait for completion of the current section, and
> not for however many contender are before us.
> 
> Not sure I have an actual (micro) benchmark that shows a difference
> though.
> 
> 
> 
> Is this all good enough to retain the thing, I dunno. Like I said, I'm
> conflicted on the whole thing. On the one hand its a nice optimization,
> on the other hand I don't want to have to keep fixing these bugs.

Yeah, if I had seen a compelling use case...  Oleg's task_work case was
closest, but given that it involved a task-local lock that shouldn't
be all -that- heavily contended, it is hard to see there being all that
much difference.

But maybe I am missing something here?  Wouldn't be the first time...

							Thanx, Paul

^ permalink raw reply	[flat|nested] 122+ messages in thread

* Re: [PATCH v2 0/9] Remove spin_unlock_wait()
  2017-07-06 17:08           ` Will Deacon
@ 2017-07-06 17:29             ` Paul E. McKenney
  0 siblings, 0 replies; 122+ messages in thread
From: Paul E. McKenney @ 2017-07-06 17:29 UTC (permalink / raw)
  To: Will Deacon
  Cc: Peter Zijlstra, David Laight, linux-kernel, netfilter-devel,
	netdev, oleg, akpm, mingo, dave, manfred, tj, arnd, linux-arch,
	stern, parri.andrea, torvalds

On Thu, Jul 06, 2017 at 06:08:50PM +0100, Will Deacon wrote:
> On Thu, Jul 06, 2017 at 06:50:36PM +0200, Peter Zijlstra wrote:
> > On Thu, Jul 06, 2017 at 09:20:24AM -0700, Paul E. McKenney wrote:
> > > On Thu, Jul 06, 2017 at 06:05:55PM +0200, Peter Zijlstra wrote:
> > > > On Thu, Jul 06, 2017 at 02:12:24PM +0000, David Laight wrote:
> > > > > From: Paul E. McKenney
> > > 
> > > [ . . . ]
> > > 
> > > > Now on the one hand I feel like Oleg that it would be a shame to loose
> > > > the optimization, OTOH this thing is really really tricky to use,
> > > > and has lead to a number of bugs already.
> > > 
> > > I do agree, it is a bit sad to see these optimizations go.  So, should
> > > this make mainline, I will be tagging the commits that spin_unlock_wait()
> > > so that they can be easily reverted should someone come up with good
> > > semantics and a compelling use case with compelling performance benefits.
> > 
> > Ha!, but what would constitute 'good semantics' ?
> > 
> > The current thing is something along the lines of:
> > 
> >   "Waits for the currently observed critical section
> >    to complete with ACQUIRE ordering such that it will observe
> >    whatever state was left by said critical section."
> > 
> > With the 'obvious' benefit of limited interference on those actually
> > wanting to acquire the lock, and a shorter wait time on our side too,
> > since we only need to wait for completion of the current section, and
> > not for however many contender are before us.
> > 
> > Not sure I have an actual (micro) benchmark that shows a difference
> > though.
> > 
> > 
> > 
> > Is this all good enough to retain the thing, I dunno. Like I said, I'm
> > conflicted on the whole thing. On the one hand its a nice optimization,
> > on the other hand I don't want to have to keep fixing these bugs.
> 
> As I've said, I'd be keen to see us drop this and bring it back if/when we
> get a compelling use-case along with performance numbers. At that point,
> we'd be in a better position to define the semantics anyway, knowing what
> exactly is expected by the use-case.

Hear, hear!!!  ;-)

							Thanx, Paul

^ permalink raw reply	[flat|nested] 122+ messages in thread

* Re: [PATCH RFC 01/26] netfilter: Replace spin_unlock_wait() with lock/unlock pair
  2017-07-03 19:57           ` Alan Stern
@ 2017-07-06 18:43             ` Manfred Spraul
  0 siblings, 0 replies; 122+ messages in thread
From: Manfred Spraul @ 2017-07-06 18:43 UTC (permalink / raw)
  To: Alan Stern
  Cc: paulmck, linux-kernel, netfilter-devel, netdev, oleg, akpm,
	mingo, dave, tj, arnd, linux-arch, will.deacon, peterz,
	parri.andrea, torvalds, Pablo Neira Ayuso, Jozsef Kadlecsik,
	Florian Westphal, David S. Miller, coreteam, 1vier1

[-- Attachment #1: Type: text/plain, Size: 519 bytes --]

Hi Alan,

On 07/03/2017 09:57 PM, Alan Stern wrote:
>
> (Alternatively, you could make nf_conntrack_all_unlock() do a
> lock+unlock on all the locks in the array, just like
> nf_conntrack_all_lock().  But of course, that would be a lot less
> efficient.)
Hmmmm.

Someone with a weakly ordered system who can test this?
semop() has a very short hotpath.

Either with aim9.shared_memory.ops_per_sec or

#sem-scalebench -t 10 -m 0
https://github.com/manfred-colorfu/ipcscale/blob/master/sem-scalebench.cpp
--
     Manfred

[-- Attachment #2: 0002-ipc-sem.c-avoid-smp_load_acuqire-in-the-hot-path.patch --]
[-- Type: text/x-patch, Size: 3330 bytes --]

>From b549e0281b66124b62aa94543f91b0e616abaf52 Mon Sep 17 00:00:00 2001
From: Manfred Spraul <manfred@colorfullife.com>
Date: Thu, 6 Jul 2017 20:05:44 +0200
Subject: [PATCH 2/2] ipc/sem.c: avoid smp_load_acuqire() in the hot-path

Alan Stern came up with an interesting idea:
If we perform a spin_lock()/spin_unlock() pair in the slow path, then
we can skip the smp_load_acquire() in the hot path.

What do you think?

* When we removed the smp_mb() from the hot path, it was a user space
  visible speed-up of 11%:

  https://lists.01.org/pipermail/lkp/2017-February/005520.html

* On x86, there is no improvement - as smp_load_acquire is READ_ONCE().

* Slowing down the slow path should not hurt:
  Due to the hysteresis code, the slow path is at least factor 10
  rarer than it was before.

Especially: Who is able to test it?

Signed-off-by: Manfred Spraul <manfred@colorfullife.com>
Cc: Alan Stern <stern@rowland.harvard.edu>
---
 ipc/sem.c | 33 +++++++++++++++++++--------------
 1 file changed, 19 insertions(+), 14 deletions(-)

diff --git a/ipc/sem.c b/ipc/sem.c
index 947dc23..75a4358 100644
--- a/ipc/sem.c
+++ b/ipc/sem.c
@@ -186,16 +186,15 @@ static int sysvipc_sem_proc_show(struct seq_file *s, void *it);
  *	* either local or global sem_lock() for read.
  *
  * Memory ordering:
- * Most ordering is enforced by using spin_lock() and spin_unlock().
+ * All ordering is enforced by using spin_lock() and spin_unlock().
  * The special case is use_global_lock:
  * Setting it from non-zero to 0 is a RELEASE, this is ensured by
- * using smp_store_release().
- * Testing if it is non-zero is an ACQUIRE, this is ensured by using
- * smp_load_acquire().
- * Setting it from 0 to non-zero must be ordered with regards to
- * this smp_load_acquire(), this is guaranteed because the smp_load_acquire()
- * is inside a spin_lock() and after a write from 0 to non-zero a
- * spin_lock()+spin_unlock() is done.
+ * performing spin_lock()/spin_lock() on every semaphore before setting to
+ * non-zero.
+ * Setting it from 0 to non-zero is an ACQUIRE, this is ensured by
+ * performing spin_lock()/spin_lock() on every semaphore after setting to
+ * non-zero.
+ * Testing if it is non-zero is within spin_lock(), no need for a barrier.
  */
 
 #define sc_semmsl	sem_ctls[0]
@@ -325,13 +324,20 @@ static void complexmode_tryleave(struct sem_array *sma)
 		return;
 	}
 	if (sma->use_global_lock == 1) {
+		int i;
+		struct sem *sem;
 		/*
 		 * Immediately after setting use_global_lock to 0,
-		 * a simple op can start. Thus: all memory writes
-		 * performed by the current operation must be visible
-		 * before we set use_global_lock to 0.
+		 * a simple op can start.
+		 * Perform a full lock/unlock, to guarantee memory
+		 * ordering.
 		 */
-		smp_store_release(&sma->use_global_lock, 0);
+		for (i = 0; i < sma->sem_nsems; i++) {
+			sem = sma->sem_base + i;
+			spin_lock(&sem->lock);
+			spin_unlock(&sem->lock);
+		}
+		sma->use_global_lock = 0;
 	} else {
 		sma->use_global_lock--;
 	}
@@ -379,8 +385,7 @@ static inline int sem_lock(struct sem_array *sma, struct sembuf *sops,
 		 */
 		spin_lock(&sem->lock);
 
-		/* pairs with smp_store_release() */
-		if (!smp_load_acquire(&sma->use_global_lock)) {
+		if (!sma->use_global_lock) {
 			/* fast path successful! */
 			return sops->sem_num;
 		}
-- 
2.9.4


^ permalink raw reply related	[flat|nested] 122+ messages in thread

* Re: [PATCH v2 1/9] net/netfilter/nf_conntrack_core: Fix net_conntrack_lock()
  2017-07-05 23:31   ` [PATCH v2 1/9] net/netfilter/nf_conntrack_core: Fix net_conntrack_lock() Paul E. McKenney
@ 2017-07-06 18:45     ` Manfred Spraul
  2017-07-06 20:26       ` Paul E. McKenney
  0 siblings, 1 reply; 122+ messages in thread
From: Manfred Spraul @ 2017-07-06 18:45 UTC (permalink / raw)
  To: Paul E. McKenney, linux-kernel
  Cc: netfilter-devel, netdev, oleg, akpm, mingo, dave, tj, arnd,
	linux-arch, will.deacon, peterz, stern, parri.andrea, torvalds,
	stable, Sasha Levin, Pablo Neira Ayuso

[-- Attachment #1: Type: text/plain, Size: 552 bytes --]

Hi Paul,

On 07/06/2017 01:31 AM, Paul E. McKenney wrote:
> From: Manfred Spraul <manfred@colorfullife.com>
>
> As we want to remove spin_unlock_wait() and replace it with explicit
> spin_lock()/spin_unlock() calls, we can use this to simplify the
> locking.
>
> In addition:
> - Reading nf_conntrack_locks_all needs ACQUIRE memory ordering.
> - The new code avoids the backwards loop.
>
> Only slightly tested, I did not manage to trigger calls to
> nf_conntrack_all_lock().

If you want:
Attached would be V2, with adapted comments.

--
     Manfred

[-- Attachment #2: 0001-net-netfilter-nf_conntrack_core-Fix-net_conntrack_lo.patch --]
[-- Type: text/x-patch, Size: 3705 bytes --]

>From e3562faa1bc96e883108505e05deecaf38c87a26 Mon Sep 17 00:00:00 2001
From: Manfred Spraul <manfred@colorfullife.com>
Date: Sun, 21 Aug 2016 07:17:55 +0200
Subject: [PATCH 1/2] net/netfilter/nf_conntrack_core: Fix net_conntrack_lock()

As we want to remove spin_unlock_wait() and replace it with explicit
spin_lock()/spin_unlock() calls, we can use this to simplify the
locking.

In addition:
- Reading nf_conntrack_locks_all needs ACQUIRE memory ordering.
- The new code avoids the backwards loop.

Only slightly tested, I did not manage to trigger calls to
nf_conntrack_all_lock().

V2: With improved comments, to clearly show how the barriers
    pair.

Fixes: b16c29191dc8
Signed-off-by: Manfred Spraul <manfred@colorfullife.com>
Cc: <stable@vger.kernel.org>
Cc: Alan Stern <stern@rowland.harvard.edu>
Cc: Sasha Levin <sasha.levin@oracle.com>
Cc: Pablo Neira Ayuso <pablo@netfilter.org>
Cc: netfilter-devel@vger.kernel.org
---
 net/netfilter/nf_conntrack_core.c | 52 ++++++++++++++++++++++-----------------
 1 file changed, 29 insertions(+), 23 deletions(-)

diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c
index 9979f46..51390fe 100644
--- a/net/netfilter/nf_conntrack_core.c
+++ b/net/netfilter/nf_conntrack_core.c
@@ -96,19 +96,26 @@ static struct conntrack_gc_work conntrack_gc_work;
 
 void nf_conntrack_lock(spinlock_t *lock) __acquires(lock)
 {
+	/* 1) Acquire the lock */
 	spin_lock(lock);
-	while (unlikely(nf_conntrack_locks_all)) {
-		spin_unlock(lock);
 
-		/*
-		 * Order the 'nf_conntrack_locks_all' load vs. the
-		 * spin_unlock_wait() loads below, to ensure
-		 * that 'nf_conntrack_locks_all_lock' is indeed held:
-		 */
-		smp_rmb(); /* spin_lock(&nf_conntrack_locks_all_lock) */
-		spin_unlock_wait(&nf_conntrack_locks_all_lock);
-		spin_lock(lock);
-	}
+	/* 2) read nf_conntrack_locks_all, with ACQUIRE semantics
+	 * It pairs with the smp_store_release() in nf_conntrack_all_unlock()
+	 */
+	if (likely(smp_load_acquire(&nf_conntrack_locks_all) == false))
+		return;
+
+	/* fast path failed, unlock */
+	spin_unlock(lock);
+
+	/* Slow path 1) get global lock */
+	spin_lock(&nf_conntrack_locks_all_lock);
+
+	/* Slow path 2) get the lock we want */
+	spin_lock(lock);
+
+	/* Slow path 3) release the global lock */
+	spin_unlock(&nf_conntrack_locks_all_lock);
 }
 EXPORT_SYMBOL_GPL(nf_conntrack_lock);
 
@@ -149,28 +156,27 @@ static void nf_conntrack_all_lock(void)
 	int i;
 
 	spin_lock(&nf_conntrack_locks_all_lock);
-	nf_conntrack_locks_all = true;
 
-	/*
-	 * Order the above store of 'nf_conntrack_locks_all' against
-	 * the spin_unlock_wait() loads below, such that if
-	 * nf_conntrack_lock() observes 'nf_conntrack_locks_all'
-	 * we must observe nf_conntrack_locks[] held:
-	 */
-	smp_mb(); /* spin_lock(&nf_conntrack_locks_all_lock) */
+	nf_conntrack_locks_all = true;
 
 	for (i = 0; i < CONNTRACK_LOCKS; i++) {
-		spin_unlock_wait(&nf_conntrack_locks[i]);
+		spin_lock(&nf_conntrack_locks[i]);
+
+		/* This spin_unlock provides the "release" to ensure that
+		 * nf_conntrack_locks_all==true is visible to everyone that
+		 * acquired spin_lock(&nf_conntrack_locks[]).
+		 */
+		spin_unlock(&nf_conntrack_locks[i]);
 	}
 }
 
 static void nf_conntrack_all_unlock(void)
 {
-	/*
-	 * All prior stores must be complete before we clear
+	/* All prior stores must be complete before we clear
 	 * 'nf_conntrack_locks_all'. Otherwise nf_conntrack_lock()
 	 * might observe the false value but not the entire
-	 * critical section:
+	 * critical section.
+	 * It pairs with the smp_load_acquire() in nf_conntrack_lock()
 	 */
 	smp_store_release(&nf_conntrack_locks_all, false);
 	spin_unlock(&nf_conntrack_locks_all_lock);
-- 
2.9.4


^ permalink raw reply related	[flat|nested] 122+ messages in thread

* Re: [PATCH v2 0/9] Remove spin_unlock_wait()
  2017-07-06 16:54             ` Peter Zijlstra
@ 2017-07-06 19:37               ` Alan Stern
  0 siblings, 0 replies; 122+ messages in thread
From: Alan Stern @ 2017-07-06 19:37 UTC (permalink / raw)
  To: Peter Zijlstra
  Cc: Paul E. McKenney, David Laight, linux-kernel, netfilter-devel,
	netdev, oleg, akpm, mingo, dave, manfred, tj, arnd, linux-arch,
	will.deacon, parri.andrea, torvalds

On Thu, 6 Jul 2017, Peter Zijlstra wrote:

> On Thu, Jul 06, 2017 at 12:49:12PM -0400, Alan Stern wrote:
> > On Thu, 6 Jul 2017, Paul E. McKenney wrote:
> > 
> > > On Thu, Jul 06, 2017 at 06:10:47PM +0200, Peter Zijlstra wrote:
> > > > On Thu, Jul 06, 2017 at 08:21:10AM -0700, Paul E. McKenney wrote:
> > > > > And yes, there are architecture-specific optimizations for an
> > > > > empty spin_lock()/spin_unlock() critical section, and the current
> > > > > arch_spin_unlock_wait() implementations show some of these optimizations.
> > > > > But I expect that performance benefits would need to be demonstrated at
> > > > > the system level.
> > > > 
> > > > I do in fact contended there are any optimizations for the exact
> > > > lock+unlock semantics.
> > > 
> > > You lost me on this one.
> > > 
> > > > The current spin_unlock_wait() is weaker. Most notably it will not (with
> > > > exception of ARM64/PPC for other reasons) cause waits on other CPUs.
> > > 
> > > Agreed, weaker semantics allow more optimizations.  So use cases needing
> > > only the weaker semantics should more readily show performance benefits.
> > > But either way, we need compelling use cases, and I do not believe that
> > > any of the existing spin_unlock_wait() calls are compelling.  Perhaps I
> > > am confused, but I am not seeing it for any of them.
> > 
> > If somebody really wants the full spin_unlock_wait semantics and
> > doesn't want to interfere with other CPUs, wouldn't synchronize_sched()
> > or something similar do the job?  It wouldn't be as efficient as
> > lock+unlock, but it also wouldn't affect other CPUs.
> 
> So please don't do that. That'll create massive pain for RT. Also I
> don't think it works. The whole point was that spin_unlock_wait() is
> _cheaper_ than lock()+unlock(). If it gets to be more expensive there is
> absolutely no point in using it.

Of course; that is obvious.

I was making a rhetorical point: You should not try to justify
spin_unlock_wait() on the basis that it doesn't cause waits on other
CPUs.

Alan Stern

^ permalink raw reply	[flat|nested] 122+ messages in thread

* Re: [PATCH v2 1/9] net/netfilter/nf_conntrack_core: Fix net_conntrack_lock()
  2017-07-06 18:45     ` Manfred Spraul
@ 2017-07-06 20:26       ` Paul E. McKenney
  0 siblings, 0 replies; 122+ messages in thread
From: Paul E. McKenney @ 2017-07-06 20:26 UTC (permalink / raw)
  To: Manfred Spraul
  Cc: linux-kernel, netfilter-devel, netdev, oleg, akpm, mingo, dave,
	tj, arnd, linux-arch, will.deacon, peterz, stern, parri.andrea,
	torvalds, stable, Sasha Levin, Pablo Neira Ayuso

On Thu, Jul 06, 2017 at 08:45:59PM +0200, Manfred Spraul wrote:
> Hi Paul,
> 
> On 07/06/2017 01:31 AM, Paul E. McKenney wrote:
> >From: Manfred Spraul <manfred@colorfullife.com>
> >
> >As we want to remove spin_unlock_wait() and replace it with explicit
> >spin_lock()/spin_unlock() calls, we can use this to simplify the
> >locking.
> >
> >In addition:
> >- Reading nf_conntrack_locks_all needs ACQUIRE memory ordering.
> >- The new code avoids the backwards loop.
> >
> >Only slightly tested, I did not manage to trigger calls to
> >nf_conntrack_all_lock().
> 
> If you want:
> Attached would be V2, with adapted comments.

I do like the improved comments, thank you!  Queued, and will be part
of a later v3 of the series.

							Thanx, Paul

> --
>     Manfred

> >From e3562faa1bc96e883108505e05deecaf38c87a26 Mon Sep 17 00:00:00 2001
> From: Manfred Spraul <manfred@colorfullife.com>
> Date: Sun, 21 Aug 2016 07:17:55 +0200
> Subject: [PATCH 1/2] net/netfilter/nf_conntrack_core: Fix net_conntrack_lock()
> 
> As we want to remove spin_unlock_wait() and replace it with explicit
> spin_lock()/spin_unlock() calls, we can use this to simplify the
> locking.
> 
> In addition:
> - Reading nf_conntrack_locks_all needs ACQUIRE memory ordering.
> - The new code avoids the backwards loop.
> 
> Only slightly tested, I did not manage to trigger calls to
> nf_conntrack_all_lock().
> 
> V2: With improved comments, to clearly show how the barriers
>     pair.
> 
> Fixes: b16c29191dc8
> Signed-off-by: Manfred Spraul <manfred@colorfullife.com>
> Cc: <stable@vger.kernel.org>
> Cc: Alan Stern <stern@rowland.harvard.edu>
> Cc: Sasha Levin <sasha.levin@oracle.com>
> Cc: Pablo Neira Ayuso <pablo@netfilter.org>
> Cc: netfilter-devel@vger.kernel.org
> ---
>  net/netfilter/nf_conntrack_core.c | 52 ++++++++++++++++++++++-----------------
>  1 file changed, 29 insertions(+), 23 deletions(-)
> 
> diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c
> index 9979f46..51390fe 100644
> --- a/net/netfilter/nf_conntrack_core.c
> +++ b/net/netfilter/nf_conntrack_core.c
> @@ -96,19 +96,26 @@ static struct conntrack_gc_work conntrack_gc_work;
> 
>  void nf_conntrack_lock(spinlock_t *lock) __acquires(lock)
>  {
> +	/* 1) Acquire the lock */
>  	spin_lock(lock);
> -	while (unlikely(nf_conntrack_locks_all)) {
> -		spin_unlock(lock);
> 
> -		/*
> -		 * Order the 'nf_conntrack_locks_all' load vs. the
> -		 * spin_unlock_wait() loads below, to ensure
> -		 * that 'nf_conntrack_locks_all_lock' is indeed held:
> -		 */
> -		smp_rmb(); /* spin_lock(&nf_conntrack_locks_all_lock) */
> -		spin_unlock_wait(&nf_conntrack_locks_all_lock);
> -		spin_lock(lock);
> -	}
> +	/* 2) read nf_conntrack_locks_all, with ACQUIRE semantics
> +	 * It pairs with the smp_store_release() in nf_conntrack_all_unlock()
> +	 */
> +	if (likely(smp_load_acquire(&nf_conntrack_locks_all) == false))
> +		return;
> +
> +	/* fast path failed, unlock */
> +	spin_unlock(lock);
> +
> +	/* Slow path 1) get global lock */
> +	spin_lock(&nf_conntrack_locks_all_lock);
> +
> +	/* Slow path 2) get the lock we want */
> +	spin_lock(lock);
> +
> +	/* Slow path 3) release the global lock */
> +	spin_unlock(&nf_conntrack_locks_all_lock);
>  }
>  EXPORT_SYMBOL_GPL(nf_conntrack_lock);
> 
> @@ -149,28 +156,27 @@ static void nf_conntrack_all_lock(void)
>  	int i;
> 
>  	spin_lock(&nf_conntrack_locks_all_lock);
> -	nf_conntrack_locks_all = true;
> 
> -	/*
> -	 * Order the above store of 'nf_conntrack_locks_all' against
> -	 * the spin_unlock_wait() loads below, such that if
> -	 * nf_conntrack_lock() observes 'nf_conntrack_locks_all'
> -	 * we must observe nf_conntrack_locks[] held:
> -	 */
> -	smp_mb(); /* spin_lock(&nf_conntrack_locks_all_lock) */
> +	nf_conntrack_locks_all = true;
> 
>  	for (i = 0; i < CONNTRACK_LOCKS; i++) {
> -		spin_unlock_wait(&nf_conntrack_locks[i]);
> +		spin_lock(&nf_conntrack_locks[i]);
> +
> +		/* This spin_unlock provides the "release" to ensure that
> +		 * nf_conntrack_locks_all==true is visible to everyone that
> +		 * acquired spin_lock(&nf_conntrack_locks[]).
> +		 */
> +		spin_unlock(&nf_conntrack_locks[i]);
>  	}
>  }
> 
>  static void nf_conntrack_all_unlock(void)
>  {
> -	/*
> -	 * All prior stores must be complete before we clear
> +	/* All prior stores must be complete before we clear
>  	 * 'nf_conntrack_locks_all'. Otherwise nf_conntrack_lock()
>  	 * might observe the false value but not the entire
> -	 * critical section:
> +	 * critical section.
> +	 * It pairs with the smp_load_acquire() in nf_conntrack_lock()
>  	 */
>  	smp_store_release(&nf_conntrack_locks_all, false);
>  	spin_unlock(&nf_conntrack_locks_all_lock);
> -- 
> 2.9.4
> 

^ permalink raw reply	[flat|nested] 122+ messages in thread

* Re: [PATCH v2 0/9] Remove spin_unlock_wait()
  2017-07-06 16:05     ` Peter Zijlstra
  2017-07-06 16:20       ` Paul E. McKenney
@ 2017-07-07  8:06       ` Ingo Molnar
  2017-07-07  9:32         ` Ingo Molnar
  1 sibling, 1 reply; 122+ messages in thread
From: Ingo Molnar @ 2017-07-07  8:06 UTC (permalink / raw)
  To: Peter Zijlstra
  Cc: David Laight, 'paulmck@linux.vnet.ibm.com',
	linux-kernel, netfilter-devel, netdev, oleg, akpm, mingo, dave,
	manfred, tj, arnd, linux-arch, will.deacon, stern, parri.andrea,
	torvalds


* Peter Zijlstra <peterz@infradead.org> wrote:

> > It might even be that this is the defined semantics of spin_unlock_wait().
> 
> As is, spin_unlock_wait() is somewhat ill defined. IIRC it grew from an 
> optimization by Oleg and subsequently got used elsewhere. And it being the 
> subtle bugger it is, there were bugs.

I believe the historical, original spin_unlock_wait() came from early SMP 
optimizations of the networking code - and then spread elsewhere, step by step. 
All but one of the networking uses went away since then - so I don't think there's 
any original usecase left.

Thanks,

	Ingo

^ permalink raw reply	[flat|nested] 122+ messages in thread

* Re: [PATCH v2 0/9] Remove spin_unlock_wait()
  2017-07-06 16:50         ` Peter Zijlstra
  2017-07-06 17:08           ` Will Deacon
  2017-07-06 17:18           ` Paul E. McKenney
@ 2017-07-07  8:31           ` Ingo Molnar
  2017-07-07  8:44             ` Peter Zijlstra
                               ` (2 more replies)
  2 siblings, 3 replies; 122+ messages in thread
From: Ingo Molnar @ 2017-07-07  8:31 UTC (permalink / raw)
  To: Peter Zijlstra
  Cc: Paul E. McKenney, David Laight, linux-kernel, netfilter-devel,
	netdev, oleg, akpm, mingo, dave, manfred, tj, arnd, linux-arch,
	will.deacon, stern, parri.andrea, torvalds


* Peter Zijlstra <peterz@infradead.org> wrote:

> On Thu, Jul 06, 2017 at 09:20:24AM -0700, Paul E. McKenney wrote:
> > On Thu, Jul 06, 2017 at 06:05:55PM +0200, Peter Zijlstra wrote:
> > > On Thu, Jul 06, 2017 at 02:12:24PM +0000, David Laight wrote:
> > > > From: Paul E. McKenney
> > 
> > [ . . . ]
> > 
> > > Now on the one hand I feel like Oleg that it would be a shame to loose
> > > the optimization, OTOH this thing is really really tricky to use,
> > > and has lead to a number of bugs already.
> > 
> > I do agree, it is a bit sad to see these optimizations go.  So, should
> > this make mainline, I will be tagging the commits that spin_unlock_wait()
> > so that they can be easily reverted should someone come up with good
> > semantics and a compelling use case with compelling performance benefits.
> 
> Ha!, but what would constitute 'good semantics' ?
> 
> The current thing is something along the lines of:
> 
>   "Waits for the currently observed critical section
>    to complete with ACQUIRE ordering such that it will observe
>    whatever state was left by said critical section."
> 
> With the 'obvious' benefit of limited interference on those actually
> wanting to acquire the lock, and a shorter wait time on our side too,
> since we only need to wait for completion of the current section, and
> not for however many contender are before us.

There's another, probably just as significant advantage: queued_spin_unlock_wait() 
is 'read-only', while spin_lock()+spin_unlock() dirties the lock cache line. On 
any bigger system this should make a very measurable difference - if 
spin_unlock_wait() is ever used in a performance critical code path.

> Not sure I have an actual (micro) benchmark that shows a difference
> though.

It should be pretty obvious from pretty much any profile, the actual lock+unlock 
sequence that modifies the lock cache line is essentially a global cacheline 
bounce.

> Is this all good enough to retain the thing, I dunno. Like I said, I'm 
> conflicted on the whole thing. On the one hand its a nice optimization, on the 
> other hand I don't want to have to keep fixing these bugs.

So on one hand it's _obvious_ that spin_unlock_wait() is both faster on the local 
_and_ the remote CPUs for any sort of use case where performance matters - I don't 
even understand how that can be argued otherwise.

The real question, does any use-case (we care about) exist.

Here's a quick list of all the use cases:

 net/netfilter/nf_conntrack_core.c:

   - This is I believe the 'original', historic spin_unlock_wait() usecase that
     still exists in the kernel. spin_unlock_wait() is only used in a rare case, 
     when the netfilter hash is resized via nf_conntrack_hash_resize() - which is 
     a very heavy operation to begin with. It will no doubt get slower with the 
     proposed changes, but it probably does not matter. A networking person 
     Acked-by would be nice though.

 drivers/ata/libata-eh.c:

   - Locking of the ATA port in ata_scsi_cmd_error_handler(), presumably this can
     race with IRQs and ioctls() on other CPUs. Very likely not performance 
     sensitive in any fashion, on IO errors things stop for many seconds anyway.

 ipc/sem.c:

   - A rare race condition branch in the SysV IPC semaphore freeing code in 
     exit_sem() - where even the main code flow is not performance sensitive, 
     because typical database workloads get their semaphore arrays during startup 
     and don't ever do heavy runtime allocation/freeing of them.

 kernel/sched/completion.c:

   - completion_done(). This is actually a (comparatively) rarely used completion 
     API call - almost all the upstream usecases are in drivers, plus two in 
     filesystems - neither usecase seems in a performance critical hot path. 
     Completions typically involve scheduling and context switching, so in the 
     worst case the proposed change adds overhead to a scheduling slow path.

So I'd argue that unless there's some surprising performance aspect of a 
completion_done() user, the proposed changes should not cause any performance 
trouble.

In fact I'd argue that any future high performance spin_unlock_wait() user is 
probably better off open coding the unlock-wait poll loop (and possibly thinking 
hard about eliminating it altogether). If such patterns pop up in the kernel we 
can think about consolidating them into a single read-only primitive again.

I.e. I think the proposed changes are doing no harm, and the unavailability of a 
generic primitive does not hinder future optimizations either in any significant 
fashion.

Thanks,

	Ingo

^ permalink raw reply	[flat|nested] 122+ messages in thread

* Re: [PATCH v2 0/9] Remove spin_unlock_wait()
  2017-07-07  8:31           ` Ingo Molnar
@ 2017-07-07  8:44             ` Peter Zijlstra
  2017-07-07 10:33               ` Ingo Molnar
  2017-07-07 14:41             ` Paul E. McKenney
  2017-07-07 17:47             ` Manfred Spraul
  2 siblings, 1 reply; 122+ messages in thread
From: Peter Zijlstra @ 2017-07-07  8:44 UTC (permalink / raw)
  To: Ingo Molnar
  Cc: Paul E. McKenney, David Laight, linux-kernel, netfilter-devel,
	netdev, oleg, akpm, mingo, dave, manfred, tj, arnd, linux-arch,
	will.deacon, stern, parri.andrea, torvalds

On Fri, Jul 07, 2017 at 10:31:28AM +0200, Ingo Molnar wrote:
> Here's a quick list of all the use cases:
> 
>  net/netfilter/nf_conntrack_core.c:
> 
>    - This is I believe the 'original', historic spin_unlock_wait() usecase that
>      still exists in the kernel. spin_unlock_wait() is only used in a rare case, 
>      when the netfilter hash is resized via nf_conntrack_hash_resize() - which is 
>      a very heavy operation to begin with. It will no doubt get slower with the 
>      proposed changes, but it probably does not matter. A networking person 
>      Acked-by would be nice though.
> 
>  drivers/ata/libata-eh.c:
> 
>    - Locking of the ATA port in ata_scsi_cmd_error_handler(), presumably this can
>      race with IRQs and ioctls() on other CPUs. Very likely not performance 
>      sensitive in any fashion, on IO errors things stop for many seconds anyway.
> 
>  ipc/sem.c:
> 
>    - A rare race condition branch in the SysV IPC semaphore freeing code in 
>      exit_sem() - where even the main code flow is not performance sensitive, 
>      because typical database workloads get their semaphore arrays during startup 
>      and don't ever do heavy runtime allocation/freeing of them.
> 
>  kernel/sched/completion.c:
> 
>    - completion_done(). This is actually a (comparatively) rarely used completion 
>      API call - almost all the upstream usecases are in drivers, plus two in 
>      filesystems - neither usecase seems in a performance critical hot path. 
>      Completions typically involve scheduling and context switching, so in the 
>      worst case the proposed change adds overhead to a scheduling slow path.
> 

You missed the one in do_exit(), which I thought was the original one.

^ permalink raw reply	[flat|nested] 122+ messages in thread

* Re: [PATCH v2 0/9] Remove spin_unlock_wait()
  2017-07-07  8:06       ` Ingo Molnar
@ 2017-07-07  9:32         ` Ingo Molnar
  0 siblings, 0 replies; 122+ messages in thread
From: Ingo Molnar @ 2017-07-07  9:32 UTC (permalink / raw)
  To: Peter Zijlstra
  Cc: David Laight, 'paulmck@linux.vnet.ibm.com',
	linux-kernel, netfilter-devel, netdev, oleg, akpm, mingo, dave,
	manfred, tj, arnd, linux-arch, will.deacon, stern, parri.andrea,
	torvalds


* Ingo Molnar <mingo@kernel.org> wrote:

> 
> * Peter Zijlstra <peterz@infradead.org> wrote:
> 
> > > It might even be that this is the defined semantics of spin_unlock_wait().
> > 
> > As is, spin_unlock_wait() is somewhat ill defined. IIRC it grew from an 
> > optimization by Oleg and subsequently got used elsewhere. And it being the 
> > subtle bugger it is, there were bugs.
> 
> I believe the historical, original spin_unlock_wait() came from early SMP 
> optimizations of the networking code - and then spread elsewhere, step by step. 
> All but one of the networking uses went away since then - so I don't think there's 
> any original usecase left.

No - the original usecase was task teardown: I still remembered that but didn't 
find the commit - but it's there in very old Linux kernel patches, done by DaveM 
originally in v2.1.36 (!):

--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -136,6 +136,12 @@ void release(struct task_struct * p)
        }
        for (i=1 ; i<NR_TASKS ; i++)
                if (task[i] == p) {
+#ifdef __SMP__
+                       /* FIXME! Cheesy, but kills the window... -DaveM */
+                       while(p->processor != NO_PROC_ID)
+                               barrier();
+                       spin_unlock_wait(&scheduler_lock);
+#endif


Other code learned to use spin_unlock_wait(): the original version of 
[hard]irq_enter() was the second user, net_family_read_lock() was the third user, 
followed by more uses in networking. All but one of those are not present in the 
current upstream kernel anymore.

This task-teardown FIXME was fixed in v2.1.114 (was replaced by an open coded poll 
loop), but the spin_unlock_wait() primitive remained.

The rest is history! ;-)

Thanks,

	Ingo

^ permalink raw reply	[flat|nested] 122+ messages in thread

* Re: [PATCH v2 0/9] Remove spin_unlock_wait()
  2017-07-07  8:44             ` Peter Zijlstra
@ 2017-07-07 10:33               ` Ingo Molnar
  2017-07-07 11:23                 ` Peter Zijlstra
  0 siblings, 1 reply; 122+ messages in thread
From: Ingo Molnar @ 2017-07-07 10:33 UTC (permalink / raw)
  To: Peter Zijlstra
  Cc: Paul E. McKenney, David Laight, linux-kernel, netfilter-devel,
	netdev, oleg, akpm, mingo, dave, manfred, tj, arnd, linux-arch,
	will.deacon, stern, parri.andrea, torvalds


* Peter Zijlstra <peterz@infradead.org> wrote:

> You missed the one in do_exit(), which I thought was the original one.

Indeed, it's raw_spin_unlock_wait() which my git grep pattern missed.

But it's not the original spin_unlock_wait(): the pi_lock and priority inheritance 
is a newfangled invention that Linus (rightfully) resisted for years.

The original spin_unlock_wait() was for the global scheduler_lock, long gone.

Here's the full history of the original spin_unlock_wait() usecase in the 
do_exit() path, for the historically interested:

 [1997/04] v2.1.36:

      the spin_unlock_wait() primitive gets introduced as part of release()

 [1998/08] v2.1.114:

      the release() usecase gets converted to an open coded spin_lock()+unlock() 
      poll loop over scheduler_lock

 [1999/05] v2.3.11pre3:

      open coded loop is changed over to poll p->has_cpu

 [1999/07] v2.3.12pre6:

      ->has_cpu loop poll loop is converted to a spin_lock()+unlock() 
      poll loop over runqueue_lock

 [2000/06] 2.4.0-test6pre4:

      combined open coded p->has_cpu poll loop is added back, in addition to the
      lock()+unlock() loop

 [2000/11] 2.4.0-test12pre4:

      lock+unlock loop is changed from scheduler_lock to task_lock

 [2001/11] v2.4.14.9:

       ->has_cpu gets renamed to ->cpus_runnable

 [2001/12] v2.5.1.10:

       poll loop is factored out from exit()'s release() function 
       to the scheduler's new wait_task_inactive() function

 ...

 [2017/07] v4.12:

      wait_task_inactive() is still alive and kicking. Its poll loop has
      increased in complexity, but it still does not use spin_unlock_wait()

So it was always a mess, and we relatively early flipped from the clever 
spin_unlock_wait() implementation to an open coded lock+unlock poll loop.

TL;DR: The original do_exit() usecase is gone, it does not use spin_unlock_wait(),
       since 1998.

Thanks,

	Ingo

^ permalink raw reply	[flat|nested] 122+ messages in thread

* Re: [PATCH v2 0/9] Remove spin_unlock_wait()
  2017-07-07 10:33               ` Ingo Molnar
@ 2017-07-07 11:23                 ` Peter Zijlstra
  0 siblings, 0 replies; 122+ messages in thread
From: Peter Zijlstra @ 2017-07-07 11:23 UTC (permalink / raw)
  To: Ingo Molnar
  Cc: Paul E. McKenney, David Laight, linux-kernel, netfilter-devel,
	netdev, oleg, akpm, mingo, dave, manfred, tj, arnd, linux-arch,
	will.deacon, stern, parri.andrea, torvalds

On Fri, Jul 07, 2017 at 12:33:49PM +0200, Ingo Molnar wrote:

>  [1997/04] v2.1.36:
> 
>       the spin_unlock_wait() primitive gets introduced as part of release()


Whee, that goes _way_ further back than I thought it did :-)

>  [2017/07] v4.12:
> 
>       wait_task_inactive() is still alive and kicking. Its poll loop has
>       increased in complexity, but it still does not use spin_unlock_wait()
> 

I've tried 'fixing' that wait_task_inactive() thing a number of times,
but always failed :/ That is very nasty code indeed.

^ permalink raw reply	[flat|nested] 122+ messages in thread

* Re: [PATCH v2 0/9] Remove spin_unlock_wait()
  2017-07-07  8:31           ` Ingo Molnar
  2017-07-07  8:44             ` Peter Zijlstra
@ 2017-07-07 14:41             ` Paul E. McKenney
  2017-07-08  8:43               ` Ingo Molnar
  2017-07-07 17:47             ` Manfred Spraul
  2 siblings, 1 reply; 122+ messages in thread
From: Paul E. McKenney @ 2017-07-07 14:41 UTC (permalink / raw)
  To: Ingo Molnar
  Cc: Peter Zijlstra, David Laight, linux-kernel, netfilter-devel,
	netdev, oleg, akpm, mingo, dave, manfred, tj, arnd, linux-arch,
	will.deacon, stern, parri.andrea, torvalds

On Fri, Jul 07, 2017 at 10:31:28AM +0200, Ingo Molnar wrote:

[ . . . ]

> In fact I'd argue that any future high performance spin_unlock_wait() user is 
> probably better off open coding the unlock-wait poll loop (and possibly thinking 
> hard about eliminating it altogether). If such patterns pop up in the kernel we 
> can think about consolidating them into a single read-only primitive again.

I would like any reintroduction to include a header comment saying exactly
what the consolidated primitive actually does and does not do.  ;-)

> I.e. I think the proposed changes are doing no harm, and the unavailability of a 
> generic primitive does not hinder future optimizations either in any significant 
> fashion.

I will have a v3 with updated comments from Manfred.  Thoughts on when/where
to push this?

The reason I ask is if this does not go in during this merge window, I need
to fix the header comment on spin_unlock_wait().

							Thanx, Paul

^ permalink raw reply	[flat|nested] 122+ messages in thread

* Re: [PATCH v2 0/9] Remove spin_unlock_wait()
  2017-07-07  8:31           ` Ingo Molnar
  2017-07-07  8:44             ` Peter Zijlstra
  2017-07-07 14:41             ` Paul E. McKenney
@ 2017-07-07 17:47             ` Manfred Spraul
  2017-07-08  8:35               ` Ingo Molnar
  2 siblings, 1 reply; 122+ messages in thread
From: Manfred Spraul @ 2017-07-07 17:47 UTC (permalink / raw)
  To: Ingo Molnar, Peter Zijlstra
  Cc: Paul E. McKenney, David Laight, linux-kernel, netfilter-devel,
	netdev, oleg, akpm, mingo, dave, tj, arnd, linux-arch,
	will.deacon, stern, parri.andrea, torvalds

Hi Ingo,

On 07/07/2017 10:31 AM, Ingo Molnar wrote:
>
> There's another, probably just as significant advantage: queued_spin_unlock_wait()
> is 'read-only', while spin_lock()+spin_unlock() dirties the lock cache line. On
> any bigger system this should make a very measurable difference - if
> spin_unlock_wait() is ever used in a performance critical code path.
At least for ipc/sem:
Dirtying the cacheline (in the slow path) allows to remove a smp_mb() in 
the hot path.
So for sem_lock(), I either need a primitive that dirties the cacheline 
or sem_lock() must continue to use spin_lock()/spin_unlock().

--
     Manfred

^ permalink raw reply	[flat|nested] 122+ messages in thread

* [PATCH v3 0/9] Remove spin_unlock_wait()
  2017-07-05 23:29 ` [PATCH v2 0/9] Remove spin_unlock_wait() Paul E. McKenney
                     ` (9 preceding siblings ...)
  2017-07-06 14:12   ` [PATCH v2 0/9] Remove spin_unlock_wait() David Laight
@ 2017-07-07 19:27   ` Paul E. McKenney
  2017-07-07 19:28     ` [PATCH v3 1/9] net/netfilter/nf_conntrack_core: Fix net_conntrack_lock() Paul E. McKenney
                       ` (8 more replies)
  10 siblings, 9 replies; 122+ messages in thread
From: Paul E. McKenney @ 2017-07-07 19:27 UTC (permalink / raw)
  To: linux-kernel
  Cc: netfilter-devel, netdev, oleg, akpm, mingo, dave, manfred, tj,
	arnd, linux-arch, will.deacon, peterz, stern, parri.andrea,
	torvalds

Hello!

There is no agreed-upon definition of spin_unlock_wait()'s semantics,
and it appears that all callers could do just as well with a lock/unlock
pair.  This series therefore removes spin_unlock_wait() and changes
its users to instead use a lock/unlock pair.  The commits are as follows,
in three groups:

1-7.	Change uses of spin_unlock_wait() and raw_spin_unlock_wait()
	to instead use a spin_lock/spin_unlock pair.  These may be
	applied in any order, but must be applied before any later
	commits in this series.  The commit logs state why I believe
	that these commits won't noticeably degrade performance.

8.	Remove core-kernel definitions for spin_unlock_wait() and
	raw_spin_unlock_wait().

9.	Remove arch-specific definitions of arch_spin_unlock_wait().

Changes since v2:

o	Add comment-only update from Manfred.

Changes since v1:

o	Disable interrupts where needed, thus avoiding embarrassing
	interrupt-based self-deadlocks.

o	Substitute Manfred's patch for contrack_lock (#1 above).

o	Substitute Oleg's patch for task_work (#2 above).

o	Use more efficient barrier based on Arnd Bergmann feedback.

o	Merge the arch commits.

							Thanx, Paul

------------------------------------------------------------------------

 arch/alpha/include/asm/spinlock.h    |    5 -
 arch/arc/include/asm/spinlock.h      |    5 -
 arch/arm/include/asm/spinlock.h      |   16 ----
 arch/arm64/include/asm/spinlock.h    |   58 +----------------
 arch/blackfin/include/asm/spinlock.h |    5 -
 arch/hexagon/include/asm/spinlock.h  |    5 -
 arch/ia64/include/asm/spinlock.h     |   21 ------
 arch/m32r/include/asm/spinlock.h     |    5 -
 arch/metag/include/asm/spinlock.h    |    5 -
 arch/mips/include/asm/spinlock.h     |   16 ----
 arch/mn10300/include/asm/spinlock.h  |    5 -
 arch/parisc/include/asm/spinlock.h   |    7 --
 arch/powerpc/include/asm/spinlock.h  |   33 ---------
 arch/s390/include/asm/spinlock.h     |    7 --
 arch/sh/include/asm/spinlock-cas.h   |    5 -
 arch/sh/include/asm/spinlock-llsc.h  |    5 -
 arch/sparc/include/asm/spinlock_32.h |    5 -
 arch/sparc/include/asm/spinlock_64.h |    5 -
 arch/tile/include/asm/spinlock_32.h  |    2 
 arch/tile/include/asm/spinlock_64.h  |    2 
 arch/tile/lib/spinlock_32.c          |   23 ------
 arch/tile/lib/spinlock_64.c          |   22 ------
 arch/xtensa/include/asm/spinlock.h   |    5 -
 drivers/ata/libata-eh.c              |    8 --
 include/asm-generic/qspinlock.h      |   14 ----
 include/linux/spinlock.h             |   31 ---------
 include/linux/spinlock_up.h          |    6 -
 ipc/sem.c                            |    3 
 kernel/exit.c                        |    3 
 kernel/locking/qspinlock.c           |  117 -----------------------------------
 kernel/sched/completion.c            |    9 --
 kernel/sched/core.c                  |    5 -
 kernel/task_work.c                   |    8 --
 net/netfilter/nf_conntrack_core.c    |   52 ++++++++-------
 34 files changed, 48 insertions(+), 475 deletions(-)

^ permalink raw reply	[flat|nested] 122+ messages in thread

* [PATCH v3 1/9] net/netfilter/nf_conntrack_core: Fix net_conntrack_lock()
  2017-07-07 19:27   ` [PATCH v3 " Paul E. McKenney
@ 2017-07-07 19:28     ` Paul E. McKenney
  2017-07-07 19:28     ` [PATCH v3 2/9] task_work: Replace spin_unlock_wait() with lock/unlock pair Paul E. McKenney
                       ` (7 subsequent siblings)
  8 siblings, 0 replies; 122+ messages in thread
From: Paul E. McKenney @ 2017-07-07 19:28 UTC (permalink / raw)
  To: linux-kernel
  Cc: netfilter-devel, netdev, oleg, akpm, mingo, dave, manfred, tj,
	arnd, linux-arch, will.deacon, peterz, stern, parri.andrea,
	torvalds, stable, Sasha Levin, Pablo Neira Ayuso,
	Paul E. McKenney

From: Manfred Spraul <manfred@colorfullife.com>

As we want to remove spin_unlock_wait() and replace it with explicit
spin_lock()/spin_unlock() calls, we can use this to simplify the
locking.

In addition:
- Reading nf_conntrack_locks_all needs ACQUIRE memory ordering.
- The new code avoids the backwards loop.

Only slightly tested, I did not manage to trigger calls to
nf_conntrack_all_lock().

V2: With improved comments, to clearly show how the barriers
    pair.

Fixes: b16c29191dc8 ("netfilter: nf_conntrack: use safer way to lock all buckets")
Signed-off-by: Manfred Spraul <manfred@colorfullife.com>
Cc: <stable@vger.kernel.org>
Cc: Alan Stern <stern@rowland.harvard.edu>
Cc: Sasha Levin <sasha.levin@oracle.com>
Cc: Pablo Neira Ayuso <pablo@netfilter.org>
Cc: netfilter-devel@vger.kernel.org
Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
---
 net/netfilter/nf_conntrack_core.c | 52 ++++++++++++++++++++++-----------------
 1 file changed, 29 insertions(+), 23 deletions(-)

diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c
index e847dbaa0c6b..e0560c41e371 100644
--- a/net/netfilter/nf_conntrack_core.c
+++ b/net/netfilter/nf_conntrack_core.c
@@ -96,19 +96,26 @@ static struct conntrack_gc_work conntrack_gc_work;
 
 void nf_conntrack_lock(spinlock_t *lock) __acquires(lock)
 {
+	/* 1) Acquire the lock */
 	spin_lock(lock);
-	while (unlikely(nf_conntrack_locks_all)) {
-		spin_unlock(lock);
 
-		/*
-		 * Order the 'nf_conntrack_locks_all' load vs. the
-		 * spin_unlock_wait() loads below, to ensure
-		 * that 'nf_conntrack_locks_all_lock' is indeed held:
-		 */
-		smp_rmb(); /* spin_lock(&nf_conntrack_locks_all_lock) */
-		spin_unlock_wait(&nf_conntrack_locks_all_lock);
-		spin_lock(lock);
-	}
+	/* 2) read nf_conntrack_locks_all, with ACQUIRE semantics
+	 * It pairs with the smp_store_release() in nf_conntrack_all_unlock()
+	 */
+	if (likely(smp_load_acquire(&nf_conntrack_locks_all) == false))
+		return;
+
+	/* fast path failed, unlock */
+	spin_unlock(lock);
+
+	/* Slow path 1) get global lock */
+	spin_lock(&nf_conntrack_locks_all_lock);
+
+	/* Slow path 2) get the lock we want */
+	spin_lock(lock);
+
+	/* Slow path 3) release the global lock */
+	spin_unlock(&nf_conntrack_locks_all_lock);
 }
 EXPORT_SYMBOL_GPL(nf_conntrack_lock);
 
@@ -149,28 +156,27 @@ static void nf_conntrack_all_lock(void)
 	int i;
 
 	spin_lock(&nf_conntrack_locks_all_lock);
-	nf_conntrack_locks_all = true;
 
-	/*
-	 * Order the above store of 'nf_conntrack_locks_all' against
-	 * the spin_unlock_wait() loads below, such that if
-	 * nf_conntrack_lock() observes 'nf_conntrack_locks_all'
-	 * we must observe nf_conntrack_locks[] held:
-	 */
-	smp_mb(); /* spin_lock(&nf_conntrack_locks_all_lock) */
+	nf_conntrack_locks_all = true;
 
 	for (i = 0; i < CONNTRACK_LOCKS; i++) {
-		spin_unlock_wait(&nf_conntrack_locks[i]);
+		spin_lock(&nf_conntrack_locks[i]);
+
+		/* This spin_unlock provides the "release" to ensure that
+		 * nf_conntrack_locks_all==true is visible to everyone that
+		 * acquired spin_lock(&nf_conntrack_locks[]).
+		 */
+		spin_unlock(&nf_conntrack_locks[i]);
 	}
 }
 
 static void nf_conntrack_all_unlock(void)
 {
-	/*
-	 * All prior stores must be complete before we clear
+	/* All prior stores must be complete before we clear
 	 * 'nf_conntrack_locks_all'. Otherwise nf_conntrack_lock()
 	 * might observe the false value but not the entire
-	 * critical section:
+	 * critical section.
+	 * It pairs with the smp_load_acquire() in nf_conntrack_lock()
 	 */
 	smp_store_release(&nf_conntrack_locks_all, false);
 	spin_unlock(&nf_conntrack_locks_all_lock);
-- 
2.5.2

^ permalink raw reply related	[flat|nested] 122+ messages in thread

* [PATCH v3 2/9] task_work: Replace spin_unlock_wait() with lock/unlock pair
  2017-07-07 19:27   ` [PATCH v3 " Paul E. McKenney
  2017-07-07 19:28     ` [PATCH v3 1/9] net/netfilter/nf_conntrack_core: Fix net_conntrack_lock() Paul E. McKenney
@ 2017-07-07 19:28     ` Paul E. McKenney
  2017-07-07 19:28     ` [PATCH v3 3/9] sched: " Paul E. McKenney
                       ` (6 subsequent siblings)
  8 siblings, 0 replies; 122+ messages in thread
From: Paul E. McKenney @ 2017-07-07 19:28 UTC (permalink / raw)
  To: linux-kernel
  Cc: netfilter-devel, netdev, oleg, akpm, mingo, dave, manfred, tj,
	arnd, linux-arch, will.deacon, peterz, stern, parri.andrea,
	torvalds, Paul E. McKenney

From: Oleg Nesterov <oleg@redhat.com>

There is no agreed-upon definition of spin_unlock_wait()'s semantics,
and it appears that all callers could do just as well with a lock/unlock
pair.  This commit therefore replaces the spin_unlock_wait() call in
task_work_run() with a spin_lock_irq() and a spin_unlock_irq() aruond
the cmpxchg() dequeue loop.  This should be safe from a performance
perspective because ->pi_lock is local to the task and because calls to
the other side of the race, task_work_cancel(), should be rare.

Signed-off-by: Oleg Nesterov <oleg@redhat.com>
Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
---
 kernel/task_work.c | 8 ++------
 1 file changed, 2 insertions(+), 6 deletions(-)

diff --git a/kernel/task_work.c b/kernel/task_work.c
index d513051fcca2..836a72a66fba 100644
--- a/kernel/task_work.c
+++ b/kernel/task_work.c
@@ -96,20 +96,16 @@ void task_work_run(void)
 		 * work->func() can do task_work_add(), do not set
 		 * work_exited unless the list is empty.
 		 */
+		raw_spin_lock_irq(&task->pi_lock);
 		do {
 			work = READ_ONCE(task->task_works);
 			head = !work && (task->flags & PF_EXITING) ?
 				&work_exited : NULL;
 		} while (cmpxchg(&task->task_works, work, head) != work);
+		raw_spin_unlock_irq(&task->pi_lock);
 
 		if (!work)
 			break;
-		/*
-		 * Synchronize with task_work_cancel(). It can't remove
-		 * the first entry == work, cmpxchg(task_works) should
-		 * fail, but it can play with *work and other entries.
-		 */
-		raw_spin_unlock_wait(&task->pi_lock);
 
 		do {
 			next = work->next;
-- 
2.5.2

^ permalink raw reply related	[flat|nested] 122+ messages in thread

* [PATCH v3 3/9] sched: Replace spin_unlock_wait() with lock/unlock pair
  2017-07-07 19:27   ` [PATCH v3 " Paul E. McKenney
  2017-07-07 19:28     ` [PATCH v3 1/9] net/netfilter/nf_conntrack_core: Fix net_conntrack_lock() Paul E. McKenney
  2017-07-07 19:28     ` [PATCH v3 2/9] task_work: Replace spin_unlock_wait() with lock/unlock pair Paul E. McKenney
@ 2017-07-07 19:28     ` Paul E. McKenney
  2017-07-07 19:28     ` [PATCH v3 4/9] completion: " Paul E. McKenney
                       ` (5 subsequent siblings)
  8 siblings, 0 replies; 122+ messages in thread
From: Paul E. McKenney @ 2017-07-07 19:28 UTC (permalink / raw)
  To: linux-kernel
  Cc: netfilter-devel, netdev, oleg, akpm, mingo, dave, manfred, tj,
	arnd, linux-arch, will.deacon, peterz, stern, parri.andrea,
	torvalds, Paul E. McKenney

There is no agreed-upon definition of spin_unlock_wait()'s semantics,
and it appears that all callers could do just as well with a lock/unlock
pair.  This commit therefore replaces the spin_unlock_wait() call in
do_task_dead() with spin_lock() followed immediately by spin_unlock().
This should be safe from a performance perspective because the lock is
this tasks ->pi_lock, and this is called only after the task exits.

Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Will Deacon <will.deacon@arm.com>
Cc: Alan Stern <stern@rowland.harvard.edu>
Cc: Andrea Parri <parri.andrea@gmail.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
[ paulmck: Replace leading smp_mb() with smp_mb__before_spinlock(),
  courtesy of Arnd Bergmann's noting its odd location. ]
---
 kernel/sched/core.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index e91138fcde86..48a8760fedf4 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -3460,8 +3460,9 @@ void __noreturn do_task_dead(void)
 	 * To avoid it, we have to wait for releasing tsk->pi_lock which
 	 * is held by try_to_wake_up()
 	 */
-	smp_mb();
-	raw_spin_unlock_wait(&current->pi_lock);
+	smp_mb__before_spinlock();
+	raw_spin_lock_irq(&current->pi_lock);
+	raw_spin_unlock_irq(&current->pi_lock);
 
 	/* Causes final put_task_struct in finish_task_switch(): */
 	__set_current_state(TASK_DEAD);
-- 
2.5.2

^ permalink raw reply related	[flat|nested] 122+ messages in thread

* [PATCH v3 4/9] completion: Replace spin_unlock_wait() with lock/unlock pair
  2017-07-07 19:27   ` [PATCH v3 " Paul E. McKenney
                       ` (2 preceding siblings ...)
  2017-07-07 19:28     ` [PATCH v3 3/9] sched: " Paul E. McKenney
@ 2017-07-07 19:28     ` Paul E. McKenney
  2017-07-07 19:28     ` [PATCH v3 5/9] exit: " Paul E. McKenney
                       ` (4 subsequent siblings)
  8 siblings, 0 replies; 122+ messages in thread
From: Paul E. McKenney @ 2017-07-07 19:28 UTC (permalink / raw)
  To: linux-kernel
  Cc: netfilter-devel, netdev, oleg, akpm, mingo, dave, manfred, tj,
	arnd, linux-arch, will.deacon, peterz, stern, parri.andrea,
	torvalds, Paul E. McKenney

There is no agreed-upon definition of spin_unlock_wait()'s semantics,
and it appears that all callers could do just as well with a lock/unlock
pair.  This commit therefore replaces the spin_unlock_wait() call in
completion_done() with spin_lock() followed immediately by spin_unlock().
This should be safe from a performance perspective because the lock
will be held only the wakeup happens really quickly.

Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Will Deacon <will.deacon@arm.com>
Cc: Alan Stern <stern@rowland.harvard.edu>
Cc: Andrea Parri <parri.andrea@gmail.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
---
 kernel/sched/completion.c | 9 ++-------
 1 file changed, 2 insertions(+), 7 deletions(-)

diff --git a/kernel/sched/completion.c b/kernel/sched/completion.c
index 53f9558fa925..3e66712e1964 100644
--- a/kernel/sched/completion.c
+++ b/kernel/sched/completion.c
@@ -307,14 +307,9 @@ bool completion_done(struct completion *x)
 	 * If ->done, we need to wait for complete() to release ->wait.lock
 	 * otherwise we can end up freeing the completion before complete()
 	 * is done referencing it.
-	 *
-	 * The RMB pairs with complete()'s RELEASE of ->wait.lock and orders
-	 * the loads of ->done and ->wait.lock such that we cannot observe
-	 * the lock before complete() acquires it while observing the ->done
-	 * after it's acquired the lock.
 	 */
-	smp_rmb();
-	spin_unlock_wait(&x->wait.lock);
+	spin_lock_irq(&x->wait.lock);
+	spin_unlock_irq(&x->wait.lock);
 	return true;
 }
 EXPORT_SYMBOL(completion_done);
-- 
2.5.2

^ permalink raw reply related	[flat|nested] 122+ messages in thread

* [PATCH v3 5/9] exit: Replace spin_unlock_wait() with lock/unlock pair
  2017-07-07 19:27   ` [PATCH v3 " Paul E. McKenney
                       ` (3 preceding siblings ...)
  2017-07-07 19:28     ` [PATCH v3 4/9] completion: " Paul E. McKenney
@ 2017-07-07 19:28     ` Paul E. McKenney
  2017-07-07 19:28     ` [PATCH v3 6/9] ipc: " Paul E. McKenney
                       ` (3 subsequent siblings)
  8 siblings, 0 replies; 122+ messages in thread
From: Paul E. McKenney @ 2017-07-07 19:28 UTC (permalink / raw)
  To: linux-kernel
  Cc: netfilter-devel, netdev, oleg, akpm, mingo, dave, manfred, tj,
	arnd, linux-arch, will.deacon, peterz, stern, parri.andrea,
	torvalds, Paul E. McKenney, Ingo Molnar

There is no agreed-upon definition of spin_unlock_wait()'s semantics, and
it appears that all callers could do just as well with a lock/unlock pair.
This commit therefore replaces the spin_unlock_wait() call in do_exit()
with spin_lock() followed immediately by spin_unlock().  This should be
safe from a performance perspective because the lock is a per-task lock,
and this is happening only at task-exit time.

Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Cc: Ingo Molnar <mingo@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Will Deacon <will.deacon@arm.com>
Cc: Alan Stern <stern@rowland.harvard.edu>
Cc: Andrea Parri <parri.andrea@gmail.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
---
 kernel/exit.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/kernel/exit.c b/kernel/exit.c
index 516acdb0e0ec..6d19c9090d43 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -832,7 +832,8 @@ void __noreturn do_exit(long code)
 	 * Ensure that we must observe the pi_state in exit_mm() ->
 	 * mm_release() -> exit_pi_state_list().
 	 */
-	raw_spin_unlock_wait(&tsk->pi_lock);
+	raw_spin_lock_irq(&tsk->pi_lock);
+	raw_spin_unlock_irq(&tsk->pi_lock);
 
 	if (unlikely(in_atomic())) {
 		pr_info("note: %s[%d] exited with preempt_count %d\n",
-- 
2.5.2

^ permalink raw reply related	[flat|nested] 122+ messages in thread

* [PATCH v3 6/9] ipc: Replace spin_unlock_wait() with lock/unlock pair
  2017-07-07 19:27   ` [PATCH v3 " Paul E. McKenney
                       ` (4 preceding siblings ...)
  2017-07-07 19:28     ` [PATCH v3 5/9] exit: " Paul E. McKenney
@ 2017-07-07 19:28     ` Paul E. McKenney
  2017-07-07 19:28     ` [PATCH v3 7/9] drivers/ata: " Paul E. McKenney
                       ` (2 subsequent siblings)
  8 siblings, 0 replies; 122+ messages in thread
From: Paul E. McKenney @ 2017-07-07 19:28 UTC (permalink / raw)
  To: linux-kernel
  Cc: netfilter-devel, netdev, oleg, akpm, mingo, dave, manfred, tj,
	arnd, linux-arch, will.deacon, peterz, stern, parri.andrea,
	torvalds, Paul E. McKenney

There is no agreed-upon definition of spin_unlock_wait()'s semantics,
and it appears that all callers could do just as well with a lock/unlock
pair.  This commit therefore replaces the spin_unlock_wait() call in
exit_sem() with spin_lock() followed immediately by spin_unlock().
This should be safe from a performance perspective because exit_sem()
is rarely invoked in production.

Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Davidlohr Bueso <dave@stgolabs.net>
Cc: Will Deacon <will.deacon@arm.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Alan Stern <stern@rowland.harvard.edu>
Cc: Andrea Parri <parri.andrea@gmail.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Acked-by: Manfred Spraul <manfred@colorfullife.com>
---
 ipc/sem.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/ipc/sem.c b/ipc/sem.c
index 947dc2348271..e88d0749a929 100644
--- a/ipc/sem.c
+++ b/ipc/sem.c
@@ -2096,7 +2096,8 @@ void exit_sem(struct task_struct *tsk)
 			 * possibility where we exit while freeary() didn't
 			 * finish unlocking sem_undo_list.
 			 */
-			spin_unlock_wait(&ulp->lock);
+			spin_lock(&ulp->lock);
+			spin_unlock(&ulp->lock);
 			rcu_read_unlock();
 			break;
 		}
-- 
2.5.2

^ permalink raw reply related	[flat|nested] 122+ messages in thread

* [PATCH v3 7/9] drivers/ata: Replace spin_unlock_wait() with lock/unlock pair
  2017-07-07 19:27   ` [PATCH v3 " Paul E. McKenney
                       ` (5 preceding siblings ...)
  2017-07-07 19:28     ` [PATCH v3 6/9] ipc: " Paul E. McKenney
@ 2017-07-07 19:28     ` Paul E. McKenney
  2017-07-07 19:28     ` [PATCH v3 8/9] locking: Remove spin_unlock_wait() generic definitions Paul E. McKenney
  2017-07-07 19:28     ` [PATCH v3 9/9] arch: Remove spin_unlock_wait() arch-specific definitions Paul E. McKenney
  8 siblings, 0 replies; 122+ messages in thread
From: Paul E. McKenney @ 2017-07-07 19:28 UTC (permalink / raw)
  To: linux-kernel
  Cc: netfilter-devel, netdev, oleg, akpm, mingo, dave, manfred, tj,
	arnd, linux-arch, will.deacon, peterz, stern, parri.andrea,
	torvalds, Paul E. McKenney, linux-ide

There is no agreed-upon definition of spin_unlock_wait()'s semantics,
and it appears that all callers could do just as well with a lock/unlock
pair.  This commit therefore eliminates the spin_unlock_wait() call and
associated else-clause and hoists the then-clause's lock and unlock out of
the "if" statement.  This should be safe from a performance perspective
because according to Tejun there should be few if any drivers that don't
set their own error handler.

Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Acked-by: Tejun Heo <tj@kernel.org>
Cc: <linux-ide@vger.kernel.org>
Cc: Will Deacon <will.deacon@arm.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Alan Stern <stern@rowland.harvard.edu>
Cc: Andrea Parri <parri.andrea@gmail.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
---
 drivers/ata/libata-eh.c | 8 +++-----
 1 file changed, 3 insertions(+), 5 deletions(-)

diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c
index ef68232b5222..779f6f18c1f4 100644
--- a/drivers/ata/libata-eh.c
+++ b/drivers/ata/libata-eh.c
@@ -645,12 +645,11 @@ void ata_scsi_cmd_error_handler(struct Scsi_Host *host, struct ata_port *ap,
 	 * completions are honored.  A scmd is determined to have
 	 * timed out iff its associated qc is active and not failed.
 	 */
+	spin_lock_irqsave(ap->lock, flags);
 	if (ap->ops->error_handler) {
 		struct scsi_cmnd *scmd, *tmp;
 		int nr_timedout = 0;
 
-		spin_lock_irqsave(ap->lock, flags);
-
 		/* This must occur under the ap->lock as we don't want
 		   a polled recovery to race the real interrupt handler
 
@@ -700,12 +699,11 @@ void ata_scsi_cmd_error_handler(struct Scsi_Host *host, struct ata_port *ap,
 		if (nr_timedout)
 			__ata_port_freeze(ap);
 
-		spin_unlock_irqrestore(ap->lock, flags);
 
 		/* initialize eh_tries */
 		ap->eh_tries = ATA_EH_MAX_TRIES;
-	} else
-		spin_unlock_wait(ap->lock);
+	}
+	spin_unlock_irqrestore(ap->lock, flags);
 
 }
 EXPORT_SYMBOL(ata_scsi_cmd_error_handler);
-- 
2.5.2

^ permalink raw reply related	[flat|nested] 122+ messages in thread

* [PATCH v3 8/9] locking: Remove spin_unlock_wait() generic definitions
  2017-07-07 19:27   ` [PATCH v3 " Paul E. McKenney
                       ` (6 preceding siblings ...)
  2017-07-07 19:28     ` [PATCH v3 7/9] drivers/ata: " Paul E. McKenney
@ 2017-07-07 19:28     ` Paul E. McKenney
  2017-07-07 19:28     ` [PATCH v3 9/9] arch: Remove spin_unlock_wait() arch-specific definitions Paul E. McKenney
  8 siblings, 0 replies; 122+ messages in thread
From: Paul E. McKenney @ 2017-07-07 19:28 UTC (permalink / raw)
  To: linux-kernel
  Cc: netfilter-devel, netdev, oleg, akpm, mingo, dave, manfred, tj,
	arnd, linux-arch, will.deacon, peterz, stern, parri.andrea,
	torvalds, Paul E. McKenney

There is no agreed-upon definition of spin_unlock_wait()'s semantics,
and it appears that all callers could do just as well with a lock/unlock
pair.  This commit therefore removes spin_unlock_wait() and related
definitions from core code.

Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Cc: Arnd Bergmann <arnd@arndb.de>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Will Deacon <will.deacon@arm.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Alan Stern <stern@rowland.harvard.edu>
Cc: Andrea Parri <parri.andrea@gmail.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
---
 include/asm-generic/qspinlock.h |  14 -----
 include/linux/spinlock.h        |  31 -----------
 include/linux/spinlock_up.h     |   6 ---
 kernel/locking/qspinlock.c      | 117 ----------------------------------------
 4 files changed, 168 deletions(-)

diff --git a/include/asm-generic/qspinlock.h b/include/asm-generic/qspinlock.h
index 9f0681bf1e87..66260777d644 100644
--- a/include/asm-generic/qspinlock.h
+++ b/include/asm-generic/qspinlock.h
@@ -22,17 +22,6 @@
 #include <asm-generic/qspinlock_types.h>
 
 /**
- * queued_spin_unlock_wait - wait until the _current_ lock holder releases the lock
- * @lock : Pointer to queued spinlock structure
- *
- * There is a very slight possibility of live-lock if the lockers keep coming
- * and the waiter is just unfortunate enough to not see any unlock state.
- */
-#ifndef queued_spin_unlock_wait
-extern void queued_spin_unlock_wait(struct qspinlock *lock);
-#endif
-
-/**
  * queued_spin_is_locked - is the spinlock locked?
  * @lock: Pointer to queued spinlock structure
  * Return: 1 if it is locked, 0 otherwise
@@ -41,8 +30,6 @@ extern void queued_spin_unlock_wait(struct qspinlock *lock);
 static __always_inline int queued_spin_is_locked(struct qspinlock *lock)
 {
 	/*
-	 * See queued_spin_unlock_wait().
-	 *
 	 * Any !0 state indicates it is locked, even if _Q_LOCKED_VAL
 	 * isn't immediately observable.
 	 */
@@ -135,6 +122,5 @@ static __always_inline bool virt_spin_lock(struct qspinlock *lock)
 #define arch_spin_trylock(l)		queued_spin_trylock(l)
 #define arch_spin_unlock(l)		queued_spin_unlock(l)
 #define arch_spin_lock_flags(l, f)	queued_spin_lock(l)
-#define arch_spin_unlock_wait(l)	queued_spin_unlock_wait(l)
 
 #endif /* __ASM_GENERIC_QSPINLOCK_H */
diff --git a/include/linux/spinlock.h b/include/linux/spinlock.h
index d9510e8522d4..ef018a6e4985 100644
--- a/include/linux/spinlock.h
+++ b/include/linux/spinlock.h
@@ -130,12 +130,6 @@ do {								\
 #define smp_mb__before_spinlock()	smp_wmb()
 #endif
 
-/**
- * raw_spin_unlock_wait - wait until the spinlock gets unlocked
- * @lock: the spinlock in question.
- */
-#define raw_spin_unlock_wait(lock)	arch_spin_unlock_wait(&(lock)->raw_lock)
-
 #ifdef CONFIG_DEBUG_SPINLOCK
  extern void do_raw_spin_lock(raw_spinlock_t *lock) __acquires(lock);
 #define do_raw_spin_lock_flags(lock, flags) do_raw_spin_lock(lock)
@@ -369,31 +363,6 @@ static __always_inline int spin_trylock_irq(spinlock_t *lock)
 	raw_spin_trylock_irqsave(spinlock_check(lock), flags); \
 })
 
-/**
- * spin_unlock_wait - Interpose between successive critical sections
- * @lock: the spinlock whose critical sections are to be interposed.
- *
- * Semantically this is equivalent to a spin_lock() immediately
- * followed by a spin_unlock().  However, most architectures have
- * more efficient implementations in which the spin_unlock_wait()
- * cannot block concurrent lock acquisition, and in some cases
- * where spin_unlock_wait() does not write to the lock variable.
- * Nevertheless, spin_unlock_wait() can have high overhead, so if
- * you feel the need to use it, please check to see if there is
- * a better way to get your job done.
- *
- * The ordering guarantees provided by spin_unlock_wait() are:
- *
- * 1.  All accesses preceding the spin_unlock_wait() happen before
- *     any accesses in later critical sections for this same lock.
- * 2.  All accesses following the spin_unlock_wait() happen after
- *     any accesses in earlier critical sections for this same lock.
- */
-static __always_inline void spin_unlock_wait(spinlock_t *lock)
-{
-	raw_spin_unlock_wait(&lock->rlock);
-}
-
 static __always_inline int spin_is_locked(spinlock_t *lock)
 {
 	return raw_spin_is_locked(&lock->rlock);
diff --git a/include/linux/spinlock_up.h b/include/linux/spinlock_up.h
index 0d9848de677d..612fb530af41 100644
--- a/include/linux/spinlock_up.h
+++ b/include/linux/spinlock_up.h
@@ -26,11 +26,6 @@
 #ifdef CONFIG_DEBUG_SPINLOCK
 #define arch_spin_is_locked(x)		((x)->slock == 0)
 
-static inline void arch_spin_unlock_wait(arch_spinlock_t *lock)
-{
-	smp_cond_load_acquire(&lock->slock, VAL);
-}
-
 static inline void arch_spin_lock(arch_spinlock_t *lock)
 {
 	lock->slock = 0;
@@ -73,7 +68,6 @@ static inline void arch_spin_unlock(arch_spinlock_t *lock)
 
 #else /* DEBUG_SPINLOCK */
 #define arch_spin_is_locked(lock)	((void)(lock), 0)
-#define arch_spin_unlock_wait(lock)	do { barrier(); (void)(lock); } while (0)
 /* for sched/core.c and kernel_lock.c: */
 # define arch_spin_lock(lock)		do { barrier(); (void)(lock); } while (0)
 # define arch_spin_lock_flags(lock, flags)	do { barrier(); (void)(lock); } while (0)
diff --git a/kernel/locking/qspinlock.c b/kernel/locking/qspinlock.c
index b2caec7315af..64a9051e4c2c 100644
--- a/kernel/locking/qspinlock.c
+++ b/kernel/locking/qspinlock.c
@@ -267,123 +267,6 @@ static __always_inline u32  __pv_wait_head_or_lock(struct qspinlock *lock,
 #define queued_spin_lock_slowpath	native_queued_spin_lock_slowpath
 #endif
 
-/*
- * Various notes on spin_is_locked() and spin_unlock_wait(), which are
- * 'interesting' functions:
- *
- * PROBLEM: some architectures have an interesting issue with atomic ACQUIRE
- * operations in that the ACQUIRE applies to the LOAD _not_ the STORE (ARM64,
- * PPC). Also qspinlock has a similar issue per construction, the setting of
- * the locked byte can be unordered acquiring the lock proper.
- *
- * This gets to be 'interesting' in the following cases, where the /should/s
- * end up false because of this issue.
- *
- *
- * CASE 1:
- *
- * So the spin_is_locked() correctness issue comes from something like:
- *
- *   CPU0				CPU1
- *
- *   global_lock();			local_lock(i)
- *     spin_lock(&G)			  spin_lock(&L[i])
- *     for (i)				  if (!spin_is_locked(&G)) {
- *       spin_unlock_wait(&L[i]);	    smp_acquire__after_ctrl_dep();
- *					    return;
- *					  }
- *					  // deal with fail
- *
- * Where it is important CPU1 sees G locked or CPU0 sees L[i] locked such
- * that there is exclusion between the two critical sections.
- *
- * The load from spin_is_locked(&G) /should/ be constrained by the ACQUIRE from
- * spin_lock(&L[i]), and similarly the load(s) from spin_unlock_wait(&L[i])
- * /should/ be constrained by the ACQUIRE from spin_lock(&G).
- *
- * Similarly, later stuff is constrained by the ACQUIRE from CTRL+RMB.
- *
- *
- * CASE 2:
- *
- * For spin_unlock_wait() there is a second correctness issue, namely:
- *
- *   CPU0				CPU1
- *
- *   flag = set;
- *   smp_mb();				spin_lock(&l)
- *   spin_unlock_wait(&l);		if (!flag)
- *					  // add to lockless list
- *					spin_unlock(&l);
- *   // iterate lockless list
- *
- * Which wants to ensure that CPU1 will stop adding bits to the list and CPU0
- * will observe the last entry on the list (if spin_unlock_wait() had ACQUIRE
- * semantics etc..)
- *
- * Where flag /should/ be ordered against the locked store of l.
- */
-
-/*
- * queued_spin_lock_slowpath() can (load-)ACQUIRE the lock before
- * issuing an _unordered_ store to set _Q_LOCKED_VAL.
- *
- * This means that the store can be delayed, but no later than the
- * store-release from the unlock. This means that simply observing
- * _Q_LOCKED_VAL is not sufficient to determine if the lock is acquired.
- *
- * There are two paths that can issue the unordered store:
- *
- *  (1) clear_pending_set_locked():	*,1,0 -> *,0,1
- *
- *  (2) set_locked():			t,0,0 -> t,0,1 ; t != 0
- *      atomic_cmpxchg_relaxed():	t,0,0 -> 0,0,1
- *
- * However, in both cases we have other !0 state we've set before to queue
- * ourseves:
- *
- * For (1) we have the atomic_cmpxchg_acquire() that set _Q_PENDING_VAL, our
- * load is constrained by that ACQUIRE to not pass before that, and thus must
- * observe the store.
- *
- * For (2) we have a more intersting scenario. We enqueue ourselves using
- * xchg_tail(), which ends up being a RELEASE. This in itself is not
- * sufficient, however that is followed by an smp_cond_acquire() on the same
- * word, giving a RELEASE->ACQUIRE ordering. This again constrains our load and
- * guarantees we must observe that store.
- *
- * Therefore both cases have other !0 state that is observable before the
- * unordered locked byte store comes through. This means we can use that to
- * wait for the lock store, and then wait for an unlock.
- */
-#ifndef queued_spin_unlock_wait
-void queued_spin_unlock_wait(struct qspinlock *lock)
-{
-	u32 val;
-
-	for (;;) {
-		val = atomic_read(&lock->val);
-
-		if (!val) /* not locked, we're done */
-			goto done;
-
-		if (val & _Q_LOCKED_MASK) /* locked, go wait for unlock */
-			break;
-
-		/* not locked, but pending, wait until we observe the lock */
-		cpu_relax();
-	}
-
-	/* any unlock is good */
-	while (atomic_read(&lock->val) & _Q_LOCKED_MASK)
-		cpu_relax();
-
-done:
-	smp_acquire__after_ctrl_dep();
-}
-EXPORT_SYMBOL(queued_spin_unlock_wait);
-#endif
-
 #endif /* _GEN_PV_LOCK_SLOWPATH */
 
 /**
-- 
2.5.2

^ permalink raw reply related	[flat|nested] 122+ messages in thread

* [PATCH v3 9/9] arch: Remove spin_unlock_wait() arch-specific definitions
  2017-07-07 19:27   ` [PATCH v3 " Paul E. McKenney
                       ` (7 preceding siblings ...)
  2017-07-07 19:28     ` [PATCH v3 8/9] locking: Remove spin_unlock_wait() generic definitions Paul E. McKenney
@ 2017-07-07 19:28     ` Paul E. McKenney
  8 siblings, 0 replies; 122+ messages in thread
From: Paul E. McKenney @ 2017-07-07 19:28 UTC (permalink / raw)
  To: linux-kernel
  Cc: netfilter-devel, netdev, oleg, akpm, mingo, dave, manfred, tj,
	arnd, linux-arch, will.deacon, peterz, stern, parri.andrea,
	torvalds, Paul E. McKenney

There is no agreed-upon definition of spin_unlock_wait()'s semantics,
and it appears that all callers could do just as well with a lock/unlock
pair.  This commit therefore removes the underlying arch-specific
arch_spin_unlock_wait() for all architectures providing them.

Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Cc: <linux-arch@vger.kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Alan Stern <stern@rowland.harvard.edu>
Cc: Andrea Parri <parri.andrea@gmail.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Acked-by: Will Deacon <will.deacon@arm.com>
Acked-by: Boqun Feng <boqun.feng@gmail.com>
---
 arch/alpha/include/asm/spinlock.h    |  5 ----
 arch/arc/include/asm/spinlock.h      |  5 ----
 arch/arm/include/asm/spinlock.h      | 16 ----------
 arch/arm64/include/asm/spinlock.h    | 58 ++++--------------------------------
 arch/blackfin/include/asm/spinlock.h |  5 ----
 arch/hexagon/include/asm/spinlock.h  |  5 ----
 arch/ia64/include/asm/spinlock.h     | 21 -------------
 arch/m32r/include/asm/spinlock.h     |  5 ----
 arch/metag/include/asm/spinlock.h    |  5 ----
 arch/mips/include/asm/spinlock.h     | 16 ----------
 arch/mn10300/include/asm/spinlock.h  |  5 ----
 arch/parisc/include/asm/spinlock.h   |  7 -----
 arch/powerpc/include/asm/spinlock.h  | 33 --------------------
 arch/s390/include/asm/spinlock.h     |  7 -----
 arch/sh/include/asm/spinlock-cas.h   |  5 ----
 arch/sh/include/asm/spinlock-llsc.h  |  5 ----
 arch/sparc/include/asm/spinlock_32.h |  5 ----
 arch/sparc/include/asm/spinlock_64.h |  5 ----
 arch/tile/include/asm/spinlock_32.h  |  2 --
 arch/tile/include/asm/spinlock_64.h  |  2 --
 arch/tile/lib/spinlock_32.c          | 23 --------------
 arch/tile/lib/spinlock_64.c          | 22 --------------
 arch/xtensa/include/asm/spinlock.h   |  5 ----
 23 files changed, 5 insertions(+), 262 deletions(-)

diff --git a/arch/alpha/include/asm/spinlock.h b/arch/alpha/include/asm/spinlock.h
index a40b9fc0c6c3..718ac0b64adf 100644
--- a/arch/alpha/include/asm/spinlock.h
+++ b/arch/alpha/include/asm/spinlock.h
@@ -16,11 +16,6 @@
 #define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock)
 #define arch_spin_is_locked(x)	((x)->lock != 0)
 
-static inline void arch_spin_unlock_wait(arch_spinlock_t *lock)
-{
-	smp_cond_load_acquire(&lock->lock, !VAL);
-}
-
 static inline int arch_spin_value_unlocked(arch_spinlock_t lock)
 {
         return lock.lock == 0;
diff --git a/arch/arc/include/asm/spinlock.h b/arch/arc/include/asm/spinlock.h
index 233d5ffe6ec7..a325e6a36523 100644
--- a/arch/arc/include/asm/spinlock.h
+++ b/arch/arc/include/asm/spinlock.h
@@ -16,11 +16,6 @@
 #define arch_spin_is_locked(x)	((x)->slock != __ARCH_SPIN_LOCK_UNLOCKED__)
 #define arch_spin_lock_flags(lock, flags)	arch_spin_lock(lock)
 
-static inline void arch_spin_unlock_wait(arch_spinlock_t *lock)
-{
-	smp_cond_load_acquire(&lock->slock, !VAL);
-}
-
 #ifdef CONFIG_ARC_HAS_LLSC
 
 static inline void arch_spin_lock(arch_spinlock_t *lock)
diff --git a/arch/arm/include/asm/spinlock.h b/arch/arm/include/asm/spinlock.h
index 4bec45442072..c030143c18c6 100644
--- a/arch/arm/include/asm/spinlock.h
+++ b/arch/arm/include/asm/spinlock.h
@@ -52,22 +52,6 @@ static inline void dsb_sev(void)
  * memory.
  */
 
-static inline void arch_spin_unlock_wait(arch_spinlock_t *lock)
-{
-	u16 owner = READ_ONCE(lock->tickets.owner);
-
-	for (;;) {
-		arch_spinlock_t tmp = READ_ONCE(*lock);
-
-		if (tmp.tickets.owner == tmp.tickets.next ||
-		    tmp.tickets.owner != owner)
-			break;
-
-		wfe();
-	}
-	smp_acquire__after_ctrl_dep();
-}
-
 #define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock)
 
 static inline void arch_spin_lock(arch_spinlock_t *lock)
diff --git a/arch/arm64/include/asm/spinlock.h b/arch/arm64/include/asm/spinlock.h
index cae331d553f8..f445bd7f2b9f 100644
--- a/arch/arm64/include/asm/spinlock.h
+++ b/arch/arm64/include/asm/spinlock.h
@@ -26,58 +26,6 @@
  * The memory barriers are implicit with the load-acquire and store-release
  * instructions.
  */
-static inline void arch_spin_unlock_wait(arch_spinlock_t *lock)
-{
-	unsigned int tmp;
-	arch_spinlock_t lockval;
-	u32 owner;
-
-	/*
-	 * Ensure prior spin_lock operations to other locks have completed
-	 * on this CPU before we test whether "lock" is locked.
-	 */
-	smp_mb();
-	owner = READ_ONCE(lock->owner) << 16;
-
-	asm volatile(
-"	sevl\n"
-"1:	wfe\n"
-"2:	ldaxr	%w0, %2\n"
-	/* Is the lock free? */
-"	eor	%w1, %w0, %w0, ror #16\n"
-"	cbz	%w1, 3f\n"
-	/* Lock taken -- has there been a subsequent unlock->lock transition? */
-"	eor	%w1, %w3, %w0, lsl #16\n"
-"	cbz	%w1, 1b\n"
-	/*
-	 * The owner has been updated, so there was an unlock->lock
-	 * transition that we missed. That means we can rely on the
-	 * store-release of the unlock operation paired with the
-	 * load-acquire of the lock operation to publish any of our
-	 * previous stores to the new lock owner and therefore don't
-	 * need to bother with the writeback below.
-	 */
-"	b	4f\n"
-"3:\n"
-	/*
-	 * Serialise against any concurrent lockers by writing back the
-	 * unlocked lock value
-	 */
-	ARM64_LSE_ATOMIC_INSN(
-	/* LL/SC */
-"	stxr	%w1, %w0, %2\n"
-	__nops(2),
-	/* LSE atomics */
-"	mov	%w1, %w0\n"
-"	cas	%w0, %w0, %2\n"
-"	eor	%w1, %w1, %w0\n")
-	/* Somebody else wrote to the lock, GOTO 10 and reload the value */
-"	cbnz	%w1, 2b\n"
-"4:"
-	: "=&r" (lockval), "=&r" (tmp), "+Q" (*lock)
-	: "r" (owner)
-	: "memory");
-}
 
 #define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock)
 
@@ -176,7 +124,11 @@ static inline int arch_spin_value_unlocked(arch_spinlock_t lock)
 
 static inline int arch_spin_is_locked(arch_spinlock_t *lock)
 {
-	smp_mb(); /* See arch_spin_unlock_wait */
+	/*
+	 * Ensure prior spin_lock operations to other locks have completed
+	 * on this CPU before we test whether "lock" is locked.
+	 */
+	smp_mb(); /* ^^^ */
 	return !arch_spin_value_unlocked(READ_ONCE(*lock));
 }
 
diff --git a/arch/blackfin/include/asm/spinlock.h b/arch/blackfin/include/asm/spinlock.h
index c58f4a83ed6f..f6431439d15d 100644
--- a/arch/blackfin/include/asm/spinlock.h
+++ b/arch/blackfin/include/asm/spinlock.h
@@ -48,11 +48,6 @@ static inline void arch_spin_unlock(arch_spinlock_t *lock)
 	__raw_spin_unlock_asm(&lock->lock);
 }
 
-static inline void arch_spin_unlock_wait(arch_spinlock_t *lock)
-{
-	smp_cond_load_acquire(&lock->lock, !VAL);
-}
-
 static inline int arch_read_can_lock(arch_rwlock_t *rw)
 {
 	return __raw_uncached_fetch_asm(&rw->lock) > 0;
diff --git a/arch/hexagon/include/asm/spinlock.h b/arch/hexagon/include/asm/spinlock.h
index a1c55788c5d6..53a8d5885887 100644
--- a/arch/hexagon/include/asm/spinlock.h
+++ b/arch/hexagon/include/asm/spinlock.h
@@ -179,11 +179,6 @@ static inline unsigned int arch_spin_trylock(arch_spinlock_t *lock)
  */
 #define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock)
 
-static inline void arch_spin_unlock_wait(arch_spinlock_t *lock)
-{
-	smp_cond_load_acquire(&lock->lock, !VAL);
-}
-
 #define arch_spin_is_locked(x) ((x)->lock != 0)
 
 #define arch_read_lock_flags(lock, flags) arch_read_lock(lock)
diff --git a/arch/ia64/include/asm/spinlock.h b/arch/ia64/include/asm/spinlock.h
index ca9e76149a4a..df2c121164b8 100644
--- a/arch/ia64/include/asm/spinlock.h
+++ b/arch/ia64/include/asm/spinlock.h
@@ -76,22 +76,6 @@ static __always_inline void __ticket_spin_unlock(arch_spinlock_t *lock)
 	ACCESS_ONCE(*p) = (tmp + 2) & ~1;
 }
 
-static __always_inline void __ticket_spin_unlock_wait(arch_spinlock_t *lock)
-{
-	int	*p = (int *)&lock->lock, ticket;
-
-	ia64_invala();
-
-	for (;;) {
-		asm volatile ("ld4.c.nc %0=[%1]" : "=r"(ticket) : "r"(p) : "memory");
-		if (!(((ticket >> TICKET_SHIFT) ^ ticket) & TICKET_MASK))
-			return;
-		cpu_relax();
-	}
-
-	smp_acquire__after_ctrl_dep();
-}
-
 static inline int __ticket_spin_is_locked(arch_spinlock_t *lock)
 {
 	long tmp = ACCESS_ONCE(lock->lock);
@@ -143,11 +127,6 @@ static __always_inline void arch_spin_lock_flags(arch_spinlock_t *lock,
 	arch_spin_lock(lock);
 }
 
-static inline void arch_spin_unlock_wait(arch_spinlock_t *lock)
-{
-	__ticket_spin_unlock_wait(lock);
-}
-
 #define arch_read_can_lock(rw)		(*(volatile int *)(rw) >= 0)
 #define arch_write_can_lock(rw)	(*(volatile int *)(rw) == 0)
 
diff --git a/arch/m32r/include/asm/spinlock.h b/arch/m32r/include/asm/spinlock.h
index 323c7fc953cd..a56825592b90 100644
--- a/arch/m32r/include/asm/spinlock.h
+++ b/arch/m32r/include/asm/spinlock.h
@@ -30,11 +30,6 @@
 #define arch_spin_is_locked(x)		(*(volatile int *)(&(x)->slock) <= 0)
 #define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock)
 
-static inline void arch_spin_unlock_wait(arch_spinlock_t *lock)
-{
-	smp_cond_load_acquire(&lock->slock, VAL > 0);
-}
-
 /**
  * arch_spin_trylock - Try spin lock and return a result
  * @lock: Pointer to the lock variable
diff --git a/arch/metag/include/asm/spinlock.h b/arch/metag/include/asm/spinlock.h
index c0c7a22be1ae..ddf7fe5708a6 100644
--- a/arch/metag/include/asm/spinlock.h
+++ b/arch/metag/include/asm/spinlock.h
@@ -15,11 +15,6 @@
  * locked.
  */
 
-static inline void arch_spin_unlock_wait(arch_spinlock_t *lock)
-{
-	smp_cond_load_acquire(&lock->lock, !VAL);
-}
-
 #define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock)
 
 #define	arch_read_lock_flags(lock, flags) arch_read_lock(lock)
diff --git a/arch/mips/include/asm/spinlock.h b/arch/mips/include/asm/spinlock.h
index a8df44d60607..81b4945031ee 100644
--- a/arch/mips/include/asm/spinlock.h
+++ b/arch/mips/include/asm/spinlock.h
@@ -50,22 +50,6 @@ static inline int arch_spin_value_unlocked(arch_spinlock_t lock)
 
 #define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock)
 
-static inline void arch_spin_unlock_wait(arch_spinlock_t *lock)
-{
-	u16 owner = READ_ONCE(lock->h.serving_now);
-	smp_rmb();
-	for (;;) {
-		arch_spinlock_t tmp = READ_ONCE(*lock);
-
-		if (tmp.h.serving_now == tmp.h.ticket ||
-		    tmp.h.serving_now != owner)
-			break;
-
-		cpu_relax();
-	}
-	smp_acquire__after_ctrl_dep();
-}
-
 static inline int arch_spin_is_contended(arch_spinlock_t *lock)
 {
 	u32 counters = ACCESS_ONCE(lock->lock);
diff --git a/arch/mn10300/include/asm/spinlock.h b/arch/mn10300/include/asm/spinlock.h
index 9c7b8f7942d8..fe413b41df6c 100644
--- a/arch/mn10300/include/asm/spinlock.h
+++ b/arch/mn10300/include/asm/spinlock.h
@@ -26,11 +26,6 @@
 
 #define arch_spin_is_locked(x)	(*(volatile signed char *)(&(x)->slock) != 0)
 
-static inline void arch_spin_unlock_wait(arch_spinlock_t *lock)
-{
-	smp_cond_load_acquire(&lock->slock, !VAL);
-}
-
 static inline void arch_spin_unlock(arch_spinlock_t *lock)
 {
 	asm volatile(
diff --git a/arch/parisc/include/asm/spinlock.h b/arch/parisc/include/asm/spinlock.h
index e32936cd7f10..55bfe4affca3 100644
--- a/arch/parisc/include/asm/spinlock.h
+++ b/arch/parisc/include/asm/spinlock.h
@@ -14,13 +14,6 @@ static inline int arch_spin_is_locked(arch_spinlock_t *x)
 
 #define arch_spin_lock(lock) arch_spin_lock_flags(lock, 0)
 
-static inline void arch_spin_unlock_wait(arch_spinlock_t *x)
-{
-	volatile unsigned int *a = __ldcw_align(x);
-
-	smp_cond_load_acquire(a, VAL);
-}
-
 static inline void arch_spin_lock_flags(arch_spinlock_t *x,
 					 unsigned long flags)
 {
diff --git a/arch/powerpc/include/asm/spinlock.h b/arch/powerpc/include/asm/spinlock.h
index 8c1b913de6d7..d256e448ea49 100644
--- a/arch/powerpc/include/asm/spinlock.h
+++ b/arch/powerpc/include/asm/spinlock.h
@@ -170,39 +170,6 @@ static inline void arch_spin_unlock(arch_spinlock_t *lock)
 	lock->slock = 0;
 }
 
-static inline void arch_spin_unlock_wait(arch_spinlock_t *lock)
-{
-	arch_spinlock_t lock_val;
-
-	smp_mb();
-
-	/*
-	 * Atomically load and store back the lock value (unchanged). This
-	 * ensures that our observation of the lock value is ordered with
-	 * respect to other lock operations.
-	 */
-	__asm__ __volatile__(
-"1:	" PPC_LWARX(%0, 0, %2, 0) "\n"
-"	stwcx. %0, 0, %2\n"
-"	bne- 1b\n"
-	: "=&r" (lock_val), "+m" (*lock)
-	: "r" (lock)
-	: "cr0", "xer");
-
-	if (arch_spin_value_unlocked(lock_val))
-		goto out;
-
-	while (lock->slock) {
-		HMT_low();
-		if (SHARED_PROCESSOR)
-			__spin_yield(lock);
-	}
-	HMT_medium();
-
-out:
-	smp_mb();
-}
-
 /*
  * Read-write spinlocks, allowing multiple readers
  * but only one writer.
diff --git a/arch/s390/include/asm/spinlock.h b/arch/s390/include/asm/spinlock.h
index f7838ecd83c6..217ee5210c32 100644
--- a/arch/s390/include/asm/spinlock.h
+++ b/arch/s390/include/asm/spinlock.h
@@ -98,13 +98,6 @@ static inline void arch_spin_unlock(arch_spinlock_t *lp)
 		: "cc", "memory");
 }
 
-static inline void arch_spin_unlock_wait(arch_spinlock_t *lock)
-{
-	while (arch_spin_is_locked(lock))
-		arch_spin_relax(lock);
-	smp_acquire__after_ctrl_dep();
-}
-
 /*
  * Read-write spinlocks, allowing multiple readers
  * but only one writer.
diff --git a/arch/sh/include/asm/spinlock-cas.h b/arch/sh/include/asm/spinlock-cas.h
index c46e8cc7b515..5ed7dbbd94ff 100644
--- a/arch/sh/include/asm/spinlock-cas.h
+++ b/arch/sh/include/asm/spinlock-cas.h
@@ -29,11 +29,6 @@ static inline unsigned __sl_cas(volatile unsigned *p, unsigned old, unsigned new
 #define arch_spin_is_locked(x)		((x)->lock <= 0)
 #define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock)
 
-static inline void arch_spin_unlock_wait(arch_spinlock_t *lock)
-{
-	smp_cond_load_acquire(&lock->lock, VAL > 0);
-}
-
 static inline void arch_spin_lock(arch_spinlock_t *lock)
 {
 	while (!__sl_cas(&lock->lock, 1, 0));
diff --git a/arch/sh/include/asm/spinlock-llsc.h b/arch/sh/include/asm/spinlock-llsc.h
index cec78143fa83..f77263aae760 100644
--- a/arch/sh/include/asm/spinlock-llsc.h
+++ b/arch/sh/include/asm/spinlock-llsc.h
@@ -21,11 +21,6 @@
 #define arch_spin_is_locked(x)		((x)->lock <= 0)
 #define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock)
 
-static inline void arch_spin_unlock_wait(arch_spinlock_t *lock)
-{
-	smp_cond_load_acquire(&lock->lock, VAL > 0);
-}
-
 /*
  * Simple spin lock operations.  There are two variants, one clears IRQ's
  * on the local processor, one does not.
diff --git a/arch/sparc/include/asm/spinlock_32.h b/arch/sparc/include/asm/spinlock_32.h
index 8011e79f59c9..67345b2dc408 100644
--- a/arch/sparc/include/asm/spinlock_32.h
+++ b/arch/sparc/include/asm/spinlock_32.h
@@ -14,11 +14,6 @@
 
 #define arch_spin_is_locked(lock) (*((volatile unsigned char *)(lock)) != 0)
 
-static inline void arch_spin_unlock_wait(arch_spinlock_t *lock)
-{
-	smp_cond_load_acquire(&lock->lock, !VAL);
-}
-
 static inline void arch_spin_lock(arch_spinlock_t *lock)
 {
 	__asm__ __volatile__(
diff --git a/arch/sparc/include/asm/spinlock_64.h b/arch/sparc/include/asm/spinlock_64.h
index 07c9f2e9bf57..923d57f9b79d 100644
--- a/arch/sparc/include/asm/spinlock_64.h
+++ b/arch/sparc/include/asm/spinlock_64.h
@@ -26,11 +26,6 @@
 
 #define arch_spin_is_locked(lp)	((lp)->lock != 0)
 
-static inline void arch_spin_unlock_wait(arch_spinlock_t *lock)
-{
-	smp_cond_load_acquire(&lock->lock, !VAL);
-}
-
 static inline void arch_spin_lock(arch_spinlock_t *lock)
 {
 	unsigned long tmp;
diff --git a/arch/tile/include/asm/spinlock_32.h b/arch/tile/include/asm/spinlock_32.h
index b14b1ba5bf9c..cba8ba9b8da6 100644
--- a/arch/tile/include/asm/spinlock_32.h
+++ b/arch/tile/include/asm/spinlock_32.h
@@ -64,8 +64,6 @@ static inline void arch_spin_unlock(arch_spinlock_t *lock)
 	lock->current_ticket = old_ticket + TICKET_QUANTUM;
 }
 
-void arch_spin_unlock_wait(arch_spinlock_t *lock);
-
 /*
  * Read-write spinlocks, allowing multiple readers
  * but only one writer.
diff --git a/arch/tile/include/asm/spinlock_64.h b/arch/tile/include/asm/spinlock_64.h
index b9718fb4e74a..9a2c2d605752 100644
--- a/arch/tile/include/asm/spinlock_64.h
+++ b/arch/tile/include/asm/spinlock_64.h
@@ -58,8 +58,6 @@ static inline void arch_spin_unlock(arch_spinlock_t *lock)
 	__insn_fetchadd4(&lock->lock, 1U << __ARCH_SPIN_CURRENT_SHIFT);
 }
 
-void arch_spin_unlock_wait(arch_spinlock_t *lock);
-
 void arch_spin_lock_slow(arch_spinlock_t *lock, u32 val);
 
 /* Grab the "next" ticket number and bump it atomically.
diff --git a/arch/tile/lib/spinlock_32.c b/arch/tile/lib/spinlock_32.c
index 076c6cc43113..db9333f2447c 100644
--- a/arch/tile/lib/spinlock_32.c
+++ b/arch/tile/lib/spinlock_32.c
@@ -62,29 +62,6 @@ int arch_spin_trylock(arch_spinlock_t *lock)
 }
 EXPORT_SYMBOL(arch_spin_trylock);
 
-void arch_spin_unlock_wait(arch_spinlock_t *lock)
-{
-	u32 iterations = 0;
-	int curr = READ_ONCE(lock->current_ticket);
-	int next = READ_ONCE(lock->next_ticket);
-
-	/* Return immediately if unlocked. */
-	if (next == curr)
-		return;
-
-	/* Wait until the current locker has released the lock. */
-	do {
-		delay_backoff(iterations++);
-	} while (READ_ONCE(lock->current_ticket) == curr);
-
-	/*
-	 * The TILE architecture doesn't do read speculation; therefore
-	 * a control dependency guarantees a LOAD->{LOAD,STORE} order.
-	 */
-	barrier();
-}
-EXPORT_SYMBOL(arch_spin_unlock_wait);
-
 /*
  * The low byte is always reserved to be the marker for a "tns" operation
  * since the low bit is set to "1" by a tns.  The next seven bits are
diff --git a/arch/tile/lib/spinlock_64.c b/arch/tile/lib/spinlock_64.c
index a4b5b2cbce93..de414c22892f 100644
--- a/arch/tile/lib/spinlock_64.c
+++ b/arch/tile/lib/spinlock_64.c
@@ -62,28 +62,6 @@ int arch_spin_trylock(arch_spinlock_t *lock)
 }
 EXPORT_SYMBOL(arch_spin_trylock);
 
-void arch_spin_unlock_wait(arch_spinlock_t *lock)
-{
-	u32 iterations = 0;
-	u32 val = READ_ONCE(lock->lock);
-	u32 curr = arch_spin_current(val);
-
-	/* Return immediately if unlocked. */
-	if (arch_spin_next(val) == curr)
-		return;
-
-	/* Wait until the current locker has released the lock. */
-	do {
-		delay_backoff(iterations++);
-	} while (arch_spin_current(READ_ONCE(lock->lock)) == curr);
-
-	/*
-	 * The TILE architecture doesn't do read speculation; therefore
-	 * a control dependency guarantees a LOAD->{LOAD,STORE} order.
-	 */
-	barrier();
-}
-EXPORT_SYMBOL(arch_spin_unlock_wait);
 
 /*
  * If the read lock fails due to a writer, we retry periodically
diff --git a/arch/xtensa/include/asm/spinlock.h b/arch/xtensa/include/asm/spinlock.h
index a36221cf6363..3bb49681ee24 100644
--- a/arch/xtensa/include/asm/spinlock.h
+++ b/arch/xtensa/include/asm/spinlock.h
@@ -33,11 +33,6 @@
 
 #define arch_spin_is_locked(x) ((x)->slock != 0)
 
-static inline void arch_spin_unlock_wait(arch_spinlock_t *lock)
-{
-	smp_cond_load_acquire(&lock->slock, !VAL);
-}
-
 #define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock)
 
 static inline void arch_spin_lock(arch_spinlock_t *lock)
-- 
2.5.2

^ permalink raw reply related	[flat|nested] 122+ messages in thread

* Re: [PATCH v2 0/9] Remove spin_unlock_wait()
  2017-07-07 17:47             ` Manfred Spraul
@ 2017-07-08  8:35               ` Ingo Molnar
  2017-07-08 11:39                 ` Paul E. McKenney
  0 siblings, 1 reply; 122+ messages in thread
From: Ingo Molnar @ 2017-07-08  8:35 UTC (permalink / raw)
  To: Manfred Spraul
  Cc: Peter Zijlstra, Paul E. McKenney, David Laight, linux-kernel,
	netfilter-devel, netdev, oleg, akpm, mingo, dave, tj, arnd,
	linux-arch, will.deacon, stern, parri.andrea, torvalds


* Manfred Spraul <manfred@colorfullife.com> wrote:

> Hi Ingo,
> 
> On 07/07/2017 10:31 AM, Ingo Molnar wrote:
> > 
> > There's another, probably just as significant advantage: queued_spin_unlock_wait()
> > is 'read-only', while spin_lock()+spin_unlock() dirties the lock cache line. On
> > any bigger system this should make a very measurable difference - if
> > spin_unlock_wait() is ever used in a performance critical code path.
> At least for ipc/sem:
> Dirtying the cacheline (in the slow path) allows to remove a smp_mb() in the
> hot path.
> So for sem_lock(), I either need a primitive that dirties the cacheline or
> sem_lock() must continue to use spin_lock()/spin_unlock().

Technically you could use spin_trylock()+spin_unlock() and avoid the lock acquire 
spinning on spin_unlock() and get very close to the slow path performance of a 
pure cacheline-dirtying behavior.

But adding something like spin_barrier(), which purely dirties the lock cacheline, 
would be even faster, right?

Thanks,

	Ingo

^ permalink raw reply	[flat|nested] 122+ messages in thread

* Re: [PATCH v2 0/9] Remove spin_unlock_wait()
  2017-07-07 14:41             ` Paul E. McKenney
@ 2017-07-08  8:43               ` Ingo Molnar
  2017-07-08 11:41                 ` Paul E. McKenney
  0 siblings, 1 reply; 122+ messages in thread
From: Ingo Molnar @ 2017-07-08  8:43 UTC (permalink / raw)
  To: Paul E. McKenney
  Cc: Peter Zijlstra, David Laight, linux-kernel, netfilter-devel,
	netdev, oleg, akpm, mingo, dave, manfred, tj, arnd, linux-arch,
	will.deacon, stern, parri.andrea, torvalds


* Paul E. McKenney <paulmck@linux.vnet.ibm.com> wrote:

> On Fri, Jul 07, 2017 at 10:31:28AM +0200, Ingo Molnar wrote:
> 
> [ . . . ]
> 
> > In fact I'd argue that any future high performance spin_unlock_wait() user is 
> > probably better off open coding the unlock-wait poll loop (and possibly thinking 
> > hard about eliminating it altogether). If such patterns pop up in the kernel we 
> > can think about consolidating them into a single read-only primitive again.
> 
> I would like any reintroduction to include a header comment saying exactly
> what the consolidated primitive actually does and does not do.  ;-)
> 
> > I.e. I think the proposed changes are doing no harm, and the unavailability of a 
> > generic primitive does not hinder future optimizations either in any significant 
> > fashion.
> 
> I will have a v3 with updated comments from Manfred.  Thoughts on when/where
> to push this?

Once everyone agrees I can apply it to the locking tree. I think PeterZ's was the 
only objection?

> The reason I ask is if this does not go in during this merge window, I need
> to fix the header comment on spin_unlock_wait().

Can try it next week after some testing - let's see how busy things get for Linus 
in the merge window?

Thanks,

	Ingo

^ permalink raw reply	[flat|nested] 122+ messages in thread

* Re: [PATCH v2 0/9] Remove spin_unlock_wait()
  2017-07-08  8:35               ` Ingo Molnar
@ 2017-07-08 11:39                 ` Paul E. McKenney
  2017-07-08 12:30                   ` Ingo Molnar
  0 siblings, 1 reply; 122+ messages in thread
From: Paul E. McKenney @ 2017-07-08 11:39 UTC (permalink / raw)
  To: Ingo Molnar
  Cc: Manfred Spraul, Peter Zijlstra, David Laight, linux-kernel,
	netfilter-devel, netdev, oleg, akpm, mingo, dave, tj, arnd,
	linux-arch, will.deacon, stern, parri.andrea, torvalds

On Sat, Jul 08, 2017 at 10:35:43AM +0200, Ingo Molnar wrote:
> 
> * Manfred Spraul <manfred@colorfullife.com> wrote:
> 
> > Hi Ingo,
> > 
> > On 07/07/2017 10:31 AM, Ingo Molnar wrote:
> > > 
> > > There's another, probably just as significant advantage: queued_spin_unlock_wait()
> > > is 'read-only', while spin_lock()+spin_unlock() dirties the lock cache line. On
> > > any bigger system this should make a very measurable difference - if
> > > spin_unlock_wait() is ever used in a performance critical code path.
> > At least for ipc/sem:
> > Dirtying the cacheline (in the slow path) allows to remove a smp_mb() in the
> > hot path.
> > So for sem_lock(), I either need a primitive that dirties the cacheline or
> > sem_lock() must continue to use spin_lock()/spin_unlock().
> 
> Technically you could use spin_trylock()+spin_unlock() and avoid the lock acquire 
> spinning on spin_unlock() and get very close to the slow path performance of a 
> pure cacheline-dirtying behavior.
> 
> But adding something like spin_barrier(), which purely dirties the lock cacheline, 
> would be even faster, right?

Interestingly enough, the arm64 and powerpc implementations of
spin_unlock_wait() were very close to what it sounds like you are
describing.

							Thanx, Paul

^ permalink raw reply	[flat|nested] 122+ messages in thread

* Re: [PATCH v2 0/9] Remove spin_unlock_wait()
  2017-07-08  8:43               ` Ingo Molnar
@ 2017-07-08 11:41                 ` Paul E. McKenney
  0 siblings, 0 replies; 122+ messages in thread
From: Paul E. McKenney @ 2017-07-08 11:41 UTC (permalink / raw)
  To: Ingo Molnar
  Cc: Peter Zijlstra, David Laight, linux-kernel, netfilter-devel,
	netdev, oleg, akpm, mingo, dave, manfred, tj, arnd, linux-arch,
	will.deacon, stern, parri.andrea, torvalds

On Sat, Jul 08, 2017 at 10:43:24AM +0200, Ingo Molnar wrote:
> 
> * Paul E. McKenney <paulmck@linux.vnet.ibm.com> wrote:
> 
> > On Fri, Jul 07, 2017 at 10:31:28AM +0200, Ingo Molnar wrote:
> > 
> > [ . . . ]
> > 
> > > In fact I'd argue that any future high performance spin_unlock_wait() user is 
> > > probably better off open coding the unlock-wait poll loop (and possibly thinking 
> > > hard about eliminating it altogether). If such patterns pop up in the kernel we 
> > > can think about consolidating them into a single read-only primitive again.
> > 
> > I would like any reintroduction to include a header comment saying exactly
> > what the consolidated primitive actually does and does not do.  ;-)
> > 
> > > I.e. I think the proposed changes are doing no harm, and the unavailability of a 
> > > generic primitive does not hinder future optimizations either in any significant 
> > > fashion.
> > 
> > I will have a v3 with updated comments from Manfred.  Thoughts on when/where
> > to push this?
> 
> Once everyone agrees I can apply it to the locking tree. I think PeterZ's was the 
> only objection?

Oleg wasn't all that happy, either, but he did supply the relevant patch.

> > The reason I ask is if this does not go in during this merge window, I need
> > to fix the header comment on spin_unlock_wait().
> 
> Can try it next week after some testing - let's see how busy things get for Linus 
> in the merge window?

Sounds good!  Either way is fine with me.

							Thanx, Paul

^ permalink raw reply	[flat|nested] 122+ messages in thread

* Re: [PATCH v2 0/9] Remove spin_unlock_wait()
  2017-07-08 11:39                 ` Paul E. McKenney
@ 2017-07-08 12:30                   ` Ingo Molnar
  2017-07-08 14:45                     ` Paul E. McKenney
  2017-07-08 16:21                     ` Alan Stern
  0 siblings, 2 replies; 122+ messages in thread
From: Ingo Molnar @ 2017-07-08 12:30 UTC (permalink / raw)
  To: Paul E. McKenney
  Cc: Manfred Spraul, Peter Zijlstra, David Laight, linux-kernel,
	netfilter-devel, netdev, oleg, akpm, mingo, dave, tj, arnd,
	linux-arch, will.deacon, stern, parri.andrea, torvalds


* Paul E. McKenney <paulmck@linux.vnet.ibm.com> wrote:

> On Sat, Jul 08, 2017 at 10:35:43AM +0200, Ingo Molnar wrote:
> > 
> > * Manfred Spraul <manfred@colorfullife.com> wrote:
> > 
> > > Hi Ingo,
> > > 
> > > On 07/07/2017 10:31 AM, Ingo Molnar wrote:
> > > > 
> > > > There's another, probably just as significant advantage: queued_spin_unlock_wait()
> > > > is 'read-only', while spin_lock()+spin_unlock() dirties the lock cache line. On
> > > > any bigger system this should make a very measurable difference - if
> > > > spin_unlock_wait() is ever used in a performance critical code path.
> > > At least for ipc/sem:
> > > Dirtying the cacheline (in the slow path) allows to remove a smp_mb() in the
> > > hot path.
> > > So for sem_lock(), I either need a primitive that dirties the cacheline or
> > > sem_lock() must continue to use spin_lock()/spin_unlock().
> > 
> > Technically you could use spin_trylock()+spin_unlock() and avoid the lock acquire 
> > spinning on spin_unlock() and get very close to the slow path performance of a 
> > pure cacheline-dirtying behavior.
> > 
> > But adding something like spin_barrier(), which purely dirties the lock cacheline, 
> > would be even faster, right?
> 
> Interestingly enough, the arm64 and powerpc implementations of
> spin_unlock_wait() were very close to what it sounds like you are
> describing.

So could we perhaps solve all our problems by defining the generic version thusly:

void spin_unlock_wait(spinlock_t *lock)
{
	if (spin_trylock(lock))
		spin_unlock(lock);
}

... and perhaps rename it to spin_barrier() [or whatever proper name there would 
be]?

Architectures can still optimize it, to remove the small window where the lock is 
held locally - as long as the ordering is at least as strong as the generic 
version.

This would have various advantages:

 - semantics are well-defined

 - the generic implementation is already pretty well optimized (no spinning)

 - it would make it usable for the IPC performance optimization

 - architectures could still optimize it to eliminate the window where the lock is
   held locally - if there's such instructions available.

Was this proposed before, or am I missing something?

Thanks,

	Ingo

^ permalink raw reply	[flat|nested] 122+ messages in thread

* Re: [PATCH v2 0/9] Remove spin_unlock_wait()
  2017-07-08 12:30                   ` Ingo Molnar
@ 2017-07-08 14:45                     ` Paul E. McKenney
  2017-07-08 16:21                     ` Alan Stern
  1 sibling, 0 replies; 122+ messages in thread
From: Paul E. McKenney @ 2017-07-08 14:45 UTC (permalink / raw)
  To: Ingo Molnar
  Cc: Manfred Spraul, Peter Zijlstra, David Laight, linux-kernel,
	netfilter-devel, netdev, oleg, akpm, mingo, dave, tj, arnd,
	linux-arch, will.deacon, stern, parri.andrea, torvalds

On Sat, Jul 08, 2017 at 02:30:19PM +0200, Ingo Molnar wrote:
> 
> * Paul E. McKenney <paulmck@linux.vnet.ibm.com> wrote:
> 
> > On Sat, Jul 08, 2017 at 10:35:43AM +0200, Ingo Molnar wrote:
> > > 
> > > * Manfred Spraul <manfred@colorfullife.com> wrote:
> > > 
> > > > Hi Ingo,
> > > > 
> > > > On 07/07/2017 10:31 AM, Ingo Molnar wrote:
> > > > > 
> > > > > There's another, probably just as significant advantage: queued_spin_unlock_wait()
> > > > > is 'read-only', while spin_lock()+spin_unlock() dirties the lock cache line. On
> > > > > any bigger system this should make a very measurable difference - if
> > > > > spin_unlock_wait() is ever used in a performance critical code path.
> > > > At least for ipc/sem:
> > > > Dirtying the cacheline (in the slow path) allows to remove a smp_mb() in the
> > > > hot path.
> > > > So for sem_lock(), I either need a primitive that dirties the cacheline or
> > > > sem_lock() must continue to use spin_lock()/spin_unlock().
> > > 
> > > Technically you could use spin_trylock()+spin_unlock() and avoid the lock acquire 
> > > spinning on spin_unlock() and get very close to the slow path performance of a 
> > > pure cacheline-dirtying behavior.
> > > 
> > > But adding something like spin_barrier(), which purely dirties the lock cacheline, 
> > > would be even faster, right?
> > 
> > Interestingly enough, the arm64 and powerpc implementations of
> > spin_unlock_wait() were very close to what it sounds like you are
> > describing.
> 
> So could we perhaps solve all our problems by defining the generic version thusly:
> 
> void spin_unlock_wait(spinlock_t *lock)
> {
> 	if (spin_trylock(lock))
> 		spin_unlock(lock);
> }
> 
> ... and perhaps rename it to spin_barrier() [or whatever proper name there would 
> be]?

As lockdep, 0day Test Robot, Linus Torvalds, and several others let me
know in response to my original (thankfully RFC!) patch series, this needs
to disable irqs to work in the general case.  For example, if the lock
in question is an irq-disabling lock, you take an interrupt just after
a successful spin_trylock(), and that interrupt acquires the same lock,
the actuarial statistics of your kernel degrade sharply and suddenly.

What I get for sending out untested patches!  :-/

> Architectures can still optimize it, to remove the small window where the lock is 
> held locally - as long as the ordering is at least as strong as the generic 
> version.
> 
> This would have various advantages:
> 
>  - semantics are well-defined
> 
>  - the generic implementation is already pretty well optimized (no spinning)
> 
>  - it would make it usable for the IPC performance optimization
> 
>  - architectures could still optimize it to eliminate the window where the lock is
>    held locally - if there's such instructions available.
> 
> Was this proposed before, or am I missing something?

It was sort of proposed...

https://marc.info/?l=linux-arch&m=149912878628355&w=2

But do we have a situation where normal usage of spin_lock() and
spin_unlock() is causing performance or scalability trouble?

(We do have at least one situation in fnic that appears to be buggy use of
spin_is_locked(), and proposing a patch for that case in on my todo list.)

							Thanx, Paul

^ permalink raw reply	[flat|nested] 122+ messages in thread

* Re: [PATCH v2 0/9] Remove spin_unlock_wait()
  2017-07-08 12:30                   ` Ingo Molnar
  2017-07-08 14:45                     ` Paul E. McKenney
@ 2017-07-08 16:21                     ` Alan Stern
  2017-07-10 17:22                       ` Manfred Spraul
  1 sibling, 1 reply; 122+ messages in thread
From: Alan Stern @ 2017-07-08 16:21 UTC (permalink / raw)
  To: Ingo Molnar
  Cc: Paul E. McKenney, Manfred Spraul, Peter Zijlstra, David Laight,
	linux-kernel, netfilter-devel, netdev, oleg, akpm, mingo, dave,
	tj, arnd, linux-arch, will.deacon, parri.andrea, torvalds

Pardon me for barging in, but I found this whole interchange extremely 
confusing...

On Sat, 8 Jul 2017, Ingo Molnar wrote:

> * Paul E. McKenney <paulmck@linux.vnet.ibm.com> wrote:
> 
> > On Sat, Jul 08, 2017 at 10:35:43AM +0200, Ingo Molnar wrote:
> > > 
> > > * Manfred Spraul <manfred@colorfullife.com> wrote:
> > > 
> > > > Hi Ingo,
> > > > 
> > > > On 07/07/2017 10:31 AM, Ingo Molnar wrote:
> > > > > 
> > > > > There's another, probably just as significant advantage: queued_spin_unlock_wait()
> > > > > is 'read-only', while spin_lock()+spin_unlock() dirties the lock cache line. On
> > > > > any bigger system this should make a very measurable difference - if
> > > > > spin_unlock_wait() is ever used in a performance critical code path.
> > > > At least for ipc/sem:
> > > > Dirtying the cacheline (in the slow path) allows to remove a smp_mb() in the
> > > > hot path.
> > > > So for sem_lock(), I either need a primitive that dirties the cacheline or
> > > > sem_lock() must continue to use spin_lock()/spin_unlock().

This statement doesn't seem to make sense.  Did Manfred mean to write 
"smp_mb()" instead of "spin_lock()/spin_unlock()"?

> > > Technically you could use spin_trylock()+spin_unlock() and avoid the lock acquire 
> > > spinning on spin_unlock() and get very close to the slow path performance of a 
> > > pure cacheline-dirtying behavior.

This is even more confusing.  Did Ingo mean to suggest using 
"spin_trylock()+spin_unlock()" in place of "spin_lock()+spin_unlock()" 
could provide the desired ordering guarantee without delaying other 
CPUs that may try to acquire the lock?  That seems highly questionable.

> > > But adding something like spin_barrier(), which purely dirties the lock cacheline, 
> > > would be even faster, right?
> > 
> > Interestingly enough, the arm64 and powerpc implementations of
> > spin_unlock_wait() were very close to what it sounds like you are
> > describing.
> 
> So could we perhaps solve all our problems by defining the generic version thusly:
> 
> void spin_unlock_wait(spinlock_t *lock)
> {
> 	if (spin_trylock(lock))
> 		spin_unlock(lock);
> }

How could this possibly be a generic version of spin_unlock_wait()?  
It does nothing at all (with no ordering properties) if some other CPU
currently holds the lock, whereas the real spin_unlock_wait() would
wait until the other CPU released the lock (or possibly longer).

And if no other CPU currently holds the lock, this has exactly the same
performance properties as spin_lock()+spin_unlock(), so what's the
advantage?

Alan Stern

> ... and perhaps rename it to spin_barrier() [or whatever proper name there would 
> be]?
> 
> Architectures can still optimize it, to remove the small window where the lock is 
> held locally - as long as the ordering is at least as strong as the generic 
> version.
> 
> This would have various advantages:
> 
>  - semantics are well-defined
> 
>  - the generic implementation is already pretty well optimized (no spinning)
> 
>  - it would make it usable for the IPC performance optimization
> 
>  - architectures could still optimize it to eliminate the window where the lock is
>    held locally - if there's such instructions available.
> 
> Was this proposed before, or am I missing something?
> 
> Thanks,
> 
> 	Ingo

^ permalink raw reply	[flat|nested] 122+ messages in thread

* Re: [PATCH v2 0/9] Remove spin_unlock_wait()
  2017-07-08 16:21                     ` Alan Stern
@ 2017-07-10 17:22                       ` Manfred Spraul
  0 siblings, 0 replies; 122+ messages in thread
From: Manfred Spraul @ 2017-07-10 17:22 UTC (permalink / raw)
  To: Alan Stern, Ingo Molnar
  Cc: Paul E. McKenney, Peter Zijlstra, David Laight, linux-kernel,
	netfilter-devel, netdev, oleg, akpm, mingo, dave, tj, arnd,
	linux-arch, will.deacon, parri.andrea, torvalds

Hi Alan,

On 07/08/2017 06:21 PM, Alan Stern wrote:
> Pardon me for barging in, but I found this whole interchange extremely
> confusing...
>
> On Sat, 8 Jul 2017, Ingo Molnar wrote:
>
>> * Paul E. McKenney <paulmck@linux.vnet.ibm.com> wrote:
>>
>>> On Sat, Jul 08, 2017 at 10:35:43AM +0200, Ingo Molnar wrote:
>>>> * Manfred Spraul <manfred@colorfullife.com> wrote:
>>>>
>>>>> Hi Ingo,
>>>>>
>>>>> On 07/07/2017 10:31 AM, Ingo Molnar wrote:
>>>>>> There's another, probably just as significant advantage: queued_spin_unlock_wait()
>>>>>> is 'read-only', while spin_lock()+spin_unlock() dirties the lock cache line. On
>>>>>> any bigger system this should make a very measurable difference - if
>>>>>> spin_unlock_wait() is ever used in a performance critical code path.
>>>>> At least for ipc/sem:
>>>>> Dirtying the cacheline (in the slow path) allows to remove a smp_mb() in the
>>>>> hot path.
>>>>> So for sem_lock(), I either need a primitive that dirties the cacheline or
>>>>> sem_lock() must continue to use spin_lock()/spin_unlock().
> This statement doesn't seem to make sense.  Did Manfred mean to write
> "smp_mb()" instead of "spin_lock()/spin_unlock()"?
Option 1:
     fastpath:
         spin_lock(local_lock)
         smp_mb(); [[1]]
         smp_load_acquire(global_flag);
     slow path:
         global_flag = 1;
         smp_mb();
         <spin_unlock_wait_without_cacheline_dirtying>

Option 2:
     fastpath:
         spin_lock(local_lock);
         smp_load_acquire(global_flag)
     slow path:
         global_flag = 1;
         spin_lock(local_lock);spin_unlock(local_lock).

Rational:
The ACQUIRE from spin_lock is at the read of local_lock, not at the write.
i.e.: Without the smp_mb() at [[1]], the CPU can do:
         read local_lock;
         read global_flag;
         write local_lock;
For Option 2, the smp_mb() is not required, because fast path and slow 
path acquire the same lock.

>>>> Technically you could use spin_trylock()+spin_unlock() and avoid the lock acquire
>>>> spinning on spin_unlock() and get very close to the slow path performance of a
>>>> pure cacheline-dirtying behavior.
> This is even more confusing.  Did Ingo mean to suggest using
> "spin_trylock()+spin_unlock()" in place of "spin_lock()+spin_unlock()"
> could provide the desired ordering guarantee without delaying other
> CPUs that may try to acquire the lock?  That seems highly questionable.
I agree :-)

--
     Manfred

^ permalink raw reply	[flat|nested] 122+ messages in thread

end of thread, other threads:[~2017-07-10 17:22 UTC | newest]

Thread overview: 122+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-06-29 23:59 [PATCH RFC 0/26] Remove spin_unlock_wait() Paul E. McKenney
2017-06-30  0:01 ` [PATCH RFC 01/26] netfilter: Replace spin_unlock_wait() with lock/unlock pair Paul E. McKenney
     [not found]   ` <a6642feb-2f3a-980f-5ed6-2deb79563e6b@colorfullife.com>
2017-07-02  2:00     ` Paul E. McKenney
2017-07-03 14:39     ` Alan Stern
2017-07-03 17:14       ` Paul E. McKenney
2017-07-03 19:01         ` Manfred Spraul
2017-07-03 19:57           ` Alan Stern
2017-07-06 18:43             ` Manfred Spraul
2017-07-03 20:04         ` Alan Stern
2017-07-03 20:53           ` Paul E. McKenney
2017-06-30  0:01 ` [PATCH RFC 02/26] task_work: " Paul E. McKenney
2017-06-30 11:04   ` Oleg Nesterov
2017-06-30 12:50     ` Paul E. McKenney
2017-06-30 15:20       ` Oleg Nesterov
2017-06-30 16:16         ` Paul E. McKenney
2017-06-30 17:21           ` Paul E. McKenney
2017-06-30 19:21           ` Oleg Nesterov
2017-06-30 19:50             ` Alan Stern
2017-06-30 20:04               ` Paul E. McKenney
2017-06-30 20:02             ` Paul E. McKenney
2017-06-30 20:19               ` Paul E. McKenney
2017-06-30  0:01 ` [PATCH RFC 03/26] sched: " Paul E. McKenney
2017-06-30 10:31   ` Arnd Bergmann
2017-06-30 12:35     ` Paul E. McKenney
2017-06-30  0:01 ` [PATCH RFC 04/26] completion: " Paul E. McKenney
2017-06-30  0:01 ` [PATCH RFC 05/26] exit: " Paul E. McKenney
2017-06-30  0:01 ` [PATCH RFC 07/26] drivers/ata: " Paul E. McKenney
2017-06-30  0:01 ` [PATCH RFC 08/26] locking: Remove spin_unlock_wait() generic definitions Paul E. McKenney
2017-06-30  9:19   ` Will Deacon
2017-06-30 12:38     ` Paul E. McKenney
2017-06-30 13:13       ` Will Deacon
2017-06-30 22:18         ` Paul E. McKenney
2017-07-03 13:15           ` Will Deacon
2017-07-03 16:18             ` Paul E. McKenney
2017-07-03 16:40               ` Linus Torvalds
2017-07-03 17:13                 ` Will Deacon
2017-07-03 22:30                   ` Paul E. McKenney
2017-07-03 22:49                     ` Linus Torvalds
2017-07-04  0:39                       ` Paul E. McKenney
2017-07-04  0:54                         ` Paul E. McKenney
2017-07-03 21:10                 ` Paul E. McKenney
2017-06-30  0:01 ` [PATCH RFC 09/26] alpha: Remove spin_unlock_wait() arch-specific definitions Paul E. McKenney
2017-06-30  0:01 ` [PATCH RFC 10/26] arc: " Paul E. McKenney
2017-06-30  0:01 ` [PATCH RFC 11/26] arm: " Paul E. McKenney
2017-06-30  0:01 ` [PATCH RFC 12/26] arm64: " Paul E. McKenney
2017-06-30  9:20   ` Will Deacon
2017-06-30 17:29     ` Paul E. McKenney
2017-06-30  0:01 ` [PATCH RFC 13/26] blackfin: " Paul E. McKenney
2017-06-30  0:01 ` [PATCH RFC 14/26] hexagon: " Paul E. McKenney
2017-06-30  0:01 ` [PATCH RFC 15/26] ia64: " Paul E. McKenney
2017-06-30  0:01 ` [PATCH RFC 16/26] m32r: " Paul E. McKenney
2017-06-30  0:01 ` [PATCH RFC 18/26] mips: " Paul E. McKenney
2017-06-30  0:01 ` [PATCH RFC 19/26] mn10300: " Paul E. McKenney
2017-06-30  0:01 ` [PATCH RFC 20/26] parisc: " Paul E. McKenney
2017-06-30  0:01 ` [PATCH RFC 21/26] powerpc: " Paul E. McKenney
2017-07-02  3:58   ` Boqun Feng
2017-07-05 23:57     ` Paul E. McKenney
2017-06-30  0:01 ` [PATCH RFC 22/26] s390: " Paul E. McKenney
2017-06-30  0:01 ` [PATCH RFC 23/26] sh: " Paul E. McKenney
2017-06-30  0:01 ` [PATCH RFC 24/26] sparc: " Paul E. McKenney
2017-06-30  0:01 ` [PATCH RFC 25/26] tile: " Paul E. McKenney
2017-06-30  0:06   ` Linus Torvalds
2017-06-30  0:09     ` Paul E. McKenney
2017-06-30  0:14       ` Paul E. McKenney
2017-06-30  0:10     ` Linus Torvalds
2017-06-30  0:24       ` Paul E. McKenney
2017-06-30  0:01 ` [PATCH RFC 26/26] xtensa: " Paul E. McKenney
     [not found] ` <1498780894-8253-6-git-send-email-paulmck@linux.vnet.ibm.com>
2017-07-01 19:23   ` [PATCH RFC 06/26] ipc: Replace spin_unlock_wait() with lock/unlock pair Manfred Spraul
2017-07-02  3:16     ` Paul E. McKenney
2017-07-05 23:29 ` [PATCH v2 0/9] Remove spin_unlock_wait() Paul E. McKenney
2017-07-05 23:31   ` [PATCH v2 1/9] net/netfilter/nf_conntrack_core: Fix net_conntrack_lock() Paul E. McKenney
2017-07-06 18:45     ` Manfred Spraul
2017-07-06 20:26       ` Paul E. McKenney
2017-07-05 23:31   ` [PATCH v2 2/9] task_work: Replace spin_unlock_wait() with lock/unlock pair Paul E. McKenney
2017-07-05 23:31   ` [PATCH v2 3/9] sched: " Paul E. McKenney
2017-07-05 23:31   ` [PATCH v2 4/9] completion: " Paul E. McKenney
2017-07-05 23:31   ` [PATCH v2 5/9] exit: " Paul E. McKenney
2017-07-05 23:31   ` [PATCH v2 6/9] ipc: " Paul E. McKenney
2017-07-05 23:31   ` [PATCH v2 7/9] drivers/ata: " Paul E. McKenney
2017-07-05 23:31   ` [PATCH v2 8/9] locking: Remove spin_unlock_wait() generic definitions Paul E. McKenney
2017-07-05 23:31   ` [PATCH v2 9/9] arch: Remove spin_unlock_wait() arch-specific definitions Paul E. McKenney
2017-07-06 14:12   ` [PATCH v2 0/9] Remove spin_unlock_wait() David Laight
2017-07-06 15:21     ` Paul E. McKenney
2017-07-06 16:10       ` Peter Zijlstra
2017-07-06 16:24         ` Paul E. McKenney
2017-07-06 16:41           ` Peter Zijlstra
2017-07-06 17:03             ` Paul E. McKenney
2017-07-06 16:49           ` Alan Stern
2017-07-06 16:54             ` Peter Zijlstra
2017-07-06 19:37               ` Alan Stern
2017-07-06 16:05     ` Peter Zijlstra
2017-07-06 16:20       ` Paul E. McKenney
2017-07-06 16:50         ` Peter Zijlstra
2017-07-06 17:08           ` Will Deacon
2017-07-06 17:29             ` Paul E. McKenney
2017-07-06 17:18           ` Paul E. McKenney
2017-07-07  8:31           ` Ingo Molnar
2017-07-07  8:44             ` Peter Zijlstra
2017-07-07 10:33               ` Ingo Molnar
2017-07-07 11:23                 ` Peter Zijlstra
2017-07-07 14:41             ` Paul E. McKenney
2017-07-08  8:43               ` Ingo Molnar
2017-07-08 11:41                 ` Paul E. McKenney
2017-07-07 17:47             ` Manfred Spraul
2017-07-08  8:35               ` Ingo Molnar
2017-07-08 11:39                 ` Paul E. McKenney
2017-07-08 12:30                   ` Ingo Molnar
2017-07-08 14:45                     ` Paul E. McKenney
2017-07-08 16:21                     ` Alan Stern
2017-07-10 17:22                       ` Manfred Spraul
2017-07-07  8:06       ` Ingo Molnar
2017-07-07  9:32         ` Ingo Molnar
2017-07-07 19:27   ` [PATCH v3 " Paul E. McKenney
2017-07-07 19:28     ` [PATCH v3 1/9] net/netfilter/nf_conntrack_core: Fix net_conntrack_lock() Paul E. McKenney
2017-07-07 19:28     ` [PATCH v3 2/9] task_work: Replace spin_unlock_wait() with lock/unlock pair Paul E. McKenney
2017-07-07 19:28     ` [PATCH v3 3/9] sched: " Paul E. McKenney
2017-07-07 19:28     ` [PATCH v3 4/9] completion: " Paul E. McKenney
2017-07-07 19:28     ` [PATCH v3 5/9] exit: " Paul E. McKenney
2017-07-07 19:28     ` [PATCH v3 6/9] ipc: " Paul E. McKenney
2017-07-07 19:28     ` [PATCH v3 7/9] drivers/ata: " Paul E. McKenney
2017-07-07 19:28     ` [PATCH v3 8/9] locking: Remove spin_unlock_wait() generic definitions Paul E. McKenney
2017-07-07 19:28     ` [PATCH v3 9/9] arch: Remove spin_unlock_wait() arch-specific definitions Paul E. McKenney

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).