diff options
-rw-r--r-- | Documentation/sysrq.txt | 2 | ||||
-rw-r--r-- | drivers/char/sysrq.c | 46 |
2 files changed, 48 insertions, 0 deletions
diff --git a/Documentation/sysrq.txt b/Documentation/sysrq.txt index 10c8f6922ef4..5ce0952aa065 100644 --- a/Documentation/sysrq.txt +++ b/Documentation/sysrq.txt | |||
@@ -85,6 +85,8 @@ On all - write a character to /proc/sysrq-trigger. e.g.: | |||
85 | 'k' - Secure Access Key (SAK) Kills all programs on the current virtual | 85 | 'k' - Secure Access Key (SAK) Kills all programs on the current virtual |
86 | console. NOTE: See important comments below in SAK section. | 86 | console. NOTE: See important comments below in SAK section. |
87 | 87 | ||
88 | 'l' - Shows a stack backtrace for all active CPUs. | ||
89 | |||
88 | 'm' - Will dump current memory info to your console. | 90 | 'm' - Will dump current memory info to your console. |
89 | 91 | ||
90 | 'n' - Used to make RT tasks nice-able | 92 | 'n' - Used to make RT tasks nice-able |
diff --git a/drivers/char/sysrq.c b/drivers/char/sysrq.c index 1ade193c9128..9e9bad8bdcf4 100644 --- a/drivers/char/sysrq.c +++ b/drivers/char/sysrq.c | |||
@@ -196,6 +196,48 @@ static struct sysrq_key_op sysrq_showlocks_op = { | |||
196 | #define sysrq_showlocks_op (*(struct sysrq_key_op *)0) | 196 | #define sysrq_showlocks_op (*(struct sysrq_key_op *)0) |
197 | #endif | 197 | #endif |
198 | 198 | ||
199 | #ifdef CONFIG_SMP | ||
200 | static DEFINE_SPINLOCK(show_lock); | ||
201 | |||
202 | static void showacpu(void *dummy) | ||
203 | { | ||
204 | unsigned long flags; | ||
205 | |||
206 | /* Idle CPUs have no interesting backtrace. */ | ||
207 | if (idle_cpu(smp_processor_id())) | ||
208 | return; | ||
209 | |||
210 | spin_lock_irqsave(&show_lock, flags); | ||
211 | printk(KERN_INFO "CPU%d:\n", smp_processor_id()); | ||
212 | show_stack(NULL, NULL); | ||
213 | spin_unlock_irqrestore(&show_lock, flags); | ||
214 | } | ||
215 | |||
216 | static void sysrq_showregs_othercpus(struct work_struct *dummy) | ||
217 | { | ||
218 | smp_call_function(showacpu, NULL, 0, 0); | ||
219 | } | ||
220 | |||
221 | static DECLARE_WORK(sysrq_showallcpus, sysrq_showregs_othercpus); | ||
222 | |||
223 | static void sysrq_handle_showallcpus(int key, struct tty_struct *tty) | ||
224 | { | ||
225 | struct pt_regs *regs = get_irq_regs(); | ||
226 | if (regs) { | ||
227 | printk(KERN_INFO "CPU%d:\n", smp_processor_id()); | ||
228 | show_regs(regs); | ||
229 | } | ||
230 | schedule_work(&sysrq_showallcpus); | ||
231 | } | ||
232 | |||
233 | static struct sysrq_key_op sysrq_showallcpus_op = { | ||
234 | .handler = sysrq_handle_showallcpus, | ||
235 | .help_msg = "aLlcpus", | ||
236 | .action_msg = "Show backtrace of all active CPUs", | ||
237 | .enable_mask = SYSRQ_ENABLE_DUMP, | ||
238 | }; | ||
239 | #endif | ||
240 | |||
199 | static void sysrq_handle_showregs(int key, struct tty_struct *tty) | 241 | static void sysrq_handle_showregs(int key, struct tty_struct *tty) |
200 | { | 242 | { |
201 | struct pt_regs *regs = get_irq_regs(); | 243 | struct pt_regs *regs = get_irq_regs(); |
@@ -340,7 +382,11 @@ static struct sysrq_key_op *sysrq_key_table[36] = { | |||
340 | &sysrq_kill_op, /* i */ | 382 | &sysrq_kill_op, /* i */ |
341 | NULL, /* j */ | 383 | NULL, /* j */ |
342 | &sysrq_SAK_op, /* k */ | 384 | &sysrq_SAK_op, /* k */ |
385 | #ifdef CONFIG_SMP | ||
386 | &sysrq_showallcpus_op, /* l */ | ||
387 | #else | ||
343 | NULL, /* l */ | 388 | NULL, /* l */ |
389 | #endif | ||
344 | &sysrq_showmem_op, /* m */ | 390 | &sysrq_showmem_op, /* m */ |
345 | &sysrq_unrt_op, /* n */ | 391 | &sysrq_unrt_op, /* n */ |
346 | /* o: This will often be registered as 'Off' at init time */ | 392 | /* o: This will often be registered as 'Off' at init time */ |