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,

_