]> xenbits.xensource.com Git - xen.git/commitdiff
Move the suspend event channel function to libxc, it will use the
authorKeir Fraser <keir.fraser@citrix.com>
Wed, 18 Mar 2009 11:49:26 +0000 (11:49 +0000)
committerKeir Fraser <keir.fraser@citrix.com>
Wed, 18 Mar 2009 11:49:26 +0000 (11:49 +0000)
/var/lib/xen/suspend_evtchn_lock.d to protect the access.

Signed-off-by: Jiang Yunhong <yunhong.jiang@intel.com>
tools/libxc/xc_domain_save.c
tools/libxc/xenguest.h
tools/xcutils/xc_save.c
tools/xenstore/xs.c
tools/xenstore/xs.h

index efd581966c714b5242ed983e457cb6cc5ccc66a8..d830dfce1f9a344425daa6021ef50cedee2a3b2f 100644 (file)
@@ -744,7 +744,114 @@ static xen_pfn_t *map_and_save_p2m_table(int xc_handle,
     return success ? p2m : NULL;
 }
 
+#define SUSPEND_LOCK_FILE "/var/lib/xen/suspend_evtchn_lock.d"
+static int lock_suspend_event(void)
+{
+    int fd;
+    mode_t mask;
+    char buf[128];
+
+    mask = umask(022);
+    fd = open(SUSPEND_LOCK_FILE, O_CREAT | O_EXCL | O_RDWR, 0666);
+    if (fd < 0)
+    {
+        ERROR("Can't create lock file for suspend event channel\n");
+        return -EINVAL;
+    }
+    umask(mask);
+    snprintf(buf, sizeof(buf), "%10ld", (long)getpid());
+
+    write(fd, buf, strlen(buf));
+    close(fd);
+
+    return 0;
+}
+
+static int unlock_suspend_event(void)
+{
+    int fd, pid, n;
+    char buf[128];
+
+    fd = open(SUSPEND_LOCK_FILE, O_RDWR);
+
+    if (fd < 0)
+        return -EINVAL;
+
+    n = read(fd, buf, 127);
+
+    close(fd);
+
+    if (n > 0)
+    {
+        sscanf(buf, "%d", &pid);
+        /* We are the owner, so we can simply delete the file */
+        if (pid == getpid())
+        {
+            unlink(SUSPEND_LOCK_FILE);
+            return 0;
+        }
+    }
+
+    return -EPERM;
+}
+
+int xc_await_suspend(int xce, int suspend_evtchn)
+{
+    int rc;
 
+    do {
+        rc = xc_evtchn_pending(xce);
+        if (rc < 0) {
+            ERROR("error polling suspend notification channel: %d", rc);
+            return -1;
+        }
+    } while (rc != suspend_evtchn);
+
+    /* harmless for one-off suspend */
+    if (xc_evtchn_unmask(xce, suspend_evtchn) < 0)
+        ERROR("failed to unmask suspend notification channel: %d", rc);
+
+    return 0;
+}
+
+int xc_suspend_evtchn_release(int xce, int suspend_evtchn)
+{
+    if (suspend_evtchn >= 0)
+        xc_evtchn_unbind(xce, suspend_evtchn);
+
+    return unlock_suspend_event();
+}
+
+int xc_suspend_evtchn_init(int xc, int xce, int domid, int port)
+{
+    int rc, suspend_evtchn = -1;
+
+    if (lock_suspend_event())
+        return -EINVAL;
+
+    suspend_evtchn = xc_evtchn_bind_interdomain(xce, domid, port);
+    if (suspend_evtchn < 0) {
+        ERROR("failed to bind suspend event channel: %d", suspend_evtchn);
+        goto cleanup;
+    }
+
+    rc = xc_domain_subscribe_for_suspend(xc, domid, port);
+    if (rc < 0) {
+        ERROR("failed to subscribe to domain: %d", rc);
+        goto cleanup;
+    }
+
+    /* event channel is pending immediately after binding */
+    xc_await_suspend(xce, suspend_evtchn);
+
+    return suspend_evtchn;
+
+cleanup:
+    if (suspend_evtchn > 0)
+        xc_suspend_evtchn_release(xce, suspend_evtchn);
+
+    return -1;
+}
 
 int xc_domain_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters,
                    uint32_t max_factor, uint32_t flags, int (*suspend)(void),
index 7261e391ac4ce83de54063608b99685fe4ee768a..d64fc4554bbc97c1370f86956031bb7125126283 100644 (file)
@@ -142,4 +142,10 @@ int xc_hvm_build_mem(int xc_handle,
                      const char *image_buffer,
                      unsigned long image_size);
 
+int xc_suspend_evtchn_release(int xce, int suspend_evtchn);
+
+int xc_suspend_evtchn_init(int xc, int xce, int domid, int port);
+
+int xc_await_suspend(int xce, int suspend_evtchn);
+
 #endif /* XENGUEST_H */
index 0202d88720dc97064f0f26d5c84bb4047bb53e33..d38bea409e726feb0928716ea7a1aef0131c38f4 100644 (file)
@@ -46,83 +46,6 @@ static int compat_suspend(void)
             !strncmp(ans, "done\n", 5));
 }
 
-static int suspend_evtchn_release(int xce, int suspend_evtchn)
-{
-    if (suspend_evtchn >= 0)
-        xc_evtchn_unbind(xce, suspend_evtchn);
-
-    return 0;
-}
-
-static int await_suspend(int xce, int suspend_evtchn)
-{
-    int rc;
-
-    do {
-        rc = xc_evtchn_pending(xce);
-        if (rc < 0) {
-            warnx("error polling suspend notification channel: %d", rc);
-            return -1;
-        }
-    } while (rc != suspend_evtchn);
-
-    /* harmless for one-off suspend */
-    if (xc_evtchn_unmask(xce, suspend_evtchn) < 0)
-        warnx("failed to unmask suspend notification channel: %d", rc);
-
-    return 0;
-}
-
-static int suspend_evtchn_init(int xc, int xce, int domid)
-{
-    struct xs_handle *xs;
-    char path[128];
-    char *portstr;
-    unsigned int plen;
-    int port;
-    int rc, suspend_evtchn = -1;
-
-    xs = xs_daemon_open();
-    if (!xs) {
-        warnx("failed to get xenstore handle");
-        return -1;
-    }
-    sprintf(path, "/local/domain/%d/device/suspend/event-channel", domid);
-    portstr = xs_read(xs, XBT_NULL, path, &plen);
-    xs_daemon_close(xs);
-
-    if (!portstr || !plen) {
-        warnx("could not read suspend event channel");
-        return -1;
-    }
-
-    port = atoi(portstr);
-    free(portstr);
-
-    suspend_evtchn = xc_evtchn_bind_interdomain(xce, domid, port);
-    if (suspend_evtchn < 0) {
-        warnx("failed to bind suspend event channel: %d", si.suspend_evtchn);
-        goto cleanup;
-    }
-
-    rc = xc_domain_subscribe_for_suspend(xc, domid, port);
-    if (rc < 0) {
-        warnx("failed to subscribe to domain: %d", rc);
-        goto cleanup;
-    }
-
-    /* event channel is pending immediately after binding */
-    await_suspend(xce, suspend_evtchn);
-
-    return suspend_evtchn;
-
-cleanup:
-    if (suspend_evtchn > 0)
-        suspend_evtchn_release(xce, suspend_evtchn);
-
-    return -1;
-}
-
 /**
  * Issue a suspend request to a dedicated event channel in the guest, and
  * receive the acknowledgement from the subscribe event channel. */
@@ -136,7 +59,7 @@ static int evtchn_suspend(void)
         return 0;
     }
 
-    if (await_suspend(si.xce, si.suspend_evtchn) < 0) {
+    if (xc_await_suspend(si.xce, si.suspend_evtchn) < 0) {
         warnx("suspend failed");
         return 0;
     }
@@ -289,12 +212,11 @@ static void *init_qemu_maps(int domid, unsigned int bitmap_size)
     return seg;
 }
 
-
 int
 main(int argc, char **argv)
 {
     unsigned int maxit, max_f;
-    int io_fd, ret;
+    int io_fd, ret, port;
 
     if (argc != 6)
         errx(1, "usage: %s iofd domid maxit maxf flags", argv[0]);
@@ -309,23 +231,37 @@ main(int argc, char **argv)
     max_f = atoi(argv[4]);
     si.flags = atoi(argv[5]);
 
+    si.suspend_evtchn = si.xce = -1;
 
     si.xce = xc_evtchn_open();
     if (si.xce < 0)
-        errx(1, "failed to open event channel handle");
-
-    si.suspend_evtchn = suspend_evtchn_init(si.xc_fd, si.xce, si.domid);
-
-    if (si.suspend_evtchn < 0)
-        warnx("suspend event channel initialization failed, using slow path");
-
+        warnx("failed to open event channel handle");
+
+    if (si.xce > 0)
+    {
+        port = xs_suspend_evtchn_port(si.domid);
+
+        if (port < 0)
+            warnx("faield to get the suspend evtchn port\n");
+        else
+        {
+            si.suspend_evtchn =
+              xc_suspend_evtchn_init(si.xc_fd, si.xce, si.domid, port);
+
+            if (si.suspend_evtchn < 0)
+                warnx("suspend event channel initialization failed"
+                       "using slow path");
+        }
+    }
     ret = xc_domain_save(si.xc_fd, io_fd, si.domid, maxit, max_f, si.flags, 
                          &suspend, !!(si.flags & XCFLAGS_HVM),
                          &init_qemu_maps, &qemu_flip_buffer);
 
-    suspend_evtchn_release(si.xce, si.suspend_evtchn);
+    if (si.suspend_evtchn > 0)
+        xc_suspend_evtchn_release(si.xce, si.suspend_evtchn);
 
-    xc_evtchn_close(si.xce);
+    if (si.xce > 0)
+        xc_evtchn_close(si.xce);
 
     xc_interface_close(si.xc_fd);
 
index 7fef574fbdcb9f653b19bba97909349ba00ef6fd..9707d19ca28d244c72a2d22aeca0085af46669f4 100644 (file)
@@ -802,6 +802,31 @@ bool xs_is_domain_introduced(struct xs_handle *h, unsigned int domid)
        return rc;
 }
 
+int xs_suspend_evtchn_port(int domid)
+{
+    char path[128];
+    char *portstr;
+    int port;
+    unsigned int plen;
+    struct xs_handle *xs;
+
+    xs = xs_daemon_open();
+    if (!xs)
+        return -1;
+
+    sprintf(path, "/local/domain/%d/device/suspend/event-channel", domid);
+    portstr = xs_read(xs, XBT_NULL, path, &plen);
+    xs_daemon_close(xs);
+
+    if (!portstr || !plen)
+        return -1;
+
+    port = atoi(portstr);
+    free(portstr);
+
+    return port;
+}
+
 /* Only useful for DEBUG versions */
 char *xs_debug_command(struct xs_handle *h, const char *cmd,
                       void *data, unsigned int len)
index dd8cbf8c956f7de957507c8d9b74f3027be5a83b..629395291ac7d7b871257b15a87e2aba1fb9d21f 100644 (file)
@@ -163,6 +163,7 @@ bool xs_is_domain_introduced(struct xs_handle *h, unsigned int domid);
 char *xs_debug_command(struct xs_handle *h, const char *cmd,
                       void *data, unsigned int len);
 
+int xs_suspend_evtchn_port(int domid);
 #endif /* _XS_H */
 
 /*