[RFC PATCH v4 3/3] softirq: defer softirq processing to ksoftirqd if CPU is busy with RT

From: John Stultz
Date: Mon Oct 03 2022 - 19:21:04 EST

From: Pavankumar Kondeti <pkondeti@xxxxxxxxxxxxxx>

Defer the softirq processing to ksoftirqd if a RT task is
running or queued on the current CPU. This complements the RT
task placement algorithm which tries to find a CPU that is not
currently busy with softirqs.

Currently NET_TX, NET_RX, BLOCK and IRQ_POLL softirqs are only
deferred as they can potentially run for long time.

Additionally, this patch stubs out ksoftirqd_running() logic,
in the CONFIG_RT_SOFTIRQ_OPTIMIZATION case, as deferring
potentially long-running softirqs will cause the logic to not
process shorter-running softirqs immediately. By stubbing it out
the potentially long running softirqs are deferred, but the
shorter running ones can still run immediately.

This patch includes folded-in fixes by:
Lingutla Chandrasekhar <clingutla@xxxxxxxxxxxxxx>
Satya Durga Srinivasu Prabhala <satyap@xxxxxxxxxxxxxx>
J. Avila <elavila@xxxxxxxxxx>

Cc: John Dias <joaodias@xxxxxxxxxx>
Cc: Connor O'Brien <connoro@xxxxxxxxxx>
Cc: Rick Yiu <rickyiu@xxxxxxxxxx>
Cc: John Kacur <jkacur@xxxxxxxxxx>
Cc: Qais Yousef <qais.yousef@xxxxxxx>
Cc: Chris Redpath <chris.redpath@xxxxxxx>
Cc: Abhijeet Dharmapurikar <adharmap@xxxxxxxxxxx>
Cc: Peter Zijlstra <peterz@xxxxxxxxxxxxx>
Cc: Ingo Molnar <mingo@xxxxxxxxxx>
Cc: Juri Lelli <juri.lelli@xxxxxxxxxx>
Cc: Vincent Guittot <vincent.guittot@xxxxxxxxxx>
Cc: Dietmar Eggemann <dietmar.eggemann@xxxxxxx>
Cc: Steven Rostedt <rostedt@xxxxxxxxxxx>
Cc: Thomas Gleixner <tglx@xxxxxxxxxxxxx>
Cc: kernel-team@xxxxxxxxxxx
Signed-off-by: Pavankumar Kondeti <pkondeti@xxxxxxxxxxxxxx>
[satyap@xxxxxxxxxxxxxx: trivial merge conflict resolution.]
Signed-off-by: Satya Durga Srinivasu Prabhala <satyap@xxxxxxxxxxxxxx>
[elavila: Port to mainline, squash with bugfix]
Signed-off-by: J. Avila <elavila@xxxxxxxxxx>
[jstultz: Rebase to linus/HEAD, minor rearranging of code,
included bug fix Reported-by: Qais Yousef <qais.yousef@xxxxxxx> ]
Signed-off-by: John Stultz <jstultz@xxxxxxxxxx>
* Fix commit message to accurately note long-running softirqs
(suggested by Qais)
* Switch to using rt_task(current) (suggested by Qais)
kernel/softirq.c | 29 +++++++++++++++++++++++++++--
1 file changed, 27 insertions(+), 2 deletions(-)

diff --git a/kernel/softirq.c b/kernel/softirq.c
index 35ee79dd8786..c8ce12bbab04 100644
--- a/kernel/softirq.c
+++ b/kernel/softirq.c
@@ -87,6 +87,7 @@ static void wakeup_softirqd(void)

* If ksoftirqd is scheduled, we do not want to process pending softirqs
* right now. Let ksoftirqd handle this at its own rate, to get fairness,
@@ -101,6 +102,9 @@ static bool ksoftirqd_running(unsigned long pending)
return false;
return tsk && task_is_running(tsk) && !__kthread_should_park(tsk);
+#define ksoftirqd_running(pending) (false)

DEFINE_PER_CPU(int, hardirqs_enabled);
@@ -532,6 +536,21 @@ static inline bool lockdep_softirq_start(void) { return false; }
static inline void lockdep_softirq_end(bool in_hardirq) { }

+static __u32 softirq_deferred_for_rt(__u32 *pending)
+ __u32 deferred = 0;
+ if (rt_task(current)) {
+ deferred = *pending & LONG_SOFTIRQ_MASK;
+ *pending &= ~LONG_SOFTIRQ_MASK;
+ }
+ return deferred;
+#define softirq_deferred_for_rt(x) (0)
asmlinkage __visible void __softirq_entry __do_softirq(void)
unsigned long end = jiffies + MAX_SOFTIRQ_TIME;
@@ -539,6 +558,7 @@ asmlinkage __visible void __softirq_entry __do_softirq(void)
int max_restart = MAX_SOFTIRQ_RESTART;
struct softirq_action *h;
bool in_hardirq;
+ __u32 deferred;
__u32 pending;
int softirq_bit;

@@ -550,14 +570,16 @@ asmlinkage __visible void __softirq_entry __do_softirq(void)
current->flags &= ~PF_MEMALLOC;

pending = local_softirq_pending();
+ deferred = softirq_deferred_for_rt(&pending);

in_hardirq = lockdep_softirq_start();

/* Reset the pending bitmask before enabling irqs */
- set_softirq_pending(0);
+ set_softirq_pending(deferred);
__this_cpu_write(active_softirqs, pending);

@@ -596,13 +618,16 @@ asmlinkage __visible void __softirq_entry __do_softirq(void)

pending = local_softirq_pending();
+ deferred = softirq_deferred_for_rt(&pending);
if (pending) {
if (time_before(jiffies, end) && !need_resched() &&
goto restart;
+ }

+ if (pending | deferred)
- }