[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