From: Frederic Weisbecker <frederic@kernel.org>
To: Peter Zijlstra <peterz@infradead.org>,
"Paul E . McKenney" <paulmck@kernel.org>
Cc: LKML <linux-kernel@vger.kernel.org>,
Frederic Weisbecker <frederic@kernel.org>,
"Rafael J . Wysocki" <rafael.j.wysocki@intel.com>,
Ingo Molnar <mingo@kernel.org>,
Thomas Gleixner <tglx@linutronix.de>,
stable@vger.kernel.org
Subject: [RFC PATCH 3/8] rcu/nocb: Perform deferred wake up before last idle's need_resched() check
Date: Sat, 9 Jan 2021 03:05:31 +0100 [thread overview]
Message-ID: <20210109020536.127953-4-frederic@kernel.org> (raw)
In-Reply-To: <20210109020536.127953-1-frederic@kernel.org>
Entering RCU idle mode may cause a deferred wake up of an RCU NOCB_GP
kthread (rcuog) to be serviced.
Usually a local wake up happening while running the idle task is handled
in one of the need_resched() checks carefully placed within the idle
loop that can break to the scheduler.
Unfortunately the call to rcu_idle_enter() is already beyond the last
generic need_resched() check and we may halt the CPU with a resched
request unhandled, leaving the task hanging.
Fix this with splitting the rcuog wakeup handling from rcu_idle_enter()
and place it before the last generic need_resched() check in the idle
loop. It is then assumed that no call to call_rcu() will be performed
after that in the idle loop until the CPU is put in low power mode.
Further debug code will help spotting the offenders.
Reported-by: Paul E. McKenney <paulmck@kernel.org>
Fixes: 96d3fd0d315a (rcu: Break call_rcu() deadlock involving scheduler and perf)
Cc: stable@vger.kernel.org
Cc: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Ingo Molnar<mingo@kernel.org>
Signed-off-by: Frederic Weisbecker <frederic@kernel.org>
---
include/linux/rcupdate.h | 2 ++
kernel/rcu/tree.c | 3 ---
kernel/rcu/tree_plugin.h | 5 +++++
kernel/sched/idle.c | 3 +++
4 files changed, 10 insertions(+), 3 deletions(-)
diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h
index de0826411311..4068234fb303 100644
--- a/include/linux/rcupdate.h
+++ b/include/linux/rcupdate.h
@@ -104,8 +104,10 @@ static inline void rcu_user_exit(void) { }
#ifdef CONFIG_RCU_NOCB_CPU
void rcu_init_nohz(void);
+void rcu_nocb_flush_deferred_wakeup(void);
#else /* #ifdef CONFIG_RCU_NOCB_CPU */
static inline void rcu_init_nohz(void) { }
+static inline void rcu_nocb_flush_deferred_wakeup(void) { }
#endif /* #else #ifdef CONFIG_RCU_NOCB_CPU */
/**
diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c
index b9fff18d14d9..b6e1377774e3 100644
--- a/kernel/rcu/tree.c
+++ b/kernel/rcu/tree.c
@@ -670,10 +670,7 @@ static noinstr void rcu_eqs_enter(bool user)
*/
void rcu_idle_enter(void)
{
- struct rcu_data *rdp = this_cpu_ptr(&rcu_data);
-
lockdep_assert_irqs_disabled();
- do_nocb_deferred_wakeup(rdp);
rcu_eqs_enter(false);
}
EXPORT_SYMBOL_GPL(rcu_idle_enter);
diff --git a/kernel/rcu/tree_plugin.h b/kernel/rcu/tree_plugin.h
index 7e291ce0a1d6..d5b38c28abd1 100644
--- a/kernel/rcu/tree_plugin.h
+++ b/kernel/rcu/tree_plugin.h
@@ -2187,6 +2187,11 @@ static void do_nocb_deferred_wakeup(struct rcu_data *rdp)
do_nocb_deferred_wakeup_common(rdp);
}
+void rcu_nocb_flush_deferred_wakeup(void)
+{
+ do_nocb_deferred_wakeup(this_cpu_ptr(&rcu_data));
+}
+
void __init rcu_init_nohz(void)
{
int cpu;
diff --git a/kernel/sched/idle.c b/kernel/sched/idle.c
index 305727ea0677..b601a3aa2152 100644
--- a/kernel/sched/idle.c
+++ b/kernel/sched/idle.c
@@ -55,6 +55,7 @@ __setup("hlt", cpu_idle_nopoll_setup);
static noinline int __cpuidle cpu_idle_poll(void)
{
trace_cpu_idle(0, smp_processor_id());
+ rcu_nocb_flush_deferred_wakeup();
stop_critical_timings();
rcu_idle_enter();
local_irq_enable();
@@ -173,6 +174,8 @@ static void cpuidle_idle_call(void)
struct cpuidle_driver *drv = cpuidle_get_cpu_driver(dev);
int next_state, entered_state;
+ rcu_nocb_flush_deferred_wakeup();
+
/*
* Check if the idle task must be rescheduled. If it is the
* case, exit the function after re-enabling the local irq.
--
2.25.1
next prev parent reply other threads:[~2021-01-09 2:06 UTC|newest]
Thread overview: 25+ messages / expand[flat|nested] mbox.gz Atom feed top
2021-01-09 2:05 [RFC PATCH 0/8] rcu/sched: Fix ignored rescheduling after rcu_eqs_enter() v3 Frederic Weisbecker
2021-01-09 2:05 ` [RFC PATCH 1/8] rcu: Remove superfluous rdp fetch Frederic Weisbecker
2021-01-09 9:03 ` Greg KH
2021-01-10 10:59 ` Frederic Weisbecker
2021-01-09 2:05 ` [RFC PATCH 2/8] rcu: Pull deferred rcuog wake up to rcu_eqs_enter() callers Frederic Weisbecker
2021-01-09 2:05 ` Frederic Weisbecker [this message]
2021-01-09 2:05 ` [RFC PATCH 4/8] rcu/nocb: Trigger self-IPI on late deferred wake up before user resume Frederic Weisbecker
2021-01-11 12:04 ` Peter Zijlstra
2021-01-11 12:35 ` Frederic Weisbecker
2021-01-09 2:05 ` [RFC PATCH 5/8] entry: Explicitly flush pending rcuog wakeup before last rescheduling points Frederic Weisbecker
2021-01-11 0:40 ` Frederic Weisbecker
2021-01-11 5:13 ` Paul E. McKenney
2021-01-11 11:50 ` Frederic Weisbecker
2021-01-11 12:08 ` Peter Zijlstra
2021-01-11 12:54 ` Frederic Weisbecker
2021-01-09 2:05 ` [RFC PATCH 6/8] sched: Report local wake up on resched blind zone within idle loop Frederic Weisbecker
2021-01-11 12:25 ` Peter Zijlstra
2021-01-11 12:56 ` Frederic Weisbecker
2021-01-12 8:24 ` [sched] 9720a64438: WARNING:at_kernel/sched/core.c:#sched_resched_local_assert_allowed kernel test robot
2021-01-12 8:24 ` kernel test robot
[not found] ` <161062476680.19482.8402362019173198799@build.alporthouse.com>
2021-01-14 15:19 ` [RFC PATCH 6/8] sched: Report local wake up on resched blind zone within idle loop Paul E. McKenney
2021-01-09 2:05 ` [RFC PATCH 7/8] entry: Report local wake up on resched blind zone while resuming to user Frederic Weisbecker
2021-01-13 2:46 ` [entry] 8e01c5f104: unixbench.score -2.2% regression kernel test robot
2021-01-13 2:46 ` kernel test robot
2021-01-09 2:05 ` [RFC PATCH 8/8] timer: Report ignored local enqueue in nohz mode Frederic Weisbecker
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20210109020536.127953-4-frederic@kernel.org \
--to=frederic@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=mingo@kernel.org \
--cc=paulmck@kernel.org \
--cc=peterz@infradead.org \
--cc=rafael.j.wysocki@intel.com \
--cc=stable@vger.kernel.org \
--cc=tglx@linutronix.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.