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 v2.6.26 943 lines 21 kB view raw
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 31static int do_unlink_socket(struct notifier_block *notifier, 32 unsigned long what, void *data) 33{ 34 return mconsole_unlink_socket(); 35} 36 37 38static 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 48static LIST_HEAD(mc_requests); 49 50static 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 65static DECLARE_WORK(mconsole_work, mc_work_proc); 66 67static 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 95void 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 105void 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 122void 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 202void 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 277void mconsole_help(struct mc_request *req) 278{ 279 mconsole_reply(req, UML_MCONSOLE_HELPTEXT, 0, 0); 280} 281 282void mconsole_halt(struct mc_request *req) 283{ 284 mconsole_reply(req, "", 0, 0); 285 machine_halt(); 286} 287 288void mconsole_reboot(struct mc_request *req) 289{ 290 mconsole_reply(req, "", 0, 0); 291 machine_restart(NULL); 292} 293 294void mconsole_cad(struct mc_request *req) 295{ 296 mconsole_reply(req, "", 0, 0); 297 ctrl_alt_del(); 298} 299 300void mconsole_go(struct mc_request *req) 301{ 302 mconsole_reply(req, "Not stopped", 1, 0); 303} 304 305void 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 333static DEFINE_SPINLOCK(mc_devices_lock); 334static LIST_HEAD(mconsole_devices); 335 336void 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 344static 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 360struct unplugged_pages { 361 struct list_head list; 362 void *pages[UNPLUGGED_PER_PAGE]; 363}; 364 365static DEFINE_MUTEX(plug_mem_mutex); 366static unsigned long long unplugged_pages_count = 0; 367static LIST_HEAD(unplugged_pages); 368static int unplug_index = UNPLUGGED_PER_PAGE; 369 370static 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; 457out_unlock: 458 mutex_unlock(&plug_mem_mutex); 459out: 460 return err; 461} 462 463static 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 474static 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 482static int mem_remove(int n, char **error_out) 483{ 484 *error_out = "Memory doesn't support the remove operation"; 485 return -EBUSY; 486} 487 488static 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 497static 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 510static 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 553void 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 580void 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 } 627out: 628 mconsole_reply(req, err_msg, err, 0); 629} 630 631struct mconsole_output { 632 struct list_head list; 633 struct mc_request *req; 634}; 635 636static DEFINE_SPINLOCK(client_lock); 637static LIST_HEAD(clients); 638static char console_buf[MCONSOLE_MAX_DATA]; 639 640static 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 664static struct console mc_console = { .name = "mc", 665 .write = console_write, 666 .flags = CON_ENABLED, 667 .index = -1 }; 668 669static int mc_add_console(void) 670{ 671 register_console(&mc_console); 672 return 0; 673} 674 675late_initcall(mc_add_console); 676 677static 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 701static void sysrq_proc(void *arg) 702{ 703 char *op = arg; 704 handle_sysrq(*op, NULL); 705} 706 707void 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 724void mconsole_sysrq(struct mc_request *req) 725{ 726 mconsole_reply(req, "Sysrq not compiled in", 1, 0); 727} 728#endif 729 730static 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 */ 744void 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 */ 781static char *notify_socket = NULL; 782 783static 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 833static 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 855static 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 874static DEFINE_SPINLOCK(notify_spinlock); 875 876void lock_notify(void) 877{ 878 spin_lock(&notify_spinlock); 879} 880 881void unlock_notify(void) 882{ 883 spin_unlock(&notify_spinlock); 884} 885 886__initcall(create_proc_mconsole); 887 888#define NOTIFY "notify:" 889 890static 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 910static 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 923static struct notifier_block panic_exit_notifier = { 924 .notifier_call = notify_panic, 925 .next = NULL, 926 .priority = 1 927}; 928 929static 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 938char *mconsole_notify_socket(void) 939{ 940 return notify_socket; 941} 942 943EXPORT_SYMBOL(mconsole_notify_socket);