diff options
author | Jeff Dike <jdike@addtoit.com> | 2006-01-06 03:19:04 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-01-06 11:33:48 -0500 |
commit | 6f517d3fc862d3c8d8ba65c0b2472d399aceb9ed (patch) | |
tree | d8062920a60939dd2dda3b2deb39a4e206e0ae06 /arch | |
parent | 7b033e1fdeef3d8bacac3cd5cfa53c9d670d1f3d (diff) |
[PATCH] uml: capture printk output for mconsole stack
The stack command now sends the printk output back to the mconsole client.
This is done by registering a special console for the mconsole driver. This
receives all printk output. Normally, it is ignored, but when a stack command
is issued, any printk output will be sent back to the client.
This will capture any printk output, whether it is stack output or not, since
we can't tell the difference.
Signed-off-by: Jeff Dike <jdike@addtoit.com>
Cc: Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/um/drivers/mconsole_kern.c | 87 |
1 files changed, 81 insertions, 6 deletions
diff --git a/arch/um/drivers/mconsole_kern.c b/arch/um/drivers/mconsole_kern.c index b5217bd7bc41..e9bbc14f3655 100644 --- a/arch/um/drivers/mconsole_kern.c +++ b/arch/um/drivers/mconsole_kern.c | |||
@@ -20,6 +20,7 @@ | |||
20 | #include "linux/namei.h" | 20 | #include "linux/namei.h" |
21 | #include "linux/proc_fs.h" | 21 | #include "linux/proc_fs.h" |
22 | #include "linux/syscalls.h" | 22 | #include "linux/syscalls.h" |
23 | #include "linux/console.h" | ||
23 | #include "asm/irq.h" | 24 | #include "asm/irq.h" |
24 | #include "asm/uaccess.h" | 25 | #include "asm/uaccess.h" |
25 | #include "user_util.h" | 26 | #include "user_util.h" |
@@ -480,6 +481,82 @@ void mconsole_sysrq(struct mc_request *req) | |||
480 | } | 481 | } |
481 | #endif | 482 | #endif |
482 | 483 | ||
484 | static DEFINE_SPINLOCK(console_lock); | ||
485 | static LIST_HEAD(clients); | ||
486 | static char console_buf[MCONSOLE_MAX_DATA]; | ||
487 | static int console_index = 0; | ||
488 | |||
489 | static void console_write(struct console *console, const char *string, | ||
490 | unsigned len) | ||
491 | { | ||
492 | struct list_head *ele; | ||
493 | int n; | ||
494 | |||
495 | if(list_empty(&clients)) | ||
496 | return; | ||
497 | |||
498 | while(1){ | ||
499 | n = min(len, ARRAY_SIZE(console_buf) - console_index); | ||
500 | strncpy(&console_buf[console_index], string, n); | ||
501 | console_index += n; | ||
502 | string += n; | ||
503 | len -= n; | ||
504 | if(len == 0) | ||
505 | return; | ||
506 | |||
507 | list_for_each(ele, &clients){ | ||
508 | struct mconsole_entry *entry; | ||
509 | |||
510 | entry = list_entry(ele, struct mconsole_entry, list); | ||
511 | mconsole_reply_len(&entry->request, console_buf, | ||
512 | console_index, 0, 1); | ||
513 | } | ||
514 | |||
515 | console_index = 0; | ||
516 | } | ||
517 | } | ||
518 | |||
519 | static struct console mc_console = { .name = "mc", | ||
520 | .write = console_write, | ||
521 | .flags = CON_PRINTBUFFER | CON_ENABLED, | ||
522 | .index = -1 }; | ||
523 | |||
524 | static int mc_add_console(void) | ||
525 | { | ||
526 | register_console(&mc_console); | ||
527 | return 0; | ||
528 | } | ||
529 | |||
530 | late_initcall(mc_add_console); | ||
531 | |||
532 | static void with_console(struct mc_request *req, void (*proc)(void *), | ||
533 | void *arg) | ||
534 | { | ||
535 | struct mconsole_entry entry; | ||
536 | unsigned long flags; | ||
537 | |||
538 | INIT_LIST_HEAD(&entry.list); | ||
539 | entry.request = *req; | ||
540 | list_add(&entry.list, &clients); | ||
541 | spin_lock_irqsave(&console_lock, flags); | ||
542 | |||
543 | (*proc)(arg); | ||
544 | |||
545 | mconsole_reply_len(req, console_buf, console_index, 0, 0); | ||
546 | console_index = 0; | ||
547 | |||
548 | spin_unlock_irqrestore(&console_lock, flags); | ||
549 | list_del(&entry.list); | ||
550 | } | ||
551 | |||
552 | static void stack_proc(void *arg) | ||
553 | { | ||
554 | struct task_struct *from = current, *to = arg; | ||
555 | |||
556 | to->thread.saved_task = from; | ||
557 | switch_to(from, to, from); | ||
558 | } | ||
559 | |||
483 | /* Mconsole stack trace | 560 | /* Mconsole stack trace |
484 | * Added by Allan Graves, Jeff Dike | 561 | * Added by Allan Graves, Jeff Dike |
485 | * Dumps a stacks registers to the linux console. | 562 | * Dumps a stacks registers to the linux console. |
@@ -489,7 +566,7 @@ void do_stack(struct mc_request *req) | |||
489 | { | 566 | { |
490 | char *ptr = req->request.data; | 567 | char *ptr = req->request.data; |
491 | int pid_requested= -1; | 568 | int pid_requested= -1; |
492 | struct task_struct *from = NULL; | 569 | struct task_struct *from = NULL; |
493 | struct task_struct *to = NULL; | 570 | struct task_struct *to = NULL; |
494 | 571 | ||
495 | /* Would be nice: | 572 | /* Would be nice: |
@@ -507,17 +584,15 @@ void do_stack(struct mc_request *req) | |||
507 | return; | 584 | return; |
508 | } | 585 | } |
509 | 586 | ||
510 | from = current; | 587 | from = current; |
511 | to = find_task_by_pid(pid_requested); | ||
512 | 588 | ||
589 | to = find_task_by_pid(pid_requested); | ||
513 | if((to == NULL) || (pid_requested == 0)) { | 590 | if((to == NULL) || (pid_requested == 0)) { |
514 | mconsole_reply(req, "Couldn't find that pid", 1, 0); | 591 | mconsole_reply(req, "Couldn't find that pid", 1, 0); |
515 | return; | 592 | return; |
516 | } | 593 | } |
517 | to->thread.saved_task = current; | ||
518 | 594 | ||
519 | switch_to(from, to, from); | 595 | with_console(req, stack_proc, to); |
520 | mconsole_reply(req, "Stack Dumped to console and message log", 0, 0); | ||
521 | } | 596 | } |
522 | 597 | ||
523 | void mconsole_stack(struct mc_request *req) | 598 | void mconsole_stack(struct mc_request *req) |