To date, anyone performing a block copy and pivot ends up with the destination being treated as <disk type='file'>. While this works for data access for a block device, it has at least one noticeable shortcoming: virDomainGetBlockInfo() reports allocation differently for block devices visited as files (the size of the device) than for block devices visited as <disk type='block'> (the maximum sector used, as reported by qemu); and this difference is significant when trying to manage qcow2 format on block devices that can be grown as needed. I still plan to add a virDomainBlockCopy() API that takes the destination disk as XML, allowing full expressive capability to copy to a network disk. But a new API can't be backported, while a new flag to an existing API can. So this patch enhances blockcopy to let the user flag when the resulting XML after the copy must list the device as type='block'. * include/libvirt/libvirt.h.in (VIR_DOMAIN_BLOCK_REBASE_COPY_DEV): New flag. * src/libvirt.c (virDomainBlockRebase): Document it. * tools/virsh-domain.c (opts_block_copy, blockJobImpl): Add --blockdev option. * tools/virsh.pod (blockcopy): Document it. * src/qemu/qemu_driver.c (qemuDomainBlockRebase): Allow new flag. (qemuDomainBlockCopy): Remember the flag. * tests/qemuxml2argvdata/qemuxml2argv-disk-mirror.xml: Test it. Signed-off-by: Eric Blake <eblake@xxxxxxxxxx> --- include/libvirt/libvirt.h.in | 2 ++ src/libvirt.c | 8 ++++++-- src/qemu/qemu_driver.c | 12 ++++++++---- .../qemuxml2argvdata/qemuxml2argv-disk-mirror.xml | 4 ++-- tools/virsh-domain.c | 6 ++++++ tools/virsh.pod | 7 +++++-- 6 files changed, 29 insertions(+), 10 deletions(-) diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in index 47ea695..f2a02ea 100644 --- a/include/libvirt/libvirt.h.in +++ b/include/libvirt/libvirt.h.in @@ -2590,6 +2590,8 @@ typedef enum { VIR_DOMAIN_BLOCK_REBASE_RELATIVE = 1 << 4, /* Keep backing chain referenced using relative names */ + VIR_DOMAIN_BLOCK_REBASE_COPY_DEV = 1 << 5, /* Treat destination as block + device instead of file */ } virDomainBlockRebaseFlags; int virDomainBlockRebase(virDomainPtr dom, const char *disk, diff --git a/src/libvirt.c b/src/libvirt.c index 992e4f2..c4643e8 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -19881,7 +19881,10 @@ virDomainBlockPull(virDomainPtr dom, const char *disk, * pre-create files with relative backing file names, rather than the default * of absolute backing file names; as a security precaution, you should * generally only use reuse_ext with the shallow flag and a non-raw - * destination file. + * destination file. By default, the copy destination will be treated as + * type='file', but using VIR_DOMAIN_BLOCK_REBASE_COPY_DEV treats the + * destination as type='block' (affecting how virDomainGetBlockInfo() will + * report allocation after pivoting). * * A copy job has two parts; in the first phase, the @bandwidth parameter * affects how fast the source is pulled into the destination, and the job @@ -19950,7 +19953,8 @@ virDomainBlockRebase(virDomainPtr dom, const char *disk, virCheckNonNullArgGoto(base, error); } else if (flags & (VIR_DOMAIN_BLOCK_REBASE_SHALLOW | VIR_DOMAIN_BLOCK_REBASE_REUSE_EXT | - VIR_DOMAIN_BLOCK_REBASE_COPY_RAW)) { + VIR_DOMAIN_BLOCK_REBASE_COPY_RAW | + VIR_DOMAIN_BLOCK_REBASE_COPY_DEV)) { virReportInvalidArg(flags, _("use of flags in %s requires a copy job"), __FUNCTION__); diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index b6219ba..e74227e 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -15295,7 +15295,8 @@ qemuDomainBlockCopy(virDomainObjPtr vm, /* Preliminaries: find the disk we are editing, sanity checks */ virCheckFlags(VIR_DOMAIN_BLOCK_REBASE_SHALLOW | - VIR_DOMAIN_BLOCK_REBASE_REUSE_EXT, -1); + VIR_DOMAIN_BLOCK_REBASE_REUSE_EXT | + VIR_DOMAIN_BLOCK_REBASE_COPY_DEV, -1); priv = vm->privateData; cfg = virQEMUDriverGetConfig(driver); @@ -15374,7 +15375,8 @@ qemuDomainBlockCopy(virDomainObjPtr vm, if (VIR_ALLOC(mirror) < 0) goto endjob; /* XXX Allow non-file mirror destinations */ - mirror->type = VIR_STORAGE_TYPE_FILE; + mirror->type = flags & VIR_DOMAIN_BLOCK_REBASE_COPY_DEV ? + VIR_STORAGE_TYPE_BLOCK : VIR_STORAGE_TYPE_FILE; if (format) { if ((mirror->format = virStorageFileFormatTypeFromString(format)) <= 0) { @@ -15466,7 +15468,8 @@ qemuDomainBlockRebase(virDomainPtr dom, const char *path, const char *base, VIR_DOMAIN_BLOCK_REBASE_REUSE_EXT | VIR_DOMAIN_BLOCK_REBASE_COPY | VIR_DOMAIN_BLOCK_REBASE_COPY_RAW | - VIR_DOMAIN_BLOCK_REBASE_RELATIVE, -1); + VIR_DOMAIN_BLOCK_REBASE_RELATIVE | + VIR_DOMAIN_BLOCK_REBASE_COPY_DEV, -1); if (!(vm = qemuDomObjFromDomain(dom))) return -1; @@ -15482,7 +15485,8 @@ qemuDomainBlockRebase(virDomainPtr dom, const char *path, const char *base, format = "raw"; flags &= ~(VIR_DOMAIN_BLOCK_REBASE_COPY | VIR_DOMAIN_BLOCK_REBASE_COPY_RAW); - return qemuDomainBlockCopy(vm, dom->conn, path, base, format, bandwidth, flags); + return qemuDomainBlockCopy(vm, dom->conn, path, base, format, + bandwidth, flags); } return qemuDomainBlockJobImpl(vm, dom->conn, path, base, bandwidth, NULL, diff --git a/tests/qemuxml2argvdata/qemuxml2argv-disk-mirror.xml b/tests/qemuxml2argvdata/qemuxml2argv-disk-mirror.xml index 46f2a3e..7495a45 100644 --- a/tests/qemuxml2argvdata/qemuxml2argv-disk-mirror.xml +++ b/tests/qemuxml2argvdata/qemuxml2argv-disk-mirror.xml @@ -17,8 +17,8 @@ <disk type='block' device='disk'> <source dev='/dev/HostVG/QEMUGuest1'/> <backingStore/> - <mirror type='file' file='/dev/HostVG/QEMUGuest1Copy' job='copy' ready='yes'> - <source file='/dev/HostVG/QEMUGuest1Copy'/> + <mirror type='block' job='copy' ready='yes'> + <source dev='/dev/HostVG/QEMUGuest1Copy'/> </mirror> <target dev='hda' bus='ide'/> <address type='drive' controller='0' bus='0' target='0' unit='0'/> diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c index f7193cb..1fbd36e 100644 --- a/tools/virsh-domain.c +++ b/tools/virsh-domain.c @@ -1521,6 +1521,8 @@ blockJobImpl(vshControl *ctl, const vshCmd *cmd, flags |= VIR_DOMAIN_BLOCK_REBASE_REUSE_EXT; if (vshCommandOptBool(cmd, "raw")) flags |= VIR_DOMAIN_BLOCK_REBASE_COPY_RAW; + if (vshCommandOptBool(cmd, "blockdev")) + flags |= VIR_DOMAIN_BLOCK_REBASE_COPY_DEV; if (vshCommandOptStringReq(ctl, cmd, "dest", &base) < 0) goto cleanup; ret = virDomainBlockRebase(dom, path, base, bandwidth, flags); @@ -1828,6 +1830,10 @@ static const vshCmdOptDef opts_block_copy[] = { .type = VSH_OT_BOOL, .help = N_("use raw destination file") }, + {.name = "blockdev", + .type = VSH_OT_BOOL, + .help = N_("copy destination is block device instead of regular file") + }, {.name = "wait", .type = VSH_OT_BOOL, .help = N_("wait for job to reach mirroring phase") diff --git a/tools/virsh.pod b/tools/virsh.pod index f07deec..8178868 100644 --- a/tools/virsh.pod +++ b/tools/virsh.pod @@ -873,7 +873,8 @@ unlimited. The hypervisor can choose whether to reject the value or convert it to the maximum value allowed. =item B<blockcopy> I<domain> I<path> I<dest> [I<bandwidth>] [I<--shallow>] -[I<--reuse-external>] [I<--raw>] [I<--wait> [I<--async>] [I<--verbose>]] +[I<--reuse-external>] [I<--raw>] [I<--blockdev>] +[I<--wait> [I<--async>] [I<--verbose>]] [{I<--pivot> | I<--finish>}] [I<--timeout> B<seconds>] Copy a disk backing image chain to I<dest>. By default, this command @@ -891,7 +892,9 @@ The format of the destination is determined by the first match in the following list: if I<--raw> is specified, it will be raw; if I<--reuse-external> is specified, the existing destination is probed for a format; and in all other cases, the destination format will -match the source format. +match the source format. The destination is treated as a regular +file unless I<--blockdev> is used to signal that it is a block +device. By default, the copy job runs in the background, and consists of two phases. Initially, the job must copy all data from the source, and -- 1.7.1 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list