linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [patch 00/14] tasklets: Replace the spin wait loops and make it RT safe
@ 2021-03-09  8:42 Thomas Gleixner
  2021-03-09  8:42 ` [patch 01/14] tasklets: Replace barrier() with cpu_relax() in tasklet_unlock_wait() Thomas Gleixner
                   ` (14 more replies)
  0 siblings, 15 replies; 36+ messages in thread
From: Thomas Gleixner @ 2021-03-09  8:42 UTC (permalink / raw)
  To: LKML
  Cc: Frederic Weisbecker, Sebastian Andrzej Siewior, Ahmed S. Darwish,
	Peter Zijlstra, Denis Kirjanov, David S. Miller, Jakub Kicinski,
	netdev, ath9k-devel, Kalle Valo, linux-wireless, Chas Williams,
	linux-atm-general, K. Y. Srinivasan, Haiyang Zhang,
	Stephen Hemminger, Wei Liu, Lorenzo Pieralisi, Rob Herring,
	Bjorn Helgaas, linux-hyperv, linux-pci, Stefan Richter,
	linux1394-devel

This is a follow up to the review comments of the series which makes
softirq processing PREEMPT_RT safe:

 https://lore.kernel.org/r/20201207114743.GK3040@hirez.programming.kicks-ass.net

Peter suggested to replace the spin waiting in tasklet_disable() and
tasklet_kill() with wait_event(). This also gets rid of the ill defined
sched_yield() in tasklet_kill().

Analyzing all usage sites of tasklet_disable() and tasklet_unlock_wait() we
found that most of them are safe to be converted to a sleeping wait.

Only a few instances invoke tasklet_disable() from atomic context. A few
bugs which have been found in course of this analysis have been already
addressed seperately.

The following series takes the following approach:

    1) Provide a variant of tasklet_disable() which can be invoked from
       atomic contexts

    2) Convert the usage sites which cannot be easily changed to a
       sleepable wait to use this new function

    3) Replace the spin waits in tasklet_disable() and tasklet_kill() with
       sleepable variants.

If this is agreed on then the merging can be either done in bulk or the
first 4 patches could be applied on top of rc2 and tagged for consumption
in the relevant subsystem trees (networking, pci, firewire). In this case
the last patch which changes the implementation of tasklet_disable() has to
be post-poned until all other changes have reached mainline.

The series is also available from git:

  git://git.kernel.org/pub/scm/linux/kernel/git/tglx/devel.git tasklet-2021-03-09

Thanks,

	tglx



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

* [patch 01/14] tasklets: Replace barrier() with cpu_relax() in tasklet_unlock_wait()
  2021-03-09  8:42 [patch 00/14] tasklets: Replace the spin wait loops and make it RT safe Thomas Gleixner
@ 2021-03-09  8:42 ` Thomas Gleixner
  2021-03-17 15:49   ` [tip: irq/core] " tip-bot2 for Thomas Gleixner
  2021-03-09  8:42 ` [patch 02/14] tasklets: Use static inlines for stub implementations Thomas Gleixner
                   ` (13 subsequent siblings)
  14 siblings, 1 reply; 36+ messages in thread
From: Thomas Gleixner @ 2021-03-09  8:42 UTC (permalink / raw)
  To: LKML
  Cc: Frederic Weisbecker, Sebastian Andrzej Siewior, Ahmed S. Darwish,
	Peter Zijlstra, Denis Kirjanov, David S. Miller, Jakub Kicinski,
	netdev, ath9k-devel, Kalle Valo, linux-wireless, Chas Williams,
	linux-atm-general, K. Y. Srinivasan, Haiyang Zhang,
	Stephen Hemminger, Wei Liu, Lorenzo Pieralisi, Rob Herring,
	Bjorn Helgaas, linux-hyperv, linux-pci, Stefan Richter,
	linux1394-devel

A barrier() in a tight loop which waits for something to happen on a remote
CPU is a pointless exercise. Replace it with cpu_relax() which allows HT
siblings to make progress.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Tested-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
---
 include/linux/interrupt.h |    3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

--- a/include/linux/interrupt.h
+++ b/include/linux/interrupt.h
@@ -672,7 +672,8 @@ static inline void tasklet_unlock(struct
 
 static inline void tasklet_unlock_wait(struct tasklet_struct *t)
 {
-	while (test_bit(TASKLET_STATE_RUN, &(t)->state)) { barrier(); }
+	while (test_bit(TASKLET_STATE_RUN, &t->state))
+		cpu_relax();
 }
 #else
 #define tasklet_trylock(t) 1


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

* [patch 02/14] tasklets: Use static inlines for stub implementations
  2021-03-09  8:42 [patch 00/14] tasklets: Replace the spin wait loops and make it RT safe Thomas Gleixner
  2021-03-09  8:42 ` [patch 01/14] tasklets: Replace barrier() with cpu_relax() in tasklet_unlock_wait() Thomas Gleixner
@ 2021-03-09  8:42 ` Thomas Gleixner
  2021-03-17 15:48   ` [tip: irq/core] " tip-bot2 for Thomas Gleixner
  2021-03-09  8:42 ` [patch 03/14] tasklets: Provide tasklet_disable_in_atomic() Thomas Gleixner
                   ` (12 subsequent siblings)
  14 siblings, 1 reply; 36+ messages in thread
From: Thomas Gleixner @ 2021-03-09  8:42 UTC (permalink / raw)
  To: LKML
  Cc: Frederic Weisbecker, Sebastian Andrzej Siewior, Ahmed S. Darwish,
	Peter Zijlstra, Denis Kirjanov, David S. Miller, Jakub Kicinski,
	netdev, ath9k-devel, Kalle Valo, linux-wireless, Chas Williams,
	linux-atm-general, K. Y. Srinivasan, Haiyang Zhang,
	Stephen Hemminger, Wei Liu, Lorenzo Pieralisi, Rob Herring,
	Bjorn Helgaas, linux-hyperv, linux-pci, Stefan Richter,
	linux1394-devel

Inlines exist for a reason.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Tested-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
---
 include/linux/interrupt.h |    6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

--- a/include/linux/interrupt.h
+++ b/include/linux/interrupt.h
@@ -676,9 +676,9 @@ static inline void tasklet_unlock_wait(s
 		cpu_relax();
 }
 #else
-#define tasklet_trylock(t) 1
-#define tasklet_unlock_wait(t) do { } while (0)
-#define tasklet_unlock(t) do { } while (0)
+static inline int tasklet_trylock(struct tasklet_struct *t) { return 1; }
+static inline void tasklet_unlock(struct tasklet_struct *t) { }
+static inline void tasklet_unlock_wait(struct tasklet_struct *t) { }
 #endif
 
 extern void __tasklet_schedule(struct tasklet_struct *t);


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

* [patch 03/14] tasklets: Provide tasklet_disable_in_atomic()
  2021-03-09  8:42 [patch 00/14] tasklets: Replace the spin wait loops and make it RT safe Thomas Gleixner
  2021-03-09  8:42 ` [patch 01/14] tasklets: Replace barrier() with cpu_relax() in tasklet_unlock_wait() Thomas Gleixner
  2021-03-09  8:42 ` [patch 02/14] tasklets: Use static inlines for stub implementations Thomas Gleixner
@ 2021-03-09  8:42 ` Thomas Gleixner
  2021-03-17 15:48   ` [tip: irq/core] " tip-bot2 for Thomas Gleixner
  2021-03-09  8:42 ` [patch 04/14] tasklets: Use spin wait in tasklet_disable() temporarily Thomas Gleixner
                   ` (11 subsequent siblings)
  14 siblings, 1 reply; 36+ messages in thread
From: Thomas Gleixner @ 2021-03-09  8:42 UTC (permalink / raw)
  To: LKML
  Cc: Frederic Weisbecker, Sebastian Andrzej Siewior, Ahmed S. Darwish,
	Peter Zijlstra, Denis Kirjanov, David S. Miller, Jakub Kicinski,
	netdev, ath9k-devel, Kalle Valo, linux-wireless, Chas Williams,
	linux-atm-general, K. Y. Srinivasan, Haiyang Zhang,
	Stephen Hemminger, Wei Liu, Lorenzo Pieralisi, Rob Herring,
	Bjorn Helgaas, linux-hyperv, linux-pci, Stefan Richter,
	linux1394-devel

Replacing the spin wait loops in tasklet_unlock_wait() with
wait_var_event() is not possible as a handful of tasklet_disable()
invocations are happening in atomic context. All other invocations are in
teardown paths which can sleep.

Provide tasklet_disable_in_atomic() and tasklet_unlock_spin_wait() to
convert the few atomic use cases over, which allows to change
tasklet_disable() and tasklet_unlock_wait() in a later step.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
---
 include/linux/interrupt.h |   22 ++++++++++++++++++++++
 1 file changed, 22 insertions(+)

--- a/include/linux/interrupt.h
+++ b/include/linux/interrupt.h
@@ -675,10 +675,21 @@ static inline void tasklet_unlock_wait(s
 	while (test_bit(TASKLET_STATE_RUN, &t->state))
 		cpu_relax();
 }
+
+/*
+ * Do not use in new code. Waiting for tasklets from atomic contexts is
+ * error prone and should be avoided.
+ */
+static inline void tasklet_unlock_spin_wait(struct tasklet_struct *t)
+{
+	while (test_bit(TASKLET_STATE_RUN, &t->state))
+		cpu_relax();
+}
 #else
 static inline int tasklet_trylock(struct tasklet_struct *t) { return 1; }
 static inline void tasklet_unlock(struct tasklet_struct *t) { }
 static inline void tasklet_unlock_wait(struct tasklet_struct *t) { }
+static inline void tasklet_unlock_spin_wait(struct tasklet_struct *t) { }
 #endif
 
 extern void __tasklet_schedule(struct tasklet_struct *t);
@@ -703,6 +714,17 @@ static inline void tasklet_disable_nosyn
 	smp_mb__after_atomic();
 }
 
+/*
+ * Do not use in new code. Disabling tasklets from atomic contexts is
+ * error prone and should be avoided.
+ */
+static inline void tasklet_disable_in_atomic(struct tasklet_struct *t)
+{
+	tasklet_disable_nosync(t);
+	tasklet_unlock_spin_wait(t);
+	smp_mb();
+}
+
 static inline void tasklet_disable(struct tasklet_struct *t)
 {
 	tasklet_disable_nosync(t);


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

* [patch 04/14] tasklets: Use spin wait in tasklet_disable() temporarily
  2021-03-09  8:42 [patch 00/14] tasklets: Replace the spin wait loops and make it RT safe Thomas Gleixner
                   ` (2 preceding siblings ...)
  2021-03-09  8:42 ` [patch 03/14] tasklets: Provide tasklet_disable_in_atomic() Thomas Gleixner
@ 2021-03-09  8:42 ` Thomas Gleixner
  2021-03-17 15:48   ` [tip: irq/core] " tip-bot2 for Thomas Gleixner
  2021-03-09  8:42 ` [patch 05/14] tasklets: Replace spin wait in tasklet_unlock_wait() Thomas Gleixner
                   ` (10 subsequent siblings)
  14 siblings, 1 reply; 36+ messages in thread
From: Thomas Gleixner @ 2021-03-09  8:42 UTC (permalink / raw)
  To: LKML
  Cc: Frederic Weisbecker, Sebastian Andrzej Siewior, Ahmed S. Darwish,
	Peter Zijlstra, Denis Kirjanov, David S. Miller, Jakub Kicinski,
	netdev, ath9k-devel, Kalle Valo, linux-wireless, Chas Williams,
	linux-atm-general, K. Y. Srinivasan, Haiyang Zhang,
	Stephen Hemminger, Wei Liu, Lorenzo Pieralisi, Rob Herring,
	Bjorn Helgaas, linux-hyperv, linux-pci, Stefan Richter,
	linux1394-devel

To ease the transition use spin waiting in tasklet_disable() until all
usage sites from atomic context have been cleaned up.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
---
 include/linux/interrupt.h |    3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

--- a/include/linux/interrupt.h
+++ b/include/linux/interrupt.h
@@ -728,7 +728,8 @@ static inline void tasklet_disable_in_at
 static inline void tasklet_disable(struct tasklet_struct *t)
 {
 	tasklet_disable_nosync(t);
-	tasklet_unlock_wait(t);
+	/* Spin wait until all atomic users are converted */
+	tasklet_unlock_spin_wait(t);
 	smp_mb();
 }
 


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

* [patch 05/14] tasklets: Replace spin wait in tasklet_unlock_wait()
  2021-03-09  8:42 [patch 00/14] tasklets: Replace the spin wait loops and make it RT safe Thomas Gleixner
                   ` (3 preceding siblings ...)
  2021-03-09  8:42 ` [patch 04/14] tasklets: Use spin wait in tasklet_disable() temporarily Thomas Gleixner
@ 2021-03-09  8:42 ` Thomas Gleixner
  2021-03-17 15:48   ` [tip: irq/core] " tip-bot2 for Peter Zijlstra
  2021-03-09  8:42 ` [patch 06/14] tasklets: Replace spin wait in tasklet_kill() Thomas Gleixner
                   ` (9 subsequent siblings)
  14 siblings, 1 reply; 36+ messages in thread
From: Thomas Gleixner @ 2021-03-09  8:42 UTC (permalink / raw)
  To: LKML
  Cc: Frederic Weisbecker, Sebastian Andrzej Siewior, Ahmed S. Darwish,
	Peter Zijlstra, Denis Kirjanov, David S. Miller, Jakub Kicinski,
	netdev, ath9k-devel, Kalle Valo, linux-wireless, Chas Williams,
	linux-atm-general, K. Y. Srinivasan, Haiyang Zhang,
	Stephen Hemminger, Wei Liu, Lorenzo Pieralisi, Rob Herring,
	Bjorn Helgaas, linux-hyperv, linux-pci, Stefan Richter,
	linux1394-devel

From: Peter Zijlstra <peterz@infradead.org>

tasklet_unlock_wait() spin waits for TASKLET_STATE_RUN to be cleared. This
is wasting CPU cycles in a tight loop which is especially painful in a
guest when the CPU running the tasklet is scheduled out.

tasklet_unlock_wait() is invoked from tasklet_kill() which is used in
teardown paths and not performance critical at all. Replace the spin wait
with wait_var_event().

There are no users of tasklet_unlock_wait() which are invoked from atomic
contexts. The usage in tasklet_disable() has been replaced temporarily with
the spin waiting variant until the atomic users are fixed up and will be
converted to the sleep wait variant later.

Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
---
 include/linux/interrupt.h |   13 ++-----------
 kernel/softirq.c          |   18 ++++++++++++++++++
 2 files changed, 20 insertions(+), 11 deletions(-)

--- a/include/linux/interrupt.h
+++ b/include/linux/interrupt.h
@@ -664,17 +664,8 @@ static inline int tasklet_trylock(struct
 	return !test_and_set_bit(TASKLET_STATE_RUN, &(t)->state);
 }
 
-static inline void tasklet_unlock(struct tasklet_struct *t)
-{
-	smp_mb__before_atomic();
-	clear_bit(TASKLET_STATE_RUN, &(t)->state);
-}
-
-static inline void tasklet_unlock_wait(struct tasklet_struct *t)
-{
-	while (test_bit(TASKLET_STATE_RUN, &t->state))
-		cpu_relax();
-}
+void tasklet_unlock(struct tasklet_struct *t);
+void tasklet_unlock_wait(struct tasklet_struct *t);
 
 /*
  * Do not use in new code. Waiting for tasklets from atomic contexts is
--- a/kernel/softirq.c
+++ b/kernel/softirq.c
@@ -25,6 +25,7 @@
 #include <linux/smpboot.h>
 #include <linux/tick.h>
 #include <linux/irq.h>
+#include <linux/wait_bit.h>
 
 #include <asm/softirq_stack.h>
 
@@ -621,6 +622,23 @@ void tasklet_kill(struct tasklet_struct
 }
 EXPORT_SYMBOL(tasklet_kill);
 
+#ifdef CONFIG_SMP
+void tasklet_unlock(struct tasklet_struct *t)
+{
+	smp_mb__before_atomic();
+	clear_bit(TASKLET_STATE_RUN, &t->state);
+	smp_mb__after_atomic();
+	wake_up_var(&t->state);
+}
+EXPORT_SYMBOL_GPL(tasklet_unlock);
+
+void tasklet_unlock_wait(struct tasklet_struct *t)
+{
+	wait_var_event(&t->state, !test_bit(TASKLET_STATE_RUN, &t->state));
+}
+EXPORT_SYMBOL_GPL(tasklet_unlock_wait);
+#endif
+
 void __init softirq_init(void)
 {
 	int cpu;


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

* [patch 06/14] tasklets: Replace spin wait in tasklet_kill()
  2021-03-09  8:42 [patch 00/14] tasklets: Replace the spin wait loops and make it RT safe Thomas Gleixner
                   ` (4 preceding siblings ...)
  2021-03-09  8:42 ` [patch 05/14] tasklets: Replace spin wait in tasklet_unlock_wait() Thomas Gleixner
@ 2021-03-09  8:42 ` Thomas Gleixner
  2021-03-17 15:48   ` [tip: irq/core] " tip-bot2 for Peter Zijlstra
  2021-03-09  8:42 ` [patch 07/14] tasklets: Prevent tasklet_unlock_spin_wait() deadlock on RT Thomas Gleixner
                   ` (8 subsequent siblings)
  14 siblings, 1 reply; 36+ messages in thread
From: Thomas Gleixner @ 2021-03-09  8:42 UTC (permalink / raw)
  To: LKML
  Cc: Frederic Weisbecker, Sebastian Andrzej Siewior, Ahmed S. Darwish,
	Peter Zijlstra, Denis Kirjanov, David S. Miller, Jakub Kicinski,
	netdev, ath9k-devel, Kalle Valo, linux-wireless, Chas Williams,
	linux-atm-general, K. Y. Srinivasan, Haiyang Zhang,
	Stephen Hemminger, Wei Liu, Lorenzo Pieralisi, Rob Herring,
	Bjorn Helgaas, linux-hyperv, linux-pci, Stefan Richter,
	linux1394-devel

From: Peter Zijlstra <peterz@infradead.org>

tasklet_kill() spin waits for TASKLET_STATE_SCHED to be cleared invoking
yield() from inside the loop. yield() is an ill defined mechanism and the
result might still be wasting CPU cycles in a tight loop which is
especially painful in a guest when the CPU running the tasklet is scheduled
out.

tasklet_kill() is used in teardown paths and not performance critical at
all. Replace the spin wait with wait_var_event().

Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
---
 kernel/softirq.c |   23 +++++++++++++++--------
 1 file changed, 15 insertions(+), 8 deletions(-)

--- a/kernel/softirq.c
+++ b/kernel/softirq.c
@@ -532,6 +532,16 @@ void __tasklet_hi_schedule(struct taskle
 }
 EXPORT_SYMBOL(__tasklet_hi_schedule);
 
+static inline bool tasklet_clear_sched(struct tasklet_struct *t)
+{
+	if (test_and_clear_bit(TASKLET_STATE_SCHED, &t->state)) {
+		wake_up_var(&t->state);
+		return true;
+	}
+
+	return false;
+}
+
 static void tasklet_action_common(struct softirq_action *a,
 				  struct tasklet_head *tl_head,
 				  unsigned int softirq_nr)
@@ -551,8 +561,7 @@ static void tasklet_action_common(struct
 
 		if (tasklet_trylock(t)) {
 			if (!atomic_read(&t->count)) {
-				if (!test_and_clear_bit(TASKLET_STATE_SCHED,
-							&t->state))
+				if (!tasklet_clear_sched(t))
 					BUG();
 				if (t->use_callback)
 					t->callback(t);
@@ -612,13 +621,11 @@ void tasklet_kill(struct tasklet_struct
 	if (in_interrupt())
 		pr_notice("Attempt to kill tasklet from interrupt\n");
 
-	while (test_and_set_bit(TASKLET_STATE_SCHED, &t->state)) {
-		do {
-			yield();
-		} while (test_bit(TASKLET_STATE_SCHED, &t->state));
-	}
+	while (test_and_set_bit(TASKLET_STATE_SCHED, &t->state))
+		wait_var_event(&t->state, !test_bit(TASKLET_STATE_SCHED, &t->state));
+
 	tasklet_unlock_wait(t);
-	clear_bit(TASKLET_STATE_SCHED, &t->state);
+	tasklet_clear_sched(t);
 }
 EXPORT_SYMBOL(tasklet_kill);
 


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

* [patch 07/14] tasklets: Prevent tasklet_unlock_spin_wait() deadlock on RT
  2021-03-09  8:42 [patch 00/14] tasklets: Replace the spin wait loops and make it RT safe Thomas Gleixner
                   ` (5 preceding siblings ...)
  2021-03-09  8:42 ` [patch 06/14] tasklets: Replace spin wait in tasklet_kill() Thomas Gleixner
@ 2021-03-09  8:42 ` Thomas Gleixner
  2021-03-09 15:00   ` Sebastian Andrzej Siewior
  2021-03-17 15:48   ` [tip: irq/core] " tip-bot2 for Thomas Gleixner
  2021-03-09  8:42 ` [patch 08/14] net: jme: Replace link-change tasklet with work Thomas Gleixner
                   ` (7 subsequent siblings)
  14 siblings, 2 replies; 36+ messages in thread
From: Thomas Gleixner @ 2021-03-09  8:42 UTC (permalink / raw)
  To: LKML
  Cc: Frederic Weisbecker, Sebastian Andrzej Siewior, Ahmed S. Darwish,
	Peter Zijlstra, Denis Kirjanov, David S. Miller, Jakub Kicinski,
	netdev, ath9k-devel, Kalle Valo, linux-wireless, Chas Williams,
	linux-atm-general, K. Y. Srinivasan, Haiyang Zhang,
	Stephen Hemminger, Wei Liu, Lorenzo Pieralisi, Rob Herring,
	Bjorn Helgaas, linux-hyperv, linux-pci, Stefan Richter,
	linux1394-devel

tasklet_unlock_spin_wait() spin waits for the TASKLET_STATE_SCHED bit in
the tasklet state to be cleared. This works on !RT nicely because the
corresponding execution can only happen on a different CPU.

On RT softirq processing is preemptible, therefore a task preempting the
softirq processing thread can spin forever.

Prevent this by invoking local_bh_disable()/enable() inside the loop. In
case that the softirq processing thread was preempted by the current task,
current will block on the local lock which yields the CPU to the preempted
softirq processing thread. If the tasklet is processed on a different CPU
then the local_bh_disable()/enable() pair is just a waste of processor
cycles.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Tested-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
---
 include/linux/interrupt.h |    2 +-
 kernel/softirq.c          |   28 +++++++++++++++++++++++++++-
 2 files changed, 28 insertions(+), 2 deletions(-)

--- a/include/linux/interrupt.h
+++ b/include/linux/interrupt.h
@@ -658,7 +658,7 @@ enum
 	TASKLET_STATE_RUN	/* Tasklet is running (SMP only) */
 };
 
-#ifdef CONFIG_SMP
+#if defined(CONFIG_SMP) || defined(CONFIG_PREEMPT_RT)
 static inline int tasklet_trylock(struct tasklet_struct *t)
 {
 	return !test_and_set_bit(TASKLET_STATE_RUN, &(t)->state);
--- a/kernel/softirq.c
+++ b/kernel/softirq.c
@@ -616,6 +616,32 @@ void tasklet_init(struct tasklet_struct
 }
 EXPORT_SYMBOL(tasklet_init);
 
+#if defined(CONFIG_SMP) || defined(CONFIG_PREEMPT_RT)
+/*
+ * Do not use in new code. There is no real reason to invoke this from
+ * atomic contexts.
+ */
+void tasklet_unlock_spin_wait(struct tasklet_struct *t)
+{
+	while (test_bit(TASKLET_STATE_RUN, &(t)->state)) {
+		if (IS_ENABLED(CONFIG_PREEMPT_RT)) {
+			/*
+			 * Prevent a live lock when current preempted soft
+			 * interrupt processing or prevents ksoftirqd from
+			 * running. If the tasklet runs on a different CPU
+			 * then this has no effect other than doing the BH
+			 * disable/enable dance for nothing.
+			 */
+			local_bh_disable();
+			local_bh_enable();
+		} else {
+			cpu_relax();
+		}
+	}
+}
+EXPORT_SYMBOL(tasklet_unlock_spin_wait);
+#endif
+
 void tasklet_kill(struct tasklet_struct *t)
 {
 	if (in_interrupt())
@@ -629,7 +655,7 @@ void tasklet_kill(struct tasklet_struct
 }
 EXPORT_SYMBOL(tasklet_kill);
 
-#ifdef CONFIG_SMP
+#if defined(CONFIG_SMP) || defined(CONFIG_PREEMPT_RT)
 void tasklet_unlock(struct tasklet_struct *t)
 {
 	smp_mb__before_atomic();


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

* [patch 08/14] net: jme: Replace link-change tasklet with work
  2021-03-09  8:42 [patch 00/14] tasklets: Replace the spin wait loops and make it RT safe Thomas Gleixner
                   ` (6 preceding siblings ...)
  2021-03-09  8:42 ` [patch 07/14] tasklets: Prevent tasklet_unlock_spin_wait() deadlock on RT Thomas Gleixner
@ 2021-03-09  8:42 ` Thomas Gleixner
  2021-03-17 15:48   ` [tip: irq/core] " tip-bot2 for Sebastian Andrzej Siewior
  2021-03-09  8:42 ` [patch 09/14] net: sundance: Use tasklet_disable_in_atomic() Thomas Gleixner
                   ` (6 subsequent siblings)
  14 siblings, 1 reply; 36+ messages in thread
From: Thomas Gleixner @ 2021-03-09  8:42 UTC (permalink / raw)
  To: LKML
  Cc: Frederic Weisbecker, Sebastian Andrzej Siewior, Ahmed S. Darwish,
	Peter Zijlstra, Denis Kirjanov, David S. Miller, Jakub Kicinski,
	netdev, ath9k-devel, Kalle Valo, linux-wireless, Chas Williams,
	linux-atm-general, K. Y. Srinivasan, Haiyang Zhang,
	Stephen Hemminger, Wei Liu, Lorenzo Pieralisi, Rob Herring,
	Bjorn Helgaas, linux-hyperv, linux-pci, Stefan Richter,
	linux1394-devel

From: Sebastian Andrzej Siewior <bigeasy@linutronix.de>

The link change tasklet disables the tasklets for tx/rx processing while
upating hw parameters and then enables the tasklets again.

This update can also be pushed into a workqueue where it can be performed
in preemptible context. This allows tasklet_disable() to become sleeping.

Replace the linkch_task tasklet with a work.

Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
---
 drivers/net/ethernet/jme.c |   10 +++++-----
 drivers/net/ethernet/jme.h |    2 +-
 2 files changed, 6 insertions(+), 6 deletions(-)

--- a/drivers/net/ethernet/jme.c
+++ b/drivers/net/ethernet/jme.c
@@ -1265,9 +1265,9 @@ jme_stop_shutdown_timer(struct jme_adapt
 	jwrite32f(jme, JME_APMC, apmc);
 }
 
-static void jme_link_change_tasklet(struct tasklet_struct *t)
+static void jme_link_change_work(struct work_struct *work)
 {
-	struct jme_adapter *jme = from_tasklet(jme, t, linkch_task);
+	struct jme_adapter *jme = container_of(work, struct jme_adapter, linkch_task);
 	struct net_device *netdev = jme->dev;
 	int rc;
 
@@ -1510,7 +1510,7 @@ jme_intr_msi(struct jme_adapter *jme, u3
 		 * all other events are ignored
 		 */
 		jwrite32(jme, JME_IEVE, intrstat);
-		tasklet_schedule(&jme->linkch_task);
+		schedule_work(&jme->linkch_task);
 		goto out_reenable;
 	}
 
@@ -1832,7 +1832,6 @@ jme_open(struct net_device *netdev)
 	jme_clear_pm_disable_wol(jme);
 	JME_NAPI_ENABLE(jme);
 
-	tasklet_setup(&jme->linkch_task, jme_link_change_tasklet);
 	tasklet_setup(&jme->txclean_task, jme_tx_clean_tasklet);
 	tasklet_setup(&jme->rxclean_task, jme_rx_clean_tasklet);
 	tasklet_setup(&jme->rxempty_task, jme_rx_empty_tasklet);
@@ -1920,7 +1919,7 @@ jme_close(struct net_device *netdev)
 
 	JME_NAPI_DISABLE(jme);
 
-	tasklet_kill(&jme->linkch_task);
+	cancel_work_sync(&jme->linkch_task);
 	tasklet_kill(&jme->txclean_task);
 	tasklet_kill(&jme->rxclean_task);
 	tasklet_kill(&jme->rxempty_task);
@@ -3035,6 +3034,7 @@ jme_init_one(struct pci_dev *pdev,
 	atomic_set(&jme->rx_empty, 1);
 
 	tasklet_setup(&jme->pcc_task, jme_pcc_tasklet);
+	INIT_WORK(&jme->linkch_task, jme_link_change_work);
 	jme->dpi.cur = PCC_P1;
 
 	jme->reg_ghc = 0;
--- a/drivers/net/ethernet/jme.h
+++ b/drivers/net/ethernet/jme.h
@@ -411,7 +411,7 @@ struct jme_adapter {
 	struct tasklet_struct	rxempty_task;
 	struct tasklet_struct	rxclean_task;
 	struct tasklet_struct	txclean_task;
-	struct tasklet_struct	linkch_task;
+	struct work_struct	linkch_task;
 	struct tasklet_struct	pcc_task;
 	unsigned long		flags;
 	u32			reg_txcs;


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

* [patch 09/14] net: sundance: Use tasklet_disable_in_atomic().
  2021-03-09  8:42 [patch 00/14] tasklets: Replace the spin wait loops and make it RT safe Thomas Gleixner
                   ` (7 preceding siblings ...)
  2021-03-09  8:42 ` [patch 08/14] net: jme: Replace link-change tasklet with work Thomas Gleixner
@ 2021-03-09  8:42 ` Thomas Gleixner
  2021-03-17 15:48   ` [tip: irq/core] " tip-bot2 for Sebastian Andrzej Siewior
  2021-03-09  8:42 ` [patch 10/14] ath9k: " Thomas Gleixner
                   ` (5 subsequent siblings)
  14 siblings, 1 reply; 36+ messages in thread
From: Thomas Gleixner @ 2021-03-09  8:42 UTC (permalink / raw)
  To: LKML
  Cc: Frederic Weisbecker, Sebastian Andrzej Siewior, Ahmed S. Darwish,
	Denis Kirjanov, David S. Miller, Jakub Kicinski, netdev,
	Peter Zijlstra, ath9k-devel, Kalle Valo, linux-wireless,
	Chas Williams, linux-atm-general, K. Y. Srinivasan,
	Haiyang Zhang, Stephen Hemminger, Wei Liu, Lorenzo Pieralisi,
	Rob Herring, Bjorn Helgaas, linux-hyperv, linux-pci,
	Stefan Richter, linux1394-devel

From: Sebastian Andrzej Siewior <bigeasy@linutronix.de>

tasklet_disable() is used in the timer callback. This might be distangled,
but without access to the hardware that's a bit risky.

Replace it with tasklet_disable_in_atomic() so tasklet_disable() can be
changed to a sleep wait once all remaining atomic users are converted.

Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Cc: Denis Kirjanov <kda@linux-powerpc.org>
Cc: "David S. Miller" <davem@davemloft.net>
Cc: Jakub Kicinski <kuba@kernel.org>
Cc: netdev@vger.kernel.org
---
 drivers/net/ethernet/dlink/sundance.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

--- a/drivers/net/ethernet/dlink/sundance.c
+++ b/drivers/net/ethernet/dlink/sundance.c
@@ -963,7 +963,7 @@ static void tx_timeout(struct net_device
 	unsigned long flag;
 
 	netif_stop_queue(dev);
-	tasklet_disable(&np->tx_tasklet);
+	tasklet_disable_in_atomic(&np->tx_tasklet);
 	iowrite16(0, ioaddr + IntrEnable);
 	printk(KERN_WARNING "%s: Transmit timed out, TxStatus %2.2x "
 		   "TxFrameId %2.2x,"


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

* [patch 10/14] ath9k: Use tasklet_disable_in_atomic()
  2021-03-09  8:42 [patch 00/14] tasklets: Replace the spin wait loops and make it RT safe Thomas Gleixner
                   ` (8 preceding siblings ...)
  2021-03-09  8:42 ` [patch 09/14] net: sundance: Use tasklet_disable_in_atomic() Thomas Gleixner
@ 2021-03-09  8:42 ` Thomas Gleixner
  2021-03-09 10:23   ` Kalle Valo
  2021-03-17 15:48   ` [tip: irq/core] " tip-bot2 for Sebastian Andrzej Siewior
  2021-03-09  8:42 ` [patch 11/14] atm: eni: Use tasklet_disable_in_atomic() in the send() callback Thomas Gleixner
                   ` (4 subsequent siblings)
  14 siblings, 2 replies; 36+ messages in thread
From: Thomas Gleixner @ 2021-03-09  8:42 UTC (permalink / raw)
  To: LKML
  Cc: Frederic Weisbecker, Sebastian Andrzej Siewior, Ahmed S. Darwish,
	ath9k-devel, Kalle Valo, David S. Miller, Jakub Kicinski,
	linux-wireless, netdev, Peter Zijlstra, Denis Kirjanov,
	Chas Williams, linux-atm-general, K. Y. Srinivasan,
	Haiyang Zhang, Stephen Hemminger, Wei Liu, Lorenzo Pieralisi,
	Rob Herring, Bjorn Helgaas, linux-hyperv, linux-pci,
	Stefan Richter, linux1394-devel

From: Sebastian Andrzej Siewior <bigeasy@linutronix.de>

All callers of ath9k_beacon_ensure_primary_slot() are preemptible /
acquire a mutex except for this callchain:

  spin_lock_bh(&sc->sc_pcu_lock);
  ath_complete_reset()
  -> ath9k_calculate_summary_state()
     -> ath9k_beacon_ensure_primary_slot()

It's unclear how that can be distangled, so use tasklet_disable_in_atomic()
for now. This allows tasklet_disable() to become sleepable once the
remaining atomic users are cleaned up.

Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Cc: ath9k-devel@qca.qualcomm.com
Cc: Kalle Valo <kvalo@codeaurora.org>
Cc: "David S. Miller" <davem@davemloft.net>
Cc: Jakub Kicinski <kuba@kernel.org>
Cc: linux-wireless@vger.kernel.org
Cc: netdev@vger.kernel.org
---
 drivers/net/wireless/ath/ath9k/beacon.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

--- a/drivers/net/wireless/ath/ath9k/beacon.c
+++ b/drivers/net/wireless/ath/ath9k/beacon.c
@@ -251,7 +251,7 @@ void ath9k_beacon_ensure_primary_slot(st
 	int first_slot = ATH_BCBUF;
 	int slot;
 
-	tasklet_disable(&sc->bcon_tasklet);
+	tasklet_disable_in_atomic(&sc->bcon_tasklet);
 
 	/* Find first taken slot. */
 	for (slot = 0; slot < ATH_BCBUF; slot++) {


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

* [patch 11/14] atm: eni: Use tasklet_disable_in_atomic() in the send() callback
  2021-03-09  8:42 [patch 00/14] tasklets: Replace the spin wait loops and make it RT safe Thomas Gleixner
                   ` (9 preceding siblings ...)
  2021-03-09  8:42 ` [patch 10/14] ath9k: " Thomas Gleixner
@ 2021-03-09  8:42 ` Thomas Gleixner
  2021-03-17 15:48   ` [tip: irq/core] " tip-bot2 for Sebastian Andrzej Siewior
  2021-03-09  8:42 ` [patch 12/14] PCI: hv: Use tasklet_disable_in_atomic() Thomas Gleixner
                   ` (3 subsequent siblings)
  14 siblings, 1 reply; 36+ messages in thread
From: Thomas Gleixner @ 2021-03-09  8:42 UTC (permalink / raw)
  To: LKML
  Cc: Frederic Weisbecker, Sebastian Andrzej Siewior, Ahmed S. Darwish,
	Chas Williams, linux-atm-general, netdev, Peter Zijlstra,
	Denis Kirjanov, David S. Miller, Jakub Kicinski, ath9k-devel,
	Kalle Valo, linux-wireless, K. Y. Srinivasan, Haiyang Zhang,
	Stephen Hemminger, Wei Liu, Lorenzo Pieralisi, Rob Herring,
	Bjorn Helgaas, linux-hyperv, linux-pci, Stefan Richter,
	linux1394-devel

From: Sebastian Andrzej Siewior <bigeasy@linutronix.de>

The atmdev_ops::send callback which calls tasklet_disable() is invoked with
bottom halfs disabled from net_device_ops::ndo_start_xmit(). All other
invocations of tasklet_disable() in this driver happen in preemptible
context.

Change the send() call to use tasklet_disable_in_atomic() which allows
tasklet_disable() to be made sleepable once the remaining atomic context
usage sites are cleaned up.

Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Cc: Chas Williams <3chas3@gmail.com>
Cc: linux-atm-general@lists.sourceforge.net
Cc: netdev@vger.kernel.org
---
 drivers/atm/eni.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

--- a/drivers/atm/eni.c
+++ b/drivers/atm/eni.c
@@ -2054,7 +2054,7 @@ static int eni_send(struct atm_vcc *vcc,
 	}
 	submitted++;
 	ATM_SKB(skb)->vcc = vcc;
-	tasklet_disable(&ENI_DEV(vcc->dev)->task);
+	tasklet_disable_in_atomic(&ENI_DEV(vcc->dev)->task);
 	res = do_tx(skb);
 	tasklet_enable(&ENI_DEV(vcc->dev)->task);
 	if (res == enq_ok) return 0;


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

* [patch 12/14] PCI: hv: Use tasklet_disable_in_atomic()
  2021-03-09  8:42 [patch 00/14] tasklets: Replace the spin wait loops and make it RT safe Thomas Gleixner
                   ` (10 preceding siblings ...)
  2021-03-09  8:42 ` [patch 11/14] atm: eni: Use tasklet_disable_in_atomic() in the send() callback Thomas Gleixner
@ 2021-03-09  8:42 ` Thomas Gleixner
  2021-03-09 22:17   ` Bjorn Helgaas
                     ` (2 more replies)
  2021-03-09  8:42 ` [patch 13/14] firewire: ohci: Use tasklet_disable_in_atomic() where required Thomas Gleixner
                   ` (2 subsequent siblings)
  14 siblings, 3 replies; 36+ messages in thread
From: Thomas Gleixner @ 2021-03-09  8:42 UTC (permalink / raw)
  To: LKML
  Cc: Frederic Weisbecker, Sebastian Andrzej Siewior, Ahmed S. Darwish,
	K. Y. Srinivasan, Haiyang Zhang, Stephen Hemminger, Wei Liu,
	Lorenzo Pieralisi, Rob Herring, Bjorn Helgaas, linux-hyperv,
	linux-pci, Peter Zijlstra, Denis Kirjanov, David S. Miller,
	Jakub Kicinski, netdev, ath9k-devel, Kalle Valo, linux-wireless,
	Chas Williams, linux-atm-general, Stefan Richter,
	linux1394-devel

From: Sebastian Andrzej Siewior <bigeasy@linutronix.de>

The hv_compose_msi_msg() callback in irq_chip::irq_compose_msi_msg is
invoked via irq_chip_compose_msi_msg(), which itself is always invoked from
atomic contexts from the guts of the interrupt core code.

There is no way to change this w/o rewriting the whole driver, so use
tasklet_disable_in_atomic() which allows to make tasklet_disable()
sleepable once the remaining atomic users are addressed.

Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Cc: "K. Y. Srinivasan" <kys@microsoft.com>
Cc: Haiyang Zhang <haiyangz@microsoft.com>
Cc: Stephen Hemminger <sthemmin@microsoft.com>
Cc: Wei Liu <wei.liu@kernel.org>
Cc: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Cc: Rob Herring <robh@kernel.org>
Cc: Bjorn Helgaas <bhelgaas@google.com>
Cc: linux-hyperv@vger.kernel.org
Cc: linux-pci@vger.kernel.org
---
 drivers/pci/controller/pci-hyperv.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

--- a/drivers/pci/controller/pci-hyperv.c
+++ b/drivers/pci/controller/pci-hyperv.c
@@ -1458,7 +1458,7 @@ static void hv_compose_msi_msg(struct ir
 	 * Prevents hv_pci_onchannelcallback() from running concurrently
 	 * in the tasklet.
 	 */
-	tasklet_disable(&channel->callback_event);
+	tasklet_disable_in_atomic(&channel->callback_event);
 
 	/*
 	 * Since this function is called with IRQ locks held, can't


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

* [patch 13/14] firewire: ohci: Use tasklet_disable_in_atomic() where required
  2021-03-09  8:42 [patch 00/14] tasklets: Replace the spin wait loops and make it RT safe Thomas Gleixner
                   ` (11 preceding siblings ...)
  2021-03-09  8:42 ` [patch 12/14] PCI: hv: Use tasklet_disable_in_atomic() Thomas Gleixner
@ 2021-03-09  8:42 ` Thomas Gleixner
  2021-03-17 15:48   ` [tip: irq/core] " tip-bot2 for Sebastian Andrzej Siewior
  2021-03-09  8:42 ` [patch 14/14] tasklets: Switch tasklet_disable() to the sleep wait variant Thomas Gleixner
  2021-03-09 14:04 ` [patch 00/14] tasklets: Replace the spin wait loops and make it RT safe Peter Zijlstra
  14 siblings, 1 reply; 36+ messages in thread
From: Thomas Gleixner @ 2021-03-09  8:42 UTC (permalink / raw)
  To: LKML
  Cc: Frederic Weisbecker, Sebastian Andrzej Siewior, Ahmed S. Darwish,
	Stefan Richter, linux1394-devel, Peter Zijlstra, Denis Kirjanov,
	David S. Miller, Jakub Kicinski, netdev, ath9k-devel, Kalle Valo,
	linux-wireless, Chas Williams, linux-atm-general,
	K. Y. Srinivasan, Haiyang Zhang, Stephen Hemminger, Wei Liu,
	Lorenzo Pieralisi, Rob Herring, Bjorn Helgaas, linux-hyperv,
	linux-pci

From: Sebastian Andrzej Siewior <bigeasy@linutronix.de>

tasklet_disable() is invoked in several places. Some of them are in atomic
context which prevents a conversion of tasklet_disable() to a sleepable
function.

The atomic callchains are:

 ar_context_tasklet()
   ohci_cancel_packet()
     tasklet_disable()

 ...
   ohci_flush_iso_completions()
     tasklet_disable()

The invocation of tasklet_disable() from at_context_flush() is always in
preemptible context.

Use tasklet_disable_in_atomic() for the two invocations in
ohci_cancel_packet() and ohci_flush_iso_completions().

Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Cc: Stefan Richter <stefanr@s5r6.in-berlin.de>
Cc: linux1394-devel@lists.sourceforge.net
---
 drivers/firewire/ohci.c |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

--- a/drivers/firewire/ohci.c
+++ b/drivers/firewire/ohci.c
@@ -2545,7 +2545,7 @@ static int ohci_cancel_packet(struct fw_
 	struct driver_data *driver_data = packet->driver_data;
 	int ret = -ENOENT;
 
-	tasklet_disable(&ctx->tasklet);
+	tasklet_disable_in_atomic(&ctx->tasklet);
 
 	if (packet->ack != 0)
 		goto out;
@@ -3465,7 +3465,7 @@ static int ohci_flush_iso_completions(st
 	struct iso_context *ctx = container_of(base, struct iso_context, base);
 	int ret = 0;
 
-	tasklet_disable(&ctx->context.tasklet);
+	tasklet_disable_in_atomic(&ctx->context.tasklet);
 
 	if (!test_and_set_bit_lock(0, &ctx->flushing_completions)) {
 		context_tasklet((unsigned long)&ctx->context);


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

* [patch 14/14] tasklets: Switch tasklet_disable() to the sleep wait variant
  2021-03-09  8:42 [patch 00/14] tasklets: Replace the spin wait loops and make it RT safe Thomas Gleixner
                   ` (12 preceding siblings ...)
  2021-03-09  8:42 ` [patch 13/14] firewire: ohci: Use tasklet_disable_in_atomic() where required Thomas Gleixner
@ 2021-03-09  8:42 ` Thomas Gleixner
  2021-03-17 15:48   ` [tip: irq/core] " tip-bot2 for Thomas Gleixner
  2021-03-09 14:04 ` [patch 00/14] tasklets: Replace the spin wait loops and make it RT safe Peter Zijlstra
  14 siblings, 1 reply; 36+ messages in thread
From: Thomas Gleixner @ 2021-03-09  8:42 UTC (permalink / raw)
  To: LKML
  Cc: Frederic Weisbecker, Sebastian Andrzej Siewior, Ahmed S. Darwish,
	Peter Zijlstra, Denis Kirjanov, David S. Miller, Jakub Kicinski,
	netdev, ath9k-devel, Kalle Valo, linux-wireless, Chas Williams,
	linux-atm-general, K. Y. Srinivasan, Haiyang Zhang,
	Stephen Hemminger, Wei Liu, Lorenzo Pieralisi, Rob Herring,
	Bjorn Helgaas, linux-hyperv, linux-pci, Stefan Richter,
	linux1394-devel

 -- NOT FOR IMMEDIATE MERGING --

Now that all users of tasklet_disable() are invoked from sleepable context,
convert it to use tasklet_unlock_wait() which might sleep.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
---
 include/linux/interrupt.h |    3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

--- a/include/linux/interrupt.h
+++ b/include/linux/interrupt.h
@@ -716,8 +716,7 @@ static inline void tasklet_disable_in_at
 static inline void tasklet_disable(struct tasklet_struct *t)
 {
 	tasklet_disable_nosync(t);
-	/* Spin wait until all atomic users are converted */
-	tasklet_unlock_spin_wait(t);
+	tasklet_unlock_wait(t);
 	smp_mb();
 }
 


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

* Re: [patch 10/14] ath9k: Use tasklet_disable_in_atomic()
  2021-03-09  8:42 ` [patch 10/14] ath9k: " Thomas Gleixner
@ 2021-03-09 10:23   ` Kalle Valo
  2021-03-17 15:48   ` [tip: irq/core] " tip-bot2 for Sebastian Andrzej Siewior
  1 sibling, 0 replies; 36+ messages in thread
From: Kalle Valo @ 2021-03-09 10:23 UTC (permalink / raw)
  To: Thomas Gleixner
  Cc: LKML, Frederic Weisbecker, Sebastian Andrzej Siewior,
	Ahmed S. Darwish, ath9k-devel, David S. Miller, Jakub Kicinski,
	linux-wireless, netdev, Peter Zijlstra, Denis Kirjanov,
	Chas Williams, linux-atm-general, K. Y. Srinivasan,
	Haiyang Zhang, Stephen Hemminger, Wei Liu, Lorenzo Pieralisi,
	Rob Herring, Bjorn Helgaas, linux-hyperv, linux-pci,
	Stefan Richter, linux1394-devel

Thomas Gleixner <tglx@linutronix.de> writes:

> From: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
>
> All callers of ath9k_beacon_ensure_primary_slot() are preemptible /
> acquire a mutex except for this callchain:
>
>   spin_lock_bh(&sc->sc_pcu_lock);
>   ath_complete_reset()
>   -> ath9k_calculate_summary_state()
>      -> ath9k_beacon_ensure_primary_slot()
>
> It's unclear how that can be distangled, so use tasklet_disable_in_atomic()
> for now. This allows tasklet_disable() to become sleepable once the
> remaining atomic users are cleaned up.
>
> Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
> Cc: ath9k-devel@qca.qualcomm.com
> Cc: Kalle Valo <kvalo@codeaurora.org>
> Cc: "David S. Miller" <davem@davemloft.net>
> Cc: Jakub Kicinski <kuba@kernel.org>
> Cc: linux-wireless@vger.kernel.org
> Cc: netdev@vger.kernel.org
> ---
>  drivers/net/wireless/ath/ath9k/beacon.c |    2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)

I assume this goes via some other tree:

Acked-by: Kalle Valo <kvalo@codeaurora.org>

-- 
https://patchwork.kernel.org/project/linux-wireless/list/

https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches

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

* Re: [patch 00/14] tasklets: Replace the spin wait loops and make it RT safe
  2021-03-09  8:42 [patch 00/14] tasklets: Replace the spin wait loops and make it RT safe Thomas Gleixner
                   ` (13 preceding siblings ...)
  2021-03-09  8:42 ` [patch 14/14] tasklets: Switch tasklet_disable() to the sleep wait variant Thomas Gleixner
@ 2021-03-09 14:04 ` Peter Zijlstra
  14 siblings, 0 replies; 36+ messages in thread
From: Peter Zijlstra @ 2021-03-09 14:04 UTC (permalink / raw)
  To: Thomas Gleixner
  Cc: LKML, Frederic Weisbecker, Sebastian Andrzej Siewior,
	Ahmed S. Darwish, Denis Kirjanov, David S. Miller,
	Jakub Kicinski, netdev, ath9k-devel, Kalle Valo, linux-wireless,
	Chas Williams, linux-atm-general, K. Y. Srinivasan,
	Haiyang Zhang, Stephen Hemminger, Wei Liu, Lorenzo Pieralisi,
	Rob Herring, Bjorn Helgaas, linux-hyperv, linux-pci,
	Stefan Richter, linux1394-devel

On Tue, Mar 09, 2021 at 09:42:03AM +0100, Thomas Gleixner wrote:
> This is a follow up to the review comments of the series which makes
> softirq processing PREEMPT_RT safe:
> 
>  https://lore.kernel.org/r/20201207114743.GK3040@hirez.programming.kicks-ass.net
> 
> Peter suggested to replace the spin waiting in tasklet_disable() and
> tasklet_kill() with wait_event(). This also gets rid of the ill defined
> sched_yield() in tasklet_kill().
> 
> Analyzing all usage sites of tasklet_disable() and tasklet_unlock_wait() we
> found that most of them are safe to be converted to a sleeping wait.
> 
> Only a few instances invoke tasklet_disable() from atomic context. A few
> bugs which have been found in course of this analysis have been already
> addressed seperately.

Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org>

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

* Re: [patch 07/14] tasklets: Prevent tasklet_unlock_spin_wait() deadlock on RT
  2021-03-09  8:42 ` [patch 07/14] tasklets: Prevent tasklet_unlock_spin_wait() deadlock on RT Thomas Gleixner
@ 2021-03-09 15:00   ` Sebastian Andrzej Siewior
  2021-03-09 15:21     ` Sebastian Andrzej Siewior
  2021-03-17 15:48   ` [tip: irq/core] " tip-bot2 for Thomas Gleixner
  1 sibling, 1 reply; 36+ messages in thread
From: Sebastian Andrzej Siewior @ 2021-03-09 15:00 UTC (permalink / raw)
  To: Thomas Gleixner
  Cc: LKML, Frederic Weisbecker, Ahmed S. Darwish, Peter Zijlstra,
	Denis Kirjanov, David S. Miller, Jakub Kicinski, netdev,
	ath9k-devel, Kalle Valo, linux-wireless, Chas Williams,
	linux-atm-general, K. Y. Srinivasan, Haiyang Zhang,
	Stephen Hemminger, Wei Liu, Lorenzo Pieralisi, Rob Herring,
	Bjorn Helgaas, linux-hyperv, linux-pci, Stefan Richter,
	linux1394-devel

On 2021-03-09 09:42:10 [+0100], Thomas Gleixner wrote:
> tasklet_unlock_spin_wait() spin waits for the TASKLET_STATE_SCHED bit in
> the tasklet state to be cleared. This works on !RT nicely because the
…

Could you please fold this:

diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h
index 07c7329d21aa7..1c14ccd351091 100644
--- a/include/linux/interrupt.h
+++ b/include/linux/interrupt.h
@@ -663,15 +663,6 @@ static inline int tasklet_trylock(struct tasklet_struct *t)
 void tasklet_unlock(struct tasklet_struct *t);
 void tasklet_unlock_wait(struct tasklet_struct *t);
 
-/*
- * Do not use in new code. Waiting for tasklets from atomic contexts is
- * error prone and should be avoided.
- */
-static inline void tasklet_unlock_spin_wait(struct tasklet_struct *t)
-{
-	while (test_bit(TASKLET_STATE_RUN, &t->state))
-		cpu_relax();
-}
 #else
 static inline int tasklet_trylock(struct tasklet_struct *t) { return 1; }
 static inline void tasklet_unlock(struct tasklet_struct *t) { }
diff --git a/kernel/softirq.c b/kernel/softirq.c
index f0074f1344402..c9adc5c462485 100644
--- a/kernel/softirq.c
+++ b/kernel/softirq.c
@@ -830,8 +830,8 @@ EXPORT_SYMBOL(tasklet_init);
 
 #if defined(CONFIG_SMP) || defined(CONFIG_PREEMPT_RT)
 /*
- * Do not use in new code. There is no real reason to invoke this from
- * atomic contexts.
+ * Do not use in new code. Waiting for tasklets from atomic contexts is
+ * error prone and should be avoided.
  */
 void tasklet_unlock_spin_wait(struct tasklet_struct *t)
 {
-- 
2.30.1


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

* Re: [patch 07/14] tasklets: Prevent tasklet_unlock_spin_wait() deadlock on RT
  2021-03-09 15:00   ` Sebastian Andrzej Siewior
@ 2021-03-09 15:21     ` Sebastian Andrzej Siewior
  2021-03-10  8:35       ` Thomas Gleixner
  0 siblings, 1 reply; 36+ messages in thread
From: Sebastian Andrzej Siewior @ 2021-03-09 15:21 UTC (permalink / raw)
  To: Thomas Gleixner
  Cc: LKML, Frederic Weisbecker, Ahmed S. Darwish, Peter Zijlstra,
	Denis Kirjanov, David S. Miller, Jakub Kicinski, netdev,
	ath9k-devel, Kalle Valo, linux-wireless, Chas Williams,
	linux-atm-general, K. Y. Srinivasan, Haiyang Zhang,
	Stephen Hemminger, Wei Liu, Lorenzo Pieralisi, Rob Herring,
	Bjorn Helgaas, linux-hyperv, linux-pci, Stefan Richter,
	linux1394-devel

On 2021-03-09 16:00:37 [+0100], To Thomas Gleixner wrote:
> diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h
> index 07c7329d21aa7..1c14ccd351091 100644
> --- a/include/linux/interrupt.h
> +++ b/include/linux/interrupt.h
> @@ -663,15 +663,6 @@ static inline int tasklet_trylock(struct tasklet_struct *t)
>  void tasklet_unlock(struct tasklet_struct *t);
>  void tasklet_unlock_wait(struct tasklet_struct *t);
>  
> -/*
> - * Do not use in new code. Waiting for tasklets from atomic contexts is
> - * error prone and should be avoided.
> - */
> -static inline void tasklet_unlock_spin_wait(struct tasklet_struct *t)
> -{
> -	while (test_bit(TASKLET_STATE_RUN, &t->state))
> -		cpu_relax();
> -}

Look at that. The forward declaration for tasklet_unlock_spin_wait()
should have remained. Sorry for that.

Sebastian

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

* Re: [patch 12/14] PCI: hv: Use tasklet_disable_in_atomic()
  2021-03-09  8:42 ` [patch 12/14] PCI: hv: Use tasklet_disable_in_atomic() Thomas Gleixner
@ 2021-03-09 22:17   ` Bjorn Helgaas
  2021-03-10 11:34   ` Wei Liu
  2021-03-17 15:48   ` [tip: irq/core] " tip-bot2 for Sebastian Andrzej Siewior
  2 siblings, 0 replies; 36+ messages in thread
From: Bjorn Helgaas @ 2021-03-09 22:17 UTC (permalink / raw)
  To: Thomas Gleixner
  Cc: LKML, Frederic Weisbecker, Sebastian Andrzej Siewior,
	Ahmed S. Darwish, K. Y. Srinivasan, Haiyang Zhang,
	Stephen Hemminger, Wei Liu, Lorenzo Pieralisi, Rob Herring,
	Bjorn Helgaas, linux-hyperv, linux-pci, Peter Zijlstra,
	Denis Kirjanov, David S. Miller, Jakub Kicinski, netdev,
	ath9k-devel, Kalle Valo, linux-wireless, Chas Williams,
	linux-atm-general, Stefan Richter, linux1394-devel

On Tue, Mar 09, 2021 at 09:42:15AM +0100, Thomas Gleixner wrote:
> From: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
> 
> The hv_compose_msi_msg() callback in irq_chip::irq_compose_msi_msg is
> invoked via irq_chip_compose_msi_msg(), which itself is always invoked from
> atomic contexts from the guts of the interrupt core code.
> 
> There is no way to change this w/o rewriting the whole driver, so use
> tasklet_disable_in_atomic() which allows to make tasklet_disable()
> sleepable once the remaining atomic users are addressed.
> 
> Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
> Cc: "K. Y. Srinivasan" <kys@microsoft.com>
> Cc: Haiyang Zhang <haiyangz@microsoft.com>
> Cc: Stephen Hemminger <sthemmin@microsoft.com>
> Cc: Wei Liu <wei.liu@kernel.org>
> Cc: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
> Cc: Rob Herring <robh@kernel.org>
> Cc: Bjorn Helgaas <bhelgaas@google.com>
> Cc: linux-hyperv@vger.kernel.org
> Cc: linux-pci@vger.kernel.org

Acked-by: Bjorn Helgaas <bhelgaas@google.com>

It'd be ideal if you could merge this as a group.  Let me know if you
want me to do anything else.

> ---
>  drivers/pci/controller/pci-hyperv.c |    2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> --- a/drivers/pci/controller/pci-hyperv.c
> +++ b/drivers/pci/controller/pci-hyperv.c
> @@ -1458,7 +1458,7 @@ static void hv_compose_msi_msg(struct ir
>  	 * Prevents hv_pci_onchannelcallback() from running concurrently
>  	 * in the tasklet.
>  	 */
> -	tasklet_disable(&channel->callback_event);
> +	tasklet_disable_in_atomic(&channel->callback_event);
>  
>  	/*
>  	 * Since this function is called with IRQ locks held, can't
> 

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

* Re: [patch 07/14] tasklets: Prevent tasklet_unlock_spin_wait() deadlock on RT
  2021-03-09 15:21     ` Sebastian Andrzej Siewior
@ 2021-03-10  8:35       ` Thomas Gleixner
  0 siblings, 0 replies; 36+ messages in thread
From: Thomas Gleixner @ 2021-03-10  8:35 UTC (permalink / raw)
  To: Sebastian Andrzej Siewior
  Cc: LKML, Frederic Weisbecker, Ahmed S. Darwish, Peter Zijlstra,
	Denis Kirjanov, David S. Miller, Jakub Kicinski, netdev,
	ath9k-devel, Kalle Valo, linux-wireless, Chas Williams,
	linux-atm-general, K. Y. Srinivasan, Haiyang Zhang,
	Stephen Hemminger, Wei Liu, Lorenzo Pieralisi, Rob Herring,
	Bjorn Helgaas, linux-hyperv, linux-pci, Stefan Richter,
	linux1394-devel

On Tue, Mar 09 2021 at 16:21, Sebastian Andrzej Siewior wrote:

> On 2021-03-09 16:00:37 [+0100], To Thomas Gleixner wrote:
>> diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h
>> index 07c7329d21aa7..1c14ccd351091 100644
>> --- a/include/linux/interrupt.h
>> +++ b/include/linux/interrupt.h
>> @@ -663,15 +663,6 @@ static inline int tasklet_trylock(struct tasklet_struct *t)
>>  void tasklet_unlock(struct tasklet_struct *t);
>>  void tasklet_unlock_wait(struct tasklet_struct *t);
>>  
>> -/*
>> - * Do not use in new code. Waiting for tasklets from atomic contexts is
>> - * error prone and should be avoided.
>> - */
>> -static inline void tasklet_unlock_spin_wait(struct tasklet_struct *t)
>> -{
>> -	while (test_bit(TASKLET_STATE_RUN, &t->state))
>> -		cpu_relax();
>> -}
>
> Look at that. The forward declaration for tasklet_unlock_spin_wait()
> should have remained. Sorry for that.

No idea how I managed to mess that up and fail to notice. Brown
paperbags to the rescue.

Thanks,

        tglx

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

* Re: [patch 12/14] PCI: hv: Use tasklet_disable_in_atomic()
  2021-03-09  8:42 ` [patch 12/14] PCI: hv: Use tasklet_disable_in_atomic() Thomas Gleixner
  2021-03-09 22:17   ` Bjorn Helgaas
@ 2021-03-10 11:34   ` Wei Liu
  2021-03-17 15:48   ` [tip: irq/core] " tip-bot2 for Sebastian Andrzej Siewior
  2 siblings, 0 replies; 36+ messages in thread
From: Wei Liu @ 2021-03-10 11:34 UTC (permalink / raw)
  To: Thomas Gleixner
  Cc: LKML, Frederic Weisbecker, Sebastian Andrzej Siewior,
	Ahmed S. Darwish, K. Y. Srinivasan, Haiyang Zhang,
	Stephen Hemminger, Wei Liu, Lorenzo Pieralisi, Rob Herring,
	Bjorn Helgaas, linux-hyperv, linux-pci, Peter Zijlstra,
	Denis Kirjanov, David S. Miller, Jakub Kicinski, netdev,
	ath9k-devel, Kalle Valo, linux-wireless, Chas Williams,
	linux-atm-general, Stefan Richter, linux1394-devel

On Tue, Mar 09, 2021 at 09:42:15AM +0100, Thomas Gleixner wrote:
> From: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
> 
> The hv_compose_msi_msg() callback in irq_chip::irq_compose_msi_msg is
> invoked via irq_chip_compose_msi_msg(), which itself is always invoked from
> atomic contexts from the guts of the interrupt core code.
> 
> There is no way to change this w/o rewriting the whole driver, so use
> tasklet_disable_in_atomic() which allows to make tasklet_disable()
> sleepable once the remaining atomic users are addressed.
> 
> Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>

Acked-by: Wei Liu <wei.liu@kernel.org>

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

* [tip: irq/core] firewire: ohci: Use tasklet_disable_in_atomic() where required
  2021-03-09  8:42 ` [patch 13/14] firewire: ohci: Use tasklet_disable_in_atomic() where required Thomas Gleixner
@ 2021-03-17 15:48   ` tip-bot2 for Sebastian Andrzej Siewior
  0 siblings, 0 replies; 36+ messages in thread
From: tip-bot2 for Sebastian Andrzej Siewior @ 2021-03-17 15:48 UTC (permalink / raw)
  To: linux-tip-commits
  Cc: Sebastian Andrzej Siewior, Thomas Gleixner,
	Peter Zijlstra (Intel),
	x86, linux-kernel, maz

The following commit has been merged into the irq/core branch of tip:

Commit-ID:     f339fc16fba0167d67c4026678ef4c405bca3085
Gitweb:        https://git.kernel.org/tip/f339fc16fba0167d67c4026678ef4c405bca3085
Author:        Sebastian Andrzej Siewior <bigeasy@linutronix.de>
AuthorDate:    Tue, 09 Mar 2021 09:42:16 +01:00
Committer:     Thomas Gleixner <tglx@linutronix.de>
CommitterDate: Wed, 17 Mar 2021 16:34:05 +01:00

firewire: ohci: Use tasklet_disable_in_atomic() where required

tasklet_disable() is invoked in several places. Some of them are in atomic
context which prevents a conversion of tasklet_disable() to a sleepable
function.

The atomic callchains are:

 ar_context_tasklet()
   ohci_cancel_packet()
     tasklet_disable()

 ...
   ohci_flush_iso_completions()
     tasklet_disable()

The invocation of tasklet_disable() from at_context_flush() is always in
preemptible context.

Use tasklet_disable_in_atomic() for the two invocations in
ohci_cancel_packet() and ohci_flush_iso_completions().

Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Link: https://lore.kernel.org/r/20210309084242.616379058@linutronix.de

---
 drivers/firewire/ohci.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c
index 9811c40..17c9d82 100644
--- a/drivers/firewire/ohci.c
+++ b/drivers/firewire/ohci.c
@@ -2545,7 +2545,7 @@ static int ohci_cancel_packet(struct fw_card *card, struct fw_packet *packet)
 	struct driver_data *driver_data = packet->driver_data;
 	int ret = -ENOENT;
 
-	tasklet_disable(&ctx->tasklet);
+	tasklet_disable_in_atomic(&ctx->tasklet);
 
 	if (packet->ack != 0)
 		goto out;
@@ -3465,7 +3465,7 @@ static int ohci_flush_iso_completions(struct fw_iso_context *base)
 	struct iso_context *ctx = container_of(base, struct iso_context, base);
 	int ret = 0;
 
-	tasklet_disable(&ctx->context.tasklet);
+	tasklet_disable_in_atomic(&ctx->context.tasklet);
 
 	if (!test_and_set_bit_lock(0, &ctx->flushing_completions)) {
 		context_tasklet((unsigned long)&ctx->context);

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

* [tip: irq/core] tasklets: Switch tasklet_disable() to the sleep wait variant
  2021-03-09  8:42 ` [patch 14/14] tasklets: Switch tasklet_disable() to the sleep wait variant Thomas Gleixner
@ 2021-03-17 15:48   ` tip-bot2 for Thomas Gleixner
  0 siblings, 0 replies; 36+ messages in thread
From: tip-bot2 for Thomas Gleixner @ 2021-03-17 15:48 UTC (permalink / raw)
  To: linux-tip-commits
  Cc: Thomas Gleixner, Peter Zijlstra (Intel), x86, linux-kernel, maz

The following commit has been merged into the irq/core branch of tip:

Commit-ID:     6fd4e861250b5c89ad460a9f265caeb1bbbfc323
Gitweb:        https://git.kernel.org/tip/6fd4e861250b5c89ad460a9f265caeb1bbbfc323
Author:        Thomas Gleixner <tglx@linutronix.de>
AuthorDate:    Tue, 09 Mar 2021 09:42:17 +01:00
Committer:     Thomas Gleixner <tglx@linutronix.de>
CommitterDate: Wed, 17 Mar 2021 16:34:07 +01:00

tasklets: Switch tasklet_disable() to the sleep wait variant

 -- NOT FOR IMMEDIATE MERGING --

Now that all users of tasklet_disable() are invoked from sleepable context,
convert it to use tasklet_unlock_wait() which might sleep.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Link: https://lore.kernel.org/r/20210309084242.726452321@linutronix.de

---
 include/linux/interrupt.h | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h
index 352db93..4777850 100644
--- a/include/linux/interrupt.h
+++ b/include/linux/interrupt.h
@@ -711,8 +711,7 @@ static inline void tasklet_disable_in_atomic(struct tasklet_struct *t)
 static inline void tasklet_disable(struct tasklet_struct *t)
 {
 	tasklet_disable_nosync(t);
-	/* Spin wait until all atomic users are converted */
-	tasklet_unlock_spin_wait(t);
+	tasklet_unlock_wait(t);
 	smp_mb();
 }
 

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

* [tip: irq/core] PCI: hv: Use tasklet_disable_in_atomic()
  2021-03-09  8:42 ` [patch 12/14] PCI: hv: Use tasklet_disable_in_atomic() Thomas Gleixner
  2021-03-09 22:17   ` Bjorn Helgaas
  2021-03-10 11:34   ` Wei Liu
@ 2021-03-17 15:48   ` tip-bot2 for Sebastian Andrzej Siewior
  2 siblings, 0 replies; 36+ messages in thread
From: tip-bot2 for Sebastian Andrzej Siewior @ 2021-03-17 15:48 UTC (permalink / raw)
  To: linux-tip-commits
  Cc: Sebastian Andrzej Siewior, Thomas Gleixner, Wei Liu,
	Bjorn Helgaas, Peter Zijlstra (Intel),
	x86, linux-kernel, maz

The following commit has been merged into the irq/core branch of tip:

Commit-ID:     be4017cea0aec6369275df7eafbb09682f810e7e
Gitweb:        https://git.kernel.org/tip/be4017cea0aec6369275df7eafbb09682f810e7e
Author:        Sebastian Andrzej Siewior <bigeasy@linutronix.de>
AuthorDate:    Tue, 09 Mar 2021 09:42:15 +01:00
Committer:     Thomas Gleixner <tglx@linutronix.de>
CommitterDate: Wed, 17 Mar 2021 16:34:03 +01:00

PCI: hv: Use tasklet_disable_in_atomic()

The hv_compose_msi_msg() callback in irq_chip::irq_compose_msi_msg is
invoked via irq_chip_compose_msi_msg(), which itself is always invoked from
atomic contexts from the guts of the interrupt core code.

There is no way to change this w/o rewriting the whole driver, so use
tasklet_disable_in_atomic() which allows to make tasklet_disable()
sleepable once the remaining atomic users are addressed.

Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Acked-by: Wei Liu <wei.liu@kernel.org>
Acked-by: Bjorn Helgaas <bhelgaas@google.com>
Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Link: https://lore.kernel.org/r/20210309084242.516519290@linutronix.de

---
 drivers/pci/controller/pci-hyperv.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/pci/controller/pci-hyperv.c b/drivers/pci/controller/pci-hyperv.c
index 27a17a1..a313708 100644
--- a/drivers/pci/controller/pci-hyperv.c
+++ b/drivers/pci/controller/pci-hyperv.c
@@ -1458,7 +1458,7 @@ static void hv_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
 	 * Prevents hv_pci_onchannelcallback() from running concurrently
 	 * in the tasklet.
 	 */
-	tasklet_disable(&channel->callback_event);
+	tasklet_disable_in_atomic(&channel->callback_event);
 
 	/*
 	 * Since this function is called with IRQ locks held, can't

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

* [tip: irq/core] atm: eni: Use tasklet_disable_in_atomic() in the send() callback
  2021-03-09  8:42 ` [patch 11/14] atm: eni: Use tasklet_disable_in_atomic() in the send() callback Thomas Gleixner
@ 2021-03-17 15:48   ` tip-bot2 for Sebastian Andrzej Siewior
  0 siblings, 0 replies; 36+ messages in thread
From: tip-bot2 for Sebastian Andrzej Siewior @ 2021-03-17 15:48 UTC (permalink / raw)
  To: linux-tip-commits
  Cc: Sebastian Andrzej Siewior, Thomas Gleixner,
	Peter Zijlstra (Intel),
	x86, linux-kernel, maz

The following commit has been merged into the irq/core branch of tip:

Commit-ID:     405698ca359a23b1ef1a502ef2bdc4597dc6da36
Gitweb:        https://git.kernel.org/tip/405698ca359a23b1ef1a502ef2bdc4597dc6da36
Author:        Sebastian Andrzej Siewior <bigeasy@linutronix.de>
AuthorDate:    Tue, 09 Mar 2021 09:42:14 +01:00
Committer:     Thomas Gleixner <tglx@linutronix.de>
CommitterDate: Wed, 17 Mar 2021 16:34:02 +01:00

atm: eni: Use tasklet_disable_in_atomic() in the send() callback

The atmdev_ops::send callback which calls tasklet_disable() is invoked with
bottom halfs disabled from net_device_ops::ndo_start_xmit(). All other
invocations of tasklet_disable() in this driver happen in preemptible
context.

Change the send() call to use tasklet_disable_in_atomic() which allows
tasklet_disable() to be made sleepable once the remaining atomic context
usage sites are cleaned up.

Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Link: https://lore.kernel.org/r/20210309084242.415583839@linutronix.de

---
 drivers/atm/eni.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/atm/eni.c b/drivers/atm/eni.c
index 316a994..e96a4e8 100644
--- a/drivers/atm/eni.c
+++ b/drivers/atm/eni.c
@@ -2054,7 +2054,7 @@ static int eni_send(struct atm_vcc *vcc,struct sk_buff *skb)
 	}
 	submitted++;
 	ATM_SKB(skb)->vcc = vcc;
-	tasklet_disable(&ENI_DEV(vcc->dev)->task);
+	tasklet_disable_in_atomic(&ENI_DEV(vcc->dev)->task);
 	res = do_tx(skb);
 	tasklet_enable(&ENI_DEV(vcc->dev)->task);
 	if (res == enq_ok) return 0;

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

* [tip: irq/core] ath9k: Use tasklet_disable_in_atomic()
  2021-03-09  8:42 ` [patch 10/14] ath9k: " Thomas Gleixner
  2021-03-09 10:23   ` Kalle Valo
@ 2021-03-17 15:48   ` tip-bot2 for Sebastian Andrzej Siewior
  1 sibling, 0 replies; 36+ messages in thread
From: tip-bot2 for Sebastian Andrzej Siewior @ 2021-03-17 15:48 UTC (permalink / raw)
  To: linux-tip-commits
  Cc: Sebastian Andrzej Siewior, Thomas Gleixner, Kalle Valo,
	Peter Zijlstra (Intel),
	x86, linux-kernel, maz

The following commit has been merged into the irq/core branch of tip:

Commit-ID:     3250aa8a293b1859d76577714a3e1fe95732c721
Gitweb:        https://git.kernel.org/tip/3250aa8a293b1859d76577714a3e1fe95732c721
Author:        Sebastian Andrzej Siewior <bigeasy@linutronix.de>
AuthorDate:    Tue, 09 Mar 2021 09:42:13 +01:00
Committer:     Thomas Gleixner <tglx@linutronix.de>
CommitterDate: Wed, 17 Mar 2021 16:34:02 +01:00

ath9k: Use tasklet_disable_in_atomic()

All callers of ath9k_beacon_ensure_primary_slot() are preemptible /
acquire a mutex except for this callchain:

  spin_lock_bh(&sc->sc_pcu_lock);
  ath_complete_reset()
  -> ath9k_calculate_summary_state()
     -> ath9k_beacon_ensure_primary_slot()

It's unclear how that can be distangled, so use tasklet_disable_in_atomic()
for now. This allows tasklet_disable() to become sleepable once the
remaining atomic users are cleaned up.

Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Acked-by: Kalle Valo <kvalo@codeaurora.org>
Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Link: https://lore.kernel.org/r/20210309084242.313899703@linutronix.de

---
 drivers/net/wireless/ath/ath9k/beacon.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c
index 71e2ada..72e2e71 100644
--- a/drivers/net/wireless/ath/ath9k/beacon.c
+++ b/drivers/net/wireless/ath/ath9k/beacon.c
@@ -251,7 +251,7 @@ void ath9k_beacon_ensure_primary_slot(struct ath_softc *sc)
 	int first_slot = ATH_BCBUF;
 	int slot;
 
-	tasklet_disable(&sc->bcon_tasklet);
+	tasklet_disable_in_atomic(&sc->bcon_tasklet);
 
 	/* Find first taken slot. */
 	for (slot = 0; slot < ATH_BCBUF; slot++) {

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

* [tip: irq/core] net: jme: Replace link-change tasklet with work
  2021-03-09  8:42 ` [patch 08/14] net: jme: Replace link-change tasklet with work Thomas Gleixner
@ 2021-03-17 15:48   ` tip-bot2 for Sebastian Andrzej Siewior
  0 siblings, 0 replies; 36+ messages in thread
From: tip-bot2 for Sebastian Andrzej Siewior @ 2021-03-17 15:48 UTC (permalink / raw)
  To: linux-tip-commits
  Cc: Sebastian Andrzej Siewior, Thomas Gleixner,
	Peter Zijlstra (Intel),
	x86, linux-kernel, maz

The following commit has been merged into the irq/core branch of tip:

Commit-ID:     c62c38e349c73cad90f59f00fe8070b3648b6d08
Gitweb:        https://git.kernel.org/tip/c62c38e349c73cad90f59f00fe8070b3648b6d08
Author:        Sebastian Andrzej Siewior <bigeasy@linutronix.de>
AuthorDate:    Tue, 09 Mar 2021 09:42:11 +01:00
Committer:     Thomas Gleixner <tglx@linutronix.de>
CommitterDate: Wed, 17 Mar 2021 16:33:58 +01:00

net: jme: Replace link-change tasklet with work

The link change tasklet disables the tasklets for tx/rx processing while
upating hw parameters and then enables the tasklets again.

This update can also be pushed into a workqueue where it can be performed
in preemptible context. This allows tasklet_disable() to become sleeping.

Replace the linkch_task tasklet with a work.

Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Link: https://lore.kernel.org/r/20210309084242.106288922@linutronix.de

---
 drivers/net/ethernet/jme.c | 10 +++++-----
 drivers/net/ethernet/jme.h |  2 +-
 2 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/drivers/net/ethernet/jme.c b/drivers/net/ethernet/jme.c
index e9efe07..f1b9284 100644
--- a/drivers/net/ethernet/jme.c
+++ b/drivers/net/ethernet/jme.c
@@ -1265,9 +1265,9 @@ jme_stop_shutdown_timer(struct jme_adapter *jme)
 	jwrite32f(jme, JME_APMC, apmc);
 }
 
-static void jme_link_change_tasklet(struct tasklet_struct *t)
+static void jme_link_change_work(struct work_struct *work)
 {
-	struct jme_adapter *jme = from_tasklet(jme, t, linkch_task);
+	struct jme_adapter *jme = container_of(work, struct jme_adapter, linkch_task);
 	struct net_device *netdev = jme->dev;
 	int rc;
 
@@ -1510,7 +1510,7 @@ jme_intr_msi(struct jme_adapter *jme, u32 intrstat)
 		 * all other events are ignored
 		 */
 		jwrite32(jme, JME_IEVE, intrstat);
-		tasklet_schedule(&jme->linkch_task);
+		schedule_work(&jme->linkch_task);
 		goto out_reenable;
 	}
 
@@ -1832,7 +1832,6 @@ jme_open(struct net_device *netdev)
 	jme_clear_pm_disable_wol(jme);
 	JME_NAPI_ENABLE(jme);
 
-	tasklet_setup(&jme->linkch_task, jme_link_change_tasklet);
 	tasklet_setup(&jme->txclean_task, jme_tx_clean_tasklet);
 	tasklet_setup(&jme->rxclean_task, jme_rx_clean_tasklet);
 	tasklet_setup(&jme->rxempty_task, jme_rx_empty_tasklet);
@@ -1920,7 +1919,7 @@ jme_close(struct net_device *netdev)
 
 	JME_NAPI_DISABLE(jme);
 
-	tasklet_kill(&jme->linkch_task);
+	cancel_work_sync(&jme->linkch_task);
 	tasklet_kill(&jme->txclean_task);
 	tasklet_kill(&jme->rxclean_task);
 	tasklet_kill(&jme->rxempty_task);
@@ -3035,6 +3034,7 @@ jme_init_one(struct pci_dev *pdev,
 	atomic_set(&jme->rx_empty, 1);
 
 	tasklet_setup(&jme->pcc_task, jme_pcc_tasklet);
+	INIT_WORK(&jme->linkch_task, jme_link_change_work);
 	jme->dpi.cur = PCC_P1;
 
 	jme->reg_ghc = 0;
diff --git a/drivers/net/ethernet/jme.h b/drivers/net/ethernet/jme.h
index a2c3b00..2af7632 100644
--- a/drivers/net/ethernet/jme.h
+++ b/drivers/net/ethernet/jme.h
@@ -411,7 +411,7 @@ struct jme_adapter {
 	struct tasklet_struct	rxempty_task;
 	struct tasklet_struct	rxclean_task;
 	struct tasklet_struct	txclean_task;
-	struct tasklet_struct	linkch_task;
+	struct work_struct	linkch_task;
 	struct tasklet_struct	pcc_task;
 	unsigned long		flags;
 	u32			reg_txcs;

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

* [tip: irq/core] tasklets: Prevent tasklet_unlock_spin_wait() deadlock on RT
  2021-03-09  8:42 ` [patch 07/14] tasklets: Prevent tasklet_unlock_spin_wait() deadlock on RT Thomas Gleixner
  2021-03-09 15:00   ` Sebastian Andrzej Siewior
@ 2021-03-17 15:48   ` tip-bot2 for Thomas Gleixner
  1 sibling, 0 replies; 36+ messages in thread
From: tip-bot2 for Thomas Gleixner @ 2021-03-17 15:48 UTC (permalink / raw)
  To: linux-tip-commits
  Cc: Thomas Gleixner, Sebastian Andrzej Siewior,
	Peter Zijlstra (Intel),
	x86, linux-kernel, maz

The following commit has been merged into the irq/core branch of tip:

Commit-ID:     eb2dafbba8b824ee77f166629babd470dd0b1c0a
Gitweb:        https://git.kernel.org/tip/eb2dafbba8b824ee77f166629babd470dd0b1c0a
Author:        Thomas Gleixner <tglx@linutronix.de>
AuthorDate:    Tue, 09 Mar 2021 09:42:10 +01:00
Committer:     Thomas Gleixner <tglx@linutronix.de>
CommitterDate: Wed, 17 Mar 2021 16:33:57 +01:00

tasklets: Prevent tasklet_unlock_spin_wait() deadlock on RT

tasklet_unlock_spin_wait() spin waits for the TASKLET_STATE_SCHED bit in
the tasklet state to be cleared. This works on !RT nicely because the
corresponding execution can only happen on a different CPU.

On RT softirq processing is preemptible, therefore a task preempting the
softirq processing thread can spin forever.

Prevent this by invoking local_bh_disable()/enable() inside the loop. In
case that the softirq processing thread was preempted by the current task,
current will block on the local lock which yields the CPU to the preempted
softirq processing thread. If the tasklet is processed on a different CPU
then the local_bh_disable()/enable() pair is just a waste of processor
cycles.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Tested-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Link: https://lore.kernel.org/r/20210309084241.988908275@linutronix.de

---
 include/linux/interrupt.h | 12 ++----------
 kernel/softirq.c          | 28 +++++++++++++++++++++++++++-
 2 files changed, 29 insertions(+), 11 deletions(-)

diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h
index b50be4f..352db93 100644
--- a/include/linux/interrupt.h
+++ b/include/linux/interrupt.h
@@ -658,7 +658,7 @@ enum
 	TASKLET_STATE_RUN	/* Tasklet is running (SMP only) */
 };
 
-#ifdef CONFIG_SMP
+#if defined(CONFIG_SMP) || defined(CONFIG_PREEMPT_RT)
 static inline int tasklet_trylock(struct tasklet_struct *t)
 {
 	return !test_and_set_bit(TASKLET_STATE_RUN, &(t)->state);
@@ -666,16 +666,8 @@ static inline int tasklet_trylock(struct tasklet_struct *t)
 
 void tasklet_unlock(struct tasklet_struct *t);
 void tasklet_unlock_wait(struct tasklet_struct *t);
+void tasklet_unlock_spin_wait(struct tasklet_struct *t);
 
-/*
- * Do not use in new code. Waiting for tasklets from atomic contexts is
- * error prone and should be avoided.
- */
-static inline void tasklet_unlock_spin_wait(struct tasklet_struct *t)
-{
-	while (test_bit(TASKLET_STATE_RUN, &t->state))
-		cpu_relax();
-}
 #else
 static inline int tasklet_trylock(struct tasklet_struct *t) { return 1; }
 static inline void tasklet_unlock(struct tasklet_struct *t) { }
diff --git a/kernel/softirq.c b/kernel/softirq.c
index ba89ca7..f1eb83d 100644
--- a/kernel/softirq.c
+++ b/kernel/softirq.c
@@ -620,6 +620,32 @@ void tasklet_init(struct tasklet_struct *t,
 }
 EXPORT_SYMBOL(tasklet_init);
 
+#if defined(CONFIG_SMP) || defined(CONFIG_PREEMPT_RT)
+/*
+ * Do not use in new code. Waiting for tasklets from atomic contexts is
+ * error prone and should be avoided.
+ */
+void tasklet_unlock_spin_wait(struct tasklet_struct *t)
+{
+	while (test_bit(TASKLET_STATE_RUN, &(t)->state)) {
+		if (IS_ENABLED(CONFIG_PREEMPT_RT)) {
+			/*
+			 * Prevent a live lock when current preempted soft
+			 * interrupt processing or prevents ksoftirqd from
+			 * running. If the tasklet runs on a different CPU
+			 * then this has no effect other than doing the BH
+			 * disable/enable dance for nothing.
+			 */
+			local_bh_disable();
+			local_bh_enable();
+		} else {
+			cpu_relax();
+		}
+	}
+}
+EXPORT_SYMBOL(tasklet_unlock_spin_wait);
+#endif
+
 void tasklet_kill(struct tasklet_struct *t)
 {
 	if (in_interrupt())
@@ -633,7 +659,7 @@ void tasklet_kill(struct tasklet_struct *t)
 }
 EXPORT_SYMBOL(tasklet_kill);
 
-#ifdef CONFIG_SMP
+#if defined(CONFIG_SMP) || defined(CONFIG_PREEMPT_RT)
 void tasklet_unlock(struct tasklet_struct *t)
 {
 	smp_mb__before_atomic();

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

* [tip: irq/core] net: sundance: Use tasklet_disable_in_atomic().
  2021-03-09  8:42 ` [patch 09/14] net: sundance: Use tasklet_disable_in_atomic() Thomas Gleixner
@ 2021-03-17 15:48   ` tip-bot2 for Sebastian Andrzej Siewior
  0 siblings, 0 replies; 36+ messages in thread
From: tip-bot2 for Sebastian Andrzej Siewior @ 2021-03-17 15:48 UTC (permalink / raw)
  To: linux-tip-commits
  Cc: Sebastian Andrzej Siewior, Thomas Gleixner,
	Peter Zijlstra (Intel),
	x86, linux-kernel, maz

The following commit has been merged into the irq/core branch of tip:

Commit-ID:     25cf87df1a3a85959bf1bf27df0eb2e6e04b2161
Gitweb:        https://git.kernel.org/tip/25cf87df1a3a85959bf1bf27df0eb2e6e04b2161
Author:        Sebastian Andrzej Siewior <bigeasy@linutronix.de>
AuthorDate:    Tue, 09 Mar 2021 09:42:12 +01:00
Committer:     Thomas Gleixner <tglx@linutronix.de>
CommitterDate: Wed, 17 Mar 2021 16:34:00 +01:00

net: sundance: Use tasklet_disable_in_atomic().

tasklet_disable() is used in the timer callback. This might be distangled,
but without access to the hardware that's a bit risky.

Replace it with tasklet_disable_in_atomic() so tasklet_disable() can be
changed to a sleep wait once all remaining atomic users are converted.

Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Link: https://lore.kernel.org/r/20210309084242.209110861@linutronix.de

---
 drivers/net/ethernet/dlink/sundance.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/dlink/sundance.c b/drivers/net/ethernet/dlink/sundance.c
index e3a8858..df0eab4 100644
--- a/drivers/net/ethernet/dlink/sundance.c
+++ b/drivers/net/ethernet/dlink/sundance.c
@@ -963,7 +963,7 @@ static void tx_timeout(struct net_device *dev, unsigned int txqueue)
 	unsigned long flag;
 
 	netif_stop_queue(dev);
-	tasklet_disable(&np->tx_tasklet);
+	tasklet_disable_in_atomic(&np->tx_tasklet);
 	iowrite16(0, ioaddr + IntrEnable);
 	printk(KERN_WARNING "%s: Transmit timed out, TxStatus %2.2x "
 		   "TxFrameId %2.2x,"

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

* [tip: irq/core] tasklets: Replace spin wait in tasklet_kill()
  2021-03-09  8:42 ` [patch 06/14] tasklets: Replace spin wait in tasklet_kill() Thomas Gleixner
@ 2021-03-17 15:48   ` tip-bot2 for Peter Zijlstra
  0 siblings, 0 replies; 36+ messages in thread
From: tip-bot2 for Peter Zijlstra @ 2021-03-17 15:48 UTC (permalink / raw)
  To: linux-tip-commits; +Cc: Peter Zijlstra, Thomas Gleixner, x86, linux-kernel, maz

The following commit has been merged into the irq/core branch of tip:

Commit-ID:     697d8c63c4a2991a22a896a5e6adcdbb28fefe56
Gitweb:        https://git.kernel.org/tip/697d8c63c4a2991a22a896a5e6adcdbb28fefe56
Author:        Peter Zijlstra <peterz@infradead.org>
AuthorDate:    Tue, 09 Mar 2021 09:42:09 +01:00
Committer:     Thomas Gleixner <tglx@linutronix.de>
CommitterDate: Wed, 17 Mar 2021 16:33:57 +01:00

tasklets: Replace spin wait in tasklet_kill()

tasklet_kill() spin waits for TASKLET_STATE_SCHED to be cleared invoking
yield() from inside the loop. yield() is an ill defined mechanism and the
result might still be wasting CPU cycles in a tight loop which is
especially painful in a guest when the CPU running the tasklet is scheduled
out.

tasklet_kill() is used in teardown paths and not performance critical at
all. Replace the spin wait with wait_var_event().

Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Link: https://lore.kernel.org/r/20210309084241.890532921@linutronix.de

---
 kernel/softirq.c | 18 +++++++++---------
 1 file changed, 9 insertions(+), 9 deletions(-)

diff --git a/kernel/softirq.c b/kernel/softirq.c
index ef6429a..ba89ca7 100644
--- a/kernel/softirq.c
+++ b/kernel/softirq.c
@@ -532,10 +532,12 @@ void __tasklet_hi_schedule(struct tasklet_struct *t)
 }
 EXPORT_SYMBOL(__tasklet_hi_schedule);
 
-static bool tasklet_should_run(struct tasklet_struct *t)
+static bool tasklet_clear_sched(struct tasklet_struct *t)
 {
-	if (test_and_clear_bit(TASKLET_STATE_SCHED, &t->state))
+	if (test_and_clear_bit(TASKLET_STATE_SCHED, &t->state)) {
+		wake_up_var(&t->state);
 		return true;
+	}
 
 	WARN_ONCE(1, "tasklet SCHED state not set: %s %pS\n",
 		  t->use_callback ? "callback" : "func",
@@ -563,7 +565,7 @@ static void tasklet_action_common(struct softirq_action *a,
 
 		if (tasklet_trylock(t)) {
 			if (!atomic_read(&t->count)) {
-				if (tasklet_should_run(t)) {
+				if (tasklet_clear_sched(t)) {
 					if (t->use_callback)
 						t->callback(t);
 					else
@@ -623,13 +625,11 @@ void tasklet_kill(struct tasklet_struct *t)
 	if (in_interrupt())
 		pr_notice("Attempt to kill tasklet from interrupt\n");
 
-	while (test_and_set_bit(TASKLET_STATE_SCHED, &t->state)) {
-		do {
-			yield();
-		} while (test_bit(TASKLET_STATE_SCHED, &t->state));
-	}
+	while (test_and_set_bit(TASKLET_STATE_SCHED, &t->state))
+		wait_var_event(&t->state, !test_bit(TASKLET_STATE_SCHED, &t->state));
+
 	tasklet_unlock_wait(t);
-	clear_bit(TASKLET_STATE_SCHED, &t->state);
+	tasklet_clear_sched(t);
 }
 EXPORT_SYMBOL(tasklet_kill);
 

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

* [tip: irq/core] tasklets: Replace spin wait in tasklet_unlock_wait()
  2021-03-09  8:42 ` [patch 05/14] tasklets: Replace spin wait in tasklet_unlock_wait() Thomas Gleixner
@ 2021-03-17 15:48   ` tip-bot2 for Peter Zijlstra
  0 siblings, 0 replies; 36+ messages in thread
From: tip-bot2 for Peter Zijlstra @ 2021-03-17 15:48 UTC (permalink / raw)
  To: linux-tip-commits; +Cc: Peter Zijlstra, Thomas Gleixner, x86, linux-kernel, maz

The following commit has been merged into the irq/core branch of tip:

Commit-ID:     da044747401fc16202e223c9da970ed4e84fd84d
Gitweb:        https://git.kernel.org/tip/da044747401fc16202e223c9da970ed4e84fd84d
Author:        Peter Zijlstra <peterz@infradead.org>
AuthorDate:    Tue, 09 Mar 2021 09:42:08 +01:00
Committer:     Thomas Gleixner <tglx@linutronix.de>
CommitterDate: Wed, 17 Mar 2021 16:33:55 +01:00

tasklets: Replace spin wait in tasklet_unlock_wait()

tasklet_unlock_wait() spin waits for TASKLET_STATE_RUN to be cleared. This
is wasting CPU cycles in a tight loop which is especially painful in a
guest when the CPU running the tasklet is scheduled out.

tasklet_unlock_wait() is invoked from tasklet_kill() which is used in
teardown paths and not performance critical at all. Replace the spin wait
with wait_var_event().

There are no users of tasklet_unlock_wait() which are invoked from atomic
contexts. The usage in tasklet_disable() has been replaced temporarily with
the spin waiting variant until the atomic users are fixed up and will be
converted to the sleep wait variant later.

Signed-off-by: Peter Zijlstra <peterz@infradead.org>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Link: https://lore.kernel.org/r/20210309084241.783936921@linutronix.de

---
 include/linux/interrupt.h | 13 ++-----------
 kernel/softirq.c          | 18 ++++++++++++++++++
 2 files changed, 20 insertions(+), 11 deletions(-)

diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h
index b7f0012..b50be4f 100644
--- a/include/linux/interrupt.h
+++ b/include/linux/interrupt.h
@@ -664,17 +664,8 @@ static inline int tasklet_trylock(struct tasklet_struct *t)
 	return !test_and_set_bit(TASKLET_STATE_RUN, &(t)->state);
 }
 
-static inline void tasklet_unlock(struct tasklet_struct *t)
-{
-	smp_mb__before_atomic();
-	clear_bit(TASKLET_STATE_RUN, &(t)->state);
-}
-
-static inline void tasklet_unlock_wait(struct tasklet_struct *t)
-{
-	while (test_bit(TASKLET_STATE_RUN, &t->state))
-		cpu_relax();
-}
+void tasklet_unlock(struct tasklet_struct *t);
+void tasklet_unlock_wait(struct tasklet_struct *t);
 
 /*
  * Do not use in new code. Waiting for tasklets from atomic contexts is
diff --git a/kernel/softirq.c b/kernel/softirq.c
index 8d56bbf..ef6429a 100644
--- a/kernel/softirq.c
+++ b/kernel/softirq.c
@@ -25,6 +25,7 @@
 #include <linux/smpboot.h>
 #include <linux/tick.h>
 #include <linux/irq.h>
+#include <linux/wait_bit.h>
 
 #include <asm/softirq_stack.h>
 
@@ -632,6 +633,23 @@ void tasklet_kill(struct tasklet_struct *t)
 }
 EXPORT_SYMBOL(tasklet_kill);
 
+#ifdef CONFIG_SMP
+void tasklet_unlock(struct tasklet_struct *t)
+{
+	smp_mb__before_atomic();
+	clear_bit(TASKLET_STATE_RUN, &t->state);
+	smp_mb__after_atomic();
+	wake_up_var(&t->state);
+}
+EXPORT_SYMBOL_GPL(tasklet_unlock);
+
+void tasklet_unlock_wait(struct tasklet_struct *t)
+{
+	wait_var_event(&t->state, !test_bit(TASKLET_STATE_RUN, &t->state));
+}
+EXPORT_SYMBOL_GPL(tasklet_unlock_wait);
+#endif
+
 void __init softirq_init(void)
 {
 	int cpu;

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

* [tip: irq/core] tasklets: Use spin wait in tasklet_disable() temporarily
  2021-03-09  8:42 ` [patch 04/14] tasklets: Use spin wait in tasklet_disable() temporarily Thomas Gleixner
@ 2021-03-17 15:48   ` tip-bot2 for Thomas Gleixner
  0 siblings, 0 replies; 36+ messages in thread
From: tip-bot2 for Thomas Gleixner @ 2021-03-17 15:48 UTC (permalink / raw)
  To: linux-tip-commits
  Cc: Thomas Gleixner, Peter Zijlstra (Intel), x86, linux-kernel, maz

The following commit has been merged into the irq/core branch of tip:

Commit-ID:     b0cd02c2a9494dbf0a1cc7dc7a3b8b400c158d37
Gitweb:        https://git.kernel.org/tip/b0cd02c2a9494dbf0a1cc7dc7a3b8b400c158d37
Author:        Thomas Gleixner <tglx@linutronix.de>
AuthorDate:    Tue, 09 Mar 2021 09:42:07 +01:00
Committer:     Thomas Gleixner <tglx@linutronix.de>
CommitterDate: Wed, 17 Mar 2021 16:33:54 +01:00

tasklets: Use spin wait in tasklet_disable() temporarily

To ease the transition use spin waiting in tasklet_disable() until all
usage sites from atomic context have been cleaned up.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Link: https://lore.kernel.org/r/20210309084241.685352806@linutronix.de

---
 include/linux/interrupt.h | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h
index 3c8a291..b7f0012 100644
--- a/include/linux/interrupt.h
+++ b/include/linux/interrupt.h
@@ -728,7 +728,8 @@ static inline void tasklet_disable_in_atomic(struct tasklet_struct *t)
 static inline void tasklet_disable(struct tasklet_struct *t)
 {
 	tasklet_disable_nosync(t);
-	tasklet_unlock_wait(t);
+	/* Spin wait until all atomic users are converted */
+	tasklet_unlock_spin_wait(t);
 	smp_mb();
 }
 

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

* [tip: irq/core] tasklets: Use static inlines for stub implementations
  2021-03-09  8:42 ` [patch 02/14] tasklets: Use static inlines for stub implementations Thomas Gleixner
@ 2021-03-17 15:48   ` tip-bot2 for Thomas Gleixner
  0 siblings, 0 replies; 36+ messages in thread
From: tip-bot2 for Thomas Gleixner @ 2021-03-17 15:48 UTC (permalink / raw)
  To: linux-tip-commits
  Cc: Thomas Gleixner, Sebastian Andrzej Siewior,
	Peter Zijlstra (Intel),
	x86, linux-kernel, maz

The following commit has been merged into the irq/core branch of tip:

Commit-ID:     6951547a1399c8f56468ed93bea8f769b891aec3
Gitweb:        https://git.kernel.org/tip/6951547a1399c8f56468ed93bea8f769b891aec3
Author:        Thomas Gleixner <tglx@linutronix.de>
AuthorDate:    Tue, 09 Mar 2021 09:42:05 +01:00
Committer:     Thomas Gleixner <tglx@linutronix.de>
CommitterDate: Wed, 17 Mar 2021 16:33:51 +01:00

tasklets: Use static inlines for stub implementations

Inlines exist for a reason.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Tested-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Link: https://lore.kernel.org/r/20210309084241.407702697@linutronix.de

---
 include/linux/interrupt.h | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h
index d689fd7..0a4ce25 100644
--- a/include/linux/interrupt.h
+++ b/include/linux/interrupt.h
@@ -676,9 +676,9 @@ static inline void tasklet_unlock_wait(struct tasklet_struct *t)
 		cpu_relax();
 }
 #else
-#define tasklet_trylock(t) 1
-#define tasklet_unlock_wait(t) do { } while (0)
-#define tasklet_unlock(t) do { } while (0)
+static inline int tasklet_trylock(struct tasklet_struct *t) { return 1; }
+static inline void tasklet_unlock(struct tasklet_struct *t) { }
+static inline void tasklet_unlock_wait(struct tasklet_struct *t) { }
 #endif
 
 extern void __tasklet_schedule(struct tasklet_struct *t);

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

* [tip: irq/core] tasklets: Provide tasklet_disable_in_atomic()
  2021-03-09  8:42 ` [patch 03/14] tasklets: Provide tasklet_disable_in_atomic() Thomas Gleixner
@ 2021-03-17 15:48   ` tip-bot2 for Thomas Gleixner
  0 siblings, 0 replies; 36+ messages in thread
From: tip-bot2 for Thomas Gleixner @ 2021-03-17 15:48 UTC (permalink / raw)
  To: linux-tip-commits
  Cc: Thomas Gleixner, Peter Zijlstra (Intel), x86, linux-kernel, maz

The following commit has been merged into the irq/core branch of tip:

Commit-ID:     ca5f625118955fc544c3cb3dee7055d33ecadafb
Gitweb:        https://git.kernel.org/tip/ca5f625118955fc544c3cb3dee7055d33ecadafb
Author:        Thomas Gleixner <tglx@linutronix.de>
AuthorDate:    Tue, 09 Mar 2021 09:42:06 +01:00
Committer:     Thomas Gleixner <tglx@linutronix.de>
CommitterDate: Wed, 17 Mar 2021 16:33:52 +01:00

tasklets: Provide tasklet_disable_in_atomic()

Replacing the spin wait loops in tasklet_unlock_wait() with
wait_var_event() is not possible as a handful of tasklet_disable()
invocations are happening in atomic context. All other invocations are in
teardown paths which can sleep.

Provide tasklet_disable_in_atomic() and tasklet_unlock_spin_wait() to
convert the few atomic use cases over, which allows to change
tasklet_disable() and tasklet_unlock_wait() in a later step.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Link: https://lore.kernel.org/r/20210309084241.563164193@linutronix.de

---
 include/linux/interrupt.h | 22 ++++++++++++++++++++++
 1 file changed, 22 insertions(+)

diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h
index 0a4ce25..3c8a291 100644
--- a/include/linux/interrupt.h
+++ b/include/linux/interrupt.h
@@ -675,10 +675,21 @@ static inline void tasklet_unlock_wait(struct tasklet_struct *t)
 	while (test_bit(TASKLET_STATE_RUN, &t->state))
 		cpu_relax();
 }
+
+/*
+ * Do not use in new code. Waiting for tasklets from atomic contexts is
+ * error prone and should be avoided.
+ */
+static inline void tasklet_unlock_spin_wait(struct tasklet_struct *t)
+{
+	while (test_bit(TASKLET_STATE_RUN, &t->state))
+		cpu_relax();
+}
 #else
 static inline int tasklet_trylock(struct tasklet_struct *t) { return 1; }
 static inline void tasklet_unlock(struct tasklet_struct *t) { }
 static inline void tasklet_unlock_wait(struct tasklet_struct *t) { }
+static inline void tasklet_unlock_spin_wait(struct tasklet_struct *t) { }
 #endif
 
 extern void __tasklet_schedule(struct tasklet_struct *t);
@@ -703,6 +714,17 @@ static inline void tasklet_disable_nosync(struct tasklet_struct *t)
 	smp_mb__after_atomic();
 }
 
+/*
+ * Do not use in new code. Disabling tasklets from atomic contexts is
+ * error prone and should be avoided.
+ */
+static inline void tasklet_disable_in_atomic(struct tasklet_struct *t)
+{
+	tasklet_disable_nosync(t);
+	tasklet_unlock_spin_wait(t);
+	smp_mb();
+}
+
 static inline void tasklet_disable(struct tasklet_struct *t)
 {
 	tasklet_disable_nosync(t);

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

* [tip: irq/core] tasklets: Replace barrier() with cpu_relax() in tasklet_unlock_wait()
  2021-03-09  8:42 ` [patch 01/14] tasklets: Replace barrier() with cpu_relax() in tasklet_unlock_wait() Thomas Gleixner
@ 2021-03-17 15:49   ` tip-bot2 for Thomas Gleixner
  0 siblings, 0 replies; 36+ messages in thread
From: tip-bot2 for Thomas Gleixner @ 2021-03-17 15:49 UTC (permalink / raw)
  To: linux-tip-commits
  Cc: Thomas Gleixner, Sebastian Andrzej Siewior,
	Peter Zijlstra (Intel),
	x86, linux-kernel, maz

The following commit has been merged into the irq/core branch of tip:

Commit-ID:     d2da74d1278a1b51ef18beafa9da770f0db1c617
Gitweb:        https://git.kernel.org/tip/d2da74d1278a1b51ef18beafa9da770f0db1c617
Author:        Thomas Gleixner <tglx@linutronix.de>
AuthorDate:    Tue, 09 Mar 2021 09:42:04 +01:00
Committer:     Thomas Gleixner <tglx@linutronix.de>
CommitterDate: Wed, 17 Mar 2021 16:33:51 +01:00

tasklets: Replace barrier() with cpu_relax() in tasklet_unlock_wait()

A barrier() in a tight loop which waits for something to happen on a remote
CPU is a pointless exercise. Replace it with cpu_relax() which allows HT
siblings to make progress.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Tested-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Link: https://lore.kernel.org/r/20210309084241.249343366@linutronix.de

---
 include/linux/interrupt.h | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h
index 2b98156..d689fd7 100644
--- a/include/linux/interrupt.h
+++ b/include/linux/interrupt.h
@@ -672,7 +672,8 @@ static inline void tasklet_unlock(struct tasklet_struct *t)
 
 static inline void tasklet_unlock_wait(struct tasklet_struct *t)
 {
-	while (test_bit(TASKLET_STATE_RUN, &(t)->state)) { barrier(); }
+	while (test_bit(TASKLET_STATE_RUN, &t->state))
+		cpu_relax();
 }
 #else
 #define tasklet_trylock(t) 1

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

end of thread, other threads:[~2021-03-17 15:50 UTC | newest]

Thread overview: 36+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-03-09  8:42 [patch 00/14] tasklets: Replace the spin wait loops and make it RT safe Thomas Gleixner
2021-03-09  8:42 ` [patch 01/14] tasklets: Replace barrier() with cpu_relax() in tasklet_unlock_wait() Thomas Gleixner
2021-03-17 15:49   ` [tip: irq/core] " tip-bot2 for Thomas Gleixner
2021-03-09  8:42 ` [patch 02/14] tasklets: Use static inlines for stub implementations Thomas Gleixner
2021-03-17 15:48   ` [tip: irq/core] " tip-bot2 for Thomas Gleixner
2021-03-09  8:42 ` [patch 03/14] tasklets: Provide tasklet_disable_in_atomic() Thomas Gleixner
2021-03-17 15:48   ` [tip: irq/core] " tip-bot2 for Thomas Gleixner
2021-03-09  8:42 ` [patch 04/14] tasklets: Use spin wait in tasklet_disable() temporarily Thomas Gleixner
2021-03-17 15:48   ` [tip: irq/core] " tip-bot2 for Thomas Gleixner
2021-03-09  8:42 ` [patch 05/14] tasklets: Replace spin wait in tasklet_unlock_wait() Thomas Gleixner
2021-03-17 15:48   ` [tip: irq/core] " tip-bot2 for Peter Zijlstra
2021-03-09  8:42 ` [patch 06/14] tasklets: Replace spin wait in tasklet_kill() Thomas Gleixner
2021-03-17 15:48   ` [tip: irq/core] " tip-bot2 for Peter Zijlstra
2021-03-09  8:42 ` [patch 07/14] tasklets: Prevent tasklet_unlock_spin_wait() deadlock on RT Thomas Gleixner
2021-03-09 15:00   ` Sebastian Andrzej Siewior
2021-03-09 15:21     ` Sebastian Andrzej Siewior
2021-03-10  8:35       ` Thomas Gleixner
2021-03-17 15:48   ` [tip: irq/core] " tip-bot2 for Thomas Gleixner
2021-03-09  8:42 ` [patch 08/14] net: jme: Replace link-change tasklet with work Thomas Gleixner
2021-03-17 15:48   ` [tip: irq/core] " tip-bot2 for Sebastian Andrzej Siewior
2021-03-09  8:42 ` [patch 09/14] net: sundance: Use tasklet_disable_in_atomic() Thomas Gleixner
2021-03-17 15:48   ` [tip: irq/core] " tip-bot2 for Sebastian Andrzej Siewior
2021-03-09  8:42 ` [patch 10/14] ath9k: " Thomas Gleixner
2021-03-09 10:23   ` Kalle Valo
2021-03-17 15:48   ` [tip: irq/core] " tip-bot2 for Sebastian Andrzej Siewior
2021-03-09  8:42 ` [patch 11/14] atm: eni: Use tasklet_disable_in_atomic() in the send() callback Thomas Gleixner
2021-03-17 15:48   ` [tip: irq/core] " tip-bot2 for Sebastian Andrzej Siewior
2021-03-09  8:42 ` [patch 12/14] PCI: hv: Use tasklet_disable_in_atomic() Thomas Gleixner
2021-03-09 22:17   ` Bjorn Helgaas
2021-03-10 11:34   ` Wei Liu
2021-03-17 15:48   ` [tip: irq/core] " tip-bot2 for Sebastian Andrzej Siewior
2021-03-09  8:42 ` [patch 13/14] firewire: ohci: Use tasklet_disable_in_atomic() where required Thomas Gleixner
2021-03-17 15:48   ` [tip: irq/core] " tip-bot2 for Sebastian Andrzej Siewior
2021-03-09  8:42 ` [patch 14/14] tasklets: Switch tasklet_disable() to the sleep wait variant Thomas Gleixner
2021-03-17 15:48   ` [tip: irq/core] " tip-bot2 for Thomas Gleixner
2021-03-09 14:04 ` [patch 00/14] tasklets: Replace the spin wait loops and make it RT safe Peter Zijlstra

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).