Move SysRq register dump processing into do_IRQ
Subsystems (4)
RFC 1/1 Move SysRq register dump processing into do_IRQ
Hi,
As I mentioned in my other email current implementation of SysRq's "showPc" option requires sysrq_handle_showregs to be called from the hard interrupt context only, otherwise the call trace will be wrong. Having entire input processing execute in hard IRQ context is not always feasible, some interrupts may need splitting into IRQ/tasklet pairs.
Also, pt_regs structure is currently propagated throughout entire input and USB systems for no other benefit than displaying the registers and call trace at SysRq request.
I propose to change SysRq register dump processing in the following fashion:
- SysRq-P merely posts a request for the data (registers and call trace) to be printed;
- do_IRQ (or whatever arch's equivalent) checks the at the end of IRQ dispatching routine and prints the requested information next time some IRQ is raised. The check is cheap as rough attempt can be done without locking and if we miss request it's ok as next time do_IRQ called it will notice it.
The patch below implements the SysRq changes and do_IRQ for most popular (IMO) arches. It works for me on i386. Please let me know if you think it is acceptable and I will modify the rest of the arches and will remove pt_regs handling from input system and then from USB.
===== arch/alpha/kernel/irq.c 1.29 vs edited =====
arch/alpha/kernel/irq.c +3 -0
@@ -25,6 +25,7 @@#include <linux/irq.h> #include <linux/proc_fs.h> #include <linux/seq_file.h> +#include <linux/sysrq.h> #include <asm/system.h> #include <asm/io.h>
@@ -679,6 +680,8 @@spin_unlock (&desc->lock);irq_exit (); + +sysrq_irq_show_registers (regs); }/*
===== arch/i386/kernel/irq.c 1.52 vs edited =====
arch/i386/kernel/irq.c +3 -0
@@ -34,6 +34,7 @@#include <linux/proc_fs.h> #include <linux/seq_file.h> #include <linux/kallsyms.h> +#include <linux/sysrq.h> #include <asm/atomic.h> #include <asm/io.h>
@@ -569,6 +570,8 @@spin_unlock (&desc->lock);irq_exit (); + +sysrq_irq_show_registers (®s);return 1 ; }
===== arch/ia64/kernel/irq.c 1.37 vs edited =====
arch/ia64/kernel/irq.c +4 -0
@@ -35,6 +35,7 @@#include <linux/proc_fs.h> #include <linux/seq_file.h> #include <linux/kallsyms.h> +#include <linux/sysrq.h> #include <asm/atomic.h> #include <asm/io.h>
@@ -524,6 +525,9 @@ desc->handler->end (irq);spin_unlock (&desc->lock); } + +sysrq_irq_show_registers (regs); +return 1 ; }
===== arch/ppc/kernel/irq.c 1.36 vs edited =====
arch/ppc/kernel/irq.c +2 -0
@@ -46,6 +46,7 @@#include <linux/random.h> #include <linux/seq_file.h> #include <linux/cpumask.h> +#include <linux/sysrq.h> #include <asm/uaccess.h> #include <asm/bitops.h>
@@ -531,6 +532,7 @@/* That's not SMP safe ... but who cares ? */ ppc_spurious_interrupts++;irq_exit (); +sysrq_irq_show_registers (regs); }unsigned long probe_irq_on (void )
===== arch/ppc64/kernel/irq.c 1.52 vs edited =====
arch/ppc64/kernel/irq.c +5 -0
@@ -41,6 +41,7 @@#include <linux/proc_fs.h> #include <linux/random.h> #include <linux/kallsyms.h> +#include <linux/sysrq.h> #include <asm/uaccess.h> #include <asm/bitops.h>
@@ -617,6 +618,8 @@timer_interrupt (regs); } +sysrq_irq_show_registers (regs); +return 1 ;/* lets ret_from_int know we can do checks */ }
@@ -645,6 +648,8 @@ ppc_spurious_interrupts++;irq_exit (); + +sysrq_irq_show_registers (regs);return 1 ;/* lets ret_from_int know we can do checks */ }
===== arch/sparc/kernel/irq.c 1.28 vs edited =====
arch/sparc/kernel/irq.c +2 -0
@@ -30,6 +30,7 @@#include <linux/threads.h> #include <linux/spinlock.h> #include <linux/seq_file.h> +#include <linux/sysrq.h> #include <asm/ptrace.h> #include <asm/processor.h>
@@ -341,6 +342,7 @@ }while (action);enable_pil_irq (irq);irq_exit (); +sysrq_irq_show_registers (regs); }#ifdef CONFIG_BLK_DEV_FD
===== arch/sparc64/kernel/irq.c 1.40 vs edited =====
arch/sparc64/kernel/irq.c +2 -0
@@ -21,6 +21,7 @@#include <linux/delay.h> #include <linux/proc_fs.h> #include <linux/seq_file.h> +#include <linux/sysrq.h> #include <asm/ptrace.h> #include <asm/processor.h>
@@ -822,6 +823,7 @@ bp->flags &= ~IBF_INPROGRESS ; }irq_exit (); +sysrq_irq_show_registers (regs); }#ifdef CONFIG_BLK_DEV_FD
===== arch/x86_64/kernel/irq.c 1.22 vs edited =====
arch/x86_64/kernel/irq.c +4 -0
@@ -33,6 +33,7 @@#include <linux/irq.h> #include <linux/proc_fs.h> #include <linux/seq_file.h> +#include <linux/sysrq.h> #include <asm/atomic.h> #include <asm/io.h>
@@ -405,6 +406,9 @@spin_unlock (&desc->lock);irq_exit (); + +sysrq_irq_show_registers (regs); +return 1 ; }
===== drivers/char/sysrq.c 1.29 vs edited =====
drivers/char/sysrq.c +23 -2
@@ -135,12 +135,33 @@/* SHOW SYSRQ HANDLERS BLOCK */ +unsigned int sysrq_register_dump_requested; +static spinlock_t show_registers_lock =SPIN_LOCK_UNLOCKED ; + +void __sysrq_irq_show_registers (struct pt_regs *pt_regs) +{ +unsigned long flags; +int doit =0 ; + +spin_lock_irqsave (&show_registers_lock, flags); +if (sysrq_register_dump_requested) { + sysrq_register_dump_requested--; + doit =1 ; + } +spin_unlock_irqrestore (&show_registers_lock, flags); + +if (doit) +show_regs (pt_regs); +}static void sysrq_handle_showregs (int key,struct pt_regs *pt_regs,struct tty_struct *tty) { -if (pt_regs) -show_regs (pt_regs); +unsigned long flags; + +spin_lock_irqsave (&show_registers_lock, flags); + sysrq_register_dump_requested++; +spin_unlock_irqrestore (&show_registers_lock, flags); }static struct sysrq_key_op sysrq_showregs_op = { .handler = sysrq_handle_showregs,
===== include/linux/sysrq.h 1.5 vs edited =====
include/linux/sysrq.h +19 -2
@@ -31,13 +31,26 @@void handle_sysrq (int ,struct pt_regs *,struct tty_struct *); -/* +/* * Nonlocking version of handle sysrq, used by sysrq handlers that need to * call sysrq handlers */ void __handle_sysrq_nolock (int ,struct pt_regs *,struct tty_struct *); + +/* +* Check whether register dump has been requested and print it +*/ +extern unsigned int sysrq_register_dump_requested; +void __sysrq_irq_show_registers (struct pt_regs *); +static inline void sysrq_irq_show_registers (struct pt_regs *pt_regs) +{ +if (unlikely (sysrq_register_dump_requested !=0 )) +__sysrq_irq_show_registers (pt_regs); +} + +/* * Sysrq registration manipulation functions */
@@ -70,7 +83,7 @@__sysrq_unlock_table ();return retval; } - +static inline int register_sysrq_key (int key,struct sysrq_key_op *op_p) {return __sysrq_swap_key_ops (key, op_p,NULL );
@@ -90,5 +103,9 @@#define register_sysrq_key (ig,nore) __reterr()#define unregister_sysrq_key (ig,nore) __reterr() + +static inline void sysrq_irq_show_registes (struct pt_regs *pt_regs) +{ +}#endif