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,
* 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
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__);
/* 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);
virReportSystemError(errno, _("unable to stat for disk %s: %s"),
disk->dst, dest);
goto endjob;
- } else if (flags & VIR_DOMAIN_BLOCK_REBASE_REUSE_EXT) {
+ } else if (flags & (VIR_DOMAIN_BLOCK_REBASE_REUSE_EXT |
+ VIR_DOMAIN_BLOCK_REBASE_COPY_DEV)) {
virReportSystemError(errno,
_("missing destination file for disk %s: %s"),
disk->dst, dest);
goto endjob;
}
- } else if (!S_ISBLK(st.st_mode) && st.st_size &&
- !(flags & VIR_DOMAIN_BLOCK_REBASE_REUSE_EXT)) {
- virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
- _("external destination file for disk %s already "
- "exists and is not a block device: %s"),
- disk->dst, dest);
- goto endjob;
+ } else if (!S_ISBLK(st.st_mode)) {
+ if (st.st_size && !(flags & VIR_DOMAIN_BLOCK_REBASE_REUSE_EXT)) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("external destination file for disk %s already "
+ "exists and is not a block device: %s"),
+ disk->dst, dest);
+ goto endjob;
+ }
+ if (flags & VIR_DOMAIN_BLOCK_REBASE_COPY_DEV) {
+ virReportError(VIR_ERR_INVALID_ARG,
+ _("blockdev flag requested for disk %s, but file "
+ "'%s' is not a block device"), disk->dst, dest);
+ goto endjob;
+ }
}
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) {
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;
}
flags &= (VIR_DOMAIN_BLOCK_REBASE_SHALLOW |
- VIR_DOMAIN_BLOCK_REBASE_REUSE_EXT);
+ VIR_DOMAIN_BLOCK_REBASE_REUSE_EXT |
+ VIR_DOMAIN_BLOCK_REBASE_COPY_DEV);
ret = qemuDomainBlockCopy(vm, dom->conn, path, base, format,
bandwidth, flags);
vm = NULL;
<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'/>
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;
if (virDomainBlockRebase(dom, path, base, bandwidth, flags) < 0)
.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")
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
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