ia64/xen-unstable

changeset 19387:a5f497f02e34

Move the suspend event channel function to libxc, it will use the
/var/lib/xen/suspend_evtchn_lock.d to protect the access.

Signed-off-by: Jiang Yunhong <yunhong.jiang@intel.com>
author Keir Fraser <keir.fraser@citrix.com>
date Wed Mar 18 11:49:26 2009 +0000 (2009-03-18)
parents f00e5d83b9ec
children f68c081bfe0b
files tools/libxc/xc_domain_save.c tools/libxc/xenguest.h tools/xcutils/xc_save.c tools/xenstore/xs.c tools/xenstore/xs.h
line diff
     1.1 --- a/tools/libxc/xc_domain_save.c	Wed Mar 18 11:48:48 2009 +0000
     1.2 +++ b/tools/libxc/xc_domain_save.c	Wed Mar 18 11:49:26 2009 +0000
     1.3 @@ -744,7 +744,114 @@ static xen_pfn_t *map_and_save_p2m_table
     1.4      return success ? p2m : NULL;
     1.5  }
     1.6  
     1.7 +#define SUSPEND_LOCK_FILE "/var/lib/xen/suspend_evtchn_lock.d"
     1.8 +static int lock_suspend_event(void)
     1.9 +{
    1.10 +    int fd;
    1.11 +    mode_t mask;
    1.12 +    char buf[128];
    1.13  
    1.14 +    mask = umask(022);
    1.15 +    fd = open(SUSPEND_LOCK_FILE, O_CREAT | O_EXCL | O_RDWR, 0666);
    1.16 +    if (fd < 0)
    1.17 +    {
    1.18 +        ERROR("Can't create lock file for suspend event channel\n");
    1.19 +        return -EINVAL;
    1.20 +    }
    1.21 +    umask(mask);
    1.22 +    snprintf(buf, sizeof(buf), "%10ld", (long)getpid());
    1.23 +
    1.24 +    write(fd, buf, strlen(buf));
    1.25 +    close(fd);
    1.26 +
    1.27 +    return 0;
    1.28 +}
    1.29 +
    1.30 +static int unlock_suspend_event(void)
    1.31 +{
    1.32 +    int fd, pid, n;
    1.33 +    char buf[128];
    1.34 +
    1.35 +    fd = open(SUSPEND_LOCK_FILE, O_RDWR);
    1.36 +
    1.37 +    if (fd < 0)
    1.38 +        return -EINVAL;
    1.39 +
    1.40 +    n = read(fd, buf, 127);
    1.41 +
    1.42 +    close(fd);
    1.43 +
    1.44 +    if (n > 0)
    1.45 +    {
    1.46 +        sscanf(buf, "%d", &pid);
    1.47 +        /* We are the owner, so we can simply delete the file */
    1.48 +        if (pid == getpid())
    1.49 +        {
    1.50 +            unlink(SUSPEND_LOCK_FILE);
    1.51 +            return 0;
    1.52 +        }
    1.53 +    }
    1.54 +
    1.55 +    return -EPERM;
    1.56 +}
    1.57 +
    1.58 +int xc_await_suspend(int xce, int suspend_evtchn)
    1.59 +{
    1.60 +    int rc;
    1.61 +
    1.62 +    do {
    1.63 +        rc = xc_evtchn_pending(xce);
    1.64 +        if (rc < 0) {
    1.65 +            ERROR("error polling suspend notification channel: %d", rc);
    1.66 +            return -1;
    1.67 +        }
    1.68 +    } while (rc != suspend_evtchn);
    1.69 +
    1.70 +    /* harmless for one-off suspend */
    1.71 +    if (xc_evtchn_unmask(xce, suspend_evtchn) < 0)
    1.72 +        ERROR("failed to unmask suspend notification channel: %d", rc);
    1.73 +
    1.74 +    return 0;
    1.75 +}
    1.76 +
    1.77 +int xc_suspend_evtchn_release(int xce, int suspend_evtchn)
    1.78 +{
    1.79 +    if (suspend_evtchn >= 0)
    1.80 +        xc_evtchn_unbind(xce, suspend_evtchn);
    1.81 +
    1.82 +    return unlock_suspend_event();
    1.83 +}
    1.84 +
    1.85 +int xc_suspend_evtchn_init(int xc, int xce, int domid, int port)
    1.86 +{
    1.87 +    int rc, suspend_evtchn = -1;
    1.88 +
    1.89 +    if (lock_suspend_event())
    1.90 +        return -EINVAL;
    1.91 +
    1.92 +    suspend_evtchn = xc_evtchn_bind_interdomain(xce, domid, port);
    1.93 +    if (suspend_evtchn < 0) {
    1.94 +        ERROR("failed to bind suspend event channel: %d", suspend_evtchn);
    1.95 +        goto cleanup;
    1.96 +    }
    1.97 +
    1.98 +    rc = xc_domain_subscribe_for_suspend(xc, domid, port);
    1.99 +    if (rc < 0) {
   1.100 +        ERROR("failed to subscribe to domain: %d", rc);
   1.101 +        goto cleanup;
   1.102 +    }
   1.103 +
   1.104 +    /* event channel is pending immediately after binding */
   1.105 +    xc_await_suspend(xce, suspend_evtchn);
   1.106 +
   1.107 +    return suspend_evtchn;
   1.108 +
   1.109 +cleanup:
   1.110 +    if (suspend_evtchn > 0)
   1.111 +        xc_suspend_evtchn_release(xce, suspend_evtchn);
   1.112 +
   1.113 +    return -1;
   1.114 +}
   1.115  
   1.116  int xc_domain_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters,
   1.117                     uint32_t max_factor, uint32_t flags, int (*suspend)(void),
     2.1 --- a/tools/libxc/xenguest.h	Wed Mar 18 11:48:48 2009 +0000
     2.2 +++ b/tools/libxc/xenguest.h	Wed Mar 18 11:49:26 2009 +0000
     2.3 @@ -142,4 +142,10 @@ int xc_hvm_build_mem(int xc_handle,
     2.4                       const char *image_buffer,
     2.5                       unsigned long image_size);
     2.6  
     2.7 +int xc_suspend_evtchn_release(int xce, int suspend_evtchn);
     2.8 +
     2.9 +int xc_suspend_evtchn_init(int xc, int xce, int domid, int port);
    2.10 +
    2.11 +int xc_await_suspend(int xce, int suspend_evtchn);
    2.12 +
    2.13  #endif /* XENGUEST_H */
     3.1 --- a/tools/xcutils/xc_save.c	Wed Mar 18 11:48:48 2009 +0000
     3.2 +++ b/tools/xcutils/xc_save.c	Wed Mar 18 11:49:26 2009 +0000
     3.3 @@ -46,83 +46,6 @@ static int compat_suspend(void)
     3.4              !strncmp(ans, "done\n", 5));
     3.5  }
     3.6  
     3.7 -static int suspend_evtchn_release(int xce, int suspend_evtchn)
     3.8 -{
     3.9 -    if (suspend_evtchn >= 0)
    3.10 -        xc_evtchn_unbind(xce, suspend_evtchn);
    3.11 -
    3.12 -    return 0;
    3.13 -}
    3.14 -
    3.15 -static int await_suspend(int xce, int suspend_evtchn)
    3.16 -{
    3.17 -    int rc;
    3.18 -
    3.19 -    do {
    3.20 -        rc = xc_evtchn_pending(xce);
    3.21 -        if (rc < 0) {
    3.22 -            warnx("error polling suspend notification channel: %d", rc);
    3.23 -            return -1;
    3.24 -        }
    3.25 -    } while (rc != suspend_evtchn);
    3.26 -
    3.27 -    /* harmless for one-off suspend */
    3.28 -    if (xc_evtchn_unmask(xce, suspend_evtchn) < 0)
    3.29 -        warnx("failed to unmask suspend notification channel: %d", rc);
    3.30 -
    3.31 -    return 0;
    3.32 -}
    3.33 -
    3.34 -static int suspend_evtchn_init(int xc, int xce, int domid)
    3.35 -{
    3.36 -    struct xs_handle *xs;
    3.37 -    char path[128];
    3.38 -    char *portstr;
    3.39 -    unsigned int plen;
    3.40 -    int port;
    3.41 -    int rc, suspend_evtchn = -1;
    3.42 -
    3.43 -    xs = xs_daemon_open();
    3.44 -    if (!xs) {
    3.45 -        warnx("failed to get xenstore handle");
    3.46 -        return -1;
    3.47 -    }
    3.48 -    sprintf(path, "/local/domain/%d/device/suspend/event-channel", domid);
    3.49 -    portstr = xs_read(xs, XBT_NULL, path, &plen);
    3.50 -    xs_daemon_close(xs);
    3.51 -
    3.52 -    if (!portstr || !plen) {
    3.53 -        warnx("could not read suspend event channel");
    3.54 -        return -1;
    3.55 -    }
    3.56 -
    3.57 -    port = atoi(portstr);
    3.58 -    free(portstr);
    3.59 -
    3.60 -    suspend_evtchn = xc_evtchn_bind_interdomain(xce, domid, port);
    3.61 -    if (suspend_evtchn < 0) {
    3.62 -        warnx("failed to bind suspend event channel: %d", si.suspend_evtchn);
    3.63 -        goto cleanup;
    3.64 -    }
    3.65 -
    3.66 -    rc = xc_domain_subscribe_for_suspend(xc, domid, port);
    3.67 -    if (rc < 0) {
    3.68 -        warnx("failed to subscribe to domain: %d", rc);
    3.69 -        goto cleanup;
    3.70 -    }
    3.71 -
    3.72 -    /* event channel is pending immediately after binding */
    3.73 -    await_suspend(xce, suspend_evtchn);
    3.74 -
    3.75 -    return suspend_evtchn;
    3.76 -
    3.77 -cleanup:
    3.78 -    if (suspend_evtchn > 0)
    3.79 -        suspend_evtchn_release(xce, suspend_evtchn);
    3.80 -
    3.81 -    return -1;
    3.82 -}
    3.83 -
    3.84  /**
    3.85   * Issue a suspend request to a dedicated event channel in the guest, and
    3.86   * receive the acknowledgement from the subscribe event channel. */
    3.87 @@ -136,7 +59,7 @@ static int evtchn_suspend(void)
    3.88          return 0;
    3.89      }
    3.90  
    3.91 -    if (await_suspend(si.xce, si.suspend_evtchn) < 0) {
    3.92 +    if (xc_await_suspend(si.xce, si.suspend_evtchn) < 0) {
    3.93          warnx("suspend failed");
    3.94          return 0;
    3.95      }
    3.96 @@ -289,12 +212,11 @@ static void *init_qemu_maps(int domid, u
    3.97      return seg;
    3.98  }
    3.99  
   3.100 -
   3.101  int
   3.102  main(int argc, char **argv)
   3.103  {
   3.104      unsigned int maxit, max_f;
   3.105 -    int io_fd, ret;
   3.106 +    int io_fd, ret, port;
   3.107  
   3.108      if (argc != 6)
   3.109          errx(1, "usage: %s iofd domid maxit maxf flags", argv[0]);
   3.110 @@ -309,23 +231,37 @@ main(int argc, char **argv)
   3.111      max_f = atoi(argv[4]);
   3.112      si.flags = atoi(argv[5]);
   3.113  
   3.114 +    si.suspend_evtchn = si.xce = -1;
   3.115  
   3.116      si.xce = xc_evtchn_open();
   3.117      if (si.xce < 0)
   3.118 -        errx(1, "failed to open event channel handle");
   3.119 +        warnx("failed to open event channel handle");
   3.120  
   3.121 -    si.suspend_evtchn = suspend_evtchn_init(si.xc_fd, si.xce, si.domid);
   3.122 +    if (si.xce > 0)
   3.123 +    {
   3.124 +        port = xs_suspend_evtchn_port(si.domid);
   3.125  
   3.126 -    if (si.suspend_evtchn < 0)
   3.127 -        warnx("suspend event channel initialization failed, using slow path");
   3.128 +        if (port < 0)
   3.129 +            warnx("faield to get the suspend evtchn port\n");
   3.130 +        else
   3.131 +        {
   3.132 +            si.suspend_evtchn =
   3.133 +              xc_suspend_evtchn_init(si.xc_fd, si.xce, si.domid, port);
   3.134  
   3.135 +            if (si.suspend_evtchn < 0)
   3.136 +                warnx("suspend event channel initialization failed"
   3.137 +                       "using slow path");
   3.138 +        }
   3.139 +    }
   3.140      ret = xc_domain_save(si.xc_fd, io_fd, si.domid, maxit, max_f, si.flags, 
   3.141                           &suspend, !!(si.flags & XCFLAGS_HVM),
   3.142                           &init_qemu_maps, &qemu_flip_buffer);
   3.143  
   3.144 -    suspend_evtchn_release(si.xce, si.suspend_evtchn);
   3.145 +    if (si.suspend_evtchn > 0)
   3.146 +        xc_suspend_evtchn_release(si.xce, si.suspend_evtchn);
   3.147  
   3.148 -    xc_evtchn_close(si.xce);
   3.149 +    if (si.xce > 0)
   3.150 +        xc_evtchn_close(si.xce);
   3.151  
   3.152      xc_interface_close(si.xc_fd);
   3.153  
     4.1 --- a/tools/xenstore/xs.c	Wed Mar 18 11:48:48 2009 +0000
     4.2 +++ b/tools/xenstore/xs.c	Wed Mar 18 11:49:26 2009 +0000
     4.3 @@ -802,6 +802,31 @@ bool xs_is_domain_introduced(struct xs_h
     4.4  	return rc;
     4.5  }
     4.6  
     4.7 +int xs_suspend_evtchn_port(int domid)
     4.8 +{
     4.9 +    char path[128];
    4.10 +    char *portstr;
    4.11 +    int port;
    4.12 +    unsigned int plen;
    4.13 +    struct xs_handle *xs;
    4.14 +
    4.15 +    xs = xs_daemon_open();
    4.16 +    if (!xs)
    4.17 +        return -1;
    4.18 +
    4.19 +    sprintf(path, "/local/domain/%d/device/suspend/event-channel", domid);
    4.20 +    portstr = xs_read(xs, XBT_NULL, path, &plen);
    4.21 +    xs_daemon_close(xs);
    4.22 +
    4.23 +    if (!portstr || !plen)
    4.24 +        return -1;
    4.25 +
    4.26 +    port = atoi(portstr);
    4.27 +    free(portstr);
    4.28 +
    4.29 +    return port;
    4.30 +}
    4.31 +
    4.32  /* Only useful for DEBUG versions */
    4.33  char *xs_debug_command(struct xs_handle *h, const char *cmd,
    4.34  		       void *data, unsigned int len)
     5.1 --- a/tools/xenstore/xs.h	Wed Mar 18 11:48:48 2009 +0000
     5.2 +++ b/tools/xenstore/xs.h	Wed Mar 18 11:49:26 2009 +0000
     5.3 @@ -163,6 +163,7 @@ bool xs_is_domain_introduced(struct xs_h
     5.4  char *xs_debug_command(struct xs_handle *h, const char *cmd,
     5.5  		       void *data, unsigned int len);
     5.6  
     5.7 +int xs_suspend_evtchn_port(int domid);
     5.8  #endif /* _XS_H */
     5.9  
    5.10  /*