On Tue, Jun 18, 2019 at 22:47:53 -0500, Eric Blake wrote:
> Time to actually issue the QMP transactions that create and
> delete persistent checkpoints.  For create, we only need one
> transaction: inside, we visit all disks affected by the
> checkpoint, and create a new enabled bitmap, as well as
> disabling the bitmap of the parent checkpoint (if any).  For
> deletion, we need multiple calls: if the checkpoint to be
> deleted is active, we must enable the parent; then we must
> merge the existing checkpoint into the parent, and finally
> we can delete the checkpoint.

At this point I'm lacking the interlocking with snapshots. It may be
posted as a separate patch, but none of this code should go in unless
that one is ACK'd.

> 
> Signed-off-by: Eric Blake <ebl...@redhat.com>
> ---
>  src/qemu/qemu_domain.c | 105 ++++++++++++++++++++++++++++++-----------
>  src/qemu/qemu_driver.c |  92 ++++++++++++++++++++++++++++++++++--
>  2 files changed, 165 insertions(+), 32 deletions(-)
> 
> diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c
> index e128dc169b..1364227e42 100644
> --- a/src/qemu/qemu_domain.c
> +++ b/src/qemu/qemu_domain.c
> @@ -8809,45 +8809,93 @@ qemuDomainCheckpointDiscard(virQEMUDriverPtr driver,
>      char *chkFile = NULL;
>      int ret = -1;
>      virDomainMomentObjPtr parentchk = NULL;
> +    virDomainCheckpointDefPtr parentdef = NULL;
>      virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
> +    size_t i, j;
> +    virJSONValuePtr arr = NULL;
> 
> -    if (!metadata_only) {
> -        if (!virDomainObjIsActive(vm)) {
> -            virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
> -                           _("cannot remove checkpoint from inactive 
> domain"));
> -            goto cleanup;
> -        } else {
> -            /* TODO: Implement QMP sequence to merge bitmaps */
> -            // qemuDomainObjPrivatePtr priv;
> -            // priv = vm->privateData;
> -            // qemuDomainObjEnterMonitor(driver, vm);
> -            // /* we continue on even in the face of error */
> -            // qemuMonitorDeleteCheckpoint(priv->mon, chk->def->name);
> -            // ignore_value(qemuDomainObjExitMonitor(driver, vm));
> -        }
> +    if (!metadata_only && !virDomainObjIsActive(vm)) {
> +        virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
> +                       _("cannot remove checkpoint from inactive domain"));
> +        goto cleanup;
>      }
> 
>      if (virAsprintf(&chkFile, "%s/%s/%s.xml", cfg->checkpointDir,
>                      vm->def->name, chk->def->name) < 0)
>          goto cleanup;
> 
> +    if (chk->def->parent_name) {
> +        parentchk = virDomainCheckpointFindByName(vm->checkpoints,
> +                                                  chk->def->parent_name);
> +        if (!parentchk) {
> +            VIR_WARN("missing parent checkpoint matching name '%s'",
> +                     chk->def->parent_name);
> +        }
> +        parentdef = virDomainCheckpointObjGetDef(parentchk);
> +    }
> +
> +    if (!metadata_only) {
> +        qemuDomainObjPrivatePtr priv = vm->privateData;
> +        bool success = true;
> +        virDomainCheckpointDefPtr chkdef = virDomainCheckpointObjGetDef(chk);
> +
> +        if (qemuBlockNodeNamesDetect(driver, vm, QEMU_ASYNC_JOB_NONE) < 0)
> +            goto cleanup;

I was complaining about this in the previous version.

> +        qemuDomainObjEnterMonitor(driver, vm);
> +        for (i = 0; i < chkdef->ndisks; i++) {
> +            virDomainCheckpointDiskDef *disk = &chkdef->disks[i];
> +            const char *node;
> +
> +            if (disk->type != VIR_DOMAIN_CHECKPOINT_TYPE_BITMAP)
> +                continue;
> +
> +            node = qemuBlockNodeLookup(vm, disk->name);
> +            if (parentchk) {
> +                arr = virJSONValueNewArray();
> +                if (!arr ||
> +                    virJSONValueArrayAppendString(arr, disk->bitmap) < 0) {
> +                    success = false;
> +                    break;
> +                }
> +
> +                for (j = 0; j < parentdef->ndisks; j++) {
> +                    virDomainCheckpointDiskDef *disk2;
> +
> +                    disk2 = &parentdef->disks[j];
> +                    if (STRNEQ(disk->name, disk2->name))
> +                        continue;
> +                    if (chk == 
> virDomainCheckpointGetCurrent(vm->checkpoints) &&
> +                        qemuMonitorEnableBitmap(priv->mon, node,
> +                                                disk2->bitmap) < 0) {
> +                        success = false;
> +                        break;
> +                    }
> +                    if (qemuMonitorMergeBitmaps(priv->mon, node,
> +                                                disk2->bitmap, &arr) < 0) {

We definitely need interlocking as this will not work across the backing
chain as it seems to reference the 'node'

> +                        success = false;
> +                        break;
> +                    }
> +                }
> +            }
> +            if (qemuMonitorDeleteBitmap(priv->mon, node, disk->bitmap) < 0) {
> +                success = false;
> +                break;
> +            }
> +        }
> +        if (qemuDomainObjExitMonitor(driver, vm) < 0 || !success)
> +            goto cleanup;
> +    }
> +
>      if (chk == virDomainCheckpointGetCurrent(vm->checkpoints)) {
>          virDomainCheckpointSetCurrent(vm->checkpoints, NULL);
> -        if (update_parent && chk->def->parent_name) {
> -            parentchk = virDomainCheckpointFindByName(vm->checkpoints,
> -                                                      chk->def->parent_name);
> -            if (!parentchk) {
> -                VIR_WARN("missing parent checkpoint matching name '%s'",
> +        if (update_parent && parentchk) {
> +            virDomainCheckpointSetCurrent(vm->checkpoints, parentchk);
> +            if (qemuDomainCheckpointWriteMetadata(vm, parentchk, 
> driver->caps,
> +                                                  driver->xmlopt,
> +                                                  cfg->checkpointDir) < 0) {
> +                VIR_WARN("failed to set parent checkpoint '%s' as current",
>                           chk->def->parent_name);
> -            } else {
> -                virDomainCheckpointSetCurrent(vm->checkpoints, parentchk);
> -                if (qemuDomainCheckpointWriteMetadata(vm, parentchk, 
> driver->caps,
> -                                                      driver->xmlopt,
> -                                                      cfg->checkpointDir) < 
> 0) {
> -                    VIR_WARN("failed to set parent checkpoint '%s' as 
> current",
> -                             chk->def->parent_name);
> -                    virDomainCheckpointSetCurrent(vm->checkpoints, NULL);
> -                }
> +                virDomainCheckpointSetCurrent(vm->checkpoints, NULL);
>              }
>          }
>      }

[...]

> diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
> index 5fa319b656..0cdb2dd1e2 100644
> --- a/src/qemu/qemu_driver.c
> +++ b/src/qemu/qemu_driver.c

[...]

> @@ -17016,6 +17017,53 @@ qemuDomainCheckpointPrepare(virQEMUDriverPtr driver, 
> virCapsPtr caps,
>      return ret;
>  }
> 
> +static int
> +qemuDomainCheckpointAddActions(virDomainObjPtr vm,
> +                               virJSONValuePtr actions,
> +                               virDomainMomentObjPtr old_current,
> +                               virDomainCheckpointDefPtr def)
> +{
> +    size_t i, j;
> +    int ret = -1;
> +    virDomainCheckpointDefPtr olddef;
> +
> +    olddef = virDomainCheckpointObjGetDef(old_current);
> +    for (i = 0; i < def->ndisks; i++) {
> +        virDomainCheckpointDiskDef *disk = &def->disks[i];
> +        const char *node;
> +
> +        if (disk->type != VIR_DOMAIN_CHECKPOINT_TYPE_BITMAP)
> +            continue;
> +        node = qemuBlockNodeLookup(vm, disk->name);
> +        if (qemuMonitorJSONTransactionAdd(actions,
> +                                          "block-dirty-bitmap-add",
> +                                          "s:node", node,
> +                                          "s:name", disk->bitmap,
> +                                          "b:persistent", true,
> +                                          NULL) < 0)
> +            goto cleanup;
> +        if (old_current) {
> +            for (j = 0; j < olddef->ndisks; j++) {
> +                virDomainCheckpointDiskDef *disk2;
> +
> +                disk2 = &olddef->disks[j];
> +                if (STRNEQ(disk->name, disk2->name))
> +                    continue;
> +                if (disk2->type == VIR_DOMAIN_CHECKPOINT_TYPE_BITMAP &&
> +                    qemuMonitorJSONTransactionAdd(actions,
> +                                                  
> "block-dirty-bitmap-disable",
> +                                                  "s:node", node,
> +                                                  "s:name", disk2->bitmap,
> +                                                  NULL) < 0)
> +                    goto cleanup;

optimization:
    break;


> +            }
> +        }
> +    }
> +    ret = 0;
> +
> + cleanup:

pointless label

> +    return ret;
> +}
> 
>  static virDomainCheckpointPtr
>  qemuDomainCheckpointCreateXML(virDomainPtr domain,

[...]

> @@ -17094,10 +17152,10 @@ qemuDomainCheckpointCreateXML(virDomainPtr domain,
>          def = NULL;
>      }
> 
> -    current = virDomainCheckpointGetCurrent(vm->checkpoints);
> -    if (current) {
> +    other = virDomainCheckpointGetCurrent(vm->checkpoints);
> +    if (other) {
>          if (!redefine &&
> -            VIR_STRDUP(chk->def->parent_name, current->def->name) < 0)
> +            VIR_STRDUP(chk->def->parent_name, other->def->name) < 0)

Looks like it's refactoring code from previous patch.

>              goto endjob;
>          if (update_current) {
>              virDomainCheckpointSetCurrent(vm->checkpoints, NULL);

[...]

Attachment: signature.asc
Description: PGP signature

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list

Reply via email to