Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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