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

Jim Fehlig jfehlig at novell.com
Thu Jun 2 22:02:37 UTC 2011


Markus Groß wrote:
> ---
>  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);
> +        }
> +    }
> +
>   

On success of this function, managed_save and restore_fd will leak.

>      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);
>   

This would close a caller-provided fd.  I think it is better for callers
that have opened an fd to also close it.

I'll send a patch that addresses these minor issues.  Otherwise looks
good and no problems noted in my testing.

Regards,
Jim

>      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 */
>   




More information about the libvir-list mailing list