# HG changeset patch # User Brendan Cully # Date 1178666168 25200 # Node ID 9b400773f70d590c4a3ccfd6184e58bcc89cbf2f # Parent 8f19dcd7132965ecd7f96dccaa25cf8aa94a0af3 Set up an event channel to signal guest suspend. Have xc_save use it directly instead of waiting for xend to signal the guest via xenstore. This cuts the overhead for the last round in half in my tests. Signed-off-by: Brendan Cully diff -r 8f19dcd71329 -r 9b400773f70d linux-2.6-xen-sparse/drivers/xen/core/machine_reboot.c --- a/linux-2.6-xen-sparse/drivers/xen/core/machine_reboot.c Mon May 07 15:43:52 2007 -0700 +++ b/linux-2.6-xen-sparse/drivers/xen/core/machine_reboot.c Tue May 08 16:16:08 2007 -0700 @@ -27,6 +27,8 @@ void (*pm_power_off)(void); void (*pm_power_off)(void); EXPORT_SYMBOL(pm_power_off); +int setup_suspend_evtchn(void); + void machine_emergency_restart(void) { /* We really want to get pending console data out before we die. */ @@ -227,6 +229,7 @@ int __xen_suspend(int fast_suspend) if (!suspend_cancelled) { xencons_resume(); xenbus_resume(); + setup_suspend_evtchn(); } else { xenbus_suspend_cancel(); } diff -r 8f19dcd71329 -r 9b400773f70d linux-2.6-xen-sparse/drivers/xen/core/reboot.c --- a/linux-2.6-xen-sparse/drivers/xen/core/reboot.c Mon May 07 15:43:52 2007 -0700 +++ b/linux-2.6-xen-sparse/drivers/xen/core/reboot.c Tue May 08 16:16:08 2007 -0700 @@ -7,6 +7,7 @@ #include #include #include +#include #include #ifdef HAVE_XEN_PLATFORM_COMPAT_H @@ -199,6 +200,36 @@ static struct xenbus_watch sysrq_watch = .callback = sysrq_handler }; +static irqreturn_t suspend_int(int irq, void* dev_id, struct pt_regs *ptregs) +{ + shutting_down = SHUTDOWN_SUSPEND; + schedule_work(&shutdown_work); + + return IRQ_HANDLED; +} + +int setup_suspend_evtchn(void) +{ + static int irq = -1; + int port; + char portstr[5]; /* 1024 max? */ + + if (irq > 0) + unbind_from_irqhandler(irq, NULL); + + /* TODO: get other end dynamically */ + irq = bind_listening_port_to_irqhandler(0, suspend_int, 0, "suspend", NULL); + if (irq <= 0) { + return -1; + } + port = irq_to_evtchn_port(irq); + printk(KERN_ERR "suspend: event channel %d\n", port); + sprintf(portstr, "%d", port); + xenbus_write(XBT_NIL, "device/suspend", "event-channel", portstr); + + return 0; +} + static int setup_shutdown_watcher(void) { int err; @@ -217,6 +248,13 @@ static int setup_shutdown_watcher(void) if (err) { printk(KERN_ERR "Failed to set sysrq watcher\n"); return err; + } + + /* suspend event channel */ + err = setup_suspend_evtchn(); + if (err) { + printk(KERN_ERR "Failed to register suspend event channel\n"); + return err; } return 0; diff -r 8f19dcd71329 -r 9b400773f70d tools/python/xen/xend/XendCheckpoint.py --- a/tools/python/xen/xend/XendCheckpoint.py Mon May 07 15:43:52 2007 -0700 +++ b/tools/python/xen/xend/XendCheckpoint.py Tue May 08 16:16:08 2007 -0700 @@ -92,6 +92,7 @@ def save(fd, dominfo, network, live, dst if line == "suspend": log.debug("Suspending %d ...", dominfo.getDomid()) dominfo.shutdown('suspend') + if line in ('suspend', 'suspended'): dominfo.waitForShutdown() dominfo.migrateDevices(network, dst, DEV_MIGRATE_STEP2, domain_name) diff -r 8f19dcd71329 -r 9b400773f70d tools/xcutils/xc_save.c --- a/tools/xcutils/xc_save.c Mon May 07 15:43:52 2007 -0700 +++ b/tools/xcutils/xc_save.c Tue May 08 16:16:08 2007 -0700 @@ -23,8 +23,13 @@ #include #include +#include + /* defined in xc_linux_save. Yes, this is cheezy. */ extern int do_last_round; + +static int xce = -1; +static int suspend_evtchn = -1; /** * Issue a suspend request through stdout, and receive the acknowledgement @@ -32,9 +37,24 @@ extern int do_last_round; */ static int suspend(int domid) { + static char* suspend = "suspend\n"; + static char* suspended = "suspended\n"; + char ans[30]; - - printf("suspend\n"); + char* msg; + int rc; + + msg = suspend; + + if (suspend_evtchn > 0) { + rc = xc_evtchn_notify(xce, suspend_evtchn); + if (rc < 0) + fprintf(stderr, "failed to notify suspend event channel: %d\n", rc); + else + msg = suspended; + } + + printf(msg); fflush(stdout); return (fgets(ans, sizeof(ans), stdin) != NULL && @@ -183,6 +203,59 @@ static void sigusr1(int sig) do_last_round = 1; } +static int setup_suspend_evtchn(unsigned int domid) +{ + struct xs_handle* xs; + char path[128]; + char *portstr; + unsigned int plen; + int port; + int rc = -1; + + xce = xc_evtchn_open(); + if (xce < 0) { + fprintf(stderr, "failed to open event channel handle\n"); + return -1; + } + + xs = xs_daemon_open_readonly(); + if (!xs) { + fprintf(stderr, "failed to open xenstore handle\n"); + goto xce_err; + } + + sprintf(path, "/local/domain/%d/device/suspend/event-channel", domid); + + portstr = xs_read(xs, XBT_NULL, path, &plen); + if (!portstr || !plen) { + fprintf(stderr, "failed to read suspend event channel\n"); + goto xs_err; + } + port = atoi(portstr); + free(portstr); + + fprintf(stderr, "binding to suspend evtchn %u:%d\n", domid, port); + + suspend_evtchn = xc_evtchn_bind_interdomain(xce, domid, port); + if (suspend_evtchn < 0) { + fprintf(stderr, "failed to bind suspend event channel: %d (%s)\n", + suspend_evtchn, strerror(errno)); + goto xs_err; + } + + rc = 0; + + xs_err: + xs_daemon_close(xs); + xce_err: + if (xce >= 0 && rc < 0) { + xc_evtchn_close(xce); + xce = -1; + } + + return rc; +} + int main(int argc, char **argv) { @@ -207,12 +280,17 @@ main(int argc, char **argv) sa.sa_flags = SA_RESTART; sigaction(SIGUSR1, &sa, NULL); + setup_suspend_evtchn(domid); + ret = xc_domain_save(xc_fd, io_fd, domid, maxit, max_f, flags, &suspend, flags & XCFLAGS_CONTINUAL ? checkpoint_cb : NULL, !!(flags & XCFLAGS_HVM), &init_qemu_maps, &qemu_flip_buffer); + if (xce >= 0) + xc_evtchn_close(xce); + xc_interface_close(xc_fd); return ret;