[libvirt] [PATCH] [3/4] Implement managed save operations for qemu driver

Eric Blake eblake at redhat.com
Fri Apr 2 20:26:10 UTC 2010


On 04/02/2010 01:56 PM, Daniel Veillard wrote:
> +++ b/src/qemu/qemu_driver.c
> @@ -1399,6 +1399,9 @@ qemudStartup(int privileged) {
>          if (virAsprintf(&qemu_driver->cacheDir,
>                        "%s/cache/libvirt/qemu", LOCAL_STATE_DIR) == -1)
>              goto out_of_memory;
> +        if (virAsprintf(&qemu_driver->saveDir,
> +                      "%s/lib/libvirt/qemu/save/", LOCAL_STATE_DIR) == -1)
> +            goto out_of_memory;

Would it be more efficient to write a followup patch that does:

if ((qemu_driver->savedir
    = strdup(LOCAL_STATE_DIR "/lib/libvirt/qemu/save/") == NULL)
    goto out_of_memory;

on the grounds that compile-time concatenation and strdup are much
lighter-weight than run-time concatenation of virAsprintf?

But that doesn't affect the quality of your patch.

>      } else {
>          uid_t uid = geteuid();
>          char *userdir = virGetUserDirectory(uid);
> @@ -1423,6 +1426,8 @@ qemudStartup(int privileged) {
>              goto out_of_memory;
>          if (virAsprintf(&qemu_driver->cacheDir, "%s/qemu/cache", base) == -1)
>              goto out_of_memory;
> +        if (virAsprintf(&qemu_driver->saveDir, "%s/qemu/save", base) == -1)
> +            goto out_of_memory;

And constructs like this still need virAsprintf.

> -static int qemudDomainSave(virDomainPtr dom,
> -                           const char *path)
> +static int qemudDomainSaveFlag(virDomainPtr dom, const char *path,
> +                               int compressed)

Should that be bool compressed, since we are only using it as a binary?
 Or are there plans to extend it in the future to allow choice between
multiple acceptable compression algorithms, in which case it is better
as an unsigned int?

> +static int qemudDomainSave(virDomainPtr dom, const char *path)
> +{
> +    struct qemud_driver *driver = dom->conn->privateData;
> +    int compressed;
> +
> +    /* Hm, is this safe against qemudReload? */
> +    if (driver->saveImageFormat == NULL)
> +        compressed = QEMUD_SAVE_FORMAT_RAW;
> +    else {
> +        compressed = qemudSaveCompressionTypeFromString(driver->saveImageFormat);
> +        if (compressed < 0) {
> +            qemuReportError(VIR_ERR_OPERATION_FAILED,
> +                            "%s", _("Invalid save image format specified "
> +                                    "in configuration file"));
> +            return -1;
> +        }
> +    }
> +
> +    return qemudDomainSaveFlag(dom, path, compressed);

If you convert the type of the last argument of qemudDomanSaveFlag, then
here is where you'd convert from int (qemudSaveCompressionTypeFromString
must remain int, to detect failure) to bool.

> +static int
> +qemuDomainManagedSave(virDomainPtr dom,
> +                      unsigned int flags ATTRIBUTE_UNUSED)

No - for future compability, we NEED to check that flags==0 or fail now.
 Otherwise, a future version, where flags has meaning, will mistakenly
think that our older version can honor those flags.

> +{
> +    struct qemud_driver *driver = dom->conn->privateData;
> +    virDomainObjPtr vm = NULL;
> +    char *name = NULL;
> +    int ret = -1;
> +    int compressed;
> +
> +    qemuDriverLock(driver);
> +    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
> +    if (!vm) {
> +        char uuidstr[VIR_UUID_STRING_BUFLEN];
> +        virUUIDFormat(dom->uuid, uuidstr);
> +        qemuReportError(VIR_ERR_NO_DOMAIN,
> +                        _("no domain with matching uuid '%s'"), uuidstr);
> +        goto error;
> +    }
> +
> +    if (!virDomainObjIsActive(vm)) {
> +        qemuReportError(VIR_ERR_OPERATION_INVALID,
> +                        "%s", _("domain is not running"));
> +        goto error;
> +    }
> +
> +    name = qemuDomainManagedSavePath(driver, vm);
> +    if (name == NULL)
> +        goto error;
> +
> +    VIR_DEBUG("Saving state to %s", name);
> +
> +    /* FIXME: we should take the flags parameter, and use bits out
> +     * of there to control whether we are compressing or not
> +     */
> +    compressed = QEMUD_SAVE_FORMAT_RAW;
> +
> +    /* we have to drop our locks here because qemudDomainSaveFlag is
> +     * going to pick them back up.  Unfortunately it opens a race window
> +     * between us dropping and qemudDomainSaveFlag picking it back up, but
> +     * if we want to allow other operations to be able to happen while
> +     * qemuDomainSaveFlag is running (possibly for a long time), I'm not
> +     * sure if there is a better solution
> +     */

Is there a way to tell qemudDomainSaveFlag that we called it while the
lock was already held (that is, consume one of the bits of the flag
argument that we pass to qemudDomainSaveFlag for internal use)?  That
way, we don't have to drop the lock here, but let qemudDomainSaveFlag
drop it on our behalf.

> +    virDomainObjUnlock(vm);
> +    qemuDriverUnlock(driver);
> +
> +    ret = qemudDomainSaveFlag(dom, name, compressed);
> +
> +cleanup:
> +    VIR_FREE(name);
> +
> +    return ret;
> +
> +error:
> +    if (vm)
> +        virDomainObjUnlock(vm);
> +    qemuDriverUnlock(driver);
> +    goto cleanup;
> +}
> +
> +static int
> +qemuDomainHasManagedSaveImage(virDomainPtr dom,
> +                              unsigned int flags ATTRIBUTE_UNUSED)

Again, we MUST ensure flags==0 now, to allow future compatibility.

> +{
> +    struct qemud_driver *driver = dom->conn->privateData;
> +    virDomainObjPtr vm = NULL;
> +    int ret = -1;
> +    char *name = NULL;
> +
> +    qemuDriverLock(driver);
> +    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
> +    if (!vm) {
> +        char uuidstr[VIR_UUID_STRING_BUFLEN];
> +        virUUIDFormat(dom->uuid, uuidstr);
> +        qemuReportError(VIR_ERR_NO_DOMAIN,
> +                        _("no domain with matching uuid '%s'"), uuidstr);
> +        goto cleanup;
> +    }
> +
> +    name = qemuDomainManagedSavePath(driver, vm);
> +    if (name == NULL)
> +        goto cleanup;
> +
> +    ret = virFileExists(name);
> +
> +cleanup:
> +    VIR_FREE(name);
> +    if (vm)
> +        virDomainObjUnlock(vm);
> +    qemuDriverUnlock(driver);
> +    return ret;
> +}
> +
> +static int
> +qemuDomainManagedSaveRemove(virDomainPtr dom,
> +                            unsigned int flags ATTRIBUTE_UNUSED)

And again.

> +{
> +    struct qemud_driver *driver = dom->conn->privateData;
> +    virDomainObjPtr vm = NULL;
> +    int ret = -1;
> +    char *name = NULL;
> +
> +    qemuDriverLock(driver);
> +    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
> +    if (!vm) {
> +        char uuidstr[VIR_UUID_STRING_BUFLEN];
> +        virUUIDFormat(dom->uuid, uuidstr);
> +        qemuReportError(VIR_ERR_NO_DOMAIN,
> +                        _("no domain with matching uuid '%s'"), uuidstr);
> +        goto cleanup;
> +    }
> +
> +    name = qemuDomainManagedSavePath(driver, vm);
> +    if (name == NULL)
> +        goto cleanup;
> +
> +    ret = unlink(name);
> +
> +cleanup:
> +    VIR_FREE(name);
> +    if (vm)
> +        virDomainObjUnlock(vm);
> +    qemuDriverUnlock(driver);
> +    return ret;
> +}
>  
>  static int qemudDomainCoreDump(virDomainPtr dom,
>                                 const char *path,
> @@ -5979,6 +6146,7 @@ static int qemudDomainStart(virDomainPtr dom) {
>      virDomainObjPtr vm;
>      int ret = -1;
>      virDomainEventPtr event = NULL;
> +    char *managed_save = NULL;
>  
>      qemuDriverLock(driver);
>      vm = virDomainFindByUUID(&driver->domains, dom->uuid);
> @@ -6000,6 +6168,32 @@ static int qemudDomainStart(virDomainPtr dom) {
>          goto endjob;
>      }
>  
> +    /*
> +     * If there is a managed saved state restore it instead of starting
> +     * from scratch. In any case the old state is removed.
> +     */
> +    managed_save = qemuDomainManagedSavePath(driver, vm);
> +    if ((managed_save) && (virFileExists(managed_save))) {
> +        /* We should still have a reference left to vm but */

Incomplete comment?

> +        if (qemuDomainObjEndJob(vm) == 0)
> +            vm = NULL;
> +        virDomainObjUnlock(vm);
> +        qemuDriverUnlock(driver);
> +        ret = qemudDomainRestore(dom->conn, managed_save);
> +
> +        if (unlink(managed_save) < 0) {
> +            VIR_WARN("Failed to remove the managed state %s", managed_save);
> +        }
> +
> +        if (ret == 0) {
> +            /* qemudDomainRestore should have sent the Started/Restore event */
> +            VIR_FREE(managed_save);
> +            return(ret);
> +        }
> +        qemuDriverLock(driver);
> +        virDomainObjLock(vm);
> +    }
> +

Overall, it looks like it does what you claim, but I think there's still
some work needed before an ACK.

-- 
Eric Blake   eblake at redhat.com    +1-801-349-2682
Libvirt virtualization library http://libvirt.org

-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 323 bytes
Desc: OpenPGP digital signature
URL: <http://listman.redhat.com/archives/libvir-list/attachments/20100402/bc3a667e/attachment-0001.sig>


More information about the libvir-list mailing list