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 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list