[libvirt] [PATCHv4 05/18] blockjob: add new API flags

Jiri Denemark jdenemar at redhat.com
Fri Apr 13 09:51:53 UTC 2012


On Mon, Apr 09, 2012 at 21:52:14 -0600, Eric Blake wrote:
> This patch introduces a new block job, useful for live storage
> migration using pre-copy streaming.
> 
> Using a live VM with the backing chain:
>   base <- snap1 <- snap2
> as the starting point, we have:
> 
> - virDomainBlockRebase(dom, disk, "/path/to/copy", 0,
>     VIR_DOMAIN_BLOCK_REBASE_COPY)
> creates /path/to/copy with the same format as snap2, with no backing
> file, so entire chain is copied and flattened
> 
> - virDomainBlockRebase(dom, disk, "/path/to/copy", 0,
>     VIR_DOMAIN_BLOCK_REBASE_COPY|VIR_DOMAIN_BLOCK_REBASE_COPY_RAW)
> creates /path/to/copy as a raw file, so entire chain is copied and
> flattened
> 
> - virDomainBlockRebase(dom, disk, "/path/to/copy", 0,
>     VIR_DOMAIN_BLOCK_REBASE_COPY|VIR_DOMAIN_BLOCK_REBASE_SHALLOW)
> creates /path/to/copy with the same format as snap2, but with snap1 as
> a backing file, so only snap2 is copied.
> 
> - virDomainBlockRebase(dom, disk, "/path/to/copy", 0,
>     VIR_DOMAIN_BLOCK_REBASE_COPY|VIR_DOMAIN_BLOCK_REBASE_REUSE_EXT)
> reuse existing /path/to/copy (must have empty contents, and format is
> probed from the metadata), and copy the full chain
> 
> - virDomainBlockRebase(dom, disk, "/path/to/copy", 0,
>     VIR_DOMAIN_BLOCK_REBASE_COPY|VIR_DOMAIN_BLOCK_REBASE_REUSE_EXT|
>     VIR_DOMAIN_BLOCK_REBASE_SHALLOW)
> reuse existing /path/to/copy (contents must be identical to snap1,
> and format is probed from the metadata), and copy only the contents
> of snap2
> 
> - virDomainBlockRebase(dom, disk, "/path/to/copy", 0,
>     VIR_DOMAIN_BLOCK_REBASE_COPY|VIR_DOMAIN_BLOCK_REBASE_REUSE_EXT|
>     VIR_DOMAIN_BLOCK_REBASE_SHALLOW|VIR_DOMAIN_BLOCK_REBASE_COPY_RAW)
> reuse existing /path/to/copy (must be raw volume with contents
> identical to snap1), and copy only the contents of snap2
> 
> Less useful combinations:
> 
> - virDomainBlockRebase(dom, disk, "/path/to/copy", 0,
>     VIR_DOMAIN_BLOCK_REBASE_COPY|VIR_DOMAIN_BLOCK_REBASE_SHALLOW|
>     VIR_DOMAIN_BLOCK_REBASE_COPY_RAW)
> fail if source is not raw, otherwise create /path/to/copy as raw and
> the single file is copied (no chain involved)
> 
> - virDomainBlockRebase(dom, disk, "/path/to/copy", 0,
>     VIR_DOMAIN_BLOCK_REBASE_COPY|VIR_DOMAIN_BLOCK_REBASE_REUSE_EXT|
>     VIR_DOMAIN_BLOCK_REBASE_COPY_RAW)
> makes little sense: the destination must be raw but have no contents,
> meaning that it is an empty file, so there is nothing to reuse
> 
> The other three flags are rejected without VIR_DOMAIN_BLOCK_COPY.
> 
> It would be nice if we could issue an event when pivoting from phase 1
> to phase 2, but qemu hasn't implemented that, and we would have to poll
> in order to synthesize it ourselves.  Meanwhile, qemu will give us a
> distinct job info and completion event when we either cancel or pivot
> to end the job.  Pivoting is accomplished via the new:
> 
> virDomainBlockJobAbort(dom, disk, VIR_DOMAIN_BLOCK_JOB_ABORT_PIVOT)
> 
> Management applications can pre-create the copy with a relative
> backing file name, and use the VIR_DOMAIN_BLOCK_REBASE_REUSE_EXT
> flag to have qemu reuse the metadata; if the management application
> also copies the backing files to a new location, this can be used
> to perform live storage migration of an entire backing chain.
> 
> * include/libvirt/libvirt.h.in (VIR_DOMAIN_BLOCK_JOB_TYPE_COPY):
> New block job type.
> (virDomainBlockJobAbortFlags, virDomainBlockRebaseFlags): New enums.
> * src/libvirt.c (virDomainBlockRebase): Document the new flags,
> and implement general restrictions on flag combinations.
> (virDomainBlockJobAbort): Document the new flag.
> (virDomainSaveFlags, virDomainSnapshotCreateXML)
> (virDomainRevertToSnapshot, virDomainDetachDeviceFlags): Document
> restrictions.
> * include/libvirt/virterror.h (VIR_ERR_BLOCK_COPY_ACTIVE): New
> error.
> * src/util/virterror.c (virErrorMsg): Define it.
> ---
>  include/libvirt/libvirt.h.in |   24 ++++++++++-
>  include/libvirt/virterror.h  |    1 +
>  src/libvirt.c                |   94 ++++++++++++++++++++++++++++++++++++++----
>  src/util/virterror.c         |    6 +++
>  4 files changed, 115 insertions(+), 10 deletions(-)
> 
> diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in
> index 97ad99d..ac5df95 100644
> --- a/include/libvirt/libvirt.h.in
> +++ b/include/libvirt/libvirt.h.in
> @@ -1934,12 +1934,15 @@ int virDomainUpdateDeviceFlags(virDomainPtr domain,
>  /**
>   * virDomainBlockJobType:
>   *
> - * VIR_DOMAIN_BLOCK_JOB_TYPE_PULL: Block Pull (virDomainBlockPull or
> - * virDomainBlockRebase)
> + * VIR_DOMAIN_BLOCK_JOB_TYPE_PULL: Block Pull (virDomainBlockPull, or
> + * virDomainBlockRebase without flags), job ends on completion
> + * VIR_DOMAIN_BLOCK_JOB_TYPE_COPY: Block Copy (virDomainBlockRebase with
> + * flags), job exists as long as mirroring is active
>   */
>  typedef enum {
>      VIR_DOMAIN_BLOCK_JOB_TYPE_UNKNOWN = 0,
>      VIR_DOMAIN_BLOCK_JOB_TYPE_PULL = 1,
> +    VIR_DOMAIN_BLOCK_JOB_TYPE_COPY = 2,
> 
>  #ifdef VIR_ENUM_SENTINELS
>      VIR_DOMAIN_BLOCK_JOB_TYPE_LAST
> @@ -1950,9 +1953,11 @@ typedef enum {
>   * virDomainBlockJobAbortFlags:
>   *
>   * VIR_DOMAIN_BLOCK_JOB_ABORT_ASYNC: Request only, do not wait for completion
> + * VIR_DOMAIN_BLOCK_JOB_ABORT_PIVOT: Pivot to mirror when ending a copy job
>   */
>  typedef enum {
>      VIR_DOMAIN_BLOCK_JOB_ABORT_ASYNC = 1 << 0,
> +    VIR_DOMAIN_BLOCK_JOB_ABORT_PIVOT = 1 << 1,
>  } virDomainBlockJobAbortFlags;
> 
>  /* An iterator for monitoring block job operations */
> @@ -1983,6 +1988,21 @@ int    virDomainBlockJobSetSpeed(virDomainPtr dom, const char *disk,
> 
>  int           virDomainBlockPull(virDomainPtr dom, const char *disk,
>                                   unsigned long bandwidth, unsigned int flags);
> +
> +/**
> + * virDomainBlockRebaseFlags:
> + *
> + * Flags available for virDomainBlockRebase().
> + */
> +typedef enum {
> +    VIR_DOMAIN_BLOCK_REBASE_SHALLOW   = 1 << 0, /* Limit copy to top of source
> +                                                   backing chain */
> +    VIR_DOMAIN_BLOCK_REBASE_REUSE_EXT = 1 << 1, /* Reuse existing external
> +                                                   file for a copy */
> +    VIR_DOMAIN_BLOCK_REBASE_COPY_RAW  = 1 << 2, /* Make destination file raw */
> +    VIR_DOMAIN_BLOCK_REBASE_COPY      = 1 << 3, /* Start a copy job */
> +} virDomainBlockRebaseFlags;
> +
>  int           virDomainBlockRebase(virDomainPtr dom, const char *disk,
>                                     const char *base, unsigned long bandwidth,
>                                     unsigned int flags);
> diff --git a/include/libvirt/virterror.h b/include/libvirt/virterror.h
> index e04d29e..070fdb5 100644
> --- a/include/libvirt/virterror.h
> +++ b/include/libvirt/virterror.h
> @@ -249,6 +249,7 @@ typedef enum {
>      VIR_ERR_NO_DOMAIN_METADATA = 80,    /* The metadata is not present */
>      VIR_ERR_MIGRATE_UNSAFE = 81,        /* Migration is not safe */
>      VIR_ERR_OVERFLOW = 82,              /* integer overflow */
> +    VIR_ERR_BLOCK_COPY_ACTIVE = 83,     /* action prevented by block copy job */
>  } virErrorNumber;
> 
>  /**
> diff --git a/src/libvirt.c b/src/libvirt.c
> index d44335a..753a2e0 100644
> --- a/src/libvirt.c
> +++ b/src/libvirt.c
> @@ -2696,6 +2696,10 @@ error:
>   * A save file can be inspected or modified slightly with
>   * virDomainSaveImageGetXMLDesc() and virDomainSaveImageDefineXML().
>   *
> + * Some hypervisors may prevent this operation if there is a current
> + * block copy operation; in that case, use virDomainBlockJobAbort()
> + * to stop the block copy first.
> + *
>   * Returns 0 in case of success and -1 in case of failure.
>   */
>  int
> @@ -7891,6 +7895,11 @@ error:
>   * virDomainUndefine(). A previous definition for this domain would be
>   * overriden if it already exists.
>   *
> + * Some hypervisors may prevent this operation if there is a current
> + * block copy operation on a transient domain with the same id as the
> + * domain being defined; in that case, use virDomainBlockJobAbort() to
> + * stop the block copy first.
> + *
>   * Returns NULL in case of error, a pointer to the domain otherwise
>   */
>  virDomainPtr
> @@ -9424,6 +9433,10 @@ error:
>   * return failure if LIVE is specified but it only supports removing the
>   * persisted device allocation.
>   *
> + * Some hypervisors may prevent this operation if there is a current
> + * block copy operation on the device being detached; in that case,
> + * use virDomainBlockJobAbort() to stop the block copy first.
> + *
>   * Returns 0 in case of success, -1 in case of failure.
>   */
>  int
> @@ -17124,6 +17137,10 @@ virDomainSnapshotGetConnect(virDomainSnapshotPtr snapshot)
>   * that it is still possible to fail after disks have changed, but only
>   * in the much rarer cases of running out of memory or disk space).
>   *
> + * Some hypervisors may prevent this operation if there is a current
> + * block copy operation; in that case, use virDomainBlockJobAbort()
> + * to stop the block copy first.
> + *
>   * Returns an (opaque) virDomainSnapshotPtr on success, NULL on failure.
>   */
>  virDomainSnapshotPtr
> @@ -17913,7 +17930,8 @@ error:
>   * can be found by calling virDomainGetXMLDesc() and inspecting
>   * elements within //domain/devices/disk.
>   *
> - * By default, this function performs a synchronous operation and the caller
> + * If the current block job for @disk is VIR_DOMAIN_BLOCK_JOB_TYPE_PULL, then
> + * by default, this function performs a synchronous operation and the caller
>   * may assume that the operation has completed when 0 is returned.  However,
>   * BlockJob operations may take a long time to complete, and during this time
>   * further domain interactions may be unresponsive.  To avoid this problem,
> @@ -17925,6 +17943,15 @@ error:
>   * used); but since events can be missed, it is also possible to use
>   * virDomainBlockJobInfo() to poll if the job is still running.
>   *
> + * If the current block job for @disk is VIR_DOMAIN_BLOCK_JOB_TYPE_COPY, then
> + * the default is to abort the mirroring and revert to the source disk;
> + * adding @flags of VIR_DOMAIN_BLOCK_JOB_ABORT_PIVOT causes this call to
> + * fail with VIR_ERR_BLOCK_COPY_ACTIVE if the copy is not fully populated,
> + * otherwise it will swap the disk over to the copy to end the mirroring.  An
> + * event will be issued when the job is ended, and it is possible to use
> + * VIR_DOMAIN_BLOCK_JOB_ABORT_SYNC to control whether this command waits
> + * for the completion of the job.
> + *

Oops, s/ABORT_SYNC/ABORT_ASYNC/

I notice that when reading the virsh patch where you have --async while I
remembered this ABORT_SYNC flag from here, which was of course wrong since the
enum contains ASYNC.

Jirka




More information about the libvir-list mailing list