>From cb39cb1f36d4c37b3dc7942413550bb4b7c79a84 Mon Sep 17 00:00:00 2001 From: Wen Congyang Date: Tue, 17 Apr 2012 11:01:01 +0800 Subject: [PATCH] kvm: nofity thost when guest is panicked Signed-off-by: Wen Congyang --- drivers/char/virtio_console.c | 49 +++++++++++++++++++++++++++++++++++++++++ 1 files changed, 49 insertions(+), 0 deletions(-) diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index ddf86b6..ecccd30 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c @@ -225,8 +225,14 @@ struct port { /* We should allow only one process to open a port */ bool guest_connected; + + /* We use this port to tell the host that the guest is panicked */ + bool panicked_port; + char *panicked_buf; }; +static struct port *panicked_port; + /* This is the very early arch-specified put chars function. */ static int (*early_put_chars)(u32, const char *, int); @@ -806,6 +812,15 @@ static int port_fops_open(struct inode *inode, struct file *filp) goto out; } + /* + * Don't allow opening of panicked port devices -- that's reserved + * for kernel space + */ + if (port->panicked_port) { + ret = -ENXIO; + goto out; + } + /* Allow only one process to open a particular port at a time */ spin_lock_irq(&port->inbuf_lock); if (port->guest_connected) { @@ -1126,6 +1141,20 @@ static void send_sigio_to_port(struct port *port) kill_fasync(&port->async_queue, SIGIO, POLL_OUT); } +static int +kvm_pv_panic_notify(struct notifier_block *nb, unsigned long code, void *unused) +{ + send_control_msg(panicked_port, VIRTIO_CONSOLE_PORT_OPEN, 1); + memcpy(panicked_port->panicked_buf, "Kernel panicked\n", 16); + send_buf(panicked_port, panicked_port->panicked_buf, 16, true); + send_control_msg(panicked_port, VIRTIO_CONSOLE_CONSOLE_PORT, 0); + return NOTIFY_DONE; +} + +static struct notifier_block kvm_pv_panic_nb = { + .notifier_call = kvm_pv_panic_notify, +}; + static int add_port(struct ports_device *portdev, u32 id) { char debugfs_name[16]; @@ -1262,6 +1291,10 @@ static void remove_port(struct kref *kref) debugfs_remove(port->debugfs_file); + if (port->panicked_port) + atomic_notifier_chain_unregister(&panic_notifier_list, + &kvm_pv_panic_nb); + kfree(port); } @@ -1433,6 +1466,22 @@ static void handle_control_message(struct ports_device *portdev, name_size - 1); port->name[name_size - 1] = 0; + if (!panicked_port && !strcmp(port->name, "status")) { + port->panicked_buf = kmalloc(PAGE_SIZE, GFP_KERNEL); + if (!port->panicked_buf) { + dev_warn(port->dev, + "Not enough space to store panicked" + " message"); + goto skip; + } + send_sigio_to_port(port); + port->panicked_port = true; + panicked_port = port; + atomic_notifier_chain_register(&panic_notifier_list, + &kvm_pv_panic_nb); + } + +skip: /* * Since we only have one sysfs attribute, 'name', * create it only if we have a name for the port. -- 1.7.1