From: Thomas Gleixner <tglx@kernel.org>
To: Boqun Feng <boqun@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>,
linux-kernel@vger.kernel.org, linux-tip-commits@vger.kernel.org,
x86@kernel.org
Subject: Re: [PATCH] locking: Revert switching guards to _irq_{disable,enable}()
Date: Sat, 29 Aug 2026 01:11:56 +0200 [thread overview]
Message-ID: <87mru5et6r.ffs@fw13> (raw)
In-Reply-To: <87wltbdvmd.ffs@fw13>
On Fri, Aug 28 2026 at 00:52, Thomas Gleixner wrote:
> On Thu, Aug 27 2026 at 12:41, Boqun Feng wrote:
> So I sat down and reverted
>
> 1b0866874833 ("locking: Switch to _irq_{disable,enable}() variants in cleanup guards")
> e901c1510e24 ("irq,spin_lock: Add counted interrupt disabling/enabling")
>
> and then hacked it up just to see how far I get before vanishing to bed.
>
> Three hours later it surprisingly booted right away into a full distro
> kernel and survived kernel builds and a few test cases. :)
/FACMEPALM
Yesterday night I was really surprised but too tired to think about it.
When I came around today to look at it again I was more than embarrassed
to figure out that the KVM script rebuilt the wrong branch over and
over. So the build numbers kept increasing...
Brown paperbag time ...
Of course the real thing did _NOT_ boot at all, so I sat down and
figured out what's going wrong and added a pile of debug to it, which is
sadly non-existing in this magic local_interrupt_dis/enable() code.
The overall fallout is moderate. Some of it are actual (but harmless)
bugs and the rest are the oddball cases we talked about before.
It builds and boots now for real, but of course your mileage will vary
depending on hardware and .config. Combo patch on top of the reverts is
below.
The whole pile can be retrieved from git via:
git://git.kernel.org/pub/scm/linux/kernel/git/tglx/devel.git irqflags
I have some thoughts about how to deal with the overall disaster, but
that has to wait until my brain is truly awake again...
Thanks,
tglx
---
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index 15fd9ec5ecac..c7229a7cfa7c 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -133,6 +133,7 @@ config X86
select ARCH_USES_CFI_TRAPS if X86_64 && CFI
select ARCH_SUPPORTS_LTO_CLANG
select ARCH_SUPPORTS_LTO_CLANG_THIN
+ select ARCH_SUPPORTS_PREEMPT_COUNT_IRQFLAGS
select ARCH_SUPPORTS_RT
select ARCH_USE_BUILTIN_BSWAP
select ARCH_USE_CMPXCHG_LOCKREF
diff --git a/arch/x86/include/asm/hardirq.h b/arch/x86/include/asm/hardirq.h
index dea60d66d976..34bdf24b939b 100644
--- a/arch/x86/include/asm/hardirq.h
+++ b/arch/x86/include/asm/hardirq.h
@@ -113,4 +113,6 @@ static __always_inline bool kvm_get_cpu_l1tf_flush_l1d(void)
static __always_inline void kvm_set_cpu_l1tf_flush_l1d(void) { }
#endif /* IS_ENABLED(CONFIG_KVM_INTEL) */
+#define __ARCH_IRQ_EXIT_IRQS_DISABLED 1
+
#endif /* _ASM_X86_HARDIRQ_H */
diff --git a/arch/x86/include/asm/preempt.h b/arch/x86/include/asm/preempt.h
index fafb6f8cdac3..8b4d4cbae52e 100644
--- a/arch/x86/include/asm/preempt.h
+++ b/arch/x86/include/asm/preempt.h
@@ -61,10 +61,20 @@ static __always_inline void preempt_count_set(unsigned long pc)
*/
#define init_task_preempt_count(p) do { } while (0)
-#define init_idle_preempt_count(p, cpu) do { \
- per_cpu(__preempt_count, (cpu)) = PREEMPT_DISABLED; \
+#ifdef CONFIG_PREEMPT_COUNT_IRQFLAGS
+
+#define init_idle_preempt_count(p, cpu) do { \
+ per_cpu(__preempt_count, (cpu)) = PREEMPT_DISABLED | HARDIRQ_DISABLE_OFFSET; \
} while (0)
+#else
+
+#define init_idle_preempt_count(p, cpu) do { \
+ per_cpu(__preempt_count, (cpu)) = PREEMPT_DISABLED; \
+} while (0)
+
+#endif
+
/*
* We fold the NEED_RESCHED bit into the preempt count such that
* preempt_enable() can decrement and test for needing to reschedule with a
diff --git a/arch/x86/kernel/kvm.c b/arch/x86/kernel/kvm.c
index 6b0a5861ccb8..0b5a05cb543f 100644
--- a/arch/x86/kernel/kvm.c
+++ b/arch/x86/kernel/kvm.c
@@ -256,9 +256,9 @@ noinstr u32 kvm_read_and_reset_apf_flags(void)
{
u32 flags = 0;
- if (__this_cpu_read(async_pf_enabled)) {
- flags = __this_cpu_read(apf_reason.flags);
- __this_cpu_write(apf_reason.flags, 0);
+ if (raw_cpu_read(async_pf_enabled)) {
+ flags = raw_cpu_read(apf_reason.flags);
+ raw_cpu_write(apf_reason.flags, 0);
}
return flags;
diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c
index 346c438ac880..b0be24a386f3 100644
--- a/arch/x86/kernel/process.c
+++ b/arch/x86/kernel/process.c
@@ -824,7 +824,7 @@ void __noreturn stop_this_cpu(void *dummy)
struct cpuinfo_x86 *c = this_cpu_ptr(&cpu_info);
unsigned int cpu = smp_processor_id();
- local_irq_disable();
+ raw_force_local_irq_disable();
/*
* Remove this CPU from the online mask and disable it
diff --git a/arch/x86/kernel/reboot.c b/arch/x86/kernel/reboot.c
index 0fed6d0d7e32..40104170be24 100644
--- a/arch/x86/kernel/reboot.c
+++ b/arch/x86/kernel/reboot.c
@@ -98,7 +98,7 @@ static int __init set_efi_reboot(const struct dmi_system_id *d)
void __noreturn machine_real_restart(unsigned int type)
{
- local_irq_disable();
+ raw_force_local_irq_disable();
/*
* Write zero to CMOS register number 0x0f, which the BIOS POST
@@ -535,7 +535,7 @@ static inline void nmi_shootdown_cpus_on_restart(void);
#if IS_ENABLED(CONFIG_KVM_X86)
static void emergency_reboot_disable_virtualization(void)
{
- local_irq_disable();
+ raw_force_local_irq_disable();
/*
* Disable virtualization on all CPUs before rebooting to avoid hanging
@@ -699,7 +699,7 @@ void native_machine_shutdown(void)
* not receive the per-cpu timer interrupt which may trigger
* scheduler's load balance.
*/
- local_irq_disable();
+ raw_force_local_irq_disable();
stop_other_cpus();
#endif
@@ -823,7 +823,8 @@ static int crash_nmi_callback(unsigned int val, struct pt_regs *regs)
*/
if (cpu == crashing_cpu)
return NMI_HANDLED;
- local_irq_disable();
+
+ raw_force_local_irq_disable();
if (shootdown_callback)
shootdown_callback(cpu, regs);
@@ -865,7 +866,7 @@ void nmi_shootdown_cpus(nmi_shootdown_cb callback)
{
unsigned long msecs;
- local_irq_disable();
+ raw_force_local_irq_disable();
/*
* Avoid certain doom if a shootdown already occurred; re-registering
diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c
index aa88370ce739..3164eab7cecd 100644
--- a/arch/x86/mm/fault.c
+++ b/arch/x86/mm/fault.c
@@ -1486,7 +1486,8 @@ handle_page_fault(struct pt_regs *regs, unsigned long error_code,
* page fault handling might have reenabled interrupts,
* make sure to disable them again.
*/
- local_irq_disable();
+ if (!irqs_disabled())
+ local_irq_disable();
}
DEFINE_IDTENTRY_RAW_ERRORCODE(exc_page_fault)
diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c
index 132a9df98471..f13e88fb7a78 100644
--- a/drivers/acpi/sleep.c
+++ b/drivers/acpi/sleep.c
@@ -1095,7 +1095,7 @@ static int acpi_power_off(struct sys_off_data *data)
{
/* acpi_sleep_prepare(ACPI_STATE_S5) should have already been called */
pr_debug("%s called\n", __func__);
- local_irq_disable();
+ raw_force_local_irq_disable();
acpi_enter_sleep_state(ACPI_STATE_S5);
return NOTIFY_DONE;
}
diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h
index 3bf969ad8fe0..b54afbd6e073 100644
--- a/include/linux/interrupt.h
+++ b/include/linux/interrupt.h
@@ -594,13 +594,14 @@ struct softirq_action
asmlinkage void do_softirq(void);
asmlinkage void __do_softirq(void);
+void do_softirq_irqsoff(void);
#ifdef CONFIG_PREEMPT_RT
extern void do_softirq_post_smp_call_flush(unsigned int was_pending);
#else
static inline void do_softirq_post_smp_call_flush(unsigned int unused)
{
- do_softirq();
+ do_softirq_irqsoff();
}
#endif
diff --git a/include/linux/irq-entry-common.h b/include/linux/irq-entry-common.h
index 0bb6c03481fa..ba5210fab31f 100644
--- a/include/linux/irq-entry-common.h
+++ b/include/linux/irq-entry-common.h
@@ -97,6 +97,7 @@ static __always_inline bool arch_in_rcu_eqs(void) { return false; }
*/
static __always_inline void enter_from_user_mode(struct pt_regs *regs)
{
+ __preempt_count_inc_hardirqs_disable();
arch_enter_from_user_mode(regs);
lockdep_hardirqs_off(CALLER_ADDR0);
@@ -275,6 +276,7 @@ static __always_inline void exit_to_user_mode(void)
user_enter_irqoff();
arch_exit_to_user_mode();
lockdep_hardirqs_on(CALLER_ADDR0);
+ __preempt_count_dec_hardirqs_disable();
}
/**
@@ -385,6 +387,8 @@ static __always_inline irqentry_state_t irqentry_enter_from_kernel_mode(struct p
.exit_rcu = false,
};
+ __preempt_count_inc_hardirqs_disable();
+
/*
* If this entry hit the idle task invoke ct_irq_enter() whether
* RCU is watching or not.
@@ -498,6 +502,7 @@ irqentry_exit_to_kernel_mode_after_preempt(struct pt_regs *regs, irqentry_state_
instrumentation_end();
ct_irq_exit();
lockdep_hardirqs_on(CALLER_ADDR0);
+ __preempt_count_dec_hardirqs_disable();
return;
}
@@ -514,6 +519,7 @@ irqentry_exit_to_kernel_mode_after_preempt(struct pt_regs *regs, irqentry_state_
if (state.exit_rcu)
ct_irq_exit();
}
+ __preempt_count_dec_hardirqs_disable();
}
/**
diff --git a/include/linux/irqflags.h b/include/linux/irqflags.h
index 57b074e0cfbb..dd55786768d1 100644
--- a/include/linux/irqflags.h
+++ b/include/linux/irqflags.h
@@ -13,6 +13,7 @@
#define _LINUX_TRACE_IRQFLAGS_H
#include <linux/irqflags_types.h>
+#include <linux/preempt.h>
#include <linux/typecheck.h>
#include <linux/cleanup.h>
#include <asm/irqflags.h>
@@ -163,33 +164,149 @@ extern void warn_bogus_irq_restore(void);
#endif
/*
- * Wrap the arch provided IRQ routines to provide appropriate checks.
+ * Wrap the architecture specific routines to provide appropriate checks.
*/
-#define raw_local_irq_disable() arch_local_irq_disable()
-#define raw_local_irq_enable() arch_local_irq_enable()
+#ifdef CONFIG_PREEMPT_COUNT_IRQFLAGS
+
+// FIXME: Convert this into a proper debug mechanism
+#define debug_assert(c) \
+do { \
+ WARN_ON(!(c)); \
+} while (0)
+
+static __always_inline void raw_local_irq_disable(void)
+{
+ debug_assert((preempt_count() & HARDIRQ_DISABLE_MASK) == 0);
+ arch_local_irq_disable();
+ __preempt_count_add(HARDIRQ_DISABLE_OFFSET);
+}
+
+static __always_inline void raw_force_local_irq_disable(void)
+{
+ arch_local_irq_disable();
+ __preempt_count_add(HARDIRQ_DISABLE_OFFSET);
+}
+
+static __always_inline void raw_local_irq_enable(void)
+{
+ debug_assert((preempt_count() & HARDIRQ_DISABLE_MASK) == HARDIRQ_DISABLE_OFFSET);
+ __preempt_count_sub(HARDIRQ_DISABLE_OFFSET);
+ arch_local_irq_enable();
+}
+
+static __always_inline unsigned long __raw_local_irq_save(void)
+{
+ unsigned int cnt = preempt_count() & HARDIRQ_DISABLE_MASK;
+
+ debug_assert(cnt != HARDIRQ_DISABLE_MASK);
+
+ if (!cnt)
+ arch_local_irq_disable();
+ __preempt_count_add(HARDIRQ_DISABLE_OFFSET);
+
+ return cnt;
+}
+
+static __always_inline void __raw_local_irq_restore(unsigned long cnt)
+{
+ debug_assert((preempt_count() & HARDIRQ_DISABLE_MASK) == (cnt + HARDIRQ_DISABLE_OFFSET));
+
+ if (!(__preempt_count_sub_return(HARDIRQ_DISABLE_OFFSET) & HARDIRQ_DISABLE_MASK))
+ arch_local_irq_enable();
+}
+
+static __always_inline unsigned long __raw_local_save_flags(void)
+{
+ return preempt_count() & HARDIRQ_DISABLE_MASK;
+}
+
+static __always_inline bool __raw_irqs_disabled_flags(unsigned long cnt)
+{
+ return !!cnt;
+}
+
+static __always_inline bool raw_irqs_disabled(void)
+{
+ return preempt_count() & HARDIRQ_DISABLE_MASK;
+}
+
+static __always_inline void raw_safe_halt(void)
+{
+ debug_assert((preempt_count() & HARDIRQ_DISABLE_MASK) == HARDIRQ_DISABLE_OFFSET);
+ __preempt_count_sub(HARDIRQ_DISABLE_OFFSET);
+ arch_safe_halt();
+}
+
+#else
+
+static __always_inline void raw_local_irq_disable(void)
+{
+ arch_local_irq_disable();
+}
+
+static __always_inline void raw_force_local_irq_disable(void)
+{
+ arch_local_irq_disable();
+}
+
+static __always_inline void raw_local_irq_enable(void)
+{
+ arch_local_irq_enable();
+}
+
+static __always_inline unsigned long __raw_local_irq_save(void)
+{
+ return arch_local_irq_save();
+}
+
+static __always_inline void __raw_local_irq_restore(unsigned long flags)
+{
+ arch_local_irq_restore(flags);
+}
+
+static __always_inline unsigned long __raw_local_save_flags(void)
+{
+ return arch_local_save_flags();
+}
+
+static __always_inline bool __raw_irqs_disabled_flags(unsigned long flags)
+{
+ return arch_irqs_disabled_flags(flags);
+}
+
+static __always_inline bool raw_irqs_disabled(void)
+{
+ return arch_irqs_disabled();
+}
+
+static __always_inline void raw_safe_halt(void)
+{
+ arch_safe_halt();
+}
+
+#endif
+
#define raw_local_irq_save(flags) \
do { \
typecheck(unsigned long, flags); \
- flags = arch_local_irq_save(); \
+ flags = __raw_local_irq_save(); \
} while (0)
#define raw_local_irq_restore(flags) \
do { \
typecheck(unsigned long, flags); \
raw_check_bogus_irq_restore(); \
- arch_local_irq_restore(flags); \
+ __raw_local_irq_restore(flags); \
} while (0)
#define raw_local_save_flags(flags) \
do { \
typecheck(unsigned long, flags); \
- flags = arch_local_save_flags(); \
+ flags = __raw_local_save_flags(); \
} while (0)
#define raw_irqs_disabled_flags(flags) \
({ \
typecheck(unsigned long, flags); \
- arch_irqs_disabled_flags(flags); \
+ __raw_irqs_disabled_flags(flags); \
})
-#define raw_irqs_disabled() (arch_irqs_disabled())
-#define raw_safe_halt() arch_safe_halt()
/*
* The local_irq_*() APIs are equal to the raw_local_irq*()
diff --git a/include/linux/preempt.h b/include/linux/preempt.h
index 2e689de7b29a..c953cdfb3cc2 100644
--- a/include/linux/preempt.h
+++ b/include/linux/preempt.h
@@ -54,31 +54,31 @@
* NMI_MASK: 0xf0000000
* (PREEMPT_NEED_RESCHED is in a different word)
*/
-#define PREEMPT_BITS 8
-#define SOFTIRQ_BITS 8
+#define PREEMPT_BITS 8
+#define SOFTIRQ_BITS 8
#define HARDIRQ_DISABLE_BITS 8
-#define HARDIRQ_BITS 4
-#define NMI_BITS (1 + 3*IS_ENABLED(CONFIG_HAS_SEPARATE_PREEMPT_RESCHED_BITS))
+#define HARDIRQ_BITS 4
+#define NMI_BITS (1 + 3 * IS_ENABLED(CONFIG_HAS_SEPARATE_PREEMPT_RESCHED_BITS))
-#define PREEMPT_SHIFT 0
-#define SOFTIRQ_SHIFT (PREEMPT_SHIFT + PREEMPT_BITS)
+#define PREEMPT_SHIFT 0
+#define SOFTIRQ_SHIFT (PREEMPT_SHIFT + PREEMPT_BITS)
#define HARDIRQ_DISABLE_SHIFT (SOFTIRQ_SHIFT + SOFTIRQ_BITS)
-#define HARDIRQ_SHIFT (HARDIRQ_DISABLE_SHIFT + HARDIRQ_DISABLE_BITS)
-#define NMI_SHIFT (HARDIRQ_SHIFT + HARDIRQ_BITS)
+#define HARDIRQ_SHIFT (HARDIRQ_DISABLE_SHIFT + HARDIRQ_DISABLE_BITS)
+#define NMI_SHIFT (HARDIRQ_SHIFT + HARDIRQ_BITS)
-#define __IRQ_MASK(x) ((1UL << (x))-1)
+#define __IRQ_MASK(x) ((1UL << (x))-1)
-#define PREEMPT_MASK (__IRQ_MASK(PREEMPT_BITS) << PREEMPT_SHIFT)
-#define SOFTIRQ_MASK (__IRQ_MASK(SOFTIRQ_BITS) << SOFTIRQ_SHIFT)
+#define PREEMPT_MASK (__IRQ_MASK(PREEMPT_BITS) << PREEMPT_SHIFT)
+#define SOFTIRQ_MASK (__IRQ_MASK(SOFTIRQ_BITS) << SOFTIRQ_SHIFT)
#define HARDIRQ_DISABLE_MASK (__IRQ_MASK(HARDIRQ_DISABLE_BITS) << HARDIRQ_DISABLE_SHIFT)
-#define HARDIRQ_MASK (__IRQ_MASK(HARDIRQ_BITS) << HARDIRQ_SHIFT)
-#define NMI_MASK (__IRQ_MASK(NMI_BITS) << NMI_SHIFT)
+#define HARDIRQ_MASK (__IRQ_MASK(HARDIRQ_BITS) << HARDIRQ_SHIFT)
+#define NMI_MASK (__IRQ_MASK(NMI_BITS) << NMI_SHIFT)
-#define PREEMPT_OFFSET (1UL << PREEMPT_SHIFT)
-#define SOFTIRQ_OFFSET (1UL << SOFTIRQ_SHIFT)
+#define PREEMPT_OFFSET (1UL << PREEMPT_SHIFT)
+#define SOFTIRQ_OFFSET (1UL << SOFTIRQ_SHIFT)
#define HARDIRQ_DISABLE_OFFSET (1UL << HARDIRQ_DISABLE_SHIFT)
-#define HARDIRQ_OFFSET (1UL << HARDIRQ_SHIFT)
-#define NMI_OFFSET (1UL << NMI_SHIFT)
+#define HARDIRQ_OFFSET (1UL << HARDIRQ_SHIFT)
+#define NMI_OFFSET (1UL << NMI_SHIFT)
#define SOFTIRQ_DISABLE_OFFSET (2 * SOFTIRQ_OFFSET)
@@ -90,18 +90,29 @@
*
* Reset by start_kernel()->sched_init()->init_idle()->init_idle_preempt_count().
*/
+
+#ifdef CONFIG_PREEMPT_COUNT_IRQFLAGS
+
+#define INIT_PREEMPT_COUNT (PREEMPT_OFFSET + HARDIRQ_DISABLE_OFFSET)
+#define SCHED_PREEMPT_COUNT (2 * PREEMPT_DISABLE_OFFSET + HARDIRQ_DISABLE_OFFSET)
+
+#else
+
#define INIT_PREEMPT_COUNT PREEMPT_OFFSET
+#define SCHED_PREEMPT_COUNT (2 * PREEMPT_DISABLE_OFFSET)
+
+#endif
/*
* Initial preempt_count value; reflects the preempt_count schedule invariant
* which states that during context switches:
*
- * preempt_count() == 2*PREEMPT_DISABLE_OFFSET
+ * preempt_count() == SCHED_PREEMPT_COUNT
*
- * Note: PREEMPT_DISABLE_OFFSET is 0 for !PREEMPT_COUNT kernels.
+ * Note: SCHED_PREEMPT_COUNT is 0 for !PREEMPT_COUNT kernels.
* Note: See finish_task_switch().
*/
-#define FORK_PREEMPT_COUNT (2*PREEMPT_DISABLE_OFFSET + PREEMPT_ENABLED)
+#define FORK_PREEMPT_COUNT (SCHED_PREEMPT_COUNT + PREEMPT_ENABLED)
/* preempt_count() and related functions, depends on PREEMPT_NEED_RESCHED */
#include <asm/preempt.h>
@@ -168,6 +179,16 @@ static __always_inline unsigned char interrupt_context_level(void)
#define in_softirq() (softirq_count())
#define in_interrupt() (irq_count())
+/*
+ * Check whether a fault happened in an atomic context. Depending on
+ * CONFIG_PREEMPT_COUNT and CONFIG_PREEMPTION this check might be useless.
+ */
+#ifdef CONFIG_PREEMPT_COUNT_IRQFLAGS
+# define fault_in_atomic() (preempt_count() != HARDIRQ_DISABLE_OFFSET)
+#else
+# define fault_in_atomic() in_atomic()
+#endif
+
/*
* The preempt_count offset after preempt_disable();
*/
@@ -322,6 +343,21 @@ do { \
#endif /* CONFIG_PREEMPT_COUNT */
+#ifdef CONFIG_PREEMPT_COUNT_IRQFLAGS
+static __always_inline void __preempt_count_inc_hardirqs_disable(void)
+{
+ __preempt_count_add(HARDIRQ_DISABLE_OFFSET);
+}
+
+static __always_inline void __preempt_count_dec_hardirqs_disable(void)
+{
+ __preempt_count_sub(HARDIRQ_DISABLE_OFFSET);
+}
+#else
+static __always_inline void __preempt_count_inc_hardirqs_disable(void) { }
+static __always_inline void __preempt_count_dec_hardirqs_disable(void) { }
+#endif
+
#ifdef MODULE
/*
* Modules have no business playing preemption tricks.
diff --git a/include/linux/uaccess.h b/include/linux/uaccess.h
index eddbbb65ccc4..086de4c18575 100644
--- a/include/linux/uaccess.h
+++ b/include/linux/uaccess.h
@@ -296,9 +296,9 @@ static inline bool pagefault_disabled(void)
* stick to pagefault_disabled().
* Please NEVER use preempt_disable() to disable the fault handler. With
* !CONFIG_PREEMPT_COUNT, this is like a NOP. So the handler won't be disabled.
- * in_atomic() will report different values based on !CONFIG_PREEMPT_COUNT.
+ * fault_in_atomic() will report different values based on !CONFIG_PREEMPT_COUNT.
*/
-#define faulthandler_disabled() (pagefault_disabled() || in_atomic())
+#define faulthandler_disabled() (pagefault_disabled() || fault_in_atomic())
DEFINE_LOCK_GUARD_0(pagefault, pagefault_disable(), pagefault_enable())
diff --git a/init/main.c b/init/main.c
index 2613d3f9b3ce..fa84ce260b04 100644
--- a/init/main.c
+++ b/init/main.c
@@ -991,7 +991,6 @@ void start_kernel(void)
cgroup_init_early();
- local_irq_disable();
early_boot_irqs_disabled = true;
/*
diff --git a/kernel/Kconfig.preempt b/kernel/Kconfig.preempt
index f294dad43bd7..c44607990219 100644
--- a/kernel/Kconfig.preempt
+++ b/kernel/Kconfig.preempt
@@ -152,6 +152,15 @@ config PREEMPT_DYNAMIC
Interesting if you want the same pre-built kernel should be used for
both Server and Desktop workloads.
+config ARCH_SUPPORTS_PREEMPT_COUNT_IRQFLAGS
+ bool
+
+config PREEMPT_COUNT_IRQFLAGS
+ bool "Enable reference counted interrupt disable/enable mechanisms"
+ depends on ARCH_SUPPORTS_PREEMPT_COUNT_IRQFLAGS
+ help
+ FIXME: Add some useful blurb
+
config SCHED_CORE
bool "Core Scheduling for SMT"
depends on SCHED_SMT
diff --git a/kernel/entry/common.c b/kernel/entry/common.c
index e3d381fd3d25..3c93ce7f86f6 100644
--- a/kernel/entry/common.c
+++ b/kernel/entry/common.c
@@ -171,6 +171,7 @@ irqentry_state_t noinstr irqentry_nmi_enter(struct pt_regs *regs)
{
irqentry_state_t irq_state;
+ __preempt_count_inc_hardirqs_disable();
irq_state.lockdep = lockdep_hardirqs_enabled();
__nmi_enter();
@@ -202,4 +203,5 @@ void noinstr irqentry_nmi_exit(struct pt_regs *regs, irqentry_state_t irq_state)
if (irq_state.lockdep)
lockdep_hardirqs_on(CALLER_ADDR0);
__nmi_exit();
+ __preempt_count_dec_hardirqs_disable();
}
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index f78275192036..b6d14feaaf56 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -5343,7 +5343,7 @@ static struct rq *finish_task_switch(struct task_struct *prev)
*
* Also, see FORK_PREEMPT_COUNT.
*/
- if (WARN_ONCE(preempt_count() != 2*PREEMPT_DISABLE_OFFSET,
+ if (WARN_ONCE(preempt_count() != SCHED_PREEMPT_COUNT,
"corrupted preempt_count: %s/%d/0x%x\n",
current->comm, current->pid, preempt_count()))
preempt_count_set(FORK_PREEMPT_COUNT);
diff --git a/kernel/sched/idle.c b/kernel/sched/idle.c
index eb73b65ce6c4..7132320035eb 100644
--- a/kernel/sched/idle.c
+++ b/kernel/sched/idle.c
@@ -380,7 +380,8 @@ static void do_idle(void)
* RCU relies on this call to be done outside of an RCU read-side
* critical section.
*/
- flush_smp_call_function_queue();
+ scoped_guard(irq)
+ flush_smp_call_function_queue();
schedule_idle();
if (unlikely(klp_patch_pending(current)))
diff --git a/kernel/smp.c b/kernel/smp.c
index b696bcc60c08..d51e4bc8da1b 100644
--- a/kernel/smp.c
+++ b/kernel/smp.c
@@ -665,19 +665,17 @@ static void __flush_smp_call_function_queue(bool warn_cpu_offline)
void flush_smp_call_function_queue(void)
{
unsigned int was_pending;
- unsigned long flags;
if (llist_empty(this_cpu_ptr(&call_single_queue)))
return;
- local_irq_save(flags);
+ lockdep_assert_irqs_disabled();
+
/* Get the already pending soft interrupts for RT enabled kernels */
was_pending = local_softirq_pending();
__flush_smp_call_function_queue(true);
if (local_softirq_pending())
do_softirq_post_smp_call_flush(was_pending);
-
- local_irq_restore(flags);
}
static int __smp_call_function_single(int cpu, smp_call_func_t func,
diff --git a/kernel/softirq.c b/kernel/softirq.c
index e1a773e3eb4e..33f82d03ca2b 100644
--- a/kernel/softirq.c
+++ b/kernel/softirq.c
@@ -455,7 +455,10 @@ void __local_bh_enable_ip(unsigned long ip, unsigned int cnt)
* Run softirq if any pending. And do it in its own stack
* as we may be calling this deep in a task call stack already.
*/
- do_softirq();
+ if (IS_ENABLED(CONFIG_TRACE_IRQFLAGS))
+ do_softirq_irqsoff();
+ else
+ do_softirq();
}
preempt_count_dec();
@@ -517,20 +520,21 @@ static inline void invoke_softirq(void)
asmlinkage __visible void do_softirq(void)
{
- __u32 pending;
- unsigned long flags;
-
if (in_interrupt())
return;
- local_irq_save(flags);
+ guard(irqsave)();
+ if (local_softirq_pending())
+ do_softirq_own_stack();
+}
- pending = local_softirq_pending();
+void do_softirq_irqsoff(void)
+{
+ if (in_interrupt())
+ return;
- if (pending)
+ if (local_softirq_pending())
do_softirq_own_stack();
-
- local_irq_restore(flags);
}
#endif /* !CONFIG_PREEMPT_RT */
diff --git a/kernel/time/hrtimer.c b/kernel/time/hrtimer.c
index 530d61257b9a..977dd8928934 100644
--- a/kernel/time/hrtimer.c
+++ b/kernel/time/hrtimer.c
@@ -2068,7 +2068,7 @@ static void __run_hrtimer(struct hrtimer_cpu_base *cpu_base, struct hrtimer_cloc
lockdep_hrtimer_exit(expires_in_hardirq);
trace_hrtimer_expire_exit(timer);
- raw_spin_lock_irq(&cpu_base->lock);
+ raw_spin_lock_irqsave(&cpu_base->lock, flags);
/*
* Note: We clear the running state after enqueue_hrtimer and
next prev parent reply other threads:[~2026-08-28 23:12 UTC|newest]
Thread overview: 96+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-04 16:14 [PATCH v4 00/17] Refcounted interrupt disable and SpinLockIrq for Rust Boqun Feng
2026-08-04 16:14 ` [PATCH v4 01/17] preempt: Track NMI nesting to separate per-CPU counter Boqun Feng
2026-08-08 20:48 ` [tip: locking/core] " tip-bot2 for Joel Fernandes
2026-08-04 16:14 ` [PATCH v4 02/17] preempt: Introduce HARDIRQ_DISABLE_BITS Boqun Feng
2026-08-05 6:31 ` Peter Zijlstra
2026-08-05 6:59 ` Boqun Feng
2026-08-08 20:48 ` [tip: locking/core] " tip-bot2 for Boqun Feng
2026-08-04 16:14 ` [PATCH v4 03/17] preempt: Introduce __preempt_count_{sub,add}_return() Boqun Feng
2026-08-08 20:48 ` [tip: locking/core] " tip-bot2 for Boqun Feng
2026-08-04 16:14 ` [PATCH v4 04/17] openrisc: Include <linux/cpumask.h> in smp.h Boqun Feng
2026-08-08 20:48 ` [tip: locking/core] " tip-bot2 for Lyude Paul
2026-08-04 16:14 ` [PATCH v4 05/17] irq & spin_lock: Add counted interrupt disabling/enabling Boqun Feng
2026-08-04 18:20 ` Boqun Feng
2026-08-04 18:26 ` [PATCH v4.1 " Boqun Feng
2026-08-08 20:48 ` [tip: locking/core] " tip-bot2 for Boqun Feng
2026-08-10 8:57 ` [tip: locking/core] irq,spin_lock: " tip-bot2 for Boqun Feng
2026-08-04 20:51 ` [PATCH v4 05/17] irq & spin_lock: " Shrikanth Hegde
2026-08-04 21:08 ` Boqun Feng
2026-08-05 6:36 ` Peter Zijlstra
2026-08-05 7:07 ` Boqun Feng
2026-08-05 7:09 ` Shrikanth Hegde
2026-08-05 7:19 ` Boqun Feng
2026-08-05 13:53 ` Boqun Feng
2026-08-05 14:10 ` Shrikanth Hegde
2026-08-05 14:20 ` Boqun Feng
2026-08-05 14:56 ` Shrikanth Hegde
2026-08-05 15:11 ` Boqun Feng
2026-08-05 16:53 ` Shrikanth Hegde
2026-08-05 17:38 ` Boqun Feng
2026-08-05 18:07 ` Boqun Feng
2026-08-04 16:14 ` [PATCH v4 06/17] irq: Add KUnit test for refcounted interrupt enable/disable Boqun Feng
2026-08-08 20:48 ` [tip: locking/core] " tip-bot2 for Lyude Paul
2026-08-10 8:57 ` tip-bot2 for Lyude Paul
2026-08-04 16:14 ` [PATCH v4 07/17] locking: Switch to _irq_{disable,enable}() variants in cleanup guards Boqun Feng
2026-08-08 20:48 ` [tip: locking/core] " tip-bot2 for Boqun Feng
2026-08-10 8:57 ` tip-bot2 for Boqun Feng
2026-08-24 10:47 ` Peter Zijlstra
2026-08-24 10:55 ` [PATCH] locking: Revert switching guards to _irq_{disable,enable}() Peter Zijlstra
2026-08-24 11:01 ` [tip: locking/urgent] " tip-bot2 for Peter Zijlstra
2026-08-25 1:33 ` [PATCH] " Boqun Feng
2026-08-25 22:59 ` Thomas Gleixner
2026-08-25 23:28 ` Boqun Feng
2026-08-25 23:48 ` Boqun Feng
2026-08-26 1:33 ` Boqun Feng
2026-08-27 8:30 ` Thomas Gleixner
2026-08-27 13:14 ` Boqun Feng
2026-08-27 15:43 ` Thomas Gleixner
2026-08-27 16:52 ` Boqun Feng
2026-08-27 18:15 ` Thomas Gleixner
2026-08-27 19:41 ` Boqun Feng
2026-08-27 22:52 ` Thomas Gleixner
2026-08-28 1:56 ` Boqun Feng
2026-08-28 6:42 ` Peter Zijlstra
2026-08-28 23:11 ` Thomas Gleixner [this message]
2026-08-29 0:45 ` Boqun Feng
2026-08-29 20:44 ` Thomas Gleixner
2026-08-29 20:53 ` Boqun Feng
2026-08-29 8:05 ` Peter Zijlstra
2026-08-29 19:52 ` Thomas Gleixner
2026-08-29 23:37 ` Boqun Feng
2026-08-30 15:18 ` Boqun Feng
2026-08-27 20:29 ` Thomas Gleixner
2026-08-27 21:33 ` Boqun Feng
2026-08-28 6:55 ` Peter Zijlstra
2026-08-28 8:22 ` David Laight
2026-08-28 21:26 ` Boqun Feng
2026-08-04 16:14 ` [PATCH v4 08/17] sched: Remove the unused preempt_offset parameter of __cant_sleep() Boqun Feng
2026-08-08 20:48 ` [tip: locking/core] " tip-bot2 for Boqun Feng
2026-08-10 8:57 ` tip-bot2 for Boqun Feng
2026-08-04 16:14 ` [PATCH v4 09/17] sched: Avoid signed comparison of preempt_count() in __cant_migrate() Boqun Feng
2026-08-08 20:48 ` [tip: locking/core] " tip-bot2 for Boqun Feng
2026-08-10 8:57 ` tip-bot2 for Boqun Feng
2026-08-04 16:14 ` [PATCH v4 10/17] preempt: Introduce HAS_SEPARATE_PREEMPT_RESCHED_BITS Boqun Feng
2026-08-04 20:11 ` Shrikanth Hegde
2026-08-05 6:54 ` Boqun Feng
2026-08-05 7:15 ` Shrikanth Hegde
2026-08-05 7:27 ` Boqun Feng
2026-08-06 0:58 ` Boqun Feng
2026-08-04 21:09 ` Shrikanth Hegde
2026-08-04 23:14 ` Boqun Feng
2026-08-08 20:48 ` [tip: locking/core] " tip-bot2 for Boqun Feng
2026-08-10 8:57 ` tip-bot2 for Boqun Feng
2026-08-04 16:14 ` [PATCH v4 11/17] arm64: sched/preempt: Enable HAS_SEPARATE_PREEMPT_RESCHED_BITS Boqun Feng
2026-08-08 20:48 ` [tip: locking/core] " tip-bot2 for Boqun Feng
2026-08-10 8:57 ` tip-bot2 for Boqun Feng
2026-08-04 16:14 ` [PATCH v4 12/17] s390/preempt: " Boqun Feng
2026-08-04 20:27 ` Shrikanth Hegde
2026-08-05 9:42 ` Peter Zijlstra
2026-08-05 12:37 ` Shrikanth Hegde
2026-08-08 20:48 ` [tip: locking/core] " tip-bot2 for Heiko Carstens
2026-08-10 8:57 ` tip-bot2 for Heiko Carstens
2026-08-04 16:14 ` [PATCH v4 13/17] rust: Introduce interrupt module Boqun Feng
2026-08-04 16:14 ` [PATCH v4 14/17] rust: helper: Add spin_{un,}lock_irq_{enable,disable}() helpers Boqun Feng
2026-08-04 16:14 ` [PATCH v4 15/17] rust: sync: Use super::* in spinlock.rs Boqun Feng
2026-08-04 16:14 ` [PATCH v4 16/17] rust: sync: Add SpinLockIrq Boqun Feng
2026-08-04 16:14 ` [PATCH v4 17/17] rust: sync: Introduce SpinLockIrq::lock_with() and friends Boqun Feng
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=87mru5et6r.ffs@fw13 \
--to=tglx@kernel.org \
--cc=boqun@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-tip-commits@vger.kernel.org \
--cc=peterz@infradead.org \
--cc=x86@kernel.org \
/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
all inboxes | Powered by JetHome®