[PATCH] uml: fix I/O hang when multiple devices are in use
[deliverable/linux.git] / arch / um / drivers / mconsole_kern.c
CommitLineData
1da177e4
LT
1/*
2 * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org)
3 * Copyright (C) 2001 - 2003 Jeff Dike (jdike@addtoit.com)
4 * Licensed under the GPL
5 */
6
7#include "linux/kernel.h"
8#include "linux/slab.h"
9#include "linux/init.h"
10#include "linux/notifier.h"
11#include "linux/reboot.h"
12#include "linux/utsname.h"
13#include "linux/ctype.h"
14#include "linux/interrupt.h"
15#include "linux/sysrq.h"
16#include "linux/workqueue.h"
17#include "linux/module.h"
18#include "linux/file.h"
19#include "linux/fs.h"
20#include "linux/namei.h"
21#include "linux/proc_fs.h"
22#include "linux/syscalls.h"
02dea087
JD
23#include "linux/list.h"
24#include "linux/mm.h"
6f517d3f 25#include "linux/console.h"
1da177e4
LT
26#include "asm/irq.h"
27#include "asm/uaccess.h"
28#include "user_util.h"
29#include "kern_util.h"
30#include "kern.h"
31#include "mconsole.h"
32#include "mconsole_kern.h"
33#include "irq_user.h"
34#include "init.h"
35#include "os.h"
1da177e4 36#include "irq_kern.h"
3eddddcf 37#include "choose-mode.h"
1da177e4 38
d50084a2 39static int do_unlink_socket(struct notifier_block *notifier,
1da177e4
LT
40 unsigned long what, void *data)
41{
42 return(mconsole_unlink_socket());
43}
44
45
46static struct notifier_block reboot_notifier = {
47 .notifier_call = do_unlink_socket,
48 .priority = 0,
49};
50
d50084a2 51/* Safe without explicit locking for now. Tasklets provide their own
1da177e4
LT
52 * locking, and the interrupt handler is safe because it can't interrupt
53 * itself and it can only happen on CPU 0.
54 */
55
9010772c 56static LIST_HEAD(mc_requests);
1da177e4 57
6d5aefb8 58static void mc_work_proc(struct work_struct *unused)
1da177e4
LT
59{
60 struct mconsole_entry *req;
61 unsigned long flags;
62
63 while(!list_empty(&mc_requests)){
dbdb4c06 64 local_irq_save(flags);
d50084a2 65 req = list_entry(mc_requests.next, struct mconsole_entry,
1da177e4
LT
66 list);
67 list_del(&req->list);
68 local_irq_restore(flags);
69 req->request.cmd->handler(&req->request);
70 kfree(req);
71 }
72}
73
6d5aefb8 74static DECLARE_WORK(mconsole_work, mc_work_proc);
1da177e4 75
7bea96fd 76static irqreturn_t mconsole_interrupt(int irq, void *dev_id)
1da177e4
LT
77{
78 /* long to avoid size mismatch warnings from gcc */
79 long fd;
80 struct mconsole_entry *new;
3a51237d 81 static struct mc_request req; /* that's OK */
1da177e4
LT
82
83 fd = (long) dev_id;
84 while (mconsole_get_request(fd, &req)){
85 if(req.cmd->context == MCONSOLE_INTR)
86 (*req.cmd->handler)(&req);
87 else {
60baa158 88 new = kmalloc(sizeof(*new), GFP_NOWAIT);
1da177e4
LT
89 if(new == NULL)
90 mconsole_reply(&req, "Out of memory", 1, 0);
91 else {
92 new->request = req;
3a51237d 93 new->request.regs = get_irq_regs()->regs;
1da177e4
LT
94 list_add(&new->list, &mc_requests);
95 }
96 }
97 }
98 if(!list_empty(&mc_requests))
99 schedule_work(&mconsole_work);
100 reactivate_fd(fd, MCONSOLE_IRQ);
101 return(IRQ_HANDLED);
102}
103
104void mconsole_version(struct mc_request *req)
105{
106 char version[256];
107
e9ff3990
SH
108 sprintf(version, "%s %s %s %s %s", utsname()->sysname,
109 utsname()->nodename, utsname()->release,
110 utsname()->version, utsname()->machine);
1da177e4
LT
111 mconsole_reply(req, version, 0, 0);
112}
113
114void mconsole_log(struct mc_request *req)
115{
116 int len;
117 char *ptr = req->request.data;
118
119 ptr += strlen("log ");
120
121 len = req->len - (ptr - req->request.data);
122 printk("%.*s", len, ptr);
123 mconsole_reply(req, "", 0, 0);
124}
125
126/* This is a more convoluted version of mconsole_proc, which has some stability
127 * problems; however, we need it fixed, because it is expected that UML users
128 * mount HPPFS instead of procfs on /proc. And we want mconsole_proc to still
129 * show the real procfs content, not the ones from hppfs.*/
130#if 0
131void mconsole_proc(struct mc_request *req)
132{
133 struct nameidata nd;
134 struct file_system_type *proc;
135 struct super_block *super;
136 struct file *file;
137 int n, err;
138 char *ptr = req->request.data, *buf;
139
140 ptr += strlen("proc");
141 while(isspace(*ptr)) ptr++;
142
143 proc = get_fs_type("proc");
144 if(proc == NULL){
145 mconsole_reply(req, "procfs not registered", 1, 0);
146 goto out;
147 }
148
149 super = (*proc->get_sb)(proc, 0, NULL, NULL);
150 put_filesystem(proc);
151 if(super == NULL){
152 mconsole_reply(req, "Failed to get procfs superblock", 1, 0);
153 goto out;
154 }
155 up_write(&super->s_umount);
156
157 nd.dentry = super->s_root;
158 nd.mnt = NULL;
159 nd.flags = O_RDONLY + 1;
160 nd.last_type = LAST_ROOT;
161
162 /* START: it was experienced that the stability problems are closed
163 * if commenting out these two calls + the below read cycle. To
164 * make UML crash again, it was enough to readd either one.*/
165 err = link_path_walk(ptr, &nd);
166 if(err){
167 mconsole_reply(req, "Failed to look up file", 1, 0);
168 goto out_kill;
169 }
170
171 file = dentry_open(nd.dentry, nd.mnt, O_RDONLY);
172 if(IS_ERR(file)){
173 mconsole_reply(req, "Failed to open file", 1, 0);
174 goto out_kill;
175 }
176 /*END*/
177
178 buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
179 if(buf == NULL){
180 mconsole_reply(req, "Failed to allocate buffer", 1, 0);
181 goto out_fput;
182 }
183
184 if((file->f_op != NULL) && (file->f_op->read != NULL)){
185 do {
186 n = (*file->f_op->read)(file, buf, PAGE_SIZE - 1,
187 &file->f_pos);
188 if(n >= 0){
189 buf[n] = '\0';
190 mconsole_reply(req, buf, 0, (n > 0));
191 }
192 else {
193 mconsole_reply(req, "Read of file failed",
194 1, 0);
195 goto out_free;
196 }
197 } while(n > 0);
198 }
199 else mconsole_reply(req, "", 0, 0);
200
201 out_free:
202 kfree(buf);
203 out_fput:
204 fput(file);
205 out_kill:
206 deactivate_super(super);
207 out: ;
208}
209#endif
210
211void mconsole_proc(struct mc_request *req)
212{
213 char path[64];
214 char *buf;
215 int len;
216 int fd;
217 int first_chunk = 1;
218 char *ptr = req->request.data;
219
220 ptr += strlen("proc");
221 while(isspace(*ptr)) ptr++;
222 snprintf(path, sizeof(path), "/proc/%s", ptr);
223
224 fd = sys_open(path, 0, 0);
225 if (fd < 0) {
226 mconsole_reply(req, "Failed to open file", 1, 0);
227 printk("open %s: %d\n",path,fd);
228 goto out;
229 }
230
231 buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
232 if(buf == NULL){
233 mconsole_reply(req, "Failed to allocate buffer", 1, 0);
234 goto out_close;
235 }
236
237 for (;;) {
238 len = sys_read(fd, buf, PAGE_SIZE-1);
239 if (len < 0) {
240 mconsole_reply(req, "Read of file failed", 1, 0);
241 goto out_free;
242 }
243 /*Begin the file content on his own line.*/
244 if (first_chunk) {
245 mconsole_reply(req, "\n", 0, 1);
246 first_chunk = 0;
247 }
248 if (len == PAGE_SIZE-1) {
249 buf[len] = '\0';
250 mconsole_reply(req, buf, 0, 1);
251 } else {
252 buf[len] = '\0';
253 mconsole_reply(req, buf, 0, 0);
254 break;
255 }
256 }
257
258 out_free:
259 kfree(buf);
260 out_close:
261 sys_close(fd);
262 out:
263 /* nothing */;
264}
265
266#define UML_MCONSOLE_HELPTEXT \
267"Commands: \n\
268 version - Get kernel version \n\
269 help - Print this message \n\
270 halt - Halt UML \n\
271 reboot - Reboot UML \n\
272 config <dev>=<config> - Add a new device to UML; \n\
273 same syntax as command line \n\
274 config <dev> - Query the configuration of a device \n\
275 remove <dev> - Remove a device from UML \n\
276 sysrq <letter> - Performs the SysRq action controlled by the letter \n\
db805812 277 cad - invoke the Ctrl-Alt-Del handler \n\
1da177e4
LT
278 stop - pause the UML; it will do nothing until it receives a 'go' \n\
279 go - continue the UML after a 'stop' \n\
280 log <string> - make UML enter <string> into the kernel log\n\
281 proc <file> - returns the contents of the UML's /proc/<file>\n\
3eddddcf 282 stack <pid> - returns the stack of the specified pid\n\
1da177e4
LT
283"
284
285void mconsole_help(struct mc_request *req)
286{
287 mconsole_reply(req, UML_MCONSOLE_HELPTEXT, 0, 0);
288}
289
290void mconsole_halt(struct mc_request *req)
291{
292 mconsole_reply(req, "", 0, 0);
293 machine_halt();
294}
295
296void mconsole_reboot(struct mc_request *req)
297{
298 mconsole_reply(req, "", 0, 0);
299 machine_restart(NULL);
300}
301
1da177e4
LT
302void mconsole_cad(struct mc_request *req)
303{
304 mconsole_reply(req, "", 0, 0);
305 ctrl_alt_del();
306}
307
308void mconsole_go(struct mc_request *req)
309{
310 mconsole_reply(req, "Not stopped", 1, 0);
311}
312
313void mconsole_stop(struct mc_request *req)
314{
315 deactivate_fd(req->originating_fd, MCONSOLE_IRQ);
316 os_set_fd_block(req->originating_fd, 1);
3a51237d
AV
317 mconsole_reply(req, "stopped", 0, 0);
318 while (mconsole_get_request(req->originating_fd, req)) {
319 if (req->cmd->handler == mconsole_go)
320 break;
321 if (req->cmd->handler == mconsole_stop) {
322 mconsole_reply(req, "Already stopped", 1, 0);
323 continue;
324 }
325 if (req->cmd->handler == mconsole_sysrq) {
326 struct pt_regs *old_regs;
327 old_regs = set_irq_regs((struct pt_regs *)&req->regs);
328 mconsole_sysrq(req);
329 set_irq_regs(old_regs);
330 continue;
331 }
1da177e4
LT
332 (*req->cmd->handler)(req);
333 }
334 os_set_fd_block(req->originating_fd, 0);
335 reactivate_fd(req->originating_fd, MCONSOLE_IRQ);
336 mconsole_reply(req, "", 0, 0);
337}
338
84f48d4f 339static DEFINE_SPINLOCK(mc_devices_lock);
42947cb9 340static LIST_HEAD(mconsole_devices);
1da177e4
LT
341
342void mconsole_register_dev(struct mc_device *new)
343{
84f48d4f
JD
344 spin_lock(&mc_devices_lock);
345 BUG_ON(!list_empty(&new->list));
1da177e4 346 list_add(&new->list, &mconsole_devices);
84f48d4f 347 spin_unlock(&mc_devices_lock);
1da177e4
LT
348}
349
350static struct mc_device *mconsole_find_dev(char *name)
351{
352 struct list_head *ele;
353 struct mc_device *dev;
354
355 list_for_each(ele, &mconsole_devices){
356 dev = list_entry(ele, struct mc_device, list);
357 if(!strncmp(name, dev->name, strlen(dev->name)))
358 return(dev);
359 }
360 return(NULL);
361}
362
02dea087
JD
363#define UNPLUGGED_PER_PAGE \
364 ((PAGE_SIZE - sizeof(struct list_head)) / sizeof(unsigned long))
365
366struct unplugged_pages {
367 struct list_head list;
368 void *pages[UNPLUGGED_PER_PAGE];
369};
370
84f48d4f 371static DECLARE_MUTEX(plug_mem_mutex);
02dea087 372static unsigned long long unplugged_pages_count = 0;
c59bce62 373static LIST_HEAD(unplugged_pages);
02dea087
JD
374static int unplug_index = UNPLUGGED_PER_PAGE;
375
f28169d2 376static int mem_config(char *str, char **error_out)
02dea087
JD
377{
378 unsigned long long diff;
379 int err = -EINVAL, i, add;
380 char *ret;
381
f28169d2
JD
382 if(str[0] != '='){
383 *error_out = "Expected '=' after 'mem'";
02dea087 384 goto out;
f28169d2 385 }
02dea087
JD
386
387 str++;
388 if(str[0] == '-')
389 add = 0;
390 else if(str[0] == '+'){
391 add = 1;
392 }
f28169d2
JD
393 else {
394 *error_out = "Expected increment to start with '-' or '+'";
395 goto out;
396 }
02dea087
JD
397
398 str++;
399 diff = memparse(str, &ret);
f28169d2
JD
400 if(*ret != '\0'){
401 *error_out = "Failed to parse memory increment";
02dea087 402 goto out;
f28169d2 403 }
02dea087
JD
404
405 diff /= PAGE_SIZE;
406
84f48d4f 407 down(&plug_mem_mutex);
02dea087
JD
408 for(i = 0; i < diff; i++){
409 struct unplugged_pages *unplugged;
410 void *addr;
411
412 if(add){
413 if(list_empty(&unplugged_pages))
414 break;
415
416 unplugged = list_entry(unplugged_pages.next,
417 struct unplugged_pages, list);
418 if(unplug_index > 0)
419 addr = unplugged->pages[--unplug_index];
420 else {
421 list_del(&unplugged->list);
422 addr = unplugged;
423 unplug_index = UNPLUGGED_PER_PAGE;
424 }
425
426 free_page((unsigned long) addr);
427 unplugged_pages_count--;
428 }
429 else {
430 struct page *page;
431
432 page = alloc_page(GFP_ATOMIC);
433 if(page == NULL)
434 break;
435
436 unplugged = page_address(page);
437 if(unplug_index == UNPLUGGED_PER_PAGE){
02dea087
JD
438 list_add(&unplugged->list, &unplugged_pages);
439 unplug_index = 0;
440 }
441 else {
442 struct list_head *entry = unplugged_pages.next;
443 addr = unplugged;
444
445 unplugged = list_entry(entry,
446 struct unplugged_pages,
447 list);
02dea087 448 err = os_drop_memory(addr, PAGE_SIZE);
f28169d2 449 if(err){
02dea087
JD
450 printk("Failed to release memory - "
451 "errno = %d\n", err);
f28169d2 452 *error_out = "Failed to release memory";
84f48d4f 453 goto out_unlock;
f28169d2
JD
454 }
455 unplugged->pages[unplug_index++] = addr;
02dea087
JD
456 }
457
458 unplugged_pages_count++;
459 }
460 }
461
462 err = 0;
84f48d4f
JD
463out_unlock:
464 up(&plug_mem_mutex);
02dea087
JD
465out:
466 return err;
467}
468
469static int mem_get_config(char *name, char *str, int size, char **error_out)
470{
471 char buf[sizeof("18446744073709551615")];
472 int len = 0;
473
474 sprintf(buf, "%ld", uml_physmem);
475 CONFIG_CHUNK(str, size, len, buf, 1);
476
477 return len;
478}
479
480static int mem_id(char **str, int *start_out, int *end_out)
481{
482 *start_out = 0;
483 *end_out = 0;
484
485 return 0;
486}
487
f28169d2 488static int mem_remove(int n, char **error_out)
02dea087 489{
f28169d2 490 *error_out = "Memory doesn't support the remove operation";
02dea087
JD
491 return -EBUSY;
492}
493
494static struct mc_device mem_mc = {
84f48d4f 495 .list = LIST_HEAD_INIT(mem_mc.list),
02dea087
JD
496 .name = "mem",
497 .config = mem_config,
498 .get_config = mem_get_config,
499 .id = mem_id,
500 .remove = mem_remove,
501};
502
503static int mem_mc_init(void)
504{
505 if(can_drop_memory())
506 mconsole_register_dev(&mem_mc);
507 else printk("Can't release memory to the host - memory hotplug won't "
508 "be supported\n");
509 return 0;
510}
511
512__initcall(mem_mc_init);
513
1da177e4
LT
514#define CONFIG_BUF_SIZE 64
515
d50084a2 516static void mconsole_get_config(int (*get_config)(char *, char *, int,
1da177e4
LT
517 char **),
518 struct mc_request *req, char *name)
519{
520 char default_buf[CONFIG_BUF_SIZE], *error, *buf;
521 int n, size;
522
523 if(get_config == NULL){
524 mconsole_reply(req, "No get_config routine defined", 1, 0);
525 return;
526 }
527
528 error = NULL;
91b165c0 529 size = ARRAY_SIZE(default_buf);
1da177e4
LT
530 buf = default_buf;
531
532 while(1){
533 n = (*get_config)(name, buf, size, &error);
534 if(error != NULL){
535 mconsole_reply(req, error, 1, 0);
536 goto out;
537 }
538
539 if(n <= size){
540 mconsole_reply(req, buf, 0, 0);
541 goto out;
542 }
543
544 if(buf != default_buf)
545 kfree(buf);
546
547 size = n;
548 buf = kmalloc(size, GFP_KERNEL);
549 if(buf == NULL){
550 mconsole_reply(req, "Failed to allocate buffer", 1, 0);
551 return;
552 }
553 }
554 out:
555 if(buf != default_buf)
556 kfree(buf);
1da177e4
LT
557}
558
559void mconsole_config(struct mc_request *req)
560{
561 struct mc_device *dev;
f28169d2 562 char *ptr = req->request.data, *name, *error_string = "";
1da177e4
LT
563 int err;
564
565 ptr += strlen("config");
566 while(isspace(*ptr)) ptr++;
567 dev = mconsole_find_dev(ptr);
568 if(dev == NULL){
569 mconsole_reply(req, "Bad configuration option", 1, 0);
570 return;
571 }
572
573 name = &ptr[strlen(dev->name)];
574 ptr = name;
575 while((*ptr != '=') && (*ptr != '\0'))
576 ptr++;
577
578 if(*ptr == '='){
f28169d2
JD
579 err = (*dev->config)(name, &error_string);
580 mconsole_reply(req, error_string, err, 0);
1da177e4
LT
581 }
582 else mconsole_get_config(dev->get_config, req, name);
583}
584
585void mconsole_remove(struct mc_request *req)
586{
d50084a2 587 struct mc_device *dev;
29d56cfe 588 char *ptr = req->request.data, *err_msg = "";
3a331a51 589 char error[256];
29d56cfe 590 int err, start, end, n;
1da177e4
LT
591
592 ptr += strlen("remove");
593 while(isspace(*ptr)) ptr++;
594 dev = mconsole_find_dev(ptr);
595 if(dev == NULL){
596 mconsole_reply(req, "Bad remove option", 1, 0);
597 return;
598 }
29d56cfe 599
3a331a51
JD
600 ptr = &ptr[strlen(dev->name)];
601
602 err = 1;
603 n = (*dev->id)(&ptr, &start, &end);
604 if(n < 0){
605 err_msg = "Couldn't parse device number";
606 goto out;
607 }
608 else if((n < start) || (n > end)){
609 sprintf(error, "Invalid device number - must be between "
610 "%d and %d", start, end);
611 err_msg = error;
612 goto out;
613 }
29d56cfe 614
f28169d2
JD
615 err_msg = NULL;
616 err = (*dev->remove)(n, &err_msg);
3a331a51
JD
617 switch(err){
618 case -ENODEV:
f28169d2
JD
619 if(err_msg == NULL)
620 err_msg = "Device doesn't exist";
3a331a51
JD
621 break;
622 case -EBUSY:
f28169d2
JD
623 if(err_msg == NULL)
624 err_msg = "Device is currently open";
3a331a51
JD
625 break;
626 default:
627 break;
628 }
629out:
29d56cfe 630 mconsole_reply(req, err_msg, err, 0);
1da177e4
LT
631}
632
f92afe56
JD
633struct mconsole_output {
634 struct list_head list;
635 struct mc_request *req;
636};
637
84f48d4f 638static DEFINE_SPINLOCK(client_lock);
6f517d3f
JD
639static LIST_HEAD(clients);
640static char console_buf[MCONSOLE_MAX_DATA];
641static int console_index = 0;
642
643static void console_write(struct console *console, const char *string,
644 unsigned len)
645{
646 struct list_head *ele;
647 int n;
648
649 if(list_empty(&clients))
650 return;
651
652 while(1){
6dad2d3f 653 n = min((size_t) len, ARRAY_SIZE(console_buf) - console_index);
6f517d3f
JD
654 strncpy(&console_buf[console_index], string, n);
655 console_index += n;
656 string += n;
657 len -= n;
658 if(len == 0)
659 return;
660
661 list_for_each(ele, &clients){
f92afe56 662 struct mconsole_output *entry;
6f517d3f 663
f92afe56
JD
664 entry = list_entry(ele, struct mconsole_output, list);
665 mconsole_reply_len(entry->req, console_buf,
6f517d3f
JD
666 console_index, 0, 1);
667 }
668
669 console_index = 0;
670 }
671}
672
673static struct console mc_console = { .name = "mc",
674 .write = console_write,
a174b30e 675 .flags = CON_ENABLED,
6f517d3f
JD
676 .index = -1 };
677
678static int mc_add_console(void)
679{
680 register_console(&mc_console);
681 return 0;
682}
683
684late_initcall(mc_add_console);
685
686static void with_console(struct mc_request *req, void (*proc)(void *),
687 void *arg)
688{
f92afe56 689 struct mconsole_output entry;
6f517d3f
JD
690 unsigned long flags;
691
f92afe56 692 entry.req = req;
84f48d4f 693 spin_lock_irqsave(&client_lock, flags);
6f517d3f 694 list_add(&entry.list, &clients);
84f48d4f 695 spin_unlock_irqrestore(&client_lock, flags);
6f517d3f
JD
696
697 (*proc)(arg);
698
699 mconsole_reply_len(req, console_buf, console_index, 0, 0);
700 console_index = 0;
701
84f48d4f 702 spin_lock_irqsave(&client_lock, flags);
6f517d3f 703 list_del(&entry.list);
84f48d4f 704 spin_unlock_irqrestore(&client_lock, flags);
6f517d3f
JD
705}
706
4111b025
JD
707#ifdef CONFIG_MAGIC_SYSRQ
708static void sysrq_proc(void *arg)
709{
710 char *op = arg;
7bea96fd 711 handle_sysrq(*op, NULL);
4111b025
JD
712}
713
714void mconsole_sysrq(struct mc_request *req)
715{
716 char *ptr = req->request.data;
717
718 ptr += strlen("sysrq");
719 while(isspace(*ptr)) ptr++;
720
721 /* With 'b', the system will shut down without a chance to reply,
722 * so in this case, we reply first.
723 */
724 if(*ptr == 'b')
725 mconsole_reply(req, "", 0, 0);
726
727 with_console(req, sysrq_proc, ptr);
728}
729#else
730void mconsole_sysrq(struct mc_request *req)
731{
732 mconsole_reply(req, "Sysrq not compiled in", 1, 0);
733}
734#endif
735
42947cb9
PBG
736#ifdef CONFIG_MODE_SKAS
737
6f517d3f
JD
738static void stack_proc(void *arg)
739{
740 struct task_struct *from = current, *to = arg;
741
742 to->thread.saved_task = from;
743 switch_to(from, to, from);
744}
745
3eddddcf
JD
746/* Mconsole stack trace
747 * Added by Allan Graves, Jeff Dike
748 * Dumps a stacks registers to the linux console.
749 * Usage stack <pid>.
750 */
42947cb9 751static void do_stack_trace(struct mc_request *req)
3eddddcf 752{
3a331a51
JD
753 char *ptr = req->request.data;
754 int pid_requested= -1;
6f517d3f 755 struct task_struct *from = NULL;
3eddddcf
JD
756 struct task_struct *to = NULL;
757
3a331a51
JD
758 /* Would be nice:
759 * 1) Send showregs output to mconsole.
3eddddcf
JD
760 * 2) Add a way to stack dump all pids.
761 */
762
3a331a51
JD
763 ptr += strlen("stack");
764 while(isspace(*ptr)) ptr++;
3eddddcf 765
3a331a51
JD
766 /* Should really check for multiple pids or reject bad args here */
767 /* What do the arguments in mconsole_reply mean? */
768 if(sscanf(ptr, "%d", &pid_requested) == 0){
769 mconsole_reply(req, "Please specify a pid", 1, 0);
770 return;
771 }
3eddddcf 772
6f517d3f 773 from = current;
3eddddcf 774
6f517d3f 775 to = find_task_by_pid(pid_requested);
3a331a51
JD
776 if((to == NULL) || (pid_requested == 0)) {
777 mconsole_reply(req, "Couldn't find that pid", 1, 0);
778 return;
779 }
6f517d3f 780 with_console(req, stack_proc, to);
3eddddcf 781}
42947cb9 782#endif /* CONFIG_MODE_SKAS */
3eddddcf
JD
783
784void mconsole_stack(struct mc_request *req)
785{
786 /* This command doesn't work in TT mode, so let's check and then
787 * get out of here
788 */
789 CHOOSE_MODE(mconsole_reply(req, "Sorry, this doesn't work in TT mode",
790 1, 0),
42947cb9 791 do_stack_trace(req));
3eddddcf
JD
792}
793
1da177e4
LT
794/* Changed by mconsole_setup, which is __setup, and called before SMP is
795 * active.
796 */
d50084a2 797static char *notify_socket = NULL;
1da177e4 798
9010772c 799static int mconsole_init(void)
1da177e4
LT
800{
801 /* long to avoid size mismatch warnings from gcc */
802 long sock;
803 int err;
804 char file[256];
805
806 if(umid_file_name("mconsole", file, sizeof(file))) return(-1);
807 snprintf(mconsole_socket_name, sizeof(file), "%s", file);
808
809 sock = os_create_unix_socket(file, sizeof(file), 1);
810 if (sock < 0){
811 printk("Failed to initialize management console\n");
812 return(1);
813 }
814
815 register_reboot_notifier(&reboot_notifier);
816
817 err = um_request_irq(MCONSOLE_IRQ, sock, IRQ_READ, mconsole_interrupt,
bd6aa650 818 IRQF_DISABLED | IRQF_SHARED | IRQF_SAMPLE_RANDOM,
1da177e4
LT
819 "mconsole", (void *)sock);
820 if (err){
821 printk("Failed to get IRQ for management console\n");
822 return(1);
823 }
824
825 if(notify_socket != NULL){
970d6e3a 826 notify_socket = kstrdup(notify_socket, GFP_KERNEL);
1da177e4
LT
827 if(notify_socket != NULL)
828 mconsole_notify(notify_socket, MCONSOLE_SOCKET,
d50084a2 829 mconsole_socket_name,
1da177e4
LT
830 strlen(mconsole_socket_name) + 1);
831 else printk(KERN_ERR "mconsole_setup failed to strdup "
832 "string\n");
833 }
834
d50084a2 835 printk("mconsole (version %d) initialized on %s\n",
1da177e4
LT
836 MCONSOLE_VERSION, mconsole_socket_name);
837 return(0);
838}
839
840__initcall(mconsole_init);
841
842static int write_proc_mconsole(struct file *file, const char __user *buffer,
843 unsigned long count, void *data)
844{
845 char *buf;
846
847 buf = kmalloc(count + 1, GFP_KERNEL);
d50084a2 848 if(buf == NULL)
1da177e4
LT
849 return(-ENOMEM);
850
851 if(copy_from_user(buf, buffer, count)){
852 count = -EFAULT;
853 goto out;
854 }
855
856 buf[count] = '\0';
857
858 mconsole_notify(notify_socket, MCONSOLE_USER_NOTIFY, buf, count);
859 out:
860 kfree(buf);
861 return(count);
862}
863
864static int create_proc_mconsole(void)
865{
866 struct proc_dir_entry *ent;
867
868 if(notify_socket == NULL) return(0);
869
870 ent = create_proc_entry("mconsole", S_IFREG | 0200, NULL);
871 if(ent == NULL){
30f417c6 872 printk(KERN_INFO "create_proc_mconsole : create_proc_entry failed\n");
1da177e4
LT
873 return(0);
874 }
875
876 ent->read_proc = NULL;
877 ent->write_proc = write_proc_mconsole;
878 return(0);
879}
880
881static DEFINE_SPINLOCK(notify_spinlock);
882
883void lock_notify(void)
884{
885 spin_lock(&notify_spinlock);
886}
887
888void unlock_notify(void)
889{
890 spin_unlock(&notify_spinlock);
891}
892
893__initcall(create_proc_mconsole);
894
895#define NOTIFY "=notify:"
896
897static int mconsole_setup(char *str)
898{
899 if(!strncmp(str, NOTIFY, strlen(NOTIFY))){
900 str += strlen(NOTIFY);
901 notify_socket = str;
902 }
903 else printk(KERN_ERR "mconsole_setup : Unknown option - '%s'\n", str);
904 return(1);
905}
906
907__setup("mconsole", mconsole_setup);
908
909__uml_help(mconsole_setup,
910"mconsole=notify:<socket>\n"
911" Requests that the mconsole driver send a message to the named Unix\n"
912" socket containing the name of the mconsole socket. This also serves\n"
913" to notify outside processes when UML has booted far enough to respond\n"
914" to mconsole requests.\n\n"
915);
916
917static int notify_panic(struct notifier_block *self, unsigned long unused1,
918 void *ptr)
919{
920 char *message = ptr;
921
922 if(notify_socket == NULL) return(0);
923
d50084a2 924 mconsole_notify(notify_socket, MCONSOLE_PANIC, message,
1da177e4
LT
925 strlen(message) + 1);
926 return(0);
927}
928
929static struct notifier_block panic_exit_notifier = {
930 .notifier_call = notify_panic,
931 .next = NULL,
932 .priority = 1
933};
934
935static int add_notifier(void)
936{
e041c683
AS
937 atomic_notifier_chain_register(&panic_notifier_list,
938 &panic_exit_notifier);
1da177e4
LT
939 return(0);
940}
941
942__initcall(add_notifier);
943
944char *mconsole_notify_socket(void)
945{
946 return(notify_socket);
947}
948
949EXPORT_SYMBOL(mconsole_notify_socket);
This page took 0.258082 seconds and 5 git commands to generate.