summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHaris Okanovic <harisokn@amazon.com>2026-09-11 13:31:59 -0500
committerThomas Gleixner <tglx@kernel.org>2026-10-16 00:18:41 +0200
commite74798f2f8e1562f2bbd2fed8d81929eeef39ffc (patch)
tree0beb840e84080b8e980305ef5b9b134a4d462058
parent2e2f69fc8ae2b280e1c5e01d876c17bc06dbe23f (diff)
genirq/proc: Fix missing CPU header in /proc/interrupts
irq_seq_show() must be idempotent since it may be called multiple times to render the same record, e.g. when seq_file's buffer is exceeded. It emits the CPU header behind the one-shot print_header flag, which the first pass clears, so the header is lost with the discarded buffer. This can be seen on large systems, such as 8g.48xl (192 CPUs) and 8i.96xl (384 CPUs) AWS instance types: $ head -1 /proc/interrupts 9: 0 0 ... 0 GICv3 25 Level vgic Replace print_header with the position of the first record and include the header whenever that record is emitted. Fixes: 171cc0d9eed1 ("genirq/proc: Speed up /proc/interrupts iteration") Signed-off-by: Haris Okanovic <harisokn@amazon.com> Signed-off-by: Thomas Gleixner <tglx@kernel.org> Tested-by: Michael Kelley <mhklinux@outlook.com> Reviewed-by: Radu Rendec <radu@rendec.net> Link: https://patch.msgid.link/20260911-dev-harisokn-proc-interrupts-fix-b4-v1-1-f9ff208efcfa@amazon.com
-rw-r--r--kernel/irq/proc.c24
1 files changed, 17 insertions, 7 deletions
diff --git a/kernel/irq/proc.c b/kernel/irq/proc.c
index 1b835725f7b1..0c0df16de581 100644
--- a/kernel/irq/proc.c
+++ b/kernel/irq/proc.c
@@ -462,7 +462,7 @@ int __weak arch_show_interrupts(struct seq_file *p, int prec)
static DEFINE_RAW_SPINLOCK(irq_proc_constraints_lock);
static struct irq_proc_constraints {
- bool print_header;
+ loff_t first_pos;
unsigned int num_prec;
unsigned int chip_width;
} irq_proc_constraints __read_mostly = {
@@ -543,14 +543,13 @@ static int irq_seq_show(struct seq_file *p, void *v)
struct irqaction *action;
/* Print header for the first interrupt? */
- if (constr->print_header) {
+ if (p->index == constr->first_pos) {
unsigned int cpu;
seq_printf(p, "%*s", constr->num_prec + 8, "");
for_each_online_cpu(cpu)
seq_printf(p, "CPU%-8d", cpu);
seq_putc(p, '\n');
- constr->print_header = false;
}
if (desc == ARCH_PROC_IRQDESC)
@@ -635,14 +634,25 @@ static void *irq_seq_next_desc(loff_t *pos)
static void *irq_seq_start(struct seq_file *f, loff_t *pos)
{
- if (!*pos) {
- struct irq_proc_constraints *constr = f->private;
+ struct irq_proc_constraints *constr = f->private;
+ bool first = !*pos;
+ void *ret;
+ if (first) {
constr->num_prec = READ_ONCE(irq_proc_constraints.num_prec);
constr->chip_width = READ_ONCE(irq_proc_constraints.chip_width);
- constr->print_header = true;
}
- return irq_seq_next_desc(pos);
+
+ ret = irq_seq_next_desc(pos);
+
+ /*
+ * Record position of the first output record so that irq_seq_show()
+ * knows where to write the header.
+ */
+ if (first)
+ constr->first_pos = *pos;
+
+ return ret;
}
static void *irq_seq_next(struct seq_file *f, void *v, loff_t *pos)