From: corbet@lwn.net (Jonathan Corbet) Here, anyway, is a better version of the patch. It's less intrusive, forgoes some "cleanups" I indulged in the first time, and makes it easier to update other architectures. I did x86-64, ia_64 and ppc64 just for the heck of it, but I can't test them. 25-akpm/arch/i386/kernel/irq.c | 46 +++++++++++++++++++--------------- 25-akpm/arch/ia64/kernel/irq.c | 43 +++++++++++++++++--------------- 25-akpm/arch/ppc64/kernel/irq.c | 20 ++++++++------- 25-akpm/arch/x86_64/kernel/irq.c | 43 +++++++++++++++++--------------- 25-akpm/fs/proc/proc_misc.c | 52 +++++++++++++++++++++++++-------------- 5 files changed, 117 insertions(+), 87 deletions(-) diff -puN arch/i386/kernel/irq.c~proc-interrupts-use-seq-file arch/i386/kernel/irq.c --- 25/arch/i386/kernel/irq.c~proc-interrupts-use-seq-file Thu Nov 13 13:48:43 2003 +++ 25-akpm/arch/i386/kernel/irq.c Thu Nov 13 13:48:43 2003 @@ -139,17 +139,19 @@ atomic_t irq_mis_count; int show_interrupts(struct seq_file *p, void *v) { - int i, j; + int i = *(int *) v, j; struct irqaction * action; unsigned long flags; - seq_printf(p, " "); - for (j=0; j<NR_CPUS; j++) - if (cpu_online(j)) - seq_printf(p, "CPU%d ",j); - seq_putc(p, '\n'); + if (i == 0) { + seq_printf(p, " "); + for (j=0; j<NR_CPUS; j++) + if (cpu_online(j)) + seq_printf(p, "CPU%d ",j); + seq_putc(p, '\n'); + } - for (i = 0 ; i < NR_IRQS ; i++) { + if (i < NR_IRQS) { spin_lock_irqsave(&irq_desc[i].lock, flags); action = irq_desc[i].action; if (!action) @@ -171,28 +173,32 @@ int show_interrupts(struct seq_file *p, seq_putc(p, '\n'); skip: spin_unlock_irqrestore(&irq_desc[i].lock, flags); - } - seq_printf(p, "NMI: "); - for (j = 0; j < NR_CPUS; j++) - if (cpu_online(j)) - seq_printf(p, "%10u ", nmi_count(j)); - seq_putc(p, '\n'); + } else if (i == NR_IRQS) { + seq_printf(p, "NMI: "); + for (j = 0; j < NR_CPUS; j++) + if (cpu_online(j)) + seq_printf(p, "%10u ", nmi_count(j)); + seq_putc(p, '\n'); #ifdef CONFIG_X86_LOCAL_APIC - seq_printf(p, "LOC: "); - for (j = 0; j < NR_CPUS; j++) - if (cpu_online(j)) - seq_printf(p, "%10u ", irq_stat[j].apic_timer_irqs); - seq_putc(p, '\n'); + seq_printf(p, "LOC: "); + for (j = 0; j < NR_CPUS; j++) + if (cpu_online(j)) + seq_printf(p, "%10u ", irq_stat[j].apic_timer_irqs); + seq_putc(p, '\n'); #endif - seq_printf(p, "ERR: %10u\n", atomic_read(&irq_err_count)); + seq_printf(p, "ERR: %10u\n", atomic_read(&irq_err_count)); #ifdef CONFIG_X86_IO_APIC #ifdef APIC_MISMATCH_DEBUG - seq_printf(p, "MIS: %10u\n", atomic_read(&irq_mis_count)); + seq_printf(p, "MIS: %10u\n", atomic_read(&irq_mis_count)); #endif #endif + } return 0; } + + + #ifdef CONFIG_SMP inline void synchronize_irq(unsigned int irq) { diff -puN arch/ia64/kernel/irq.c~proc-interrupts-use-seq-file arch/ia64/kernel/irq.c --- 25/arch/ia64/kernel/irq.c~proc-interrupts-use-seq-file Thu Nov 13 13:48:43 2003 +++ 25-akpm/arch/ia64/kernel/irq.c Thu Nov 13 13:48:43 2003 @@ -160,18 +160,20 @@ atomic_t irq_mis_count; int show_interrupts(struct seq_file *p, void *v) { - int i, j; + int j, i = *(int *) v; struct irqaction * action; irq_desc_t *idesc; unsigned long flags; - seq_puts(p, " "); - for (j=0; j<NR_CPUS; j++) - if (cpu_online(j)) - seq_printf(p, "CPU%d ",j); - seq_putc(p, '\n'); + if (i == 0) { + seq_puts(p, " "); + for (j=0; j<NR_CPUS; j++) + if (cpu_online(j)) + seq_printf(p, "CPU%d ",j); + seq_putc(p, '\n'); + } - for (i = 0 ; i < NR_IRQS ; i++) { + if (i < NR_IRQS) { idesc = irq_descp(i); spin_lock_irqsave(&idesc->lock, flags); action = idesc->action; @@ -194,25 +196,26 @@ int show_interrupts(struct seq_file *p, seq_putc(p, '\n'); skip: spin_unlock_irqrestore(&idesc->lock, flags); - } - seq_puts(p, "NMI: "); - for (j = 0; j < NR_CPUS; j++) - if (cpu_online(j)) - seq_printf(p, "%10u ", nmi_count(j)); - seq_putc(p, '\n'); + } else if (i == NR_IRQS) { + seq_puts(p, "NMI: "); + for (j = 0; j < NR_CPUS; j++) + if (cpu_online(j)) + seq_printf(p, "%10u ", nmi_count(j)); + seq_putc(p, '\n'); #ifdef CONFIG_X86_LOCAL_APIC - seq_puts(p, "LOC: "); - for (j = 0; j < NR_CPUS; j++) - if (cpu_online(j)) - seq_printf(p, "%10u ", irq_stat[j].apic_timer_irqs); - seq_putc(p, '\n'); + seq_puts(p, "LOC: "); + for (j = 0; j < NR_CPUS; j++) + if (cpu_online(j)) + seq_printf(p, "%10u ", irq_stat[j].apic_timer_irqs); + seq_putc(p, '\n'); #endif - seq_printf(p, "ERR: %10u\n", atomic_read(&irq_err_count)); + seq_printf(p, "ERR: %10u\n", atomic_read(&irq_err_count)); #ifdef CONFIG_X86_IO_APIC #ifdef APIC_MISMATCH_DEBUG - seq_printf(p, "MIS: %10u\n", atomic_read(&irq_mis_count)); + seq_printf(p, "MIS: %10u\n", atomic_read(&irq_mis_count)); #endif #endif + } return 0; } diff -puN arch/ppc64/kernel/irq.c~proc-interrupts-use-seq-file arch/ppc64/kernel/irq.c --- 25/arch/ppc64/kernel/irq.c~proc-interrupts-use-seq-file Thu Nov 13 13:48:43 2003 +++ 25-akpm/arch/ppc64/kernel/irq.c Thu Nov 13 13:48:43 2003 @@ -323,18 +323,20 @@ EXPORT_SYMBOL(enable_irq); int show_interrupts(struct seq_file *p, void *v) { - int i, j; + int i = *(int *) v, j; struct irqaction * action; unsigned long flags; - seq_printf(p, " "); - for (j=0; j<NR_CPUS; j++) { - if (cpu_online(j)) - seq_printf(p, "CPU%d ",j); + if (i == 0) { + seq_printf(p, " "); + for (j=0; j<NR_CPUS; j++) { + if (cpu_online(j)) + seq_printf(p, "CPU%d ",j); + } + seq_putc(p, '\n'); } - seq_putc(p, '\n'); - for (i = 0 ; i < NR_IRQS ; i++) { + if (i < NR_IRQS) { spin_lock_irqsave(&irq_desc[i].lock, flags); action = irq_desc[i].action; if (!action || !action->handler) @@ -359,8 +361,8 @@ int show_interrupts(struct seq_file *p, seq_putc(p, '\n'); skip: spin_unlock_irqrestore(&irq_desc[i].lock, flags); - } - seq_printf(p, "BAD: %10u\n", ppc_spurious_interrupts); + } else if (i == NR_IRQS) + seq_printf(p, "BAD: %10u\n", ppc_spurious_interrupts); return 0; } diff -puN arch/x86_64/kernel/irq.c~proc-interrupts-use-seq-file arch/x86_64/kernel/irq.c --- 25/arch/x86_64/kernel/irq.c~proc-interrupts-use-seq-file Thu Nov 13 13:48:43 2003 +++ 25-akpm/arch/x86_64/kernel/irq.c Thu Nov 13 13:48:43 2003 @@ -138,17 +138,19 @@ atomic_t irq_mis_count; int show_interrupts(struct seq_file *p, void *v) { - int i, j; + int i = *(int *) v, j; struct irqaction * action; unsigned long flags; - seq_printf(p, " "); - for (j=0; j<NR_CPUS; j++) - if (cpu_online(j)) - seq_printf(p, "CPU%d ",j); - seq_putc(p, '\n'); + if (i == 0) { + seq_printf(p, " "); + for (j=0; j<NR_CPUS; j++) + if (cpu_online(j)) + seq_printf(p, "CPU%d ",j); + seq_putc(p, '\n'); + } - for (i = 0 ; i < NR_IRQS ; i++) { + if (i < NR_IRQS) { spin_lock_irqsave(&irq_desc[i].lock, flags); action = irq_desc[i].action; if (!action) @@ -170,25 +172,26 @@ int show_interrupts(struct seq_file *p, seq_putc(p, '\n'); skip: spin_unlock_irqrestore(&irq_desc[i].lock, flags); - } - seq_printf(p, "NMI: "); - for (j = 0; j < NR_CPUS; j++) - if (cpu_online(j)) - seq_printf(p, "%10u ", cpu_pda[j].__nmi_count); - seq_putc(p, '\n'); + } else if (i == NR_IRQS) { + seq_printf(p, "NMI: "); + for (j = 0; j < NR_CPUS; j++) + if (cpu_online(j)) + seq_printf(p, "%10u ", cpu_pda[j].__nmi_count); + seq_putc(p, '\n'); #ifdef CONFIG_X86_LOCAL_APIC - seq_printf(p, "LOC: "); - for (j = 0; j < NR_CPUS; j++) - if (cpu_online(j)) - seq_printf(p, "%10u ", cpu_pda[j].apic_timer_irqs); - seq_putc(p, '\n'); + seq_printf(p, "LOC: "); + for (j = 0; j < NR_CPUS; j++) + if (cpu_online(j)) + seq_printf(p, "%10u ", cpu_pda[j].apic_timer_irqs); + seq_putc(p, '\n'); #endif - seq_printf(p, "ERR: %10u\n", atomic_read(&irq_err_count)); + seq_printf(p, "ERR: %10u\n", atomic_read(&irq_err_count)); #ifdef CONFIG_X86_IO_APIC #ifdef APIC_MISMATCH_DEBUG - seq_printf(p, "MIS: %10u\n", atomic_read(&irq_mis_count)); + seq_printf(p, "MIS: %10u\n", atomic_read(&irq_mis_count)); #endif #endif + } return 0; } diff -puN fs/proc/proc_misc.c~proc-interrupts-use-seq-file fs/proc/proc_misc.c --- 25/fs/proc/proc_misc.c~proc-interrupts-use-seq-file Thu Nov 13 13:48:43 2003 +++ 25-akpm/fs/proc/proc_misc.c Thu Nov 13 13:48:43 2003 @@ -473,30 +473,46 @@ static int devices_read_proc(char *page, return proc_calc_metrics(page, start, off, count, eof, len); } -extern int show_interrupts(struct seq_file *p, void *v); -static int interrupts_open(struct inode *inode, struct file *file) +/* + * /proc/interrupts + */ +static void *int_seq_start(struct seq_file *f, loff_t *pos) { - unsigned size = 4096 * (1 + num_online_cpus() / 8); - char *buf = kmalloc(size, GFP_KERNEL); - struct seq_file *m; - int res; - - if (!buf) - return -ENOMEM; - res = single_open(file, show_interrupts, NULL); - if (!res) { - m = file->private_data; - m->buf = buf; - m->size = size; - } else - kfree(buf); - return res; + return (*pos <= NR_IRQS) ? pos : NULL; } + +static void *int_seq_next(struct seq_file *f, void *v, loff_t *pos) +{ + (*pos)++; + if (*pos > NR_IRQS) + return NULL; + return pos; +} + +static void int_seq_stop(struct seq_file *f, void *v) +{ + /* Nothing to do */ +} + + +extern int show_interrupts(struct seq_file *f, void *v); /* In arch code */ +static struct seq_operations int_seq_ops = { + .start = int_seq_start, + .next = int_seq_next, + .stop = int_seq_stop, + .show = show_interrupts +}; + +int interrupts_open(struct inode *inode, struct file *filp) +{ + return seq_open(filp, &int_seq_ops); +} + static struct file_operations proc_interrupts_operations = { .open = interrupts_open, .read = seq_read, .llseek = seq_lseek, - .release = single_release, + .release = seq_release, }; static int filesystems_read_proc(char *page, char **start, off_t off, _