[libvirt] [PATCH 2/2] Add managedSave support to libxl driver

Markus Groß gross at univention.de
Wed Jun 1 10:55:34 UTC 2011


---
 src/libxl/libxl_driver.c |  353 ++++++++++++++++++++++++++++++++++++----------
 1 files changed, 276 insertions(+), 77 deletions(-)

diff --git a/src/libxl/libxl_driver.c b/src/libxl/libxl_driver.c
index 61c3494..9bcc3b9 100644
--- a/src/libxl/libxl_driver.c
+++ b/src/libxl/libxl_driver.c
@@ -66,7 +66,6 @@ static int
 libxlVmStart(libxlDriverPrivatePtr driver, virDomainObjPtr vm,
              bool start_paused, int restore_fd);
 
-
 /* Function definitions */
 static void
 libxlDriverLock(libxlDriverPrivatePtr driver)
@@ -219,6 +218,87 @@ libxlDoNodeGetInfo(libxlDriverPrivatePtr driver, virNodeInfoPtr info)
     return 0;
 }
 
+static char *
+libxlDomainManagedSavePath(libxlDriverPrivatePtr driver, virDomainObjPtr vm) {
+    char *ret;
+
+    if (virAsprintf(&ret, "%s/%s.save", driver->saveDir, vm->def->name) < 0) {
+        virReportOOMError();
+        return NULL;
+    }
+
+    return ret;
+}
+
+/* This internal function expects the driver lock to already be held on
+ * entry. */
+static int ATTRIBUTE_NONNULL(3) ATTRIBUTE_NONNULL(4)
+libxlSaveImageOpen(libxlDriverPrivatePtr driver, const char *from,
+                     virDomainDefPtr *ret_def, libxlSavefileHeaderPtr ret_hdr)
+{
+    int fd;
+    virDomainDefPtr def = NULL;
+    libxlSavefileHeader hdr;
+    char *xml = NULL;
+
+    if ((fd = virFileOpenAs(from, O_RDONLY, 0, getuid(), getgid(), 0)) < 0) {
+        libxlError(VIR_ERR_OPERATION_FAILED,
+                   "%s", _("cannot read domain image"));
+        goto error;
+    }
+
+    if (saferead(fd, &hdr, sizeof(hdr)) != sizeof(hdr)) {
+        libxlError(VIR_ERR_OPERATION_FAILED,
+                   "%s", _("failed to read libxl header"));
+        goto error;
+    }
+
+    if (memcmp(hdr.magic, LIBXL_SAVE_MAGIC, sizeof(hdr.magic))) {
+        libxlError(VIR_ERR_INVALID_ARG, "%s", _("image magic is incorrect"));
+        goto error;
+    }
+
+    if (hdr.version > LIBXL_SAVE_VERSION) {
+        libxlError(VIR_ERR_OPERATION_FAILED,
+                   _("image version is not supported (%d > %d)"),
+                   hdr.version, LIBXL_SAVE_VERSION);
+        goto error;
+    }
+
+    if (hdr.xmlLen <= 0) {
+        libxlError(VIR_ERR_OPERATION_FAILED,
+                   _("invalid XML length: %d"), hdr.xmlLen);
+        goto error;
+    }
+
+    if (VIR_ALLOC_N(xml, hdr.xmlLen) < 0) {
+        virReportOOMError();
+        goto error;
+    }
+
+    if (saferead(fd, xml, hdr.xmlLen) != hdr.xmlLen) {
+        libxlError(VIR_ERR_OPERATION_FAILED, "%s", _("failed to read XML"));
+        goto error;
+    }
+
+    if (!(def = virDomainDefParseString(driver->caps, xml,
+                                        VIR_DOMAIN_XML_INACTIVE)))
+        goto error;
+
+    VIR_FREE(xml);
+
+    *ret_def = def;
+    *ret_hdr = hdr;
+
+    return fd;
+
+error:
+    VIR_FREE(xml);
+    virDomainDefFree(def);
+    VIR_FORCE_CLOSE(fd);
+    return -1;
+}
+
 /*
  * Cleanup function for domain that has reached shutoff state.
  *
@@ -546,17 +626,53 @@ libxlVmStart(libxlDriverPrivatePtr driver, virDomainObjPtr vm,
              bool start_paused, int restore_fd)
 {
     libxl_domain_config d_config;
-    virDomainDefPtr def = vm->def;
+    virDomainDefPtr def = NULL;
     virDomainEventPtr event = NULL;
+    libxlSavefileHeader hdr;
     int ret;
     uint32_t domid = 0;
     char *dom_xml = NULL;
+    char *managed_save = NULL;
     pid_t child_console_pid = -1;
     libxlDomainObjPrivatePtr priv = vm->privateData;
 
+    /* If there is a managed saved state restore it instead of starting
+     * from scratch. The old state is removed once the restoring succeeded. */
+    if (restore_fd < 0) {
+        managed_save = libxlDomainManagedSavePath(driver, vm);
+        if (managed_save == NULL)
+            goto error;
+
+        if (virFileExists(managed_save)) {
+
+            restore_fd = libxlSaveImageOpen(driver, managed_save, &def, &hdr);
+            if (restore_fd < 0)
+                goto error;
+
+            if (STRNEQ(vm->def->name, def->name) ||
+                memcmp(vm->def->uuid, def->uuid, VIR_UUID_BUFLEN)) {
+                char vm_uuidstr[VIR_UUID_STRING_BUFLEN];
+                char def_uuidstr[VIR_UUID_STRING_BUFLEN];
+                virUUIDFormat(vm->def->uuid, vm_uuidstr);
+                virUUIDFormat(def->uuid, def_uuidstr);
+                libxlError(VIR_ERR_OPERATION_FAILED,
+                           _("cannot restore domain '%s' uuid %s from a file"
+                             " which belongs to domain '%s' uuid %s"),
+                           vm->def->name, vm_uuidstr, def->name, def_uuidstr);
+                goto error;
+            }
+
+            virDomainObjAssignDef(vm, def, true);
+            def = NULL;
+
+            if (unlink(managed_save) < 0)
+                VIR_WARN("Failed to remove the managed state %s", managed_save);
+        }
+    }
+
     memset(&d_config, 0, sizeof(d_config));
 
-    if (libxlBuildDomainConfig(driver, def, &d_config) < 0 )
+    if (libxlBuildDomainConfig(driver, vm->def, &d_config) < 0 )
         return -1;
 
     if (libxlFreeMem(priv, &d_config) < 0) {
@@ -586,8 +702,8 @@ libxlVmStart(libxlDriverPrivatePtr driver, virDomainObjPtr vm,
         goto error;
     }
 
-    def->id = domid;
-    if ((dom_xml = virDomainDefFormat(def, 0)) == NULL)
+    vm->def->id = domid;
+    if ((dom_xml = virDomainDefFormat(vm->def, 0)) == NULL)
         goto error;
 
     if (libxl_userdata_store(&priv->ctx, domid, "libvirt-xml",
@@ -627,11 +743,14 @@ libxlVmStart(libxlDriverPrivatePtr driver, virDomainObjPtr vm,
 error:
     if (domid > 0) {
         libxl_domain_destroy(&priv->ctx, domid, 0);
-        def->id = -1;
+        vm->def->id = -1;
         virDomainObjSetState(vm, VIR_DOMAIN_SHUTOFF, VIR_DOMAIN_SHUTOFF_FAILED);
     }
     libxl_domain_config_destroy(&d_config);
     VIR_FREE(dom_xml);
+    VIR_FREE(managed_save);
+    virDomainDefFree(def);
+    VIR_FORCE_CLOSE(restore_fd);
     return -1;
 }
 
@@ -1692,12 +1811,13 @@ libxlDomainGetState(virDomainPtr dom,
     return ret;
 }
 
+/* This internal function expects the driver lock to already be held on
+ * entry and the vm must be active. */
 static int
-libxlDomainSave(virDomainPtr dom, const char *to)
+libxlDoDomainSave(libxlDriverPrivatePtr driver, virDomainObjPtr vm,
+                  const char *to)
 {
-    libxlDriverPrivatePtr driver = dom->conn->privateData;
-    virDomainObjPtr vm;
-    libxlDomainObjPrivatePtr priv;
+    libxlDomainObjPrivatePtr priv = vm->privateData;
     libxlSavefileHeader hdr;
     virDomainEventPtr event = NULL;
     char *xml = NULL;
@@ -1705,28 +1825,10 @@ libxlDomainSave(virDomainPtr dom, const char *to)
     int fd;
     int ret = -1;
 
-    libxlDriverLock(driver);
-    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
-
-    if (!vm) {
-        char uuidstr[VIR_UUID_STRING_BUFLEN];
-        virUUIDFormat(dom->uuid, uuidstr);
-        libxlError(VIR_ERR_NO_DOMAIN,
-                   _("No domain with matching uuid '%s'"), uuidstr);
-        goto cleanup;
-    }
-
-    if (!virDomainObjIsActive(vm)) {
-        libxlError(VIR_ERR_OPERATION_INVALID, "%s", _("Domain is not running"));
-        goto cleanup;
-    }
-
-    priv = vm->privateData;
-
     if (virDomainObjGetState(vm, NULL) == VIR_DOMAIN_PAUSED) {
         libxlError(VIR_ERR_OPERATION_INVALID,
                    _("Domain '%d' has to be running because libxenlight will"
-                     " suspend it"), dom->id);
+                     " suspend it"), vm->def->id);
         goto cleanup;
     }
 
@@ -1758,10 +1860,10 @@ libxlDomainSave(virDomainPtr dom, const char *to)
         goto cleanup;
     }
 
-    if (libxl_domain_suspend(&priv->ctx, NULL, dom->id, fd) != 0) {
+    if (libxl_domain_suspend(&priv->ctx, NULL, vm->def->id, fd) != 0) {
         libxlError(VIR_ERR_INTERNAL_ERROR,
                     _("Failed to save domain '%d' with libxenlight"),
-                    dom->id);
+                    vm->def->id);
         goto cleanup;
     }
 
@@ -1770,7 +1872,7 @@ libxlDomainSave(virDomainPtr dom, const char *to)
 
     if (libxlVmReap(driver, vm, 1, VIR_DOMAIN_SHUTOFF_SAVED) != 0) {
         libxlError(VIR_ERR_INTERNAL_ERROR,
-                    _("Failed to destroy domain '%d'"), dom->id);
+                    _("Failed to destroy domain '%d'"), vm->def->id);
         goto cleanup;
     }
 
@@ -1785,69 +1887,57 @@ cleanup:
     VIR_FREE(xml);
     if (VIR_CLOSE(fd) < 0)
         virReportSystemError(errno, "%s", _("cannot close file"));
-    if (vm)
-        virDomainObjUnlock(vm);
     if (event)
         libxlDomainEventQueue(driver, event);
-    libxlDriverUnlock(driver);
     return ret;
 }
 
 static int
-libxlDomainRestore(virConnectPtr conn, const char *from)
+libxlDomainSave(virDomainPtr dom, const char *to)
 {
-    libxlDriverPrivatePtr driver = conn->privateData;
-    virDomainDefPtr def = NULL;
-    virDomainObjPtr vm = NULL;
-    libxlSavefileHeader hdr;
-    char *xml = NULL;
-    int fd;
+    libxlDriverPrivatePtr driver = dom->conn->privateData;
+    virDomainObjPtr vm;
     int ret = -1;
 
     libxlDriverLock(driver);
+    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
 
-    if ((fd = virFileOpenAs(from, O_RDONLY, 0, getuid(), getgid(), 0)) < 0) {
-        libxlError(VIR_ERR_OPERATION_FAILED,
-                   "%s", _("cannot read domain image"));
-        goto cleanup;
-    }
-
-    if (saferead(fd, &hdr, sizeof(hdr)) != sizeof(hdr)) {
-        libxlError(VIR_ERR_OPERATION_FAILED,
-                   "%s", _("failed to read libxl header"));
+    if (!vm) {
+        char uuidstr[VIR_UUID_STRING_BUFLEN];
+        virUUIDFormat(dom->uuid, uuidstr);
+        libxlError(VIR_ERR_NO_DOMAIN,
+                   _("No domain with matching uuid '%s'"), uuidstr);
         goto cleanup;
     }
 
-    if (memcmp(hdr.magic, LIBXL_SAVE_MAGIC, sizeof(hdr.magic))) {
-        libxlError(VIR_ERR_INVALID_ARG, "%s", _("image magic is incorrect"));
+    if (!virDomainObjIsActive(vm)) {
+        libxlError(VIR_ERR_OPERATION_INVALID, "%s", _("Domain is not running"));
         goto cleanup;
     }
 
-    if (hdr.version > LIBXL_SAVE_VERSION) {
-        libxlError(VIR_ERR_OPERATION_FAILED,
-                   _("image version is not supported (%d > %d)"),
-                   hdr.version, LIBXL_SAVE_VERSION);
-        goto cleanup;
-    }
+    ret = libxlDoDomainSave(driver, vm, to);
 
-    if (hdr.xmlLen <= 0) {
-        libxlError(VIR_ERR_OPERATION_FAILED,
-                   _("invalid XML length: %d"), hdr.xmlLen);
-        goto cleanup;
-    }
+cleanup:
+    if (vm)
+        virDomainObjUnlock(vm);
+    libxlDriverUnlock(driver);
+    return ret;
+}
 
-    if (VIR_ALLOC_N(xml, hdr.xmlLen) < 0) {
-        virReportOOMError();
-        goto cleanup;
-    }
+static int
+libxlDomainRestore(virConnectPtr conn, const char *from)
+{
+    libxlDriverPrivatePtr driver = conn->privateData;
+    virDomainObjPtr vm = NULL;
+    virDomainDefPtr def = NULL;
+    libxlSavefileHeader hdr;
+    int fd = -1;
+    int ret = -1;
 
-    if (saferead(fd, xml, hdr.xmlLen) != hdr.xmlLen) {
-        libxlError(VIR_ERR_OPERATION_FAILED, "%s", _("failed to read XML"));
-        goto cleanup;
-    }
+    libxlDriverLock(driver);
 
-    if (!(def = virDomainDefParseString(driver->caps, xml,
-                                        VIR_DOMAIN_XML_INACTIVE)))
+    fd = libxlSaveImageOpen(driver, from, &def, &hdr);
+    if (fd < 0)
         goto cleanup;
 
     if (virDomainObjIsDuplicate(&driver->domains, def, 1) < 0)
@@ -1865,10 +1955,7 @@ libxlDomainRestore(virConnectPtr conn, const char *from)
     }
 
 cleanup:
-    VIR_FREE(xml);
     virDomainDefFree(def);
-    if (VIR_CLOSE(fd) < 0)
-        virReportSystemError(errno, "%s", _("cannot close file"));
     if (vm)
         virDomainObjUnlock(vm);
     libxlDriverUnlock(driver);
@@ -1970,6 +2057,115 @@ cleanup:
 }
 
 static int
+libxlDomainManagedSave(virDomainPtr dom, unsigned int flags)
+{
+    libxlDriverPrivatePtr driver = dom->conn->privateData;
+    virDomainObjPtr vm = NULL;
+    char *name = NULL;
+    int ret = -1;
+
+    virCheckFlags(0, -1);
+
+    libxlDriverLock(driver);
+    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
+    if (!vm) {
+        char uuidstr[VIR_UUID_STRING_BUFLEN];
+        virUUIDFormat(dom->uuid, uuidstr);
+        libxlError(VIR_ERR_NO_DOMAIN,
+                   _("No domain with matching uuid '%s'"), uuidstr);
+        goto cleanup;
+    }
+
+    if (!virDomainObjIsActive(vm)) {
+        libxlError(VIR_ERR_OPERATION_INVALID, "%s", _("Domain is not running"));
+        goto cleanup;
+    }
+
+    name = libxlDomainManagedSavePath(driver, vm);
+    if (name == NULL)
+        goto cleanup;
+
+    VIR_INFO("Saving state to %s", name);
+
+    ret = libxlDoDomainSave(driver, vm, name);
+
+cleanup:
+    if (vm)
+        virDomainObjUnlock(vm);
+    libxlDriverUnlock(driver);
+    VIR_FREE(name);
+    return ret;
+}
+
+static int
+libxlDomainHasManagedSaveImage(virDomainPtr dom, unsigned int flags)
+{
+    libxlDriverPrivatePtr driver = dom->conn->privateData;
+    virDomainObjPtr vm = NULL;
+    int ret = -1;
+    char *name = NULL;
+
+    virCheckFlags(0, -1);
+
+    libxlDriverLock(driver);
+    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
+    if (!vm) {
+        char uuidstr[VIR_UUID_STRING_BUFLEN];
+        virUUIDFormat(dom->uuid, uuidstr);
+        libxlError(VIR_ERR_NO_DOMAIN,
+                   _("No domain with matching uuid '%s'"), uuidstr);
+        goto cleanup;
+    }
+
+    name = libxlDomainManagedSavePath(driver, vm);
+    if (name == NULL)
+        goto cleanup;
+
+    ret = virFileExists(name);
+
+cleanup:
+    VIR_FREE(name);
+    if (vm)
+        virDomainObjUnlock(vm);
+    libxlDriverUnlock(driver);
+    return ret;
+}
+
+static int
+libxlDomainManagedSaveRemove(virDomainPtr dom, unsigned int flags)
+{
+    libxlDriverPrivatePtr driver = dom->conn->privateData;
+    virDomainObjPtr vm = NULL;
+    int ret = -1;
+    char *name = NULL;
+
+    virCheckFlags(0, -1);
+
+    libxlDriverLock(driver);
+    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
+    if (!vm) {
+        char uuidstr[VIR_UUID_STRING_BUFLEN];
+        virUUIDFormat(dom->uuid, uuidstr);
+        libxlError(VIR_ERR_NO_DOMAIN,
+                   _("No domain with matching uuid '%s'"), uuidstr);
+        goto cleanup;
+    }
+
+    name = libxlDomainManagedSavePath(driver, vm);
+    if (name == NULL)
+        goto cleanup;
+
+    ret = unlink(name);
+
+cleanup:
+    VIR_FREE(name);
+    if (vm)
+        virDomainObjUnlock(vm);
+    libxlDriverUnlock(driver);
+    return ret;
+}
+
+static int
 libxlDomainSetVcpusFlags(virDomainPtr dom, unsigned int nvcpus,
                          unsigned int flags)
 {
@@ -3634,6 +3830,9 @@ static virDriver libxlDriver = {
     .nodeGetFreeMemory = libxlNodeGetFreeMemory, /* 0.9.0 */
     .domainEventRegister = libxlDomainEventRegister, /* 0.9.0 */
     .domainEventDeregister = libxlDomainEventDeregister, /* 0.9.0 */
+    .domainManagedSave = libxlDomainManagedSave, /* 0.9.3 */
+    .domainHasManagedSaveImage = libxlDomainHasManagedSaveImage, /* 0.9.3 */
+    .domainManagedSaveRemove = libxlDomainManagedSaveRemove, /* 0.9.3 */
     .domainIsActive = libxlDomainIsActive, /* 0.9.0 */
     .domainIsPersistent = libxlDomainIsPersistent, /* 0.9.0 */
     .domainIsUpdated = libxlDomainIsUpdated, /* 0.9.0 */
-- 
1.7.5.2




More information about the libvir-list mailing list