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