[libvirt RFC 22/24] qemu_snapshot: update metadata when deleting snapshots

Peter Krempa pkrempa at redhat.com
Wed Sep 7 13:06:51 UTC 2022


On Tue, Aug 23, 2022 at 18:32:25 +0200, Pavel Hrdina wrote:
> With external snapshots we need to modify the metadata bit more then
> what is required for internal snapshots. Mainly the storage source
> location changes with every external snapshot.
> 
> This means that if we delete non-leaf snapshot we need to update all
> children snapshots and modify the disk sources for all affected disks.
> 
> Signed-off-by: Pavel Hrdina <phrdina at redhat.com>
> ---
>  src/qemu/qemu_snapshot.c | 116 +++++++++++++++++++++++++++++++++++++++
>  1 file changed, 116 insertions(+)
> 
> diff --git a/src/qemu/qemu_snapshot.c b/src/qemu/qemu_snapshot.c
> index 64ee395230..37ae3f04d0 100644
> --- a/src/qemu/qemu_snapshot.c
> +++ b/src/qemu/qemu_snapshot.c
> @@ -2380,6 +2380,109 @@ qemuSnapshotChildrenReparent(void *payload,
>  }
>  
>  
> +typedef struct _qemuSnapshotUpdateDisksData qemuSnapshotUpdateDisksData;
> +struct _qemuSnapshotUpdateDisksData {
> +    virDomainMomentObj *snap;
> +    virDomainObj *vm;
> +    virQEMUDriver *driver;

'driver' is present in private data of 'vm'

> +    int error;
> +    int (*writeMetadata)(virDomainObj *, virDomainMomentObj *,
> +                         virDomainXMLOption *, const char *);

The only function pointer that is ever populated here is
qemuDomainSnapshotWriteMetadata. So you can use that directly from the
function that uses this.

> +};
> +
> +
> +static int
> +qemuSnapshotUpdateDisksSingle(virDomainMomentObj *snap,
> +                              virDomainDef *def,
> +                              virDomainDef *parentDef,
> +                              virDomainSnapshotDiskDef *snapDisk)
> +{
> +    virDomainDiskDef *disk = NULL;
> +
> +    if (!(disk = qemuDomainDiskByName(def, snapDisk->name)))
> +        return -1;
> +
> +    if (virDomainSnapshotIsExternal(snap)) {

So IIUC, this bit is done only for external snapshots ...

> +        virDomainDiskDef *parentDisk = NULL;
> +
> +        if (!(parentDisk = qemuDomainDiskByName(parentDef, snapDisk->name)))
> +            return -1;
> +
> +        if (virStorageSourceIsSameLocation(snapDisk->src, disk->src)) {
> +            virObjectUnref(disk->src);
> +            disk->src = virStorageSourceCopy(parentDisk->src, false);
> +        }
> +    }
> +
> +    if (disk->src->backingStore) {

... but this even for internal ones? That doesn't seem right.

> +        virStorageSource *cur = disk->src;
> +        virStorageSource *next = disk->src->backingStore;
> +
> +        while (next) {
> +            if (virStorageSourceIsSameLocation(snapDisk->src, next)) {
> +                cur->backingStore = next->backingStore;
> +                next->backingStore = NULL;
> +                virObjectUnref(next);
> +                break;
> +            }

So you are looking up the image corresponding to the snapshot disk and
trying to move it one level up, right?

> +
> +            cur = next;
> +            next = cur->backingStore;
> +        }
> +    }
> +
> +    return 0;
> +}
> +
> +
> +static int
> +qemuSnapshotDeleteUpdateDisks(void *payload,
> +                              const char *name G_GNUC_UNUSED,
> +                              void *opaque)
> +{
> +    virDomainMomentObj *snap = payload;
> +    qemuSnapshotUpdateDisksData *data = opaque;
> +    g_autoptr(virQEMUDriverConfig) cfg = virQEMUDriverGetConfig(data->driver);
> +    virDomainSnapshotDef *snapdef = virDomainSnapshotObjGetDef(data->snap);
> +    ssize_t i;
> +
> +    if (data->error < 0)
> +        return 0;

At this point I'm afraid we can't afford to deal with errors the usual
way but have to try to update as much metadata as possible.

If the first error breaks up everything then the state of the disk
images will not correspond to the metadata.

> +
> +    for (i = 0; i < snapdef->ndisks; i++) {
> +        virDomainSnapshotDiskDef *snapDisk = &(snapdef->disks[i]);
> +
> +        if (snapDisk->snapshot == VIR_DOMAIN_SNAPSHOT_LOCATION_NO)
> +            continue;
> +
> +        if (qemuSnapshotUpdateDisksSingle(snap, snap->def->dom,
> +                                          data->snap->def->dom, snapDisk) < 0) {
> +            data->error = -1;
> +            return 0;
> +        }
> +
> +        if (snap->def->inactiveDom) {
> +            virDomainDef *dom = data->snap->def->inactiveDom;
> +
> +            if (!dom)
> +                dom = data->snap->def->dom;
> +
> +            if (qemuSnapshotUpdateDisksSingle(snap, snap->def->inactiveDom,
> +                                              dom, snapDisk) < 0) {

The failure of qemuDomainDiskByName, in this case probably should not be
fatal, if the next-boot config diverges from the running config.


> +                data->error = -1;
> +                return 0;
> +            }
> +        }
> +    }
> +
> +    data->error = data->writeMetadata(data->vm,
> +                                      snap,
> +                                      data->driver->xmlopt,
> +                                      cfg->snapshotDir);
> +    return 0;
> +}


More information about the libvir-list mailing list