From: Thomas Gleixner <tglx@kernel.org>
To: syzbot <syzbot+74de56995244fe32ffe2@syzkaller.appspotmail.com>,
linux-kernel@vger.kernel.org, peterz@infradead.org,
syzkaller-bugs@googlegroups.com
Cc: Borislav Petkov <bp@alien8.de>, Tony Luck <tony.luck@intel.com>,
linux-edac@vger.kernel.org
Subject: Re: [syzbot] [kernel?] general protection fault in timers_dead_cpu
Date: Tue, 18 Aug 2026 00:12:45 +0200 [thread overview]
Message-ID: <87fr0cl7ky.ffs@fw13> (raw)
In-Reply-To: <87ik58la9w.ffs@fw13>
On Mon, Aug 17 2026 at 23:14, Thomas Gleixner wrote:
> The below quick hack, which I'm not proud of, cures it. I let the MCE
> wizards think about the underlying design problem and let them come up
> with a hopefully nicer solution.
After talking to Borislav briefly, I came up with less ugly one.
Thanks,
tglx
---
--- a/arch/x86/kernel/cpu/mce/core.c
+++ b/arch/x86/kernel/cpu/mce/core.c
@@ -1734,8 +1734,13 @@ int memory_failure(unsigned long pfn, in
*/
static unsigned long check_interval = INITIAL_CHECK_INTERVAL;
-static DEFINE_PER_CPU(unsigned long, mce_next_interval); /* in jiffies */
-static DEFINE_PER_CPU(struct timer_list, mce_timer);
+struct mce_poll_state {
+ struct timer_list timer;
+ unsigned long next_interval;
+ bool active;
+};
+
+static DEFINE_PER_CPU(struct mce_poll_state, mce_poll_state);
static void __start_timer(struct timer_list *t, unsigned long interval)
{
@@ -1764,12 +1769,12 @@ static bool should_enable_timer(unsigned
static void mce_timer_fn(struct timer_list *t)
{
- struct timer_list *cpu_t = this_cpu_ptr(&mce_timer);
+ struct mce_poll_state *pst = this_cpu_ptr(&mce_poll_state);
unsigned long iv;
- WARN_ON(cpu_t != t);
+ WARN_ON(&pst->timer != t);
- iv = __this_cpu_read(mce_next_interval);
+ iv = pst->next_interval;
if (mce_available(this_cpu_ptr(&cpu_info)))
mc_poll_banks();
@@ -1786,7 +1791,7 @@ static void mce_timer_fn(struct timer_li
if (mce_get_storm_mode()) {
__start_timer(t, HZ);
} else if (should_enable_timer(iv)) {
- __this_cpu_write(mce_next_interval, iv);
+ pst->next_interval = iv;
__start_timer(t, iv);
}
}
@@ -1798,14 +1803,14 @@ static void mce_timer_fn(struct timer_li
*/
void mce_timer_kick(bool storm)
{
- struct timer_list *t = this_cpu_ptr(&mce_timer);
+ struct mce_poll_state *pst = this_cpu_ptr(&mce_poll_state);
mce_set_storm_mode(storm);
if (storm)
- __start_timer(t, HZ);
+ __start_timer(&pst->timer, HZ);
else
- __this_cpu_write(mce_next_interval, check_interval * HZ);
+ pst->next_interval = check_interval * HZ;
}
/* Must not be called in IRQ context where timer_delete_sync() can deadlock */
@@ -1814,7 +1819,7 @@ static void mce_timer_delete_all(void)
int cpu;
for_each_online_cpu(cpu)
- timer_delete_sync(&per_cpu(mce_timer, cpu));
+ timer_delete_sync(&per_cpu(mce_poll_state.timer, cpu));
}
static void __mcheck_cpu_mce_banks_init(void)
@@ -2070,29 +2075,29 @@ static void __mcheck_cpu_clear_vendor(st
}
}
-static void mce_start_timer(struct timer_list *t)
+static void mce_start_timer(struct mce_poll_state *pst)
{
unsigned long iv = check_interval * HZ;
if (should_enable_timer(iv)) {
- this_cpu_write(mce_next_interval, iv);
- __start_timer(t, iv);
+ pst->next_interval = iv;
+ __start_timer(&pst->timer, iv);
}
}
static void __mcheck_cpu_setup_timer(void)
{
- struct timer_list *t = this_cpu_ptr(&mce_timer);
+ struct mce_poll_state *pst = this_cpu_ptr(&mce_poll_state);
- timer_setup(t, mce_timer_fn, TIMER_PINNED);
+ timer_setup(&pst->timer, mce_timer_fn, TIMER_PINNED);
}
static void __mcheck_cpu_init_timer(void)
{
- struct timer_list *t = this_cpu_ptr(&mce_timer);
+ struct mce_poll_state *pst = this_cpu_ptr(&mce_poll_state);
- timer_setup(t, mce_timer_fn, TIMER_PINNED);
- mce_start_timer(t);
+ timer_setup(&pst->timer, mce_timer_fn, TIMER_PINNED);
+ mce_start_timer(pst);
}
bool filter_mce(struct mce *m)
@@ -2459,6 +2464,8 @@ static void mce_cpu_restart(void *data)
{
if (!mce_available(raw_cpu_ptr(&cpu_info)))
return;
+ if (!this_cpu_read(mce_poll_state.active))
+ return;
__mcheck_cpu_init_generic();
__mcheck_cpu_init_prepare_banks();
__mcheck_cpu_init_timer();
@@ -2478,6 +2485,8 @@ static void mce_disable_cmci(void *data)
{
if (!mce_available(raw_cpu_ptr(&cpu_info)))
return;
+ if (!this_cpu_read(mce_poll_state.active))
+ return;
cmci_clear();
}
@@ -2485,6 +2494,8 @@ static void mce_enable_ce(void *all)
{
if (!mce_available(raw_cpu_ptr(&cpu_info)))
return;
+ if (!this_cpu_read(mce_poll_state.active))
+ return;
cmci_reenable();
cmci_recheck();
if (all)
@@ -2540,6 +2551,7 @@ static ssize_t set_bank(struct device *s
b->ctl = new;
mutex_lock(&mce_sysfs_mutex);
+ guard(cpus_read_lock)();
mce_restart();
mutex_unlock(&mce_sysfs_mutex);
@@ -2557,6 +2569,7 @@ static ssize_t set_ignore_ce(struct devi
mutex_lock(&mce_sysfs_mutex);
if (mca_cfg.ignore_ce ^ !!new) {
+ guard(cpus_read_lock)();
if (new) {
/* disable ce features */
mce_timer_delete_all();
@@ -2584,6 +2597,7 @@ static ssize_t set_cmci_disabled(struct
mutex_lock(&mce_sysfs_mutex);
if (mca_cfg.cmci_disabled ^ !!new) {
+ guard(cpus_read_lock)();
if (new) {
/* disable cmci */
on_each_cpu(mce_disable_cmci, NULL, 1);
@@ -2610,6 +2624,7 @@ static ssize_t store_int_with_restart(st
return ret;
mutex_lock(&mce_sysfs_mutex);
+ guard(cpus_read_lock)();
mce_restart();
mutex_unlock(&mce_sysfs_mutex);
@@ -2764,21 +2779,23 @@ static int mce_cpu_dead(unsigned int cpu
static int mce_cpu_online(unsigned int cpu)
{
- struct timer_list *t = this_cpu_ptr(&mce_timer);
+ struct mce_poll_state *pst = this_cpu_ptr(&mce_poll_state);
mce_device_create(cpu);
mce_threshold_create_device(cpu);
mce_reenable_cpu();
- mce_start_timer(t);
+ mce_start_timer(pst);
+ pst->active = true;
return 0;
}
static int mce_cpu_pre_down(unsigned int cpu)
{
- struct timer_list *t = this_cpu_ptr(&mce_timer);
+ struct mce_poll_state *pst = this_cpu_ptr(&mce_poll_state);
+ pst->active = false;
mce_disable_cpu();
- timer_delete_sync(t);
+ timer_delete_sync(&pst->timer);
mce_threshold_remove_device(cpu);
mce_device_remove(cpu);
return 0;
next prev parent reply other threads:[~2026-08-17 22:12 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-14 7:28 [syzbot] [kernel?] general protection fault in timers_dead_cpu syzbot
2026-08-17 21:14 ` Thomas Gleixner
2026-08-17 22:12 ` Thomas Gleixner [this message]
2026-08-18 0:21 ` Borislav Petkov
2026-08-17 22:14 ` [PATCH] timer: Keep debugobjects state consistent in migrate_timer_list() Thomas Gleixner
2026-08-17 23:55 ` [syzbot] [kernel?] general protection fault in timers_dead_cpu Borislav Petkov
2026-08-18 0:18 ` Borislav Petkov
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=87fr0cl7ky.ffs@fw13 \
--to=tglx@kernel.org \
--cc=bp@alien8.de \
--cc=linux-edac@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=peterz@infradead.org \
--cc=syzbot+74de56995244fe32ffe2@syzkaller.appspotmail.com \
--cc=syzkaller-bugs@googlegroups.com \
--cc=tony.luck@intel.com \
/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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox