diff options
Diffstat (limited to 'arch/um/drivers/mconsole_kern.c')
-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) |