[libvirt] [PATCH 1/3] block rebase: add new API virDomainBlockRebase

Laine Stump laine at laine.org
Wed Feb 1 19:40:02 UTC 2012


On 02/01/2012 12:05 AM, Eric Blake wrote:
> Qemu is adding the ability to do a partial rebase.  That is, given:
>
> base<- intermediate<- current
>
> virDomainBlockPull will produce:
>
> current
>
> but qemu now has the ability to leave base in the chain, to produce:
>
> base<- current
>
> Note that current qemu can only do a forward merge, and only with
> the current image as the destination, which is fully described by
> this API without flags.  But in the future, it may be possible to
> enhance this API for additional scenarios by using flags:
>
> Merging the current image back into a previous image (that is,
> undoing a live snapshot), could be done by passing base as the
> destination and flags with a bit requesting a backward merge.
>
> Merging any other part of the image chain, whether forwards (the
> backing image contents are pulled into the newer file) or backwards
> (the deltas recorded in the newer file are merged back into the
> backing file), could also be done by passing a new flag that says
> that base should be treated as an XML snippet rather than an
> absolute path name, where the XML could then supply the additional
> instructions of which part of the image chain is being merged into
> any other part.
>
> * include/libvirt/libvirt.h.in (virDomainBlockRebase): New
> declaration.
> * src/libvirt.c (virDomainBlockRebase): Implement it.
> * src/libvirt_public.syms (LIBVIRT_0.9.10): Export it.
> * src/driver.h (virDrvDomainBlockRebase): New driver callback.
> * src/rpc/gendispatch.pl (long_legacy): Add exemption.
> * docs/apibuild.py (long_legacy_functions): Likewise.
> ---
>   docs/apibuild.py             |    1 +
>   include/libvirt/libvirt.h.in |    9 +++-
>   src/driver.h                 |    5 ++
>   src/libvirt.c                |   84 ++++++++++++++++++++++++++++++++++++++++++
>   src/libvirt_public.syms      |    1 +
>   src/rpc/gendispatch.pl       |    1 +
>   6 files changed, 99 insertions(+), 2 deletions(-)
>
> diff --git a/docs/apibuild.py b/docs/apibuild.py
> index c8b5994..1ac0281 100755
> --- a/docs/apibuild.py
> +++ b/docs/apibuild.py
> @@ -1649,6 +1649,7 @@ class CParser:
>           "virDomainSetMemoryFlags"        : (False, ("memory")),
>           "virDomainBlockJobSetSpeed"      : (False, ("bandwidth")),
>           "virDomainBlockPull"             : (False, ("bandwidth")),
> +        "virDomainBlockRebase"           : (False, ("bandwidth")),
>           "virDomainMigrateGetMaxSpeed"    : (False, ("bandwidth")) }
>
>       def checkLongLegacyFunction(self, name, return_type, signature):
> diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in
> index d9b9b95..40ad2f8 100644
> --- a/include/libvirt/libvirt.h.in
> +++ b/include/libvirt/libvirt.h.in
> @@ -1864,7 +1864,8 @@ int virDomainUpdateDeviceFlags(virDomainPtr domain,
>   /**
>    * virDomainBlockJobType:
>    *
> - * VIR_DOMAIN_BLOCK_JOB_TYPE_PULL: Block Pull (virDomainBlockPull)
> + * VIR_DOMAIN_BLOCK_JOB_TYPE_PULL: Block Pull (virDomainBlockPull or
> + * virDomainBlockRebase)
>    */
>   typedef enum {
>       VIR_DOMAIN_BLOCK_JOB_TYPE_UNKNOWN = 0,
> @@ -1903,6 +1904,9 @@ int    virDomainBlockJobSetSpeed(virDomainPtr dom, const char *disk,
>
>   int           virDomainBlockPull(virDomainPtr dom, const char *disk,
>                                    unsigned long bandwidth, unsigned int flags);
> +int           virDomainBlockRebase(virDomainPtr dom, const char *disk,
> +                                   const char *base, unsigned long bandwidth,
> +                                   unsigned int flags);
>
>
>   /* Block I/O throttling support */
> @@ -3502,7 +3506,8 @@ typedef void (*virConnectDomainEventGraphicsCallback)(virConnectPtr conn,
>   /**
>    * virConnectDomainEventBlockJobStatus:
>    *
> - * The final status of a virDomainBlockPullAll() operation
> + * The final status of a virDomainBlockPull() or virDomainBlockRebase()
> + * operation
>    */
>   typedef enum {
>       VIR_DOMAIN_BLOCK_JOB_COMPLETED = 0,
> diff --git a/src/driver.h b/src/driver.h
> index 2e2042e..79d845a 100644
> --- a/src/driver.h
> +++ b/src/driver.h
> @@ -780,6 +780,10 @@ typedef int
>   typedef int
>       (*virDrvDomainBlockPull)(virDomainPtr dom, const char *path,
>                                unsigned long bandwidth, unsigned int flags);
> +typedef int
> +    (*virDrvDomainBlockRebase)(virDomainPtr dom, const char *path,
> +                               const char *base, unsigned long bandwidth,
> +                               unsigned int flags);
>
>   typedef int
>       (*virDrvSetKeepAlive)(virConnectPtr conn,
> @@ -975,6 +979,7 @@ struct _virDriver {
>       virDrvDomainGetBlockJobInfo domainGetBlockJobInfo;
>       virDrvDomainBlockJobSetSpeed domainBlockJobSetSpeed;
>       virDrvDomainBlockPull domainBlockPull;
> +    virDrvDomainBlockRebase domainBlockRebase;
>       virDrvSetKeepAlive setKeepAlive;
>       virDrvConnectIsAlive isAlive;
>       virDrvNodeSuspendForDuration nodeSuspendForDuration;
> diff --git a/src/libvirt.c b/src/libvirt.c
> index c609202..65d460d 100644
> --- a/src/libvirt.c
> +++ b/src/libvirt.c
> @@ -17777,6 +17777,8 @@ error:
>    * suitable default.  Some hypervisors do not support this feature and will
>    * return an error if bandwidth is not 0.
>    *
> + * This is shorthand for virDomainBlockRebase() with a NULL base.
> + *
>    * Returns 0 if the operation has started, -1 on failure.
>    */
>   int virDomainBlockPull(virDomainPtr dom, const char *disk,
> @@ -17824,6 +17826,88 @@ error:
>
>
>   /**
> + * virDomainBlockRebase:
> + * @dom: pointer to domain object
> + * @disk: path to the block device, or device shorthand
> + * @base: path to backing file to keep, or NULL for no backing file
> + * @bandwidth: (optional) specify copy bandwidth limit in Mbps
> + * @flags: extra flags; not used yet, so callers should always pass 0
> + *
> + * Populate a disk image with data from its backing image chain, and
> + * setting the backing image to @base.  @base must be the absolute
> + * path of one of the backing images further up the chain, or NULL to
> + * convert the disk image so that it has no backing image.  Once all
> + * data from its backing image chain has been pulled, the disk no
> + * longer depends on those intermediate backing images.  This function
> + * pulls data for the entire device in the background.  Progress of
> + * the operation can be checked with virDomainGetBlockJobInfo() and
> + * the operation can be aborted with virDomainBlockJobAbort().  When
> + * finished, an asynchronous event is raised to indicate the final
> + * status.
> + *
> + * The @disk parameter is either an unambiguous source name of the
> + * block device (the<source file='...'/>  sub-element, such as
> + * "/path/to/image"), or the device target shorthand (the
> + *<target dev='...'/>  sub-element, such as "xvda").  Valid names
> + * can be found by calling virDomainGetXMLDesc() and inspecting
> + * elements within //domain/devices/disk.
> + *
> + * The maximum bandwidth (in Mbps) that will be used to do the copy can be
> + * specified with the bandwidth parameter.  If set to 0, libvirt will choose a
> + * suitable default.  Some hypervisors do not support this feature and will
> + * return an error if bandwidth is not 0.
> + *
> + * When @base is NULL, this is identical to virDomainBlockPull().
> + *
> + * Returns 0 if the operation has started, -1 on failure.
> + */
> +int virDomainBlockRebase(virDomainPtr dom, const char *disk,
> +                         const char *base, unsigned long bandwidth,
> +                         unsigned int flags)
> +{
> +    virConnectPtr conn;
> +
> +    VIR_DOMAIN_DEBUG(dom, "disk=%p, base=%s bandwidth=%lu, flags=%x",

disk is just a character string, isn't it? If so, why not use %s instead 
of %p?

Otherwise, this is all pretty straightforward. ACK.

> +                     disk, NULLSTR(base), bandwidth, flags);
> +
> +    virResetLastError();
> +
> +    if (!VIR_IS_CONNECTED_DOMAIN (dom)) {
> +        virLibDomainError(VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
> +        virDispatchError(NULL);
> +        return -1;
> +    }
> +    conn = dom->conn;
> +
> +    if (dom->conn->flags&  VIR_CONNECT_RO) {
> +        virLibDomainError(VIR_ERR_OPERATION_DENIED, __FUNCTION__);
> +        goto error;
> +    }
> +
> +    if (!disk) {
> +        virLibDomainError(VIR_ERR_INVALID_ARG,
> +                          _("disk is NULL"));
> +        goto error;
> +    }
> +
> +    if (conn->driver->domainBlockRebase) {
> +        int ret;
> +        ret = conn->driver->domainBlockRebase(dom, disk, base, bandwidth,
> +                                              flags);
> +        if (ret<  0)
> +            goto error;
> +        return ret;
> +    }
> +
> +    virLibDomainError(VIR_ERR_NO_SUPPORT, __FUNCTION__);
> +
> +error:
> +    virDispatchError(dom->conn);
> +    return -1;
> +}
> +
> +
> +/**
>    * virDomainOpenGraphics:
>    * @dom: pointer to domain object
>    * @idx: index of graphics config to open
> diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms
> index 1c4e0a3..9302caa 100644
> --- a/src/libvirt_public.syms
> +++ b/src/libvirt_public.syms
> @@ -518,6 +518,7 @@ LIBVIRT_0.9.9 {
>
>   LIBVIRT_0.9.10 {
>       global:
> +        virDomainBlockRebase;
>           virDomainGetCPUStats;
>           virDomainPMSuspendForDuration;
>           virDomainShutdownFlags;
> diff --git a/src/rpc/gendispatch.pl b/src/rpc/gendispatch.pl
> index 446f229..3f37d58 100755
> --- a/src/rpc/gendispatch.pl
> +++ b/src/rpc/gendispatch.pl
> @@ -232,6 +232,7 @@ my $long_legacy = {
>       GetVersion                  =>  { ret =>  { hv_ver =>  1 } },
>       NodeGetInfo                 =>  { ret =>  { memory =>  1 } },
>       DomainBlockPull             =>  { arg =>  { bandwidth =>  1 } },
> +    DomainBlockRebase           =>  { arg =>  { bandwidth =>  1 } },
>       DomainBlockJobSetSpeed      =>  { arg =>  { bandwidth =>  1 } },
>       DomainMigrateGetMaxSpeed    =>  { ret =>  { bandwidth =>  1 } },
>   };




More information about the libvir-list mailing list