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