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