mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-08-31 03:35:32 -04:00
preempt: Track NMI nesting to separate per-CPU counter
Move NMI nesting tracking from the preempt_count bits to a separate per-CPU counter (nmi_nesting). This is to free up the NMI bits in the preempt_count, allowing those bits to be repurposed for other uses. Reduce NMI_BITS from 4 to 1, using it only to detect if we're in an NMI. The per-CPU counter currently caps nesting at 15. [boqun: Address Steven Rostedt's comment on the BUG_ON() condition] [boqun: Use preempt_count_set() in __nmi_exit() to avoid underflow] Suggested-by: Boqun Feng <boqun@kernel.org> Signed-off-by: Joel Fernandes <joelagnelf@nvidia.com> Signed-off-by: Lyude Paul <lyude@redhat.com> Signed-off-by: Boqun Feng <boqun@kernel.org> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Link: https://patch.msgid.link/20260121223933.1568682-3-lyude@redhat.com Link: https://patch.msgid.link/20260804161447.84806-2-boqun@kernel.org
This commit is contained in:
committed by
Peter Zijlstra
parent
fcb8ada128
commit
b54aa0edf0
@@ -10,6 +10,8 @@
|
||||
#include <linux/vtime.h>
|
||||
#include <asm/hardirq.h>
|
||||
|
||||
DECLARE_PER_CPU(unsigned int, nmi_nesting);
|
||||
|
||||
extern void synchronize_irq(unsigned int irq);
|
||||
extern bool synchronize_hardirq(unsigned int irq);
|
||||
|
||||
@@ -102,14 +104,17 @@ void irq_exit_rcu(void);
|
||||
*/
|
||||
|
||||
/*
|
||||
* nmi_enter() can nest up to 15 times; see NMI_BITS.
|
||||
* nmi_enter() can nest - nesting is tracked in a per-CPU counter.
|
||||
*/
|
||||
#define __nmi_enter() \
|
||||
do { \
|
||||
lockdep_off(); \
|
||||
arch_nmi_enter(); \
|
||||
BUG_ON(in_nmi() == NMI_MASK); \
|
||||
__preempt_count_add(NMI_OFFSET + HARDIRQ_OFFSET); \
|
||||
/* Maximum NMI nesting is 15. */ \
|
||||
BUG_ON(__this_cpu_read(nmi_nesting) >= 15); \
|
||||
__this_cpu_inc(nmi_nesting); \
|
||||
__preempt_count_add(HARDIRQ_OFFSET); \
|
||||
preempt_count_set(preempt_count() | NMI_MASK); \
|
||||
} while (0)
|
||||
|
||||
#define nmi_enter() \
|
||||
@@ -124,8 +129,12 @@ void irq_exit_rcu(void);
|
||||
|
||||
#define __nmi_exit() \
|
||||
do { \
|
||||
unsigned int nesting; \
|
||||
BUG_ON(!in_nmi()); \
|
||||
__preempt_count_sub(NMI_OFFSET + HARDIRQ_OFFSET); \
|
||||
__preempt_count_sub(HARDIRQ_OFFSET); \
|
||||
nesting = __this_cpu_dec_return(nmi_nesting); \
|
||||
if (!nesting) \
|
||||
preempt_count_set(preempt_count() & ~NMI_MASK); \
|
||||
arch_nmi_exit(); \
|
||||
lockdep_on(); \
|
||||
} while (0)
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
*
|
||||
* - bits 0-7 are the preemption count (max preemption depth: 256)
|
||||
* - bits 8-15 are the softirq count (max # of softirqs: 256)
|
||||
* - bits 16-19 are the hardirq count (max # of hardirqs: 16)
|
||||
* - bit 20 is the NMI flag (no nesting count, tracked separately)
|
||||
*
|
||||
* The hardirq count could in theory be the same as the number of
|
||||
* interrupts in the system, but we run all interrupt handlers with
|
||||
@@ -24,16 +26,19 @@
|
||||
* there are a few palaeontologic drivers which reenable interrupts in
|
||||
* the handler, so we need more than one bit here.
|
||||
*
|
||||
* NMI nesting depth is tracked in a separate per-CPU variable
|
||||
* (nmi_nesting) to save bits in preempt_count.
|
||||
*
|
||||
* PREEMPT_MASK: 0x000000ff
|
||||
* SOFTIRQ_MASK: 0x0000ff00
|
||||
* HARDIRQ_MASK: 0x000f0000
|
||||
* NMI_MASK: 0x00f00000
|
||||
* NMI_MASK: 0x00100000
|
||||
* PREEMPT_NEED_RESCHED: 0x80000000
|
||||
*/
|
||||
#define PREEMPT_BITS 8
|
||||
#define SOFTIRQ_BITS 8
|
||||
#define HARDIRQ_BITS 4
|
||||
#define NMI_BITS 4
|
||||
#define NMI_BITS 1
|
||||
|
||||
#define PREEMPT_SHIFT 0
|
||||
#define SOFTIRQ_SHIFT (PREEMPT_SHIFT + PREEMPT_BITS)
|
||||
|
||||
@@ -88,6 +88,8 @@ EXPORT_PER_CPU_SYMBOL_GPL(hardirqs_enabled);
|
||||
EXPORT_PER_CPU_SYMBOL_GPL(hardirq_context);
|
||||
#endif
|
||||
|
||||
DEFINE_PER_CPU(unsigned int, nmi_nesting);
|
||||
|
||||
/*
|
||||
* SOFTIRQ_OFFSET usage:
|
||||
*
|
||||
|
||||
@@ -367,7 +367,7 @@ extern int bpf_cgroup_read_xattr(struct cgroup *cgroup, const char *name__str,
|
||||
#define PREEMPT_BITS 8
|
||||
#define SOFTIRQ_BITS 8
|
||||
#define HARDIRQ_BITS 4
|
||||
#define NMI_BITS 4
|
||||
#define NMI_BITS 1
|
||||
|
||||
#define PREEMPT_SHIFT 0
|
||||
#define SOFTIRQ_SHIFT (PREEMPT_SHIFT + PREEMPT_BITS)
|
||||
|
||||
Reference in New Issue
Block a user