* [PATCH v2] stop_machine: Warn when a stop state stalls
@ 2026-07-25 19:19 Bradley Morgan
0 siblings, 0 replies; only message in thread
From: Bradley Morgan @ 2026-07-25 19:19 UTC (permalink / raw)
To: Andrew Morton; +Cc: linux-kernel, Peter Zijlstra, Tejun Heo, Bradley Morgan
multi_cpu_stop() feeds the NMI watchdog and rcu_momentary_eqs() on
every spin. so when a CPU never acks a state transition the machine
hangs, and the two detectors that wouldve caught it are the ones being
fed. no tick either, irqs are off everywhere, hung task is blind too.
the hang logs exactly nothing.
Stamp every state transition in set_state() and let waiters yell once
after ten seconds stuck in the same state. every waiter reports
itself, the culprit is the CPU missing from the output. its
local_clock() not jiffies, jiffies is dead once everyone has irqs off.
One branch in a path that already pokes two watchdogs per spin.
nothing changes while stop_machine() behaves.
Signed-off-by: Bradley Morgan <include@grrlz.net>
---
Changes since V1:
- Oh no! forgot to CC loads of people..
- No code was changed..
kernel/stop_machine.c | 21 ++++++++++++++++++++-
1 file changed, 20 insertions(+), 1 deletion(-)
diff --git a/kernel/stop_machine.c b/kernel/stop_machine.c
index 773d8e9ae30c..1e1d1d46c24d 100644
--- a/kernel/stop_machine.c
+++ b/kernel/stop_machine.c
@@ -15,12 +15,14 @@
#include <linux/export.h>
#include <linux/percpu.h>
#include <linux/sched.h>
+#include <linux/sched/clock.h>
#include <linux/stop_machine.h>
#include <linux/interrupt.h>
#include <linux/kallsyms.h>
#include <linux/smpboot.h>
#include <linux/atomic.h>
#include <linux/nmi.h>
+#include <linux/time64.h>
#include <linux/sched/wake_q.h>
/*
@@ -174,6 +176,7 @@ struct multi_stop_data {
enum multi_stop_state state;
atomic_t thread_ack;
+ u64 tstamp;
};
static void set_state(struct multi_stop_data *msdata,
@@ -181,6 +184,7 @@ static void set_state(struct multi_stop_data *msdata,
{
/* Reset ack counter. */
atomic_set(&msdata->thread_ack, msdata->num_threads);
+ WRITE_ONCE(msdata->tstamp, local_clock());
smp_wmb();
WRITE_ONCE(msdata->state, newstate);
}
@@ -197,6 +201,9 @@ notrace void __weak stop_machine_yield(const struct cpumask *cpumask)
cpu_relax();
}
+/* how long a state may sit unacked before waiting CPUs complain */
+#define MULTI_STOP_STUCK_NS (10ULL * NSEC_PER_SEC)
+
/* This is the cpu_stop function which stops the CPU. */
static int multi_cpu_stop(void *data)
{
@@ -205,7 +212,7 @@ static int multi_cpu_stop(void *data)
int cpu = smp_processor_id(), err = 0;
const struct cpumask *cpumask;
unsigned long flags;
- bool is_active;
+ bool is_active, stuck = false;
/*
* When called from stop_machine_from_inactive_cpu(), irq might
@@ -250,6 +257,18 @@ static int multi_cpu_stop(void *data)
touch_nmi_watchdog();
/* Also suppress RCU CPU stall warnings. */
rcu_momentary_eqs();
+ /*
+ * the watchdogs above eat the evidence, a CPU that
+ * never acks hangs us silently. every waiter yells
+ * once, the culprit is the one missing from the log.
+ */
+ if (!stuck &&
+ local_clock() - READ_ONCE(msdata->tstamp) > MULTI_STOP_STUCK_NS) {
+ stuck = true;
+ pr_warn("%s: CPU %d stuck in state %d (%ps), %d acks missing\n",
+ __func__, cpu, curstate, msdata->fn,
+ atomic_read(&msdata->thread_ack));
+ }
}
} while (curstate != MULTI_STOP_EXIT);
--
2.47.3
^ permalink raw reply related [flat|nested] only message in thread
only message in thread, other threads:[~2026-07-25 19:19 UTC | newest]
Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-25 19:19 [PATCH v2] stop_machine: Warn when a stop state stalls Bradley Morgan
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.