[libvirt PATCH 26/30] qemu_snapshot: when deleting snapshot invalidate parent snapshot

Peter Krempa pkrempa at redhat.com
Tue Dec 13 16:22:08 UTC 2022


On Thu, Dec 08, 2022 at 14:31:02 +0100, Pavel Hrdina wrote:
> When deleting external snapshots the operation may fail at any point
> which could lead to situation that some disks finished the block commit
> operation but for some disks it failed and the libvirt job ends.
> 
> In order to make sure that the qcow2 images are in consistent state
> introduce new element "<invalid/>" that will mark the disk in snapshot
> metadata as invalid until the snapshot delete is completed successfully.
> 
> This will prevent deleting snapshot with the invalid disk and in future
> reverting to snapshot with the invalid disk.
> 
> Signed-off-by: Pavel Hrdina <phrdina at redhat.com>
> ---
>  src/conf/snapshot_conf.c |  6 ++++
>  src/conf/snapshot_conf.h |  1 +
>  src/qemu/qemu_snapshot.c | 59 ++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 66 insertions(+)
> 
> diff --git a/src/conf/snapshot_conf.c b/src/conf/snapshot_conf.c
> index 4b5b908d66..7517208d79 100644
> --- a/src/conf/snapshot_conf.c
> +++ b/src/conf/snapshot_conf.c
> @@ -158,6 +158,9 @@ virDomainSnapshotDiskDefParseXML(xmlNodePtr node,
>          return -1;
>      }
>  
> +    if (flags & VIR_DOMAIN_DEF_PARSE_STATUS)

You want VIR_DOMAIN_SNAPSHOT_PARSE_REDEFINE as this parser doesn't
work with VIR_DOMAIN_DEF_PARSE_* flags.

In fact the only reason this works is that VIR_DOMAIN_DEF_PARSE_STATUS
and VIR_DOMAIN_SNAPSHOT_PARSE_REDEFINE have the same value.

> +        def->invalid = !!virXPathNode("./invalid", ctxt);

Based on my coment below ... the 'invalid' name of this flag might be a
bit misleading. I suppose we want to say that there's another operation
in progress, but I don't have currently ideas for a better name.

> +
>      if ((cur = virXPathNode("./source", ctxt)) &&
>          virDomainStorageSourceParse(cur, ctxt, src, flags, xmlopt) < 0)
>          return -1;

[...]

> diff --git a/src/qemu/qemu_snapshot.c b/src/qemu/qemu_snapshot.c
> index 3fbc3ce65f..253de1196b 100644
> --- a/src/qemu/qemu_snapshot.c
> +++ b/src/qemu/qemu_snapshot.c
> @@ -2302,6 +2302,12 @@ qemuSnapshotDeleteExternalPrepare(virDomainObj *vm,
>          if (snapDisk->snapshot == VIR_DOMAIN_SNAPSHOT_LOCATION_NO)
>              continue;
>  
> +        if (snapDisk->invalid) {
> +            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
> +                           _("snapshot is in invalid state"));

This error is not really actionable. You want to explain that it's most
likely a previous operation that failed and needs to be re-tried.

> +            return NULL;
> +        }
> +
>          data = g_new0(qemuSnapshotDeleteExternalData, 1);
>          data->snapDisk = snapDisk;
>  
> @@ -2620,6 +2626,53 @@ qemuSnapshotJobFinishing(virDomainObj *vm,
>  }
>  
>  
> +/**
> + * qemuSnapshotSetInvalid:
> + * @vm: vm object
> + * @snap: snapshot object that contains parent disk
> + * @disk: disk from the snapshot we are deleting
> + * @invalid: boolean to set/unset invalid state
> + *
> + * @snap should point to a ancestor snapshot from the snapshot tree that
> + * affected the @disk which doesn't have to be the direct parent.
> + *
> + * When setting snapshot with parent disk as invalid due to snapshot being
> + * deleted we should not mark the whole snapshot as invalid but only the
> + * affected disks because the snapshot can contain other disks that we are
> + * not modifying at the moment.
> + *
> + * Return 0 on success, -1 on error.
> + * */
> +static int
> +qemuSnapshotSetInvalid(virDomainObj *vm,
> +                       virDomainMomentObj *snap,
> +                       virDomainSnapshotDiskDef *disk,
> +                       bool invalid)
> +{
> +    ssize_t i;
> +    qemuDomainObjPrivate *priv = vm->privateData;
> +    virQEMUDriver *driver = priv->driver;
> +    g_autoptr(virQEMUDriverConfig) cfg = virQEMUDriverGetConfig(driver);
> +    virDomainSnapshotDef *snapdef = NULL;
> +
> +    if (!snap)
> +        return 0;
> +
> +    snapdef = virDomainSnapshotObjGetDef(snap);
> +    if (!snapdef)
> +        return 0;
> +
> +    for (i = 0; i < snapdef->ndisks; i++) {
> +        virDomainSnapshotDiskDef *snapDisk = &(snapdef->disks[i]);
> +
> +        if (STREQ(snapDisk->name, disk->name))
> +            snapDisk->invalid = invalid;
> +    }

I think you also want to mark the inactiveDef if present.

> +
> +    return qemuDomainSnapshotWriteMetadata(vm, snap, driver->xmlopt, cfg->snapshotDir);
> +}


More information about the libvir-list mailing list