[libvirt] [PATCH 8/9] qemu: Add -blockdev support for block pull job

Peter Krempa pkrempa at redhat.com
Mon Jul 29 08:40:14 UTC 2019


On Fri, Jul 26, 2019 at 14:12:57 +0200, Ján Tomko wrote:
> On Wed, Jul 24, 2019 at 11:07:35PM +0200, Peter Krempa wrote:
> > Introduce the handler for finalizing a block pull job which will allow
> > to use it with blockdev.
> > 
> > This patch also contains some additional machinery which is required to
> > store all the relevant job data in the status XML which will also be
> > reused with other block job types.
> > 
> > Signed-off-by: Peter Krempa <pkrempa at redhat.com>
> > ---
> > src/qemu/qemu_blockjob.c                      | 191 +++++++++++++++++-
> > src/qemu/qemu_blockjob.h                      |  18 ++
> > src/qemu/qemu_domain.c                        |  77 +++++++
> > src/qemu/qemu_driver.c                        |  33 ++-
> > .../blockjob-blockdev-in.xml                  |   4 +
> > 5 files changed, 313 insertions(+), 10 deletions(-)
> > 
> > diff --git a/src/qemu/qemu_blockjob.c b/src/qemu/qemu_blockjob.c
> > index 0c0ae89f10..a29af7ec48 100644
> > --- a/src/qemu/qemu_blockjob.c
> > +++ b/src/qemu/qemu_blockjob.c
> > +/**
> > + * qemuBlockJobProcessEventCompletedPull:
> > + * @driver: qemu driver object
> > + * @vm: domain object
> > + * @job: job data
> > + * @asyncJob: qemu asynchronous job type (for monitor interaction)
> > + *
> > + * This function executes the finalizing steps after a successful block pull job
> > + * (block-stream in qemu terminology. The pull job copies all the data from the
> > + * images in the backing chain up to the 'base' image. The 'base' image becomes
> > + * the backing store of the active top level image. If 'base' was not used
> > + * everything is pulled into the top level image and the top level image will
> > + * cease to have backing store. All intermediate images between the active image
> > + * and base image are no longer required and can be unplugged.
> > + */
> > +static void
> > +qemuBlockJobProcessEventCompletedPull(virQEMUDriverPtr driver,
> > +                                      virDomainObjPtr vm,
> > +                                      qemuBlockJobDataPtr job,
> > +                                      qemuDomainAsyncJob asyncJob)
> > +{
> > +    virStorageSourcePtr baseparent = NULL;
> > +    virDomainDiskDefPtr cfgdisk = NULL;
> > +    virStorageSourcePtr cfgbase = NULL;
> > +    virStorageSourcePtr cfgbaseparent = NULL;
> > +    virStorageSourcePtr n;
> > +    virStorageSourcePtr tmp;
> > +
> > +    VIR_DEBUG("pull job '%s' on VM '%s' completed", job->name, vm->def->name);
> > +
> > +    /* if the job isn't associated with a disk there's nothing to do */
> > +    if (!job->disk)
> > +        return;
> > +
> > +    if ((cfgdisk = qemuBlockJobGetConfigDisk(vm, job->disk, job->data.pull.base)))
> > +        cfgbase = cfgdisk->src->backingStore;
> > +
> 
> Consider:
>      cfgdisk = ...();
>      if (cfgdisk)
>          cfgbase = ...;
>      else
>          ...();

There is no 'else' so this format does not make much sense.

> 
> > +    if (!cfgdisk)
> > +        qemuBlockJobClearConfigChain(vm, job->disk);
> > +
> > +    /* when pulling if 'base' is right below the top image we don't have to modify it */
> > +    if (job->disk->src->backingStore == job->data.pull.base)
> > +        return;
> > +
> > +    if (job->data.pull.base) {
> > +        for (n = job->disk->src->backingStore; n && n != job->data.pull.base; n = n->backingStore) {
> > +            /* find the image on top of 'base' */
> > +
> > +            if (cfgbase) {
> > +                cfgbaseparent = cfgbase;
> > +                cfgbase = cfgbase->backingStore;
> > +            }
> > +
> > +            baseparent = n;
> > +        }
> > +    }
> > +
> > +    tmp = job->disk->src->backingStore;
> > +    job->disk->src->backingStore = job->data.pull.base;
> > +    if (baseparent)
> > +        baseparent->backingStore = NULL;
> > +    qemuBlockJobEventProcessConcludedRemoveChain(driver, vm, asyncJob, tmp);
> > +    virObjectUnref(tmp);
> > +
> > +    if (cfgdisk) {
> > +        tmp = cfgdisk->src->backingStore;
> 
> You can unref tmp directly here

No I can't. 'cfgbaseparent' is in the chain of images below now 'tmp'
and thus the undef would unref everything ...

> 
> > +        cfgdisk->src->backingStore = cfgbase;
> > +        if (cfgbaseparent)
> > +            cfgbaseparent->backingStore = NULL;

... this inhibits deletion of the part of the chain we still want.

> > +        virObjectUnref(tmp);
> > +    }
> > +}

[...]

> > diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c
> > index c508f55287..ec1dda4870 100644
> > --- a/src/qemu/qemu_domain.c
> > +++ b/src/qemu/qemu_domain.c
> > @@ -2390,6 +2390,21 @@ qemuDomainObjPrivateXMLFormatBlockjobIterator(void *payload,
> >             return -1;
> >     }
> > 
> > +    switch ((qemuBlockJobType) job->type) {
> > +        case QEMU_BLOCKJOB_TYPE_PULL:
> > +            if (job->data.pull.base)
> > +                virBufferAsprintf(&childBuf, "<base node='%s'/>\n", job->data.pull.base->nodeformat);
> > +            break;
> > +
> > +        case QEMU_BLOCKJOB_TYPE_COMMIT:
> > +        case QEMU_BLOCKJOB_TYPE_ACTIVE_COMMIT:
> > +        case QEMU_BLOCKJOB_TYPE_COPY:
> > +        case QEMU_BLOCKJOB_TYPE_NONE:
> > +        case QEMU_BLOCKJOB_TYPE_INTERNAL:
> > +        case QEMU_BLOCKJOB_TYPE_LAST:
> > +            break;
> > +    }
> > +
> >     return virXMLFormatElement(data->buf, "blockjob", &attrBuf, &childBuf);
> > }
> > 
> > @@ -2793,6 +2808,64 @@ qemuDomainObjPrivateXMLParseBlockjobChain(xmlNodePtr node,
> > }
> > 
> > 
> > +static void
> > +qemuDomainObjPrivateXMLParseBlockjobNodename(qemuBlockJobDataPtr job,
> > +                                             const char *xpath,
> > +                                             virStorageSourcePtr *src,
> > +                                             xmlXPathContextPtr ctxt)
> > +{
> > +    VIR_AUTOFREE(char *) nodename = NULL;
> > +
> > +    *src = NULL;
> > +
> > +    if (!(nodename = virXPathString(xpath, ctxt)))
> > +        return;
> > +
> > +    if (job->disk &&
> > +        (*src = virStorageSourceFindByNodeName(job->disk->src, nodename, NULL)))
> > +        return;
> > +
> > +    if (job->chain &&
> > +        (*src = virStorageSourceFindByNodeName(job->chain, nodename, NULL)))
> > +        return;
> > +
> > +    if (job->mirrorChain &&
> > +        (*src = virStorageSourceFindByNodeName(job->mirrorChain, nodename, NULL)))
> > +        return;
> > +
> > +    /* the node was in the XML but was not found in the job definitions */
> > +    VIR_DEBUG("marking block job '%s' as invalid: node name '%s' missing",
> > +              job->name, nodename);
> > +    job->invalidData = true;
> > +}
> > +
> > +
> > +static void
> > +qemuDomainObjPrivateXMLParseBlockjobDataSpecific(qemuBlockJobDataPtr job,
> > +                                                 xmlXPathContextPtr ctxt)
> > +{
> > +    switch ((qemuBlockJobType) job->type) {
> > +        case QEMU_BLOCKJOB_TYPE_PULL:
> > +            qemuDomainObjPrivateXMLParseBlockjobNodename(job,
> > +                                                         "string(./base/@node)",
> > +                                                         &job->data.pull.base,
> > +                                                         ctxt);
> > +            /* base is not present if pulling everything */
> > +            break;
> > +
> > +        case QEMU_BLOCKJOB_TYPE_COMMIT:
> > +        case QEMU_BLOCKJOB_TYPE_ACTIVE_COMMIT:
> > +        case QEMU_BLOCKJOB_TYPE_COPY:
> > +        case QEMU_BLOCKJOB_TYPE_NONE:
> > +        case QEMU_BLOCKJOB_TYPE_INTERNAL:
> 
> > +        case QEMU_BLOCKJOB_TYPE_LAST:
> 
> virReportEnumRangeError

In a void function?

> 
> > +            break;
> > +    }
> > +
> > +    return;
> > +}
> > +
> > +
> > static int
> > qemuDomainObjPrivateXMLParseBlockjobData(virDomainObjPtr vm,
> >                                          xmlNodePtr node,
> > @@ -2863,10 +2936,14 @@ qemuDomainObjPrivateXMLParseBlockjobData(virDomainObjPtr vm,
> >     job->errmsg = virXPathString("string(./errmsg)", ctxt);
> >     job->invalidData = invalidData;
> >     job->disk = disk;
> > +    if (invalidData)
> > +        VIR_DEBUG("marking block job '%s' as invalid: basic data broken", job->name);
> > 
> 
> This hunk belongs to a separate patch.
> 
> >     if (mirror)
> >         qemuBlockJobDiskRegisterMirror(job);
> > 
> > +    qemuDomainObjPrivateXMLParseBlockjobDataSpecific(job, ctxt);
> > +
> 
> Possibly this one too.

Well I'd have to introduce a function which doesn't do anything here and
then populate it later? Should I do it?

> 
> >     if (qemuBlockJobRegister(job, vm, disk, false) < 0)
> >         return -1;
> > 
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 833 bytes
Desc: not available
URL: <http://listman.redhat.com/archives/libvir-list/attachments/20190729/90e19687/attachment-0001.sig>


More information about the libvir-list mailing list