linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [patch V3 0/6] softirq: Add RT specific softirq accounting
@ 2021-03-09  8:55 Thomas Gleixner
  2021-03-09  8:55 ` [patch V3 1/6] " Thomas Gleixner
                   ` (7 more replies)
  0 siblings, 8 replies; 16+ messages in thread
From: Thomas Gleixner @ 2021-03-09  8:55 UTC (permalink / raw)
  To: LKML
  Cc: Peter Zijlstra, Paul McKenney, Sebastian Andrzej Siewior,
	Frederic Weisbecker

RT runs softirq processing always in thread context and it requires that
both the softirq execution and the BH disabled sections are preemptible.

This is achieved by serialization through per CPU local locks and
substituting a few parts of the existing softirq processing code with
helper functions.

The series applies on top of

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

and is completely available from:

   git://git.kernel.org/pub/scm/linux/kernel/git/tglx/devel.git softirq

Changes to V2 which can be found here:

  https://lore.kernel.org/r/20201204170151.960336698@linutronix.de

 - Split the tasklet changes out (seperate submission)
 
 - Rebase it on the tasklet series (no further changes)

Thanks,

	tglx


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

* [patch V3 1/6] softirq: Add RT specific softirq accounting
  2021-03-09  8:55 [patch V3 0/6] softirq: Add RT specific softirq accounting Thomas Gleixner
@ 2021-03-09  8:55 ` Thomas Gleixner
  2021-03-17 15:48   ` [tip: irq/core] " tip-bot2 for Thomas Gleixner
  2021-03-09  8:55 ` [patch V3 2/6] irqtime: Make accounting correct on RT Thomas Gleixner
                   ` (6 subsequent siblings)
  7 siblings, 1 reply; 16+ messages in thread
From: Thomas Gleixner @ 2021-03-09  8:55 UTC (permalink / raw)
  To: LKML
  Cc: Peter Zijlstra, Paul McKenney, Sebastian Andrzej Siewior,
	Frederic Weisbecker

RT requires the softirq processing and local bottomhalf disabled regions to
be preemptible. Using the normal preempt count based serialization is
therefore not possible because this implicitely disables preemption.

RT kernels use a per CPU local lock to serialize bottomhalfs. As
local_bh_disable() can nest the lock can only be acquired on the outermost
invocation of local_bh_disable() and released when the nest count becomes
zero. Tasks which hold the local lock can be preempted so its required to
keep track of the nest count per task.

Add a RT only counter to task struct and adjust the relevant macros in
preempt.h.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Tested-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Reviewed-by: Frederic Weisbecker <frederic@kernel.org>
---
 include/linux/hardirq.h |    1 +
 include/linux/preempt.h |    6 +++++-
 include/linux/sched.h   |    3 +++
 3 files changed, 9 insertions(+), 1 deletion(-)

--- a/include/linux/hardirq.h
+++ b/include/linux/hardirq.h
@@ -6,6 +6,7 @@
 #include <linux/preempt.h>
 #include <linux/lockdep.h>
 #include <linux/ftrace_irq.h>
+#include <linux/sched.h>
 #include <linux/vtime.h>
 #include <asm/hardirq.h>
 
--- a/include/linux/preempt.h
+++ b/include/linux/preempt.h
@@ -79,7 +79,11 @@
 
 #define nmi_count()	(preempt_count() & NMI_MASK)
 #define hardirq_count()	(preempt_count() & HARDIRQ_MASK)
-#define softirq_count()	(preempt_count() & SOFTIRQ_MASK)
+#ifdef CONFIG_PREEMPT_RT
+# define softirq_count()	(current->softirq_disable_cnt & SOFTIRQ_MASK)
+#else
+# define softirq_count()	(preempt_count() & SOFTIRQ_MASK)
+#endif
 #define irq_count()	(nmi_count() | hardirq_count() | softirq_count())
 
 /*
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -1044,6 +1044,9 @@ struct task_struct {
 	int				softirq_context;
 	int				irq_config;
 #endif
+#ifdef CONFIG_PREEMPT_RT
+	int				softirq_disable_cnt;
+#endif
 
 #ifdef CONFIG_LOCKDEP
 # define MAX_LOCK_DEPTH			48UL


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

* [patch V3 2/6] irqtime: Make accounting correct on RT
  2021-03-09  8:55 [patch V3 0/6] softirq: Add RT specific softirq accounting Thomas Gleixner
  2021-03-09  8:55 ` [patch V3 1/6] " Thomas Gleixner
@ 2021-03-09  8:55 ` Thomas Gleixner
  2021-03-17 15:48   ` [tip: irq/core] " tip-bot2 for Thomas Gleixner
  2021-03-09  8:55 ` [patch V3 3/6] softirq: Move various protections into inline helpers Thomas Gleixner
                   ` (5 subsequent siblings)
  7 siblings, 1 reply; 16+ messages in thread
From: Thomas Gleixner @ 2021-03-09  8:55 UTC (permalink / raw)
  To: LKML
  Cc: Peter Zijlstra, Paul McKenney, Sebastian Andrzej Siewior,
	Frederic Weisbecker

vtime_account_irq and irqtime_account_irq() base checks on preempt_count()
which fails on RT because preempt_count() does not contain the softirq
accounting which is seperate on RT.

These checks do not need the full preempt count as they only operate on the
hard and softirq sections.

Use irq_count() instead which provides the correct value on both RT and non
RT kernels. The compiler is clever enough to fold the masking for !RT:

       99b:	65 8b 05 00 00 00 00 	mov    %gs:0x0(%rip),%eax
 -     9a2:	25 ff ff ff 7f       	and    $0x7fffffff,%eax
 +     9a2:	25 00 ff ff 00       	and    $0xffff00,%eax

Reported-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Tested-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Reviewed-by: Frederic Weisbecker <frederic@kernel.org>
---
 kernel/sched/cputime.c |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

--- a/kernel/sched/cputime.c
+++ b/kernel/sched/cputime.c
@@ -60,7 +60,7 @@ void irqtime_account_irq(struct task_str
 	cpu = smp_processor_id();
 	delta = sched_clock_cpu(cpu) - irqtime->irq_start_time;
 	irqtime->irq_start_time += delta;
-	pc = preempt_count() - offset;
+	pc = irq_count() - offset;
 
 	/*
 	 * We do not account for softirq time from ksoftirqd here.
@@ -421,7 +421,7 @@ void vtime_task_switch(struct task_struc
 
 void vtime_account_irq(struct task_struct *tsk, unsigned int offset)
 {
-	unsigned int pc = preempt_count() - offset;
+	unsigned int pc = irq_count() - offset;
 
 	if (pc & HARDIRQ_OFFSET) {
 		vtime_account_hardirq(tsk);


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

* [patch V3 3/6] softirq: Move various protections into inline helpers
  2021-03-09  8:55 [patch V3 0/6] softirq: Add RT specific softirq accounting Thomas Gleixner
  2021-03-09  8:55 ` [patch V3 1/6] " Thomas Gleixner
  2021-03-09  8:55 ` [patch V3 2/6] irqtime: Make accounting correct on RT Thomas Gleixner
@ 2021-03-09  8:55 ` Thomas Gleixner
  2021-03-17 15:48   ` [tip: irq/core] " tip-bot2 for Thomas Gleixner
  2021-03-09  8:55 ` [patch V3 4/6] softirq: Make softirq control and processing RT aware Thomas Gleixner
                   ` (4 subsequent siblings)
  7 siblings, 1 reply; 16+ messages in thread
From: Thomas Gleixner @ 2021-03-09  8:55 UTC (permalink / raw)
  To: LKML
  Cc: Peter Zijlstra, Paul McKenney, Sebastian Andrzej Siewior,
	Frederic Weisbecker

To allow reuse of the bulk of softirq processing code for RT and to avoid
#ifdeffery all over the place, split protections for various code sections
out into inline helpers so the RT variant can just replace them in one go.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Tested-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Reviewed-by: Frederic Weisbecker <frederic@kernel.org>
---
 kernel/softirq.c |   39 ++++++++++++++++++++++++++++++++-------
 1 file changed, 32 insertions(+), 7 deletions(-)

--- a/kernel/softirq.c
+++ b/kernel/softirq.c
@@ -207,6 +207,32 @@ void __local_bh_enable_ip(unsigned long
 }
 EXPORT_SYMBOL(__local_bh_enable_ip);
 
+static inline void softirq_handle_begin(void)
+{
+	__local_bh_disable_ip(_RET_IP_, SOFTIRQ_OFFSET);
+}
+
+static inline void softirq_handle_end(void)
+{
+	__local_bh_enable(SOFTIRQ_OFFSET);
+	WARN_ON_ONCE(in_interrupt());
+}
+
+static inline void ksoftirqd_run_begin(void)
+{
+	local_irq_disable();
+}
+
+static inline void ksoftirqd_run_end(void)
+{
+	local_irq_enable();
+}
+
+static inline bool should_wake_ksoftirqd(void)
+{
+	return true;
+}
+
 static inline void invoke_softirq(void)
 {
 	if (ksoftirqd_running(local_softirq_pending()))
@@ -319,7 +345,7 @@ asmlinkage __visible void __softirq_entr
 
 	pending = local_softirq_pending();
 
-	__local_bh_disable_ip(_RET_IP_, SOFTIRQ_OFFSET);
+	softirq_handle_begin();
 	in_hardirq = lockdep_softirq_start();
 	account_softirq_enter(current);
 
@@ -370,8 +396,7 @@ asmlinkage __visible void __softirq_entr
 
 	account_softirq_exit(current);
 	lockdep_softirq_end(in_hardirq);
-	__local_bh_enable(SOFTIRQ_OFFSET);
-	WARN_ON_ONCE(in_interrupt());
+	softirq_handle_end();
 	current_restore_flags(old_flags, PF_MEMALLOC);
 }
 
@@ -466,7 +491,7 @@ inline void raise_softirq_irqoff(unsigne
 	 * Otherwise we wake up ksoftirqd to make sure we
 	 * schedule the softirq soon.
 	 */
-	if (!in_interrupt())
+	if (!in_interrupt() && should_wake_ksoftirqd())
 		wakeup_softirqd();
 }
 
@@ -694,18 +719,18 @@ static int ksoftirqd_should_run(unsigned
 
 static void run_ksoftirqd(unsigned int cpu)
 {
-	local_irq_disable();
+	ksoftirqd_run_begin();
 	if (local_softirq_pending()) {
 		/*
 		 * We can safely run softirq on inline stack, as we are not deep
 		 * in the task stack here.
 		 */
 		__do_softirq();
-		local_irq_enable();
+		ksoftirqd_run_end();
 		cond_resched();
 		return;
 	}
-	local_irq_enable();
+	ksoftirqd_run_end();
 }
 
 #ifdef CONFIG_HOTPLUG_CPU


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

* [patch V3 4/6] softirq: Make softirq control and processing RT aware
  2021-03-09  8:55 [patch V3 0/6] softirq: Add RT specific softirq accounting Thomas Gleixner
                   ` (2 preceding siblings ...)
  2021-03-09  8:55 ` [patch V3 3/6] softirq: Move various protections into inline helpers Thomas Gleixner
@ 2021-03-09  8:55 ` Thomas Gleixner
  2021-03-17 15:48   ` [tip: irq/core] " tip-bot2 for Thomas Gleixner
  2021-03-09  8:55 ` [patch V3 5/6] tick/sched: Prevent false positive softirq pending warnings on RT Thomas Gleixner
                   ` (3 subsequent siblings)
  7 siblings, 1 reply; 16+ messages in thread
From: Thomas Gleixner @ 2021-03-09  8:55 UTC (permalink / raw)
  To: LKML
  Cc: Peter Zijlstra, Paul McKenney, Sebastian Andrzej Siewior,
	Frederic Weisbecker

Provide a local lock based serialization for soft interrupts on RT which
allows the local_bh_disabled() sections and servicing soft interrupts to be
preemptible.

Provide the necessary inline helpers which allow to reuse the bulk of the
softirq processing code.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Tested-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Reviewed-by: Frederic Weisbecker <frederic@kernel.org>
---
 include/linux/bottom_half.h |    2 
 kernel/softirq.c            |  188 ++++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 182 insertions(+), 8 deletions(-)

--- a/include/linux/bottom_half.h
+++ b/include/linux/bottom_half.h
@@ -4,7 +4,7 @@
 
 #include <linux/preempt.h>
 
-#ifdef CONFIG_TRACE_IRQFLAGS
+#if defined(CONFIG_PREEMPT_RT) || defined(CONFIG_TRACE_IRQFLAGS)
 extern void __local_bh_disable_ip(unsigned long ip, unsigned int cnt);
 #else
 static __always_inline void __local_bh_disable_ip(unsigned long ip, unsigned int cnt)
--- a/kernel/softirq.c
+++ b/kernel/softirq.c
@@ -13,6 +13,7 @@
 #include <linux/kernel_stat.h>
 #include <linux/interrupt.h>
 #include <linux/init.h>
+#include <linux/local_lock.h>
 #include <linux/mm.h>
 #include <linux/notifier.h>
 #include <linux/percpu.h>
@@ -103,20 +104,189 @@ EXPORT_PER_CPU_SYMBOL_GPL(hardirq_contex
 #endif
 
 /*
- * preempt_count and SOFTIRQ_OFFSET usage:
- * - preempt_count is changed by SOFTIRQ_OFFSET on entering or leaving
- *   softirq processing.
- * - preempt_count is changed by SOFTIRQ_DISABLE_OFFSET (= 2 * SOFTIRQ_OFFSET)
+ * SOFTIRQ_OFFSET usage:
+ *
+ * On !RT kernels 'count' is the preempt counter, on RT kernels this applies
+ * to a per CPU counter and to task::softirqs_disabled_cnt.
+ *
+ * - count is changed by SOFTIRQ_OFFSET on entering or leaving softirq
+ *   processing.
+ *
+ * - count is changed by SOFTIRQ_DISABLE_OFFSET (= 2 * SOFTIRQ_OFFSET)
  *   on local_bh_disable or local_bh_enable.
+ *
  * This lets us distinguish between whether we are currently processing
  * softirq and whether we just have bh disabled.
  */
+#ifdef CONFIG_PREEMPT_RT
+
+/*
+ * RT accounts for BH disabled sections in task::softirqs_disabled_cnt and
+ * also in per CPU softirq_ctrl::cnt. This is necessary to allow tasks in a
+ * softirq disabled section to be preempted.
+ *
+ * The per task counter is used for softirq_count(), in_softirq() and
+ * in_serving_softirqs() because these counts are only valid when the task
+ * holding softirq_ctrl::lock is running.
+ *
+ * The per CPU counter prevents pointless wakeups of ksoftirqd in case that
+ * the task which is in a softirq disabled section is preempted or blocks.
+ */
+struct softirq_ctrl {
+	local_lock_t	lock;
+	int		cnt;
+};
+
+static DEFINE_PER_CPU(struct softirq_ctrl, softirq_ctrl) = {
+	.lock	= INIT_LOCAL_LOCK(softirq_ctrl.lock),
+};
+
+void __local_bh_disable_ip(unsigned long ip, unsigned int cnt)
+{
+	unsigned long flags;
+	int newcnt;
+
+	WARN_ON_ONCE(in_hardirq());
+
+	/* First entry of a task into a BH disabled section? */
+	if (!current->softirq_disable_cnt) {
+		if (preemptible()) {
+			local_lock(&softirq_ctrl.lock);
+			/* Required to meet the RCU bottomhalf requirements. */
+			rcu_read_lock();
+		} else {
+			DEBUG_LOCKS_WARN_ON(this_cpu_read(softirq_ctrl.cnt));
+		}
+	}
+
+	/*
+	 * Track the per CPU softirq disabled state. On RT this is per CPU
+	 * state to allow preemption of bottom half disabled sections.
+	 */
+	newcnt = __this_cpu_add_return(softirq_ctrl.cnt, cnt);
+	/*
+	 * Reflect the result in the task state to prevent recursion on the
+	 * local lock and to make softirq_count() & al work.
+	 */
+	current->softirq_disable_cnt = newcnt;
+
+	if (IS_ENABLED(CONFIG_TRACE_IRQFLAGS) && newcnt == cnt) {
+		raw_local_irq_save(flags);
+		lockdep_softirqs_off(ip);
+		raw_local_irq_restore(flags);
+	}
+}
+EXPORT_SYMBOL(__local_bh_disable_ip);
+
+static void __local_bh_enable(unsigned int cnt, bool unlock)
+{
+	unsigned long flags;
+	int newcnt;
+
+	DEBUG_LOCKS_WARN_ON(current->softirq_disable_cnt !=
+			    this_cpu_read(softirq_ctrl.cnt));
+
+	if (IS_ENABLED(CONFIG_TRACE_IRQFLAGS) && softirq_count() == cnt) {
+		raw_local_irq_save(flags);
+		lockdep_softirqs_on(_RET_IP_);
+		raw_local_irq_restore(flags);
+	}
+
+	newcnt = __this_cpu_sub_return(softirq_ctrl.cnt, cnt);
+	current->softirq_disable_cnt = newcnt;
+
+	if (!newcnt && unlock) {
+		rcu_read_unlock();
+		local_unlock(&softirq_ctrl.lock);
+	}
+}
+
+void __local_bh_enable_ip(unsigned long ip, unsigned int cnt)
+{
+	bool preempt_on = preemptible();
+	unsigned long flags;
+	u32 pending;
+	int curcnt;
+
+	WARN_ON_ONCE(in_irq());
+	lockdep_assert_irqs_enabled();
+
+	local_irq_save(flags);
+	curcnt = __this_cpu_read(softirq_ctrl.cnt);
+
+	/*
+	 * If this is not reenabling soft interrupts, no point in trying to
+	 * run pending ones.
+	 */
+	if (curcnt != cnt)
+		goto out;
+
+	pending = local_softirq_pending();
+	if (!pending || ksoftirqd_running(pending))
+		goto out;
+
+	/*
+	 * If this was called from non preemptible context, wake up the
+	 * softirq daemon.
+	 */
+	if (!preempt_on) {
+		wakeup_softirqd();
+		goto out;
+	}
+
+	/*
+	 * Adjust softirq count to SOFTIRQ_OFFSET which makes
+	 * in_serving_softirq() become true.
+	 */
+	cnt = SOFTIRQ_OFFSET;
+	__local_bh_enable(cnt, false);
+	__do_softirq();
+
+out:
+	__local_bh_enable(cnt, preempt_on);
+	local_irq_restore(flags);
+}
+EXPORT_SYMBOL(__local_bh_enable_ip);
+
+/*
+ * Invoked from ksoftirqd_run() outside of the interrupt disabled section
+ * to acquire the per CPU local lock for reentrancy protection.
+ */
+static inline void ksoftirqd_run_begin(void)
+{
+	__local_bh_disable_ip(_RET_IP_, SOFTIRQ_OFFSET);
+	local_irq_disable();
+}
+
+/* Counterpart to ksoftirqd_run_begin() */
+static inline void ksoftirqd_run_end(void)
+{
+	__local_bh_enable(SOFTIRQ_OFFSET, true);
+	WARN_ON_ONCE(in_interrupt());
+	local_irq_enable();
+}
+
+static inline void softirq_handle_begin(void) { }
+static inline void softirq_handle_end(void) { }
+
+static inline bool should_wake_ksoftirqd(void)
+{
+	return !this_cpu_read(softirq_ctrl.cnt);
+}
+
+static inline void invoke_softirq(void)
+{
+	if (should_wake_ksoftirqd())
+		wakeup_softirqd();
+}
+
+#else /* CONFIG_PREEMPT_RT */
 
-#ifdef CONFIG_TRACE_IRQFLAGS
 /*
- * This is for softirq.c-internal use, where hardirqs are disabled
+ * This one is for softirq.c-internal use, where hardirqs are disabled
  * legitimately:
  */
+#ifdef CONFIG_TRACE_IRQFLAGS
 void __local_bh_disable_ip(unsigned long ip, unsigned int cnt)
 {
 	unsigned long flags;
@@ -277,6 +447,8 @@ asmlinkage __visible void do_softirq(voi
 	local_irq_restore(flags);
 }
 
+#endif /* !CONFIG_PREEMPT_RT */
+
 /*
  * We restart softirq processing for at most MAX_SOFTIRQ_RESTART times,
  * but break the loop if need_resched() is set or after 2 ms.
@@ -381,8 +553,10 @@ asmlinkage __visible void __softirq_entr
 		pending >>= softirq_bit;
 	}
 
-	if (__this_cpu_read(ksoftirqd) == current)
+	if (!IS_ENABLED(CONFIG_PREEMPT_RT) &&
+	    __this_cpu_read(ksoftirqd) == current)
 		rcu_softirq_qs();
+
 	local_irq_disable();
 
 	pending = local_softirq_pending();


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

* [patch V3 5/6] tick/sched: Prevent false positive softirq pending warnings on RT
  2021-03-09  8:55 [patch V3 0/6] softirq: Add RT specific softirq accounting Thomas Gleixner
                   ` (3 preceding siblings ...)
  2021-03-09  8:55 ` [patch V3 4/6] softirq: Make softirq control and processing RT aware Thomas Gleixner
@ 2021-03-09  8:55 ` Thomas Gleixner
  2021-03-17 15:48   ` [tip: irq/core] " tip-bot2 for Thomas Gleixner
  2021-03-09  8:55 ` [patch V3 6/6] rcu: Prevent false positive softirq warning " Thomas Gleixner
                   ` (2 subsequent siblings)
  7 siblings, 1 reply; 16+ messages in thread
From: Thomas Gleixner @ 2021-03-09  8:55 UTC (permalink / raw)
  To: LKML
  Cc: Peter Zijlstra, Paul McKenney, Sebastian Andrzej Siewior,
	Frederic Weisbecker

On RT a task which has soft interrupts disabled can block on a lock and
schedule out to idle while soft interrupts are pending. This triggers the
warning in the NOHZ idle code which complains about going idle with pending
soft interrupts. But as the task is blocked soft interrupt processing is
temporarily blocked as well which means that such a warning is a false
positive.

To prevent that check the per CPU state which indicates that a scheduled
out task has soft interrupts disabled.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Tested-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Reviewed-by: Frederic Weisbecker <frederic@kernel.org>
---
 include/linux/bottom_half.h |    6 ++++++
 kernel/softirq.c            |   15 +++++++++++++++
 kernel/time/tick-sched.c    |    2 +-
 3 files changed, 22 insertions(+), 1 deletion(-)

--- a/include/linux/bottom_half.h
+++ b/include/linux/bottom_half.h
@@ -32,4 +32,10 @@ static inline void local_bh_enable(void)
 	__local_bh_enable_ip(_THIS_IP_, SOFTIRQ_DISABLE_OFFSET);
 }
 
+#ifdef CONFIG_PREEMPT_RT
+extern bool local_bh_blocked(void);
+#else
+static inline bool local_bh_blocked(void) { return false; }
+#endif
+
 #endif /* _LINUX_BH_H */
--- a/kernel/softirq.c
+++ b/kernel/softirq.c
@@ -141,6 +141,21 @@ static DEFINE_PER_CPU(struct softirq_ctr
 	.lock	= INIT_LOCAL_LOCK(softirq_ctrl.lock),
 };
 
+/**
+ * local_bh_blocked() - Check for idle whether BH processing is blocked
+ *
+ * Returns false if the per CPU softirq::cnt is 0 otherwise true.
+ *
+ * This is invoked from the idle task to guard against false positive
+ * softirq pending warnings, which would happen when the task which holds
+ * softirq_ctrl::lock was the only running task on the CPU and blocks on
+ * some other lock.
+ */
+bool local_bh_blocked(void)
+{
+	return __this_cpu_read(softirq_ctrl.cnt) != 0;
+}
+
 void __local_bh_disable_ip(unsigned long ip, unsigned int cnt)
 {
 	unsigned long flags;
--- a/kernel/time/tick-sched.c
+++ b/kernel/time/tick-sched.c
@@ -973,7 +973,7 @@ static bool can_stop_idle_tick(int cpu,
 	if (unlikely(local_softirq_pending())) {
 		static int ratelimit;
 
-		if (ratelimit < 10 &&
+		if (ratelimit < 10 && !local_bh_blocked() &&
 		    (local_softirq_pending() & SOFTIRQ_STOP_IDLE_MASK)) {
 			pr_warn("NOHZ tick-stop error: Non-RCU local softirq work is pending, handler #%02x!!!\n",
 				(unsigned int) local_softirq_pending());


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

* [patch V3 6/6] rcu: Prevent false positive softirq warning on RT
  2021-03-09  8:55 [patch V3 0/6] softirq: Add RT specific softirq accounting Thomas Gleixner
                   ` (4 preceding siblings ...)
  2021-03-09  8:55 ` [patch V3 5/6] tick/sched: Prevent false positive softirq pending warnings on RT Thomas Gleixner
@ 2021-03-09  8:55 ` Thomas Gleixner
  2021-03-09 13:06   ` Frederic Weisbecker
  2021-03-17 15:48   ` [tip: irq/core] " tip-bot2 for Thomas Gleixner
  2021-03-09 14:07 ` [patch V3 0/6] softirq: Add RT specific softirq accounting Peter Zijlstra
  2021-03-09 21:32 ` Paul E. McKenney
  7 siblings, 2 replies; 16+ messages in thread
From: Thomas Gleixner @ 2021-03-09  8:55 UTC (permalink / raw)
  To: LKML
  Cc: Peter Zijlstra, Paul McKenney, Sebastian Andrzej Siewior,
	Frederic Weisbecker

Soft interrupt disabled sections can legitimately be preempted or schedule
out when blocking on a lock on RT enabled kernels so the RCU preempt check
warning has to be disabled for RT kernels.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Tested-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Reviewed-by: Paul E. McKenney <paulmck@kernel.org>
---
 include/linux/rcupdate.h |    3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

--- a/include/linux/rcupdate.h
+++ b/include/linux/rcupdate.h
@@ -334,7 +334,8 @@ static inline void rcu_preempt_sleep_che
 #define rcu_sleep_check()						\
 	do {								\
 		rcu_preempt_sleep_check();				\
-		RCU_LOCKDEP_WARN(lock_is_held(&rcu_bh_lock_map),	\
+		if (!IS_ENABLED(CONFIG_PREEMPT_RT))			\
+		    RCU_LOCKDEP_WARN(lock_is_held(&rcu_bh_lock_map),	\
 				 "Illegal context switch in RCU-bh read-side critical section"); \
 		RCU_LOCKDEP_WARN(lock_is_held(&rcu_sched_lock_map),	\
 				 "Illegal context switch in RCU-sched read-side critical section"); \


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

* Re: [patch V3 6/6] rcu: Prevent false positive softirq warning on RT
  2021-03-09  8:55 ` [patch V3 6/6] rcu: Prevent false positive softirq warning " Thomas Gleixner
@ 2021-03-09 13:06   ` Frederic Weisbecker
  2021-03-17 15:48   ` [tip: irq/core] " tip-bot2 for Thomas Gleixner
  1 sibling, 0 replies; 16+ messages in thread
From: Frederic Weisbecker @ 2021-03-09 13:06 UTC (permalink / raw)
  To: Thomas Gleixner
  Cc: LKML, Peter Zijlstra, Paul McKenney, Sebastian Andrzej Siewior

On Tue, Mar 09, 2021 at 09:55:58AM +0100, Thomas Gleixner wrote:
> Soft interrupt disabled sections can legitimately be preempted or schedule
> out when blocking on a lock on RT enabled kernels so the RCU preempt check
> warning has to be disabled for RT kernels.
> 
> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
> Tested-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
> Reviewed-by: Paul E. McKenney <paulmck@kernel.org>

Reviewed-by: Frederic Weisbecker <frederic@kernel.org>

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

* Re: [patch V3 0/6] softirq: Add RT specific softirq accounting
  2021-03-09  8:55 [patch V3 0/6] softirq: Add RT specific softirq accounting Thomas Gleixner
                   ` (5 preceding siblings ...)
  2021-03-09  8:55 ` [patch V3 6/6] rcu: Prevent false positive softirq warning " Thomas Gleixner
@ 2021-03-09 14:07 ` Peter Zijlstra
  2021-03-09 21:32 ` Paul E. McKenney
  7 siblings, 0 replies; 16+ messages in thread
From: Peter Zijlstra @ 2021-03-09 14:07 UTC (permalink / raw)
  To: Thomas Gleixner
  Cc: LKML, Paul McKenney, Sebastian Andrzej Siewior, Frederic Weisbecker

On Tue, Mar 09, 2021 at 09:55:52AM +0100, Thomas Gleixner wrote:
> RT runs softirq processing always in thread context and it requires that
> both the softirq execution and the BH disabled sections are preemptible.
> 
> This is achieved by serialization through per CPU local locks and
> substituting a few parts of the existing softirq processing code with
> helper functions.

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

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

* Re: [patch V3 0/6] softirq: Add RT specific softirq accounting
  2021-03-09  8:55 [patch V3 0/6] softirq: Add RT specific softirq accounting Thomas Gleixner
                   ` (6 preceding siblings ...)
  2021-03-09 14:07 ` [patch V3 0/6] softirq: Add RT specific softirq accounting Peter Zijlstra
@ 2021-03-09 21:32 ` Paul E. McKenney
  7 siblings, 0 replies; 16+ messages in thread
From: Paul E. McKenney @ 2021-03-09 21:32 UTC (permalink / raw)
  To: Thomas Gleixner
  Cc: LKML, Peter Zijlstra, Sebastian Andrzej Siewior, Frederic Weisbecker

On Tue, Mar 09, 2021 at 09:55:52AM +0100, Thomas Gleixner wrote:
> RT runs softirq processing always in thread context and it requires that
> both the softirq execution and the BH disabled sections are preemptible.
> 
> This is achieved by serialization through per CPU local locks and
> substituting a few parts of the existing softirq processing code with
> helper functions.
> 
> The series applies on top of
> 
>    git://git.kernel.org/pub/scm/linux/kernel/git/tglx/devel.git tasklet-2021-03-09
> 
> and is completely available from:
> 
>    git://git.kernel.org/pub/scm/linux/kernel/git/tglx/devel.git softirq
> 
> Changes to V2 which can be found here:
> 
>   https://lore.kernel.org/r/20201204170151.960336698@linutronix.de
> 
>  - Split the tasklet changes out (seperate submission)
>  
>  - Rebase it on the tasklet series (no further changes)

Passes modest rcutorture testing, and I do like the "NOHZ tick-stop
error" maybe going away!  That error is rare enough that it will take
some time to be reasonably certain.  In the meantime:

Tested-by: Paul E. McKenney <paulmck@kernel.org>

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

* [tip: irq/core] rcu: Prevent false positive softirq warning on RT
  2021-03-09  8:55 ` [patch V3 6/6] rcu: Prevent false positive softirq warning " Thomas Gleixner
  2021-03-09 13:06   ` Frederic Weisbecker
@ 2021-03-17 15:48   ` tip-bot2 for Thomas Gleixner
  1 sibling, 0 replies; 16+ 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, Paul E. McKenney,
	Frederic Weisbecker, Peter Zijlstra (Intel),
	x86, linux-kernel, maz

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

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

rcu: Prevent false positive softirq warning on RT

Soft interrupt disabled sections can legitimately be preempted or schedule
out when blocking on a lock on RT enabled kernels so the RCU preempt check
warning has to be disabled for RT kernels.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Tested-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Tested-by: Paul E. McKenney <paulmck@kernel.org>
Reviewed-by: Paul E. McKenney <paulmck@kernel.org>
Reviewed-by: Frederic Weisbecker <frederic@kernel.org>
Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Link: https://lore.kernel.org/r/20210309085727.626304079@linutronix.de

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

diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h
index bd04f72..6d855ef 100644
--- a/include/linux/rcupdate.h
+++ b/include/linux/rcupdate.h
@@ -334,7 +334,8 @@ static inline void rcu_preempt_sleep_check(void) { }
 #define rcu_sleep_check()						\
 	do {								\
 		rcu_preempt_sleep_check();				\
-		RCU_LOCKDEP_WARN(lock_is_held(&rcu_bh_lock_map),	\
+		if (!IS_ENABLED(CONFIG_PREEMPT_RT))			\
+		    RCU_LOCKDEP_WARN(lock_is_held(&rcu_bh_lock_map),	\
 				 "Illegal context switch in RCU-bh read-side critical section"); \
 		RCU_LOCKDEP_WARN(lock_is_held(&rcu_sched_lock_map),	\
 				 "Illegal context switch in RCU-sched read-side critical section"); \

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

* [tip: irq/core] tick/sched: Prevent false positive softirq pending warnings on RT
  2021-03-09  8:55 ` [patch V3 5/6] tick/sched: Prevent false positive softirq pending warnings on RT Thomas Gleixner
@ 2021-03-17 15:48   ` tip-bot2 for Thomas Gleixner
  0 siblings, 0 replies; 16+ 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, Paul E. McKenney,
	Frederic Weisbecker, Peter Zijlstra (Intel),
	x86, linux-kernel, maz

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

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

tick/sched: Prevent false positive softirq pending warnings on RT

On RT a task which has soft interrupts disabled can block on a lock and
schedule out to idle while soft interrupts are pending. This triggers the
warning in the NOHZ idle code which complains about going idle with pending
soft interrupts. But as the task is blocked soft interrupt processing is
temporarily blocked as well which means that such a warning is a false
positive.

To prevent that check the per CPU state which indicates that a scheduled
out task has soft interrupts disabled.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Tested-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Tested-by: Paul E. McKenney <paulmck@kernel.org>
Reviewed-by: Frederic Weisbecker <frederic@kernel.org>
Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Link: https://lore.kernel.org/r/20210309085727.527563866@linutronix.de

---
 include/linux/bottom_half.h |  6 ++++++
 kernel/softirq.c            | 15 +++++++++++++++
 kernel/time/tick-sched.c    |  2 +-
 3 files changed, 22 insertions(+), 1 deletion(-)

diff --git a/include/linux/bottom_half.h b/include/linux/bottom_half.h
index e4dd613..eed86eb 100644
--- a/include/linux/bottom_half.h
+++ b/include/linux/bottom_half.h
@@ -32,4 +32,10 @@ static inline void local_bh_enable(void)
 	__local_bh_enable_ip(_THIS_IP_, SOFTIRQ_DISABLE_OFFSET);
 }
 
+#ifdef CONFIG_PREEMPT_RT
+extern bool local_bh_blocked(void);
+#else
+static inline bool local_bh_blocked(void) { return false; }
+#endif
+
 #endif /* _LINUX_BH_H */
diff --git a/kernel/softirq.c b/kernel/softirq.c
index 1ed1c55..5a99696 100644
--- a/kernel/softirq.c
+++ b/kernel/softirq.c
@@ -141,6 +141,21 @@ static DEFINE_PER_CPU(struct softirq_ctrl, softirq_ctrl) = {
 	.lock	= INIT_LOCAL_LOCK(softirq_ctrl.lock),
 };
 
+/**
+ * local_bh_blocked() - Check for idle whether BH processing is blocked
+ *
+ * Returns false if the per CPU softirq::cnt is 0 otherwise true.
+ *
+ * This is invoked from the idle task to guard against false positive
+ * softirq pending warnings, which would happen when the task which holds
+ * softirq_ctrl::lock was the only running task on the CPU and blocks on
+ * some other lock.
+ */
+bool local_bh_blocked(void)
+{
+	return __this_cpu_read(softirq_ctrl.cnt) != 0;
+}
+
 void __local_bh_disable_ip(unsigned long ip, unsigned int cnt)
 {
 	unsigned long flags;
diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c
index e10a4af..0cc5579 100644
--- a/kernel/time/tick-sched.c
+++ b/kernel/time/tick-sched.c
@@ -973,7 +973,7 @@ static bool can_stop_idle_tick(int cpu, struct tick_sched *ts)
 	if (unlikely(local_softirq_pending())) {
 		static int ratelimit;
 
-		if (ratelimit < 10 &&
+		if (ratelimit < 10 && !local_bh_blocked() &&
 		    (local_softirq_pending() & SOFTIRQ_STOP_IDLE_MASK)) {
 			pr_warn("NOHZ tick-stop error: Non-RCU local softirq work is pending, handler #%02x!!!\n",
 				(unsigned int) local_softirq_pending());

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

* [tip: irq/core] softirq: Move various protections into inline helpers
  2021-03-09  8:55 ` [patch V3 3/6] softirq: Move various protections into inline helpers Thomas Gleixner
@ 2021-03-17 15:48   ` tip-bot2 for Thomas Gleixner
  0 siblings, 0 replies; 16+ 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, Paul E. McKenney,
	Frederic Weisbecker, Peter Zijlstra (Intel),
	x86, linux-kernel, maz

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

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

softirq: Move various protections into inline helpers

To allow reuse of the bulk of softirq processing code for RT and to avoid
#ifdeffery all over the place, split protections for various code sections
out into inline helpers so the RT variant can just replace them in one go.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Tested-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Tested-by: Paul E. McKenney <paulmck@kernel.org>
Reviewed-by: Frederic Weisbecker <frederic@kernel.org>
Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Link: https://lore.kernel.org/r/20210309085727.310118772@linutronix.de

---
 kernel/softirq.c | 39 ++++++++++++++++++++++++++++++++-------
 1 file changed, 32 insertions(+), 7 deletions(-)

diff --git a/kernel/softirq.c b/kernel/softirq.c
index f1eb83d..eaca333 100644
--- a/kernel/softirq.c
+++ b/kernel/softirq.c
@@ -207,6 +207,32 @@ void __local_bh_enable_ip(unsigned long ip, unsigned int cnt)
 }
 EXPORT_SYMBOL(__local_bh_enable_ip);
 
+static inline void softirq_handle_begin(void)
+{
+	__local_bh_disable_ip(_RET_IP_, SOFTIRQ_OFFSET);
+}
+
+static inline void softirq_handle_end(void)
+{
+	__local_bh_enable(SOFTIRQ_OFFSET);
+	WARN_ON_ONCE(in_interrupt());
+}
+
+static inline void ksoftirqd_run_begin(void)
+{
+	local_irq_disable();
+}
+
+static inline void ksoftirqd_run_end(void)
+{
+	local_irq_enable();
+}
+
+static inline bool should_wake_ksoftirqd(void)
+{
+	return true;
+}
+
 static inline void invoke_softirq(void)
 {
 	if (ksoftirqd_running(local_softirq_pending()))
@@ -319,7 +345,7 @@ asmlinkage __visible void __softirq_entry __do_softirq(void)
 
 	pending = local_softirq_pending();
 
-	__local_bh_disable_ip(_RET_IP_, SOFTIRQ_OFFSET);
+	softirq_handle_begin();
 	in_hardirq = lockdep_softirq_start();
 	account_softirq_enter(current);
 
@@ -370,8 +396,7 @@ restart:
 
 	account_softirq_exit(current);
 	lockdep_softirq_end(in_hardirq);
-	__local_bh_enable(SOFTIRQ_OFFSET);
-	WARN_ON_ONCE(in_interrupt());
+	softirq_handle_end();
 	current_restore_flags(old_flags, PF_MEMALLOC);
 }
 
@@ -466,7 +491,7 @@ inline void raise_softirq_irqoff(unsigned int nr)
 	 * Otherwise we wake up ksoftirqd to make sure we
 	 * schedule the softirq soon.
 	 */
-	if (!in_interrupt())
+	if (!in_interrupt() && should_wake_ksoftirqd())
 		wakeup_softirqd();
 }
 
@@ -698,18 +723,18 @@ static int ksoftirqd_should_run(unsigned int cpu)
 
 static void run_ksoftirqd(unsigned int cpu)
 {
-	local_irq_disable();
+	ksoftirqd_run_begin();
 	if (local_softirq_pending()) {
 		/*
 		 * We can safely run softirq on inline stack, as we are not deep
 		 * in the task stack here.
 		 */
 		__do_softirq();
-		local_irq_enable();
+		ksoftirqd_run_end();
 		cond_resched();
 		return;
 	}
-	local_irq_enable();
+	ksoftirqd_run_end();
 }
 
 #ifdef CONFIG_HOTPLUG_CPU

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

* [tip: irq/core] softirq: Make softirq control and processing RT aware
  2021-03-09  8:55 ` [patch V3 4/6] softirq: Make softirq control and processing RT aware Thomas Gleixner
@ 2021-03-17 15:48   ` tip-bot2 for Thomas Gleixner
  0 siblings, 0 replies; 16+ 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, Paul E. McKenney,
	Frederic Weisbecker, Peter Zijlstra (Intel),
	x86, linux-kernel, maz

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

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

softirq: Make softirq control and processing RT aware

Provide a local lock based serialization for soft interrupts on RT which
allows the local_bh_disabled() sections and servicing soft interrupts to be
preemptible.

Provide the necessary inline helpers which allow to reuse the bulk of the
softirq processing code.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Tested-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Tested-by: Paul E. McKenney <paulmck@kernel.org>
Reviewed-by: Frederic Weisbecker <frederic@kernel.org>
Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Link: https://lore.kernel.org/r/20210309085727.426370483@linutronix.de

---
 include/linux/bottom_half.h |   2 +-
 kernel/softirq.c            | 188 +++++++++++++++++++++++++++++++++--
 2 files changed, 182 insertions(+), 8 deletions(-)

diff --git a/include/linux/bottom_half.h b/include/linux/bottom_half.h
index a19519f..e4dd613 100644
--- a/include/linux/bottom_half.h
+++ b/include/linux/bottom_half.h
@@ -4,7 +4,7 @@
 
 #include <linux/preempt.h>
 
-#ifdef CONFIG_TRACE_IRQFLAGS
+#if defined(CONFIG_PREEMPT_RT) || defined(CONFIG_TRACE_IRQFLAGS)
 extern void __local_bh_disable_ip(unsigned long ip, unsigned int cnt);
 #else
 static __always_inline void __local_bh_disable_ip(unsigned long ip, unsigned int cnt)
diff --git a/kernel/softirq.c b/kernel/softirq.c
index eaca333..1ed1c55 100644
--- a/kernel/softirq.c
+++ b/kernel/softirq.c
@@ -13,6 +13,7 @@
 #include <linux/kernel_stat.h>
 #include <linux/interrupt.h>
 #include <linux/init.h>
+#include <linux/local_lock.h>
 #include <linux/mm.h>
 #include <linux/notifier.h>
 #include <linux/percpu.h>
@@ -103,20 +104,189 @@ EXPORT_PER_CPU_SYMBOL_GPL(hardirq_context);
 #endif
 
 /*
- * preempt_count and SOFTIRQ_OFFSET usage:
- * - preempt_count is changed by SOFTIRQ_OFFSET on entering or leaving
- *   softirq processing.
- * - preempt_count is changed by SOFTIRQ_DISABLE_OFFSET (= 2 * SOFTIRQ_OFFSET)
+ * SOFTIRQ_OFFSET usage:
+ *
+ * On !RT kernels 'count' is the preempt counter, on RT kernels this applies
+ * to a per CPU counter and to task::softirqs_disabled_cnt.
+ *
+ * - count is changed by SOFTIRQ_OFFSET on entering or leaving softirq
+ *   processing.
+ *
+ * - count is changed by SOFTIRQ_DISABLE_OFFSET (= 2 * SOFTIRQ_OFFSET)
  *   on local_bh_disable or local_bh_enable.
+ *
  * This lets us distinguish between whether we are currently processing
  * softirq and whether we just have bh disabled.
  */
+#ifdef CONFIG_PREEMPT_RT
 
-#ifdef CONFIG_TRACE_IRQFLAGS
 /*
- * This is for softirq.c-internal use, where hardirqs are disabled
+ * RT accounts for BH disabled sections in task::softirqs_disabled_cnt and
+ * also in per CPU softirq_ctrl::cnt. This is necessary to allow tasks in a
+ * softirq disabled section to be preempted.
+ *
+ * The per task counter is used for softirq_count(), in_softirq() and
+ * in_serving_softirqs() because these counts are only valid when the task
+ * holding softirq_ctrl::lock is running.
+ *
+ * The per CPU counter prevents pointless wakeups of ksoftirqd in case that
+ * the task which is in a softirq disabled section is preempted or blocks.
+ */
+struct softirq_ctrl {
+	local_lock_t	lock;
+	int		cnt;
+};
+
+static DEFINE_PER_CPU(struct softirq_ctrl, softirq_ctrl) = {
+	.lock	= INIT_LOCAL_LOCK(softirq_ctrl.lock),
+};
+
+void __local_bh_disable_ip(unsigned long ip, unsigned int cnt)
+{
+	unsigned long flags;
+	int newcnt;
+
+	WARN_ON_ONCE(in_hardirq());
+
+	/* First entry of a task into a BH disabled section? */
+	if (!current->softirq_disable_cnt) {
+		if (preemptible()) {
+			local_lock(&softirq_ctrl.lock);
+			/* Required to meet the RCU bottomhalf requirements. */
+			rcu_read_lock();
+		} else {
+			DEBUG_LOCKS_WARN_ON(this_cpu_read(softirq_ctrl.cnt));
+		}
+	}
+
+	/*
+	 * Track the per CPU softirq disabled state. On RT this is per CPU
+	 * state to allow preemption of bottom half disabled sections.
+	 */
+	newcnt = __this_cpu_add_return(softirq_ctrl.cnt, cnt);
+	/*
+	 * Reflect the result in the task state to prevent recursion on the
+	 * local lock and to make softirq_count() & al work.
+	 */
+	current->softirq_disable_cnt = newcnt;
+
+	if (IS_ENABLED(CONFIG_TRACE_IRQFLAGS) && newcnt == cnt) {
+		raw_local_irq_save(flags);
+		lockdep_softirqs_off(ip);
+		raw_local_irq_restore(flags);
+	}
+}
+EXPORT_SYMBOL(__local_bh_disable_ip);
+
+static void __local_bh_enable(unsigned int cnt, bool unlock)
+{
+	unsigned long flags;
+	int newcnt;
+
+	DEBUG_LOCKS_WARN_ON(current->softirq_disable_cnt !=
+			    this_cpu_read(softirq_ctrl.cnt));
+
+	if (IS_ENABLED(CONFIG_TRACE_IRQFLAGS) && softirq_count() == cnt) {
+		raw_local_irq_save(flags);
+		lockdep_softirqs_on(_RET_IP_);
+		raw_local_irq_restore(flags);
+	}
+
+	newcnt = __this_cpu_sub_return(softirq_ctrl.cnt, cnt);
+	current->softirq_disable_cnt = newcnt;
+
+	if (!newcnt && unlock) {
+		rcu_read_unlock();
+		local_unlock(&softirq_ctrl.lock);
+	}
+}
+
+void __local_bh_enable_ip(unsigned long ip, unsigned int cnt)
+{
+	bool preempt_on = preemptible();
+	unsigned long flags;
+	u32 pending;
+	int curcnt;
+
+	WARN_ON_ONCE(in_irq());
+	lockdep_assert_irqs_enabled();
+
+	local_irq_save(flags);
+	curcnt = __this_cpu_read(softirq_ctrl.cnt);
+
+	/*
+	 * If this is not reenabling soft interrupts, no point in trying to
+	 * run pending ones.
+	 */
+	if (curcnt != cnt)
+		goto out;
+
+	pending = local_softirq_pending();
+	if (!pending || ksoftirqd_running(pending))
+		goto out;
+
+	/*
+	 * If this was called from non preemptible context, wake up the
+	 * softirq daemon.
+	 */
+	if (!preempt_on) {
+		wakeup_softirqd();
+		goto out;
+	}
+
+	/*
+	 * Adjust softirq count to SOFTIRQ_OFFSET which makes
+	 * in_serving_softirq() become true.
+	 */
+	cnt = SOFTIRQ_OFFSET;
+	__local_bh_enable(cnt, false);
+	__do_softirq();
+
+out:
+	__local_bh_enable(cnt, preempt_on);
+	local_irq_restore(flags);
+}
+EXPORT_SYMBOL(__local_bh_enable_ip);
+
+/*
+ * Invoked from ksoftirqd_run() outside of the interrupt disabled section
+ * to acquire the per CPU local lock for reentrancy protection.
+ */
+static inline void ksoftirqd_run_begin(void)
+{
+	__local_bh_disable_ip(_RET_IP_, SOFTIRQ_OFFSET);
+	local_irq_disable();
+}
+
+/* Counterpart to ksoftirqd_run_begin() */
+static inline void ksoftirqd_run_end(void)
+{
+	__local_bh_enable(SOFTIRQ_OFFSET, true);
+	WARN_ON_ONCE(in_interrupt());
+	local_irq_enable();
+}
+
+static inline void softirq_handle_begin(void) { }
+static inline void softirq_handle_end(void) { }
+
+static inline bool should_wake_ksoftirqd(void)
+{
+	return !this_cpu_read(softirq_ctrl.cnt);
+}
+
+static inline void invoke_softirq(void)
+{
+	if (should_wake_ksoftirqd())
+		wakeup_softirqd();
+}
+
+#else /* CONFIG_PREEMPT_RT */
+
+/*
+ * This one is for softirq.c-internal use, where hardirqs are disabled
  * legitimately:
  */
+#ifdef CONFIG_TRACE_IRQFLAGS
 void __local_bh_disable_ip(unsigned long ip, unsigned int cnt)
 {
 	unsigned long flags;
@@ -277,6 +447,8 @@ asmlinkage __visible void do_softirq(void)
 	local_irq_restore(flags);
 }
 
+#endif /* !CONFIG_PREEMPT_RT */
+
 /*
  * We restart softirq processing for at most MAX_SOFTIRQ_RESTART times,
  * but break the loop if need_resched() is set or after 2 ms.
@@ -381,8 +553,10 @@ restart:
 		pending >>= softirq_bit;
 	}
 
-	if (__this_cpu_read(ksoftirqd) == current)
+	if (!IS_ENABLED(CONFIG_PREEMPT_RT) &&
+	    __this_cpu_read(ksoftirqd) == current)
 		rcu_softirq_qs();
+
 	local_irq_disable();
 
 	pending = local_softirq_pending();

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

* [tip: irq/core] softirq: Add RT specific softirq accounting
  2021-03-09  8:55 ` [patch V3 1/6] " Thomas Gleixner
@ 2021-03-17 15:48   ` tip-bot2 for Thomas Gleixner
  0 siblings, 0 replies; 16+ 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, Paul E. McKenney,
	Frederic Weisbecker, Peter Zijlstra (Intel),
	x86, linux-kernel, maz

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

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

softirq: Add RT specific softirq accounting

RT requires the softirq processing and local bottomhalf disabled regions to
be preemptible. Using the normal preempt count based serialization is
therefore not possible because this implicitely disables preemption.

RT kernels use a per CPU local lock to serialize bottomhalfs. As
local_bh_disable() can nest the lock can only be acquired on the outermost
invocation of local_bh_disable() and released when the nest count becomes
zero. Tasks which hold the local lock can be preempted so its required to
keep track of the nest count per task.

Add a RT only counter to task struct and adjust the relevant macros in
preempt.h.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Tested-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Tested-by: Paul E. McKenney <paulmck@kernel.org>
Reviewed-by: Frederic Weisbecker <frederic@kernel.org>
Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Link: https://lore.kernel.org/r/20210309085726.983627589@linutronix.de

---
 include/linux/hardirq.h | 1 +
 include/linux/preempt.h | 6 +++++-
 include/linux/sched.h   | 3 +++
 3 files changed, 9 insertions(+), 1 deletion(-)

diff --git a/include/linux/hardirq.h b/include/linux/hardirq.h
index 7c9d6a2..69bc86e 100644
--- a/include/linux/hardirq.h
+++ b/include/linux/hardirq.h
@@ -6,6 +6,7 @@
 #include <linux/preempt.h>
 #include <linux/lockdep.h>
 #include <linux/ftrace_irq.h>
+#include <linux/sched.h>
 #include <linux/vtime.h>
 #include <asm/hardirq.h>
 
diff --git a/include/linux/preempt.h b/include/linux/preempt.h
index 69cc8b6..9881eac 100644
--- a/include/linux/preempt.h
+++ b/include/linux/preempt.h
@@ -79,7 +79,11 @@
 
 #define nmi_count()	(preempt_count() & NMI_MASK)
 #define hardirq_count()	(preempt_count() & HARDIRQ_MASK)
-#define softirq_count()	(preempt_count() & SOFTIRQ_MASK)
+#ifdef CONFIG_PREEMPT_RT
+# define softirq_count()	(current->softirq_disable_cnt & SOFTIRQ_MASK)
+#else
+# define softirq_count()	(preempt_count() & SOFTIRQ_MASK)
+#endif
 #define irq_count()	(nmi_count() | hardirq_count() | softirq_count())
 
 /*
diff --git a/include/linux/sched.h b/include/linux/sched.h
index ef00bb2..743a613 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -1044,6 +1044,9 @@ struct task_struct {
 	int				softirq_context;
 	int				irq_config;
 #endif
+#ifdef CONFIG_PREEMPT_RT
+	int				softirq_disable_cnt;
+#endif
 
 #ifdef CONFIG_LOCKDEP
 # define MAX_LOCK_DEPTH			48UL

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

* [tip: irq/core] irqtime: Make accounting correct on RT
  2021-03-09  8:55 ` [patch V3 2/6] irqtime: Make accounting correct on RT Thomas Gleixner
@ 2021-03-17 15:48   ` tip-bot2 for Thomas Gleixner
  0 siblings, 0 replies; 16+ messages in thread
From: tip-bot2 for Thomas Gleixner @ 2021-03-17 15:48 UTC (permalink / raw)
  To: linux-tip-commits
  Cc: Sebastian Andrzej Siewior, Thomas Gleixner, Paul E. McKenney,
	Frederic Weisbecker, Peter Zijlstra (Intel),
	x86, linux-kernel, maz

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

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

irqtime: Make accounting correct on RT

vtime_account_irq and irqtime_account_irq() base checks on preempt_count()
which fails on RT because preempt_count() does not contain the softirq
accounting which is seperate on RT.

These checks do not need the full preempt count as they only operate on the
hard and softirq sections.

Use irq_count() instead which provides the correct value on both RT and non
RT kernels. The compiler is clever enough to fold the masking for !RT:

       99b:	65 8b 05 00 00 00 00 	mov    %gs:0x0(%rip),%eax
 -     9a2:	25 ff ff ff 7f       	and    $0x7fffffff,%eax
 +     9a2:	25 00 ff ff 00       	and    $0xffff00,%eax

Reported-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Tested-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Tested-by: Paul E. McKenney <paulmck@kernel.org>
Reviewed-by: Frederic Weisbecker <frederic@kernel.org>
Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Link: https://lore.kernel.org/r/20210309085727.153926793@linutronix.de

---
 kernel/sched/cputime.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/kernel/sched/cputime.c b/kernel/sched/cputime.c
index 5f61165..2c36a5f 100644
--- a/kernel/sched/cputime.c
+++ b/kernel/sched/cputime.c
@@ -60,7 +60,7 @@ void irqtime_account_irq(struct task_struct *curr, unsigned int offset)
 	cpu = smp_processor_id();
 	delta = sched_clock_cpu(cpu) - irqtime->irq_start_time;
 	irqtime->irq_start_time += delta;
-	pc = preempt_count() - offset;
+	pc = irq_count() - offset;
 
 	/*
 	 * We do not account for softirq time from ksoftirqd here.
@@ -421,7 +421,7 @@ void vtime_task_switch(struct task_struct *prev)
 
 void vtime_account_irq(struct task_struct *tsk, unsigned int offset)
 {
-	unsigned int pc = preempt_count() - offset;
+	unsigned int pc = irq_count() - offset;
 
 	if (pc & HARDIRQ_OFFSET) {
 		vtime_account_hardirq(tsk);

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

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

Thread overview: 16+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-03-09  8:55 [patch V3 0/6] softirq: Add RT specific softirq accounting Thomas Gleixner
2021-03-09  8:55 ` [patch V3 1/6] " Thomas Gleixner
2021-03-17 15:48   ` [tip: irq/core] " tip-bot2 for Thomas Gleixner
2021-03-09  8:55 ` [patch V3 2/6] irqtime: Make accounting correct on RT Thomas Gleixner
2021-03-17 15:48   ` [tip: irq/core] " tip-bot2 for Thomas Gleixner
2021-03-09  8:55 ` [patch V3 3/6] softirq: Move various protections into inline helpers Thomas Gleixner
2021-03-17 15:48   ` [tip: irq/core] " tip-bot2 for Thomas Gleixner
2021-03-09  8:55 ` [patch V3 4/6] softirq: Make softirq control and processing RT aware Thomas Gleixner
2021-03-17 15:48   ` [tip: irq/core] " tip-bot2 for Thomas Gleixner
2021-03-09  8:55 ` [patch V3 5/6] tick/sched: Prevent false positive softirq pending warnings on RT Thomas Gleixner
2021-03-17 15:48   ` [tip: irq/core] " tip-bot2 for Thomas Gleixner
2021-03-09  8:55 ` [patch V3 6/6] rcu: Prevent false positive softirq warning " Thomas Gleixner
2021-03-09 13:06   ` Frederic Weisbecker
2021-03-17 15:48   ` [tip: irq/core] " tip-bot2 for Thomas Gleixner
2021-03-09 14:07 ` [patch V3 0/6] softirq: Add RT specific softirq accounting Peter Zijlstra
2021-03-09 21:32 ` Paul E. McKenney

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