Skip to content

Commit 0345691

Browse files
author
Frederic Weisbecker
committed
tick/rcu: Stop allowing RCU_SOFTIRQ in idle
RCU_SOFTIRQ used to be special in that it could be raised on purpose within the idle path to prevent from stopping the tick. Some code still prevents from unnecessary warnings related to this specific behaviour while entering in dynticks-idle mode. However the nohz layout has changed quite a bit in ten years, and the removal of CONFIG_RCU_FAST_NO_HZ has been the final straw to this safe-conduct. Now the RCU_SOFTIRQ vector is expected to be raised from sane places. A remaining corner case is admitted though when the vector is invoked in fragile hotplug path. Signed-off-by: Frederic Weisbecker <[email protected]> Cc: Thomas Gleixner <[email protected]> Cc: Peter Zijlstra <[email protected]> Cc: Paul E. McKenney <[email protected]> Cc: Paul Menzel <[email protected]>
1 parent 2984539 commit 0345691

File tree

2 files changed

+47
-11
lines changed

2 files changed

+47
-11
lines changed

include/linux/interrupt.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -579,7 +579,13 @@ enum
579579
NR_SOFTIRQS
580580
};
581581

582-
#define SOFTIRQ_STOP_IDLE_MASK (~(1 << RCU_SOFTIRQ))
582+
/*
583+
* Ignoring the RCU vector after ksoftirqd is parked is fine
584+
* because:
585+
* 1) rcutree_migrate_callbacks() takes care of the queue.
586+
* 2) rcu_report_dead() reports the final quiescent states.
587+
*/
588+
#define SOFTIRQ_HOTPLUG_SAFE_MASK (BIT(RCU_SOFTIRQ))
583589

584590
/* map softirq index to softirq name. update 'softirq_to_name' in
585591
* kernel/softirq.c when adding a new softirq.

kernel/time/tick-sched.c

Lines changed: 40 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -999,6 +999,45 @@ static void tick_nohz_full_update_tick(struct tick_sched *ts)
999999
__tick_nohz_full_update_tick(ts, ktime_get());
10001000
}
10011001

1002+
/*
1003+
* A pending softirq outside an IRQ (or softirq disabled section) context
1004+
* should be waiting for ksoftirqd to handle it. Therefore we shouldn't
1005+
* reach here due to the need_resched() early check in can_stop_idle_tick().
1006+
*
1007+
* However if we are between CPUHP_AP_SMPBOOT_THREADS and CPU_TEARDOWN_CPU on the
1008+
* cpu_down() process, softirqs can still be raised while ksoftirqd is parked,
1009+
* triggering the below since wakep_softirqd() is ignored.
1010+
*
1011+
*/
1012+
static bool report_idle_softirq(void)
1013+
{
1014+
static int ratelimit;
1015+
unsigned int pending = local_softirq_pending();
1016+
1017+
if (likely(!pending))
1018+
return false;
1019+
1020+
/* Some softirqs claim to be safe against hotplug and ksoftirqd parking */
1021+
if (!cpu_active(smp_processor_id())) {
1022+
pending &= ~SOFTIRQ_HOTPLUG_SAFE_MASK;
1023+
if (!pending)
1024+
return false;
1025+
}
1026+
1027+
if (ratelimit < 10)
1028+
return false;
1029+
1030+
/* On RT, softirqs handling may be waiting on some lock */
1031+
if (!local_bh_blocked())
1032+
return false;
1033+
1034+
pr_warn("NOHZ tick-stop error: local softirq work is pending, handler #%02x!!!\n",
1035+
pending);
1036+
ratelimit++;
1037+
1038+
return true;
1039+
}
1040+
10021041
static bool can_stop_idle_tick(int cpu, struct tick_sched *ts)
10031042
{
10041043
/*
@@ -1025,17 +1064,8 @@ static bool can_stop_idle_tick(int cpu, struct tick_sched *ts)
10251064
if (need_resched())
10261065
return false;
10271066

1028-
if (unlikely(local_softirq_pending())) {
1029-
static int ratelimit;
1030-
1031-
if (ratelimit < 10 && !local_bh_blocked() &&
1032-
(local_softirq_pending() & SOFTIRQ_STOP_IDLE_MASK)) {
1033-
pr_warn("NOHZ tick-stop error: Non-RCU local softirq work is pending, handler #%02x!!!\n",
1034-
(unsigned int) local_softirq_pending());
1035-
ratelimit++;
1036-
}
1067+
if (unlikely(report_idle_softirq()))
10371068
return false;
1038-
}
10391069

10401070
if (tick_nohz_full_enabled()) {
10411071
/*

0 commit comments

Comments
 (0)