# HG changeset patch # User Brendan Cully # Date 1180051484 25200 # Node ID fcc62feb1d2c92cfece16c0b11b8bf5ac3c411cb # Parent 5c5b8a69c9d631399b3a139dea2026f7a11f6dd7 Add facility to subscribe to a domain via event channel. This event channel will be notified when the domain transitions to the suspended state, which can be much faster than raising VIRQ_DOM_EXC and waiting for the notification to be propagated via xenstore. Signed-off-by: Brendan Cully diff -r 5c5b8a69c9d6 -r fcc62feb1d2c tools/libxc/xc_domain.c --- a/tools/libxc/xc_domain.c Thu May 24 17:04:44 2007 -0700 +++ b/tools/libxc/xc_domain.c Thu May 24 17:04:44 2007 -0700 @@ -696,6 +696,17 @@ int xc_get_hvm_param(int handle, domid_t return rc; } +int xc_dom_subscribe(int xc_handle, domid_t dom, evtchn_port_t port) +{ + DECLARE_DOMCTL; + + domctl.cmd = XEN_DOMCTL_subscribe; + domctl.domain = dom; + domctl.u.subscribe.port = port; + + return do_domctl(xc_handle, &domctl); +} + /* * Local variables: * mode: C diff -r 5c5b8a69c9d6 -r fcc62feb1d2c tools/libxc/xenctrl.h --- a/tools/libxc/xenctrl.h Thu May 24 17:04:44 2007 -0700 +++ b/tools/libxc/xenctrl.h Thu May 24 17:04:44 2007 -0700 @@ -728,6 +728,12 @@ evtchn_port_t xc_evtchn_pending(int xce_ */ int xc_evtchn_unmask(int xce_handle, evtchn_port_t port); +/* + * Subscribe to state changes in a domain via evtchn. + * Returns -1 on failure, in which case errno will be set appropriately. + */ +int xc_dom_subscribe(int xc_handle, domid_t domid, evtchn_port_t port); + /************************** * GRANT TABLE OPERATIONS * **************************/ diff -r 5c5b8a69c9d6 -r fcc62feb1d2c tools/python/xen/xend/XendCheckpoint.py --- a/tools/python/xen/xend/XendCheckpoint.py Thu May 24 17:04:44 2007 -0700 +++ b/tools/python/xen/xend/XendCheckpoint.py Thu May 24 17:04:44 2007 -0700 @@ -92,7 +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'): + if line in ('suspend'): dominfo.waitForShutdown() dominfo.migrateDevices(network, dst, DEV_MIGRATE_STEP2, domain_name) diff -r 5c5b8a69c9d6 -r fcc62feb1d2c tools/xcutils/xc_save.c --- a/tools/xcutils/xc_save.c Thu May 24 17:04:44 2007 -0700 +++ b/tools/xcutils/xc_save.c Thu May 24 17:04:44 2007 -0700 @@ -28,8 +28,12 @@ /* defined in xc_linux_save. Yes, this is cheezy. */ extern int do_last_round; +unsigned int xc_fd; static int xce = -1; +/* notify this to cause guest to start suspend */ static int suspend_evtchn = -1; +/* get call back on this when guest has finished suspend */ +static int suspended_evtchn = -1; /** * Issue a suspend request through stdout, and receive the acknowledgement @@ -50,8 +54,28 @@ static int suspend(int domid) rc = xc_evtchn_notify(xce, suspend_evtchn); if (rc < 0) fprintf(stderr, "failed to notify suspend event channel: %d\n", rc); - else + else { msg = suspended; + if (suspended_evtchn > 0) { + do { + rc = xc_evtchn_pending(xce); + } while (rc > 0 && rc != suspended_evtchn); + if (rc <= 0) { + fprintf(stderr, "failed to received suspend notification: %d\n", rc); + return 0; + } + if (xc_evtchn_unmask(xce, suspended_evtchn) < 0) { + fprintf(stderr, "failed to unmask suspend notification channel: %d\n", + rc); + return 0; + } + + printf(msg); + fflush(stdout); + + return 1; + } + } } printf(msg); @@ -224,8 +248,35 @@ static int setup_suspend_evtchn(unsigned goto xs_err; } + suspended_evtchn = xc_evtchn_bind_unbound_port(xce, domid); + if (suspended_evtchn < 0) { + fprintf(stderr, + "failed to bind suspend notification event channel: %d (%s)\n", + suspended_evtchn, strerror(errno)); + goto se_err; + } + + rc = xc_dom_subscribe(xc_fd, domid, suspended_evtchn); + if (rc < 0) { + fprintf(stderr, + "failed to subscribe to domain: %d (%s)\n", rc, strerror(errno)); + goto se2_err; + } + fprintf(stderr, "subscribed to domain %d on port %d\n", + domid, suspended_evtchn); + rc = 0; + se2_err: + if (rc < 0) { + xc_evtchn_unbind(xce, suspended_evtchn); + suspended_evtchn = -1; + } + se_err: + if (rc < 0) { + xc_evtchn_unbind(xce, suspend_evtchn); + suspend_evtchn = -1; + } xs_err: xs_daemon_close(xs); xce_err: @@ -237,8 +288,13 @@ static int setup_suspend_evtchn(unsigned return rc; } -static void release_suspend_evtchn(void) -{ +static void release_suspend_evtchn(unsigned int domid) +{ + /* TODO: teach xen to clean up if port is unbound */ + if (suspended_evtchn > 0) { + xc_dom_subscribe(xc_fd, domid, 0); + suspended_evtchn = 0; + } if (xce >= 0) { if (suspend_evtchn > 0) xc_evtchn_unbind(xce, suspend_evtchn); @@ -249,7 +305,7 @@ int int main(int argc, char **argv) { - unsigned int xc_fd, io_fd, domid, maxit, max_f, flags; + unsigned int io_fd, domid, maxit, max_f, flags; int ret; struct sigaction sa; @@ -276,7 +332,7 @@ main(int argc, char **argv) &suspend, !!(flags & XCFLAGS_HVM), &init_qemu_maps, &qemu_flip_buffer); - release_suspend_evtchn(); + release_suspend_evtchn(domid); xc_interface_close(xc_fd); diff -r 5c5b8a69c9d6 -r fcc62feb1d2c xen/common/domain.c --- a/xen/common/domain.c Thu May 24 17:04:44 2007 -0700 +++ b/xen/common/domain.c Thu May 24 17:04:44 2007 -0700 @@ -103,7 +103,13 @@ static void __domain_finalise_shutdown(s for_each_vcpu ( d, v ) vcpu_sleep_nosync(v); - send_guest_global_virq(dom0, VIRQ_DOM_EXC); + if ( d->shutdown_code == SHUTDOWN_suspend + && d->suspend_evtchn > 0 ) + { + evtchn_set_pending(dom0->vcpu[0], d->suspend_evtchn); + } + else + send_guest_global_virq(dom0, VIRQ_DOM_EXC); } static void vcpu_check_shutdown(struct vcpu *v) diff -r 5c5b8a69c9d6 -r fcc62feb1d2c xen/common/domctl.c --- a/xen/common/domctl.c Thu May 24 17:04:44 2007 -0700 +++ b/xen/common/domctl.c Thu May 24 17:04:44 2007 -0700 @@ -707,6 +707,21 @@ long do_domctl(XEN_GUEST_HANDLE(xen_domc } break; + case XEN_DOMCTL_subscribe: + { + struct domain *d; + + ret = -ESRCH; + d = rcu_lock_domain_by_id(op->domain); + if ( d != NULL ) + { + d->suspend_evtchn = op->u.subscribe.port; + rcu_unlock_domain(d); + ret = 0; + } + } + break; + default: ret = arch_do_domctl(op, u_domctl); break; diff -r 5c5b8a69c9d6 -r fcc62feb1d2c xen/include/public/domctl.h --- a/xen/include/public/domctl.h Thu May 24 17:04:44 2007 -0700 +++ b/xen/include/public/domctl.h Thu May 24 17:04:44 2007 -0700 @@ -429,7 +429,13 @@ typedef struct xen_domctl_sendtrigger xe typedef struct xen_domctl_sendtrigger xen_domctl_sendtrigger_t; DEFINE_XEN_GUEST_HANDLE(xen_domctl_sendtrigger_t); - +#define XEN_DOMCTL_subscribe 29 +struct xen_domctl_subscribe { + uint32_t port; /* IN */ +}; +typedef struct xen_domctl_subscribe xen_domctl_subscribe_t; +DEFINE_XEN_GUEST_HANDLE(xen_domctl_subscribe_t); + struct xen_domctl { uint32_t cmd; uint32_t interface_version; /* XEN_DOMCTL_INTERFACE_VERSION */ @@ -459,6 +465,7 @@ struct xen_domctl { struct xen_domctl_hvmcontext hvmcontext; struct xen_domctl_address_size address_size; struct xen_domctl_sendtrigger sendtrigger; + struct xen_domctl_subscribe subscribe; uint8_t pad[128]; } u; }; diff -r 5c5b8a69c9d6 -r fcc62feb1d2c xen/include/xen/sched.h --- a/xen/include/xen/sched.h Thu May 24 17:04:44 2007 -0700 +++ b/xen/include/xen/sched.h Thu May 24 17:04:44 2007 -0700 @@ -201,6 +201,10 @@ struct domain bool_t is_shut_down; /* fully shut down? */ int shutdown_code; + /* If this is not 0, send suspend notification here instead of + * raising DOM_EXC */ + int suspend_evtchn; + atomic_t pause_count; unsigned long vm_assist;