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