mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2025-01-18 10:35:20 +00:00
qemu: Add blockdev support for the block copy job
Implement job handling for the block copy job (drive/blockdev-mirror) when using -blockdev. In contrast to the previously implemented blockjobs the block copy job introduces new images to the running qemu instance, thus requires a bit more handling. When copying to new images the code now makes use of blockdev-create to format the images explicitly rather than depending on automagic qemu behaviour. Signed-off-by: Peter Krempa <pkrempa@redhat.com> Reviewed-by: Ján Tomko <jtomko@redhat.com>
This commit is contained in:
parent
545edb2502
commit
ce7229a3b0
@ -309,6 +309,40 @@ qemuBlockJobNewCreate(virDomainObjPtr vm,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
qemuBlockJobDataPtr
|
||||||
|
qemuBlockJobDiskNewCopy(virDomainObjPtr vm,
|
||||||
|
virDomainDiskDefPtr disk,
|
||||||
|
virStorageSourcePtr mirror,
|
||||||
|
bool shallow,
|
||||||
|
bool reuse)
|
||||||
|
{
|
||||||
|
qemuDomainObjPrivatePtr priv = vm->privateData;
|
||||||
|
VIR_AUTOUNREF(qemuBlockJobDataPtr) job = NULL;
|
||||||
|
VIR_AUTOFREE(char *) jobname = NULL;
|
||||||
|
|
||||||
|
if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_BLOCKDEV)) {
|
||||||
|
if (virAsprintf(&jobname, "copy-%s-%s", disk->dst, disk->src->nodeformat) < 0)
|
||||||
|
return NULL;
|
||||||
|
} else {
|
||||||
|
if (!(jobname = qemuAliasDiskDriveFromDisk(disk)))
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(job = qemuBlockJobDataNew(QEMU_BLOCKJOB_TYPE_COPY, jobname)))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
job->mirrorChain = virObjectRef(mirror);
|
||||||
|
|
||||||
|
if (shallow && !reuse)
|
||||||
|
job->data.copy.shallownew = true;
|
||||||
|
|
||||||
|
if (qemuBlockJobRegister(job, vm, disk, true) < 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
VIR_RETURN_PTR(job);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* qemuBlockJobDiskGetJob:
|
* qemuBlockJobDiskGetJob:
|
||||||
* @disk: disk definition
|
* @disk: disk definition
|
||||||
@ -1043,6 +1077,50 @@ qemuBlockJobProcessEventCompletedActiveCommit(virQEMUDriverPtr driver,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
qemuBlockJobProcessEventConcludedCopyPivot(virQEMUDriverPtr driver,
|
||||||
|
virDomainObjPtr vm,
|
||||||
|
qemuBlockJobDataPtr job,
|
||||||
|
qemuDomainAsyncJob asyncJob)
|
||||||
|
{
|
||||||
|
VIR_DEBUG("copy job '%s' on VM '%s' pivoted", job->name, vm->def->name);
|
||||||
|
|
||||||
|
if (!job->disk)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* for shallow copy without reusing external image the user can either not
|
||||||
|
* specify the backing chain in which case libvirt will open and use the
|
||||||
|
* chain the user provided or not specify a chain in which case we'll
|
||||||
|
* inherit the rest of the chain */
|
||||||
|
if (job->data.copy.shallownew &&
|
||||||
|
!virStorageSourceIsBacking(job->disk->mirror->backingStore))
|
||||||
|
VIR_STEAL_PTR(job->disk->mirror->backingStore, job->disk->src->backingStore);
|
||||||
|
|
||||||
|
qemuBlockJobRewriteConfigDiskSource(vm, job->disk, job->disk->mirror);
|
||||||
|
|
||||||
|
qemuBlockJobEventProcessConcludedRemoveChain(driver, vm, asyncJob, job->disk->src);
|
||||||
|
virObjectUnref(job->disk->src);
|
||||||
|
VIR_STEAL_PTR(job->disk->src, job->disk->mirror);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
qemuBlockJobProcessEventConcludedCopyAbort(virQEMUDriverPtr driver,
|
||||||
|
virDomainObjPtr vm,
|
||||||
|
qemuBlockJobDataPtr job,
|
||||||
|
qemuDomainAsyncJob asyncJob)
|
||||||
|
{
|
||||||
|
VIR_DEBUG("copy job '%s' on VM '%s' aborted", job->name, vm->def->name);
|
||||||
|
|
||||||
|
if (!job->disk)
|
||||||
|
return;
|
||||||
|
|
||||||
|
qemuBlockJobEventProcessConcludedRemoveChain(driver, vm, asyncJob, job->disk->mirror);
|
||||||
|
virObjectUnref(job->disk->mirror);
|
||||||
|
job->disk->mirror = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
qemuBlockJobProcessEventConcludedCreate(virQEMUDriverPtr driver,
|
qemuBlockJobProcessEventConcludedCreate(virQEMUDriverPtr driver,
|
||||||
virDomainObjPtr vm,
|
virDomainObjPtr vm,
|
||||||
@ -1111,6 +1189,12 @@ qemuBlockJobEventProcessConcludedTransition(qemuBlockJobDataPtr job,
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case QEMU_BLOCKJOB_TYPE_COPY:
|
case QEMU_BLOCKJOB_TYPE_COPY:
|
||||||
|
if (job->state == QEMU_BLOCKJOB_STATE_PIVOTING)
|
||||||
|
qemuBlockJobProcessEventConcludedCopyPivot(driver, vm, job, asyncJob);
|
||||||
|
else
|
||||||
|
qemuBlockJobProcessEventConcludedCopyAbort(driver, vm, job, asyncJob);
|
||||||
|
break;
|
||||||
|
|
||||||
case QEMU_BLOCKJOB_TYPE_NONE:
|
case QEMU_BLOCKJOB_TYPE_NONE:
|
||||||
case QEMU_BLOCKJOB_TYPE_INTERNAL:
|
case QEMU_BLOCKJOB_TYPE_INTERNAL:
|
||||||
case QEMU_BLOCKJOB_TYPE_LAST:
|
case QEMU_BLOCKJOB_TYPE_LAST:
|
||||||
@ -1138,6 +1222,9 @@ qemuBlockJobEventProcessConcludedTransition(qemuBlockJobDataPtr job,
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case QEMU_BLOCKJOB_TYPE_COPY:
|
case QEMU_BLOCKJOB_TYPE_COPY:
|
||||||
|
qemuBlockJobProcessEventConcludedCopyAbort(driver, vm, job, asyncJob);
|
||||||
|
break;
|
||||||
|
|
||||||
case QEMU_BLOCKJOB_TYPE_NONE:
|
case QEMU_BLOCKJOB_TYPE_NONE:
|
||||||
case QEMU_BLOCKJOB_TYPE_INTERNAL:
|
case QEMU_BLOCKJOB_TYPE_INTERNAL:
|
||||||
case QEMU_BLOCKJOB_TYPE_LAST:
|
case QEMU_BLOCKJOB_TYPE_LAST:
|
||||||
|
@ -97,6 +97,14 @@ struct _qemuBlockJobCreateData {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct _qemuBlockJobCopyData qemuBlockJobCopyData;
|
||||||
|
typedef qemuBlockJobCopyData *qemuBlockJobDataCopyPtr;
|
||||||
|
|
||||||
|
struct _qemuBlockJobCopyData {
|
||||||
|
bool shallownew;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
typedef struct _qemuBlockJobData qemuBlockJobData;
|
typedef struct _qemuBlockJobData qemuBlockJobData;
|
||||||
typedef qemuBlockJobData *qemuBlockJobDataPtr;
|
typedef qemuBlockJobData *qemuBlockJobDataPtr;
|
||||||
|
|
||||||
@ -113,6 +121,7 @@ struct _qemuBlockJobData {
|
|||||||
qemuBlockJobPullData pull;
|
qemuBlockJobPullData pull;
|
||||||
qemuBlockJobCommitData commit;
|
qemuBlockJobCommitData commit;
|
||||||
qemuBlockJobCreateData create;
|
qemuBlockJobCreateData create;
|
||||||
|
qemuBlockJobCopyData copy;
|
||||||
} data;
|
} data;
|
||||||
|
|
||||||
int type; /* qemuBlockJobType */
|
int type; /* qemuBlockJobType */
|
||||||
@ -163,6 +172,13 @@ qemuBlockJobNewCreate(virDomainObjPtr vm,
|
|||||||
virStorageSourcePtr chain,
|
virStorageSourcePtr chain,
|
||||||
bool storage);
|
bool storage);
|
||||||
|
|
||||||
|
qemuBlockJobDataPtr
|
||||||
|
qemuBlockJobDiskNewCopy(virDomainObjPtr vm,
|
||||||
|
virDomainDiskDefPtr disk,
|
||||||
|
virStorageSourcePtr mirror,
|
||||||
|
bool shallow,
|
||||||
|
bool reuse);
|
||||||
|
|
||||||
qemuBlockJobDataPtr
|
qemuBlockJobDataPtr
|
||||||
qemuBlockJobDiskGetJob(virDomainDiskDefPtr disk)
|
qemuBlockJobDiskGetJob(virDomainDiskDefPtr disk)
|
||||||
ATTRIBUTE_NONNULL(1);
|
ATTRIBUTE_NONNULL(1);
|
||||||
|
@ -2426,6 +2426,10 @@ qemuDomainObjPrivateXMLFormatBlockjobIterator(void *payload,
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case QEMU_BLOCKJOB_TYPE_COPY:
|
case QEMU_BLOCKJOB_TYPE_COPY:
|
||||||
|
if (job->data.copy.shallownew)
|
||||||
|
virBufferAddLit(&attrBuf, " shallownew='yes'");
|
||||||
|
break;
|
||||||
|
|
||||||
case QEMU_BLOCKJOB_TYPE_NONE:
|
case QEMU_BLOCKJOB_TYPE_NONE:
|
||||||
case QEMU_BLOCKJOB_TYPE_INTERNAL:
|
case QEMU_BLOCKJOB_TYPE_INTERNAL:
|
||||||
case QEMU_BLOCKJOB_TYPE_LAST:
|
case QEMU_BLOCKJOB_TYPE_LAST:
|
||||||
@ -2873,6 +2877,7 @@ qemuDomainObjPrivateXMLParseBlockjobDataSpecific(qemuBlockJobDataPtr job,
|
|||||||
virDomainXMLOptionPtr xmlopt)
|
virDomainXMLOptionPtr xmlopt)
|
||||||
{
|
{
|
||||||
VIR_AUTOFREE(char *) createmode = NULL;
|
VIR_AUTOFREE(char *) createmode = NULL;
|
||||||
|
VIR_AUTOFREE(char *) shallownew = NULL;
|
||||||
xmlNodePtr tmp;
|
xmlNodePtr tmp;
|
||||||
|
|
||||||
switch ((qemuBlockJobType) job->type) {
|
switch ((qemuBlockJobType) job->type) {
|
||||||
@ -2922,6 +2927,14 @@ qemuDomainObjPrivateXMLParseBlockjobDataSpecific(qemuBlockJobDataPtr job,
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case QEMU_BLOCKJOB_TYPE_COPY:
|
case QEMU_BLOCKJOB_TYPE_COPY:
|
||||||
|
if ((shallownew = virXPathString("string(./@shallownew)", ctxt))) {
|
||||||
|
if (STRNEQ(shallownew, "yes"))
|
||||||
|
goto broken;
|
||||||
|
|
||||||
|
job->data.copy.shallownew = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case QEMU_BLOCKJOB_TYPE_NONE:
|
case QEMU_BLOCKJOB_TYPE_NONE:
|
||||||
case QEMU_BLOCKJOB_TYPE_INTERNAL:
|
case QEMU_BLOCKJOB_TYPE_INTERNAL:
|
||||||
case QEMU_BLOCKJOB_TYPE_LAST:
|
case QEMU_BLOCKJOB_TYPE_LAST:
|
||||||
|
@ -18351,7 +18351,6 @@ qemuDomainBlockCopyCommon(virDomainObjPtr vm,
|
|||||||
{
|
{
|
||||||
virQEMUDriverPtr driver = conn->privateData;
|
virQEMUDriverPtr driver = conn->privateData;
|
||||||
qemuDomainObjPrivatePtr priv = vm->privateData;
|
qemuDomainObjPrivatePtr priv = vm->privateData;
|
||||||
VIR_AUTOFREE(char *) device = NULL;
|
|
||||||
virDomainDiskDefPtr disk = NULL;
|
virDomainDiskDefPtr disk = NULL;
|
||||||
int ret = -1;
|
int ret = -1;
|
||||||
bool need_unlink = false;
|
bool need_unlink = false;
|
||||||
@ -18363,6 +18362,11 @@ qemuDomainBlockCopyCommon(virDomainObjPtr vm,
|
|||||||
qemuBlockJobDataPtr job = NULL;
|
qemuBlockJobDataPtr job = NULL;
|
||||||
VIR_AUTOUNREF(virStorageSourcePtr) mirror = mirrorsrc;
|
VIR_AUTOUNREF(virStorageSourcePtr) mirror = mirrorsrc;
|
||||||
bool blockdev = virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_BLOCKDEV);
|
bool blockdev = virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_BLOCKDEV);
|
||||||
|
VIR_AUTOPTR(qemuBlockStorageSourceChainData) data = NULL;
|
||||||
|
VIR_AUTOPTR(qemuBlockStorageSourceChainData) crdata = NULL;
|
||||||
|
virStorageSourcePtr n;
|
||||||
|
virStorageSourcePtr mirrorBacking = NULL;
|
||||||
|
int rc = 0;
|
||||||
|
|
||||||
/* Preliminaries: find the disk we are editing, sanity checks */
|
/* Preliminaries: find the disk we are editing, sanity checks */
|
||||||
virCheckFlags(VIR_DOMAIN_BLOCK_COPY_SHALLOW |
|
virCheckFlags(VIR_DOMAIN_BLOCK_COPY_SHALLOW |
|
||||||
@ -18392,9 +18396,6 @@ qemuDomainBlockCopyCommon(virDomainObjPtr vm,
|
|||||||
if (!(disk = qemuDomainDiskByName(vm->def, path)))
|
if (!(disk = qemuDomainDiskByName(vm->def, path)))
|
||||||
goto endjob;
|
goto endjob;
|
||||||
|
|
||||||
if (!(device = qemuAliasDiskDriveFromDisk(disk)))
|
|
||||||
goto endjob;
|
|
||||||
|
|
||||||
if (qemuDomainDiskBlockJobIsActive(disk))
|
if (qemuDomainDiskBlockJobIsActive(disk))
|
||||||
goto endjob;
|
goto endjob;
|
||||||
|
|
||||||
@ -18469,7 +18470,8 @@ qemuDomainBlockCopyCommon(virDomainObjPtr vm,
|
|||||||
goto endjob;
|
goto endjob;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* pre-create the image file */
|
/* pre-create the image file. In case when 'blockdev' is used this is
|
||||||
|
* required so that libvirt can properly label the image for access by qemu */
|
||||||
if (!existing) {
|
if (!existing) {
|
||||||
if (virStorageFileCreate(mirror) < 0) {
|
if (virStorageFileCreate(mirror) < 0) {
|
||||||
virReportSystemError(errno, "%s", _("failed to create copy target"));
|
virReportSystemError(errno, "%s", _("failed to create copy target"));
|
||||||
@ -18486,6 +18488,15 @@ qemuDomainBlockCopyCommon(virDomainObjPtr vm,
|
|||||||
keepParentLabel) < 0)
|
keepParentLabel) < 0)
|
||||||
goto endjob;
|
goto endjob;
|
||||||
|
|
||||||
|
/* we must initialize XML-provided chain prior to detecting to keep semantics
|
||||||
|
* with VM startup */
|
||||||
|
if (blockdev) {
|
||||||
|
for (n = mirror; virStorageSourceIsBacking(n); n = n->backingStore) {
|
||||||
|
if (qemuDomainPrepareStorageSourceBlockdev(disk, n, priv, cfg) < 0)
|
||||||
|
goto endjob;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* If reusing an external image that includes a backing file but the user
|
/* If reusing an external image that includes a backing file but the user
|
||||||
* did not enumerate the chain in the XML we need to detect the chain */
|
* did not enumerate the chain in the XML we need to detect the chain */
|
||||||
if (mirror_reuse &&
|
if (mirror_reuse &&
|
||||||
@ -18497,18 +18508,72 @@ qemuDomainBlockCopyCommon(virDomainObjPtr vm,
|
|||||||
if (qemuDomainStorageSourceChainAccessAllow(driver, vm, mirror) < 0)
|
if (qemuDomainStorageSourceChainAccessAllow(driver, vm, mirror) < 0)
|
||||||
goto endjob;
|
goto endjob;
|
||||||
|
|
||||||
if (!(job = qemuBlockJobDiskNew(vm, disk, QEMU_BLOCKJOB_TYPE_COPY, device)))
|
if (blockdev) {
|
||||||
|
if (mirror_reuse) {
|
||||||
|
if (!(data = qemuBuildStorageSourceChainAttachPrepareBlockdev(mirror,
|
||||||
|
priv->qemuCaps)))
|
||||||
|
goto endjob;
|
||||||
|
} else {
|
||||||
|
if (qemuBlockStorageSourceCreateDetectSize(vm, mirror, disk->src, QEMU_ASYNC_JOB_NONE) < 0)
|
||||||
|
goto endjob;
|
||||||
|
|
||||||
|
if (mirror_shallow) {
|
||||||
|
/* if external backing store is populated we'll need to open it */
|
||||||
|
if (virStorageSourceHasBacking(mirror)) {
|
||||||
|
if (!(data = qemuBuildStorageSourceChainAttachPrepareBlockdev(mirror->backingStore,
|
||||||
|
priv->qemuCaps)))
|
||||||
|
goto endjob;
|
||||||
|
|
||||||
|
mirrorBacking = mirror->backingStore;
|
||||||
|
} else {
|
||||||
|
/* backing store of original image will be reused, but the
|
||||||
|
* new image must refer to it in the metadata */
|
||||||
|
mirrorBacking = disk->src->backingStore;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(crdata = qemuBuildStorageSourceChainAttachPrepareBlockdevTop(mirror,
|
||||||
|
priv->qemuCaps)))
|
||||||
|
goto endjob;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data) {
|
||||||
|
qemuDomainObjEnterMonitor(driver, vm);
|
||||||
|
rc = qemuBlockStorageSourceChainAttach(priv->mon, data);
|
||||||
|
if (qemuDomainObjExitMonitor(driver, vm) < 0)
|
||||||
|
goto endjob;
|
||||||
|
|
||||||
|
if (rc < 0)
|
||||||
|
goto endjob;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (crdata &&
|
||||||
|
qemuBlockStorageSourceCreate(vm, mirror, mirrorBacking, mirror->backingStore,
|
||||||
|
crdata->srcdata[0], QEMU_ASYNC_JOB_NONE) < 0)
|
||||||
|
goto endjob;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(job = qemuBlockJobDiskNewCopy(vm, disk, mirror, mirror_shallow, mirror_reuse)))
|
||||||
goto endjob;
|
goto endjob;
|
||||||
|
|
||||||
disk->mirrorState = VIR_DOMAIN_DISK_MIRROR_STATE_NONE;
|
disk->mirrorState = VIR_DOMAIN_DISK_MIRROR_STATE_NONE;
|
||||||
|
|
||||||
/* Actually start the mirroring */
|
/* Actually start the mirroring */
|
||||||
qemuDomainObjEnterMonitor(driver, vm);
|
qemuDomainObjEnterMonitor(driver, vm);
|
||||||
|
|
||||||
|
if (blockdev) {
|
||||||
|
ret = qemuMonitorBlockdevMirror(priv->mon, job->name, true,
|
||||||
|
disk->src->nodeformat,
|
||||||
|
mirror->nodeformat, bandwidth,
|
||||||
|
granularity, buf_size, mirror_shallow);
|
||||||
|
} else {
|
||||||
/* qemuMonitorDriveMirror needs to honor the REUSE_EXT flag as specified
|
/* qemuMonitorDriveMirror needs to honor the REUSE_EXT flag as specified
|
||||||
* by the user */
|
* by the user */
|
||||||
ret = qemuMonitorDriveMirror(priv->mon, device, mirror->path, format,
|
ret = qemuMonitorDriveMirror(priv->mon, job->name, mirror->path, format,
|
||||||
bandwidth, granularity, buf_size,
|
bandwidth, granularity, buf_size,
|
||||||
mirror_shallow, mirror_reuse);
|
mirror_shallow, mirror_reuse);
|
||||||
|
}
|
||||||
|
|
||||||
virDomainAuditDisk(vm, NULL, mirror, "mirror", ret >= 0);
|
virDomainAuditDisk(vm, NULL, mirror, "mirror", ret >= 0);
|
||||||
if (qemuDomainObjExitMonitor(driver, vm) < 0)
|
if (qemuDomainObjExitMonitor(driver, vm) < 0)
|
||||||
ret = -1;
|
ret = -1;
|
||||||
@ -18525,6 +18590,16 @@ qemuDomainBlockCopyCommon(virDomainObjPtr vm,
|
|||||||
qemuBlockJobStarted(job, vm);
|
qemuBlockJobStarted(job, vm);
|
||||||
|
|
||||||
endjob:
|
endjob:
|
||||||
|
if (rc < 0 &&
|
||||||
|
virDomainObjIsActive(vm) &&
|
||||||
|
(data || crdata)) {
|
||||||
|
qemuDomainObjEnterMonitor(driver, vm);
|
||||||
|
if (data)
|
||||||
|
qemuBlockStorageSourceChainDetach(priv->mon, data);
|
||||||
|
if (crdata)
|
||||||
|
qemuBlockStorageSourceAttachRollback(priv->mon, crdata->srcdata[0]);
|
||||||
|
ignore_value(qemuDomainObjExitMonitor(driver, vm));
|
||||||
|
}
|
||||||
if (need_unlink && virStorageFileUnlink(mirror) < 0)
|
if (need_unlink && virStorageFileUnlink(mirror) < 0)
|
||||||
VIR_WARN("%s", _("unable to remove just-created copy target"));
|
VIR_WARN("%s", _("unable to remove just-created copy target"));
|
||||||
virStorageFileDeinit(mirror);
|
virStorageFileDeinit(mirror);
|
||||||
|
@ -260,6 +260,9 @@
|
|||||||
</source>
|
</source>
|
||||||
</src>
|
</src>
|
||||||
</blockjob>
|
</blockjob>
|
||||||
|
<blockjob name='pull-vdc-libvirt-4321-format' type='copy' state='ready' shallownew='yes'>
|
||||||
|
<disk dst='vdc'/>
|
||||||
|
</blockjob>
|
||||||
<blockjob name='pull-vdc-libvirt-9-format' type='commit' state='running'>
|
<blockjob name='pull-vdc-libvirt-9-format' type='commit' state='running'>
|
||||||
<disk dst='vdc'/>
|
<disk dst='vdc'/>
|
||||||
<base node='libvirt-11-format'/>
|
<base node='libvirt-11-format'/>
|
||||||
@ -571,6 +574,17 @@
|
|||||||
</backingStore>
|
</backingStore>
|
||||||
</backingStore>
|
</backingStore>
|
||||||
</backingStore>
|
</backingStore>
|
||||||
|
<mirror type='file' file='/tmp/copy2' format='qcow2' job='copy' ready='yes'>
|
||||||
|
<format type='qcow2'/>
|
||||||
|
<source file='/tmp/copy2' index='4321'>
|
||||||
|
<privateData>
|
||||||
|
<nodenames>
|
||||||
|
<nodename type='storage' name='libvirt-4321-storage'/>
|
||||||
|
<nodename type='format' name='libvirt-4321-format'/>
|
||||||
|
</nodenames>
|
||||||
|
</privateData>
|
||||||
|
</source>
|
||||||
|
</mirror>
|
||||||
<target dev='vdc' bus='virtio'/>
|
<target dev='vdc' bus='virtio'/>
|
||||||
<alias name='virtio-disk3'/>
|
<alias name='virtio-disk3'/>
|
||||||
<address type='pci' domain='0x0000' bus='0x00' slot='0x0d' function='0x0'/>
|
<address type='pci' domain='0x0000' bus='0x00' slot='0x0d' function='0x0'/>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user