ia64/xen-unstable

changeset 18447:f2bd9bbb0593

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.

From: Brendan Cully <brendan@cs.ubc.ca>
Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Mon Sep 08 11:16:23 2008 +0100 (2008-09-08)
parents a7586ec158d0
children 06ab9cb9578e
files tools/xcutils/xc_save.c
line diff
     1.1 --- a/tools/xcutils/xc_save.c	Mon Sep 08 11:13:03 2008 +0100
     1.2 +++ b/tools/xcutils/xc_save.c	Mon Sep 08 11:16:23 2008 +0100
     1.3 @@ -46,17 +46,36 @@ static int compat_suspend(void)
     1.4  static int suspend_evtchn_release(void)
     1.5  {
     1.6      if (si.suspend_evtchn >= 0) {
     1.7 -	xc_evtchn_unbind(si.xce, si.suspend_evtchn);
     1.8 -	si.suspend_evtchn = -1;
     1.9 +        xc_evtchn_unbind(si.xce, si.suspend_evtchn);
    1.10 +        si.suspend_evtchn = -1;
    1.11      }
    1.12      if (si.xce >= 0) {
    1.13 -	xc_evtchn_close(si.xce);
    1.14 -	si.xce = -1;
    1.15 +        xc_evtchn_close(si.xce);
    1.16 +        si.xce = -1;
    1.17      }
    1.18  
    1.19      return 0;
    1.20  }
    1.21  
    1.22 +static int await_suspend(void)
    1.23 +{
    1.24 +    int rc;
    1.25 +
    1.26 +    do {
    1.27 +        rc = xc_evtchn_pending(si.xce);
    1.28 +        if (rc < 0) {
    1.29 +            warnx("error polling suspend notification channel: %d", rc);
    1.30 +            return -1;
    1.31 +        }
    1.32 +    } while (rc != si.suspend_evtchn);
    1.33 +
    1.34 +    /* harmless for one-off suspend */
    1.35 +    if (xc_evtchn_unmask(si.xce, si.suspend_evtchn) < 0)
    1.36 +        warnx("failed to unmask suspend notification channel: %d", rc);
    1.37 +
    1.38 +    return 0;
    1.39 +}
    1.40 +
    1.41  static int suspend_evtchn_init(int xc, int domid)
    1.42  {
    1.43      struct xs_handle *xs;
    1.44 @@ -71,16 +90,16 @@ static int suspend_evtchn_init(int xc, i
    1.45  
    1.46      xs = xs_daemon_open();
    1.47      if (!xs) {
    1.48 -	warnx("failed to get xenstore handle");
    1.49 -	return -1;
    1.50 +        warnx("failed to get xenstore handle");
    1.51 +        return -1;
    1.52      }
    1.53      sprintf(path, "/local/domain/%d/device/suspend/event-channel", domid);
    1.54      portstr = xs_read(xs, XBT_NULL, path, &plen);
    1.55      xs_daemon_close(xs);
    1.56  
    1.57      if (!portstr || !plen) {
    1.58 -	warnx("could not read suspend event channel");
    1.59 -	return -1;
    1.60 +        warnx("could not read suspend event channel");
    1.61 +        return -1;
    1.62      }
    1.63  
    1.64      port = atoi(portstr);
    1.65 @@ -88,22 +107,25 @@ static int suspend_evtchn_init(int xc, i
    1.66  
    1.67      si.xce = xc_evtchn_open();
    1.68      if (si.xce < 0) {
    1.69 -	warnx("failed to open event channel handle");
    1.70 -	goto cleanup;
    1.71 +        warnx("failed to open event channel handle");
    1.72 +        goto cleanup;
    1.73      }
    1.74  
    1.75      si.suspend_evtchn = xc_evtchn_bind_interdomain(si.xce, domid, port);
    1.76      if (si.suspend_evtchn < 0) {
    1.77 -	warnx("failed to bind suspend event channel: %d", si.suspend_evtchn);
    1.78 -	goto cleanup;
    1.79 +        warnx("failed to bind suspend event channel: %d", si.suspend_evtchn);
    1.80 +        goto cleanup;
    1.81      }
    1.82  
    1.83      rc = xc_domain_subscribe_for_suspend(xc, domid, port);
    1.84      if (rc < 0) {
    1.85 -	warnx("failed to subscribe to domain: %d", rc);
    1.86 -	goto cleanup;
    1.87 +        warnx("failed to subscribe to domain: %d", rc);
    1.88 +        goto cleanup;
    1.89      }
    1.90  
    1.91 +    /* event channel is pending immediately after binding */
    1.92 +    await_suspend();
    1.93 +
    1.94      return 0;
    1.95  
    1.96    cleanup:
    1.97 @@ -121,21 +143,14 @@ static int evtchn_suspend(void)
    1.98  
    1.99      rc = xc_evtchn_notify(si.xce, si.suspend_evtchn);
   1.100      if (rc < 0) {
   1.101 -	warnx("failed to notify suspend request channel: %d", rc);
   1.102 -	return 0;
   1.103 +        warnx("failed to notify suspend request channel: %d", rc);
   1.104 +        return 0;
   1.105      }
   1.106  
   1.107 -    do {
   1.108 -      rc = xc_evtchn_pending(si.xce);
   1.109 -      if (rc < 0) {
   1.110 -	warnx("error polling suspend notification channel: %d", rc);
   1.111 -	return 0;
   1.112 -      }
   1.113 -    } while (rc != si.suspend_evtchn);
   1.114 -
   1.115 -    /* harmless for one-off suspend */
   1.116 -    if (xc_evtchn_unmask(si.xce, si.suspend_evtchn) < 0)
   1.117 -	warnx("failed to unmask suspend notification channel: %d", rc);
   1.118 +    if (await_suspend() < 0) {
   1.119 +        warnx("suspend failed");
   1.120 +        return 0;
   1.121 +    }
   1.122  
   1.123      /* notify xend that it can do device migration */
   1.124      printf("suspended\n");
   1.125 @@ -147,7 +162,7 @@ static int evtchn_suspend(void)
   1.126  static int suspend(void)
   1.127  {
   1.128      if (si.suspend_evtchn >= 0)
   1.129 -	return evtchn_suspend();
   1.130 +        return evtchn_suspend();
   1.131  
   1.132      return compat_suspend();
   1.133  }
   1.134 @@ -194,7 +209,7 @@ static void qemu_flip_buffer(int domid, 
   1.135       * other buffer */
   1.136      if (!xs_write(xs, XBT_NULL, qemu_next_active_path, &digit, 1))
   1.137          errx(1, "can't write next-active to store path (%s)\n", 
   1.138 -	     qemu_next_active_path);
   1.139 +             qemu_next_active_path);
   1.140  
   1.141      /* Wait a while for qemu to signal that it has switched to the new 
   1.142       * active buffer */
   1.143 @@ -286,7 +301,7 @@ main(int argc, char **argv)
   1.144      int ret;
   1.145  
   1.146      if (argc != 6)
   1.147 -	errx(1, "usage: %s iofd domid maxit maxf flags", argv[0]);
   1.148 +        errx(1, "usage: %s iofd domid maxit maxf flags", argv[0]);
   1.149  
   1.150      xc_fd = xc_interface_open();
   1.151      if (xc_fd < 0)
   1.152 @@ -298,7 +313,8 @@ main(int argc, char **argv)
   1.153      max_f = atoi(argv[4]);
   1.154      flags = atoi(argv[5]);
   1.155  
   1.156 -    suspend_evtchn_init(xc_fd, domid);
   1.157 +    if (suspend_evtchn_init(xc_fd, domid) < 0)
   1.158 +        warnx("suspend event channel initialization failed, using slow path");
   1.159  
   1.160      ret = xc_domain_save(xc_fd, io_fd, domid, maxit, max_f, flags, 
   1.161                           &suspend, !!(flags & XCFLAGS_HVM),