format of the source). The details of the <code>source</code>
sub-element are determined by the <code>type</code> attribute
of the mirror, similar to what is done for the
- overall <code>disk</code> device element. If
- attribute <code>ready</code> is present, then it is known the
- disk is ready to pivot; otherwise, the disk is probably still
+ overall <code>disk</code> device element. The
+ attribute <code>ready</code>, if present, tracks progress of
+ the job: <code>yes</code> if the disk is known to be ready to
+ pivot, or, <span class="since">since
+ 1.2.7</span>, <code>abort</code> or <code>pivot</code> if the
+ job is in the process of completing. If <code>ready</code> is
+ not present, the disk is probably still
copying. For now, this element only valid in output; it is
ignored on input. The <code>source</code> sub-element exists
for all two-phase jobs <span class="since">since 1.2.6</span>.
</choice>
<optional>
<attribute name='ready'>
- <value>yes</value>
+ <choice>
+ <value>yes</value>
+ <value>abort</value>
+ <value>pivot</value>
+ </choice>
</attribute>
</optional>
</element>
"unmap",
"ignore")
+VIR_ENUM_IMPL(virDomainDiskMirrorState, VIR_DOMAIN_DISK_MIRROR_STATE_LAST,
+ "none",
+ "yes",
+ "abort",
+ "pivot")
+
#define VIR_DOMAIN_XML_WRITE_FLAGS VIR_DOMAIN_XML_SECURE
#define VIR_DOMAIN_XML_READ_FLAGS VIR_DOMAIN_XML_INACTIVE
}
ready = virXMLPropString(cur, "ready");
if (ready) {
- def->mirroring = true;
+ if ((def->mirrorState =
+ virDomainDiskMirrorStateTypeFromString(ready)) < 0) {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("unknown mirror ready state %s"),
+ ready);
+ VIR_FREE(ready);
+ goto error;
+ }
VIR_FREE(ready);
}
} else if (xmlStrEqual(cur->name, BAD_CAST "auth")) {
virBufferEscapeString(buf, " file='%s'", def->mirror->path);
virBufferEscapeString(buf, " format='%s'", formatStr);
}
- if (def->mirroring)
- virBufferAddLit(buf, " ready='yes'");
+ if (def->mirrorState) {
+ const char *mirror;
+
+ mirror = virDomainDiskMirrorStateTypeToString(def->mirrorState);
+ virBufferEscapeString(buf, " ready='%s'", mirror);
+ }
virBufferAddLit(buf, ">\n");
virBufferAdjustIndent(buf, 2);
virBufferEscapeString(buf, "<format type='%s'/>\n", formatStr);
typedef virDomainBlockIoTuneInfo *virDomainBlockIoTuneInfoPtr;
+typedef enum {
+ VIR_DOMAIN_DISK_MIRROR_STATE_NONE = 0, /* No job, or job still not synced */
+ VIR_DOMAIN_DISK_MIRROR_STATE_READY, /* Job in second phase */
+ VIR_DOMAIN_DISK_MIRROR_STATE_ABORT, /* Job aborted, waiting for event */
+ VIR_DOMAIN_DISK_MIRROR_STATE_PIVOT, /* Job pivoted, waiting for event */
+
+ VIR_DOMAIN_DISK_MIRROR_STATE_LAST
+} virDomainDiskMirrorState;
+
+
/* Stores the virtual disk configuration */
struct _virDomainDiskDef {
virStorageSourcePtr src; /* non-NULL. XXX Allow NULL for empty cdrom? */
int removable; /* enum virTristateSwitch */
virStorageSourcePtr mirror;
- bool mirroring;
+ int mirrorState; /* enum virDomainDiskMirrorState */
struct {
unsigned int cylinders;
VIR_ENUM_DECL(virDomainDeviceSGIO)
VIR_ENUM_DECL(virDomainDiskTray)
VIR_ENUM_DECL(virDomainDiskDiscard)
+VIR_ENUM_DECL(virDomainDiskMirrorState)
VIR_ENUM_DECL(virDomainController)
VIR_ENUM_DECL(virDomainControllerModelPCI)
VIR_ENUM_DECL(virDomainControllerModelSCSI)
format = virStorageFileFormatTypeToString(disk->mirror->format);
/* Probe the status, if needed. */
- if (!disk->mirroring) {
+ if (!disk->mirrorState) {
qemuDomainObjEnterMonitor(driver, vm);
rc = qemuMonitorBlockJob(priv->mon, device, NULL, NULL, 0, &info,
BLOCK_JOB_INFO, true);
}
if (rc == 1 && info.cur == info.end &&
info.type == VIR_DOMAIN_BLOCK_JOB_TYPE_COPY)
- disk->mirroring = true;
+ disk->mirrorState = VIR_DOMAIN_DISK_MIRROR_STATE_READY;
}
- if (!disk->mirroring) {
+ if (disk->mirrorState != VIR_DOMAIN_DISK_MIRROR_STATE_READY) {
virReportError(VIR_ERR_BLOCK_COPY_ACTIVE,
_("disk '%s' not ready for pivot yet"),
disk->dst);
}
disk->mirror = NULL;
- disk->mirroring = false;
+ disk->mirrorState = VIR_DOMAIN_DISK_MIRROR_STATE_NONE;
cleanup:
/* revert to original disk def on failure */
* avoid checking if pivot is safe. */
if (mode == BLOCK_JOB_INFO && ret == 1 && disk->mirror &&
info->cur == info->end && info->type == VIR_DOMAIN_BLOCK_JOB_TYPE_COPY)
- disk->mirroring = true;
+ disk->mirrorState = VIR_DOMAIN_DISK_MIRROR_STATE_READY;
/* A successful block job cancelation stops any mirroring. */
if (mode == BLOCK_JOB_ABORT && disk->mirror) {
* the mirror, and audit that fact, before dropping things. */
virStorageSourceFree(disk->mirror);
disk->mirror = NULL;
- disk->mirroring = false;
+ disk->mirrorState = VIR_DOMAIN_DISK_MIRROR_STATE_NONE;
}
waitjob:
qemuDomainDetermineDiskChain(driver, vm, disk, true);
if (disk->mirror && type == VIR_DOMAIN_BLOCK_JOB_TYPE_COPY) {
if (status == VIR_DOMAIN_BLOCK_JOB_READY) {
- disk->mirroring = true;
+ disk->mirrorState = VIR_DOMAIN_DISK_MIRROR_STATE_READY;
} else if (status == VIR_DOMAIN_BLOCK_JOB_FAILED) {
virStorageSourceFree(disk->mirror);
disk->mirror = NULL;
- disk->mirroring = false;
+ disk->mirrorState = VIR_DOMAIN_DISK_MIRROR_STATE_NONE;
}
}
}
<disk type='file' device='disk'>
<source file='/tmp/logs.img'/>
<backingStore/>
+ <mirror type='file' file='/tmp/logcopy.img' format='qcow2' ready='abort'>
+ <format type='qcow2'/>
+ <source file='/tmp/logcopy.img'/>
+ </mirror>
<target dev='vdb' bus='virtio'/>
</disk>
<controller type='usb' index='0'/>