# HG changeset patch # User Brendan Cully # Date 1220753629 25200 # Node ID f4cab9466a84657e181211e57af5344bdc364842 # Parent 6e53036deb06fdbaa55489610ea8fc9c9b67ca64 xc_save: ignore the first suspend event channel notification I've noticed that the suspend event channel becomes pending as soon as it is bound. I'm not sure why or whether this is intentional, but it means that the suspend function will return before the domain has completed suspending unless the first notification is cleared. Without this patch, xc_domain_save may find that the guest has not suspended and sleep in 10ms chunks until it does. Typically this is several milliseconds of wasted time. diff --git a/tools/xcutils/xc_save.c b/tools/xcutils/xc_save.c --- a/tools/xcutils/xc_save.c +++ b/tools/xcutils/xc_save.c @@ -57,6 +57,25 @@ return 0; } +static int await_suspend(struct suspendinfo *si) +{ + int rc; + + do { + rc = xc_evtchn_pending(si->xce); + if (rc < 0) { + warnx("error polling suspend notification channel: %d", rc); + return -1; + } + } while (rc != si->suspend_evtchn); + + /* harmless for one-off suspend */ + if (xc_evtchn_unmask(si->xce, si->suspend_evtchn) < 0) + warnx("failed to unmask suspend notification channel: %d", rc); + + return 0; +} + static int suspend_evtchn_init(int xc, int domid) { struct xs_handle *xs; @@ -104,6 +123,9 @@ goto cleanup; } + /* event channel is pending immediately after binding? */ + await_suspend(&si); + return 0; cleanup: @@ -125,17 +147,10 @@ return 0; } - do { - rc = xc_evtchn_pending(si.xce); - if (rc < 0) { - warnx("error polling suspend notification channel: %d", rc); + if (await_suspend(&si) < 0) { + warnx("suspend failed"); return 0; - } - } while (rc != si.suspend_evtchn); - - /* harmless for one-off suspend */ - if (xc_evtchn_unmask(si.xce, si.suspend_evtchn) < 0) - warnx("failed to unmask suspend notification channel: %d", rc); + } /* notify xend that it can do device migration */ printf("suspended\n"); @@ -298,7 +313,8 @@ max_f = atoi(argv[4]); flags = atoi(argv[5]); - suspend_evtchn_init(xc_fd, domid); + if (suspend_evtchn_init(xc_fd, domid) < 0) + warnx("suspend event channel initialization failed, using slow path"); ret = xc_domain_save(xc_fd, io_fd, domid, maxit, max_f, flags, &suspend, !!(flags & XCFLAGS_HVM),