* mirror all further changes to both source and destination. The user
* must call virDomainBlockJobAbort() to end the mirroring while choosing
* whether to revert to source or pivot to the destination. An event is
- * issued when the job ends, and in the future, an event may be added when
- * the job transitions from pulling to mirroring. If the job is aborted,
- * a new job will have to start over from the beginning of the first phase.
+ * issued when the job ends, and depending on the hypervisor, an event may
+ * also be issued when the job transitions from pulling to mirroring. If
+ * the job is aborted, a new job will have to start over from the beginning
+ * of the first phase.
*
* Some hypervisors will restrict certain actions, such as virDomainSave()
* or virDomainDetachDevice(), while a copy job is active; they may
if (ret < 0)
goto endjob;
+ /* Snoop block copy operations, so future cancel operations can
+ * 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;
+
/* With synchronous block cancel, we must synthesize an event, and
* we silently ignore the ABORT_ASYNC flag. With asynchronous
* block cancel, the event will come from qemu, but without the
static void qemuMonitorJSONHandlePMSuspend(qemuMonitorPtr mon, virJSONValuePtr data);
static void qemuMonitorJSONHandleBlockJobCompleted(qemuMonitorPtr mon, virJSONValuePtr data);
static void qemuMonitorJSONHandleBlockJobCanceled(qemuMonitorPtr mon, virJSONValuePtr data);
+static void qemuMonitorJSONHandleBlockJobReady(qemuMonitorPtr mon, virJSONValuePtr data);
static void qemuMonitorJSONHandleBalloonChange(qemuMonitorPtr mon, virJSONValuePtr data);
static void qemuMonitorJSONHandlePMSuspendDisk(qemuMonitorPtr mon, virJSONValuePtr data);
{ "BLOCK_IO_ERROR", qemuMonitorJSONHandleIOError, },
{ "BLOCK_JOB_CANCELLED", qemuMonitorJSONHandleBlockJobCanceled, },
{ "BLOCK_JOB_COMPLETED", qemuMonitorJSONHandleBlockJobCompleted, },
+ { "BLOCK_JOB_READY", qemuMonitorJSONHandleBlockJobReady, },
{ "DEVICE_TRAY_MOVED", qemuMonitorJSONHandleTrayChange, },
{ "POWERDOWN", qemuMonitorJSONHandlePowerdown, },
{ "RESET", qemuMonitorJSONHandleReset, },
type = VIR_DOMAIN_BLOCK_JOB_TYPE_PULL;
else if (STREQ(type_str, "commit"))
type = VIR_DOMAIN_BLOCK_JOB_TYPE_COMMIT;
+ else if (STREQ(type_str, "mirror"))
+ type = VIR_DOMAIN_BLOCK_JOB_TYPE_COPY;
switch ((virConnectDomainEventBlockJobStatus) event) {
case VIR_DOMAIN_BLOCK_JOB_COMPLETED:
event = VIR_DOMAIN_BLOCK_JOB_FAILED;
break;
case VIR_DOMAIN_BLOCK_JOB_CANCELED:
+ case VIR_DOMAIN_BLOCK_JOB_READY:
break;
case VIR_DOMAIN_BLOCK_JOB_FAILED:
case VIR_DOMAIN_BLOCK_JOB_LAST:
- VIR_DEBUG("should not get here");
- break;
+ VIR_DEBUG("should not get here");
+ break;
}
out:
VIR_DOMAIN_BLOCK_JOB_CANCELED);
}
+static void
+qemuMonitorJSONHandleBlockJobReady(qemuMonitorPtr mon,
+ virJSONValuePtr data)
+{
+ qemuMonitorJSONHandleBlockJobImpl(mon, data,
+ VIR_DOMAIN_BLOCK_JOB_READY);
+}
+
static void
qemuMonitorJSONHandleBalloonChange(qemuMonitorPtr mon,
virJSONValuePtr data)
info->type = VIR_DOMAIN_BLOCK_JOB_TYPE_PULL;
else if (STREQ(type, "commit"))
info->type = VIR_DOMAIN_BLOCK_JOB_TYPE_COMMIT;
+ else if (STREQ(type, "mirror"))
+ info->type = VIR_DOMAIN_BLOCK_JOB_TYPE_COPY;
else
info->type = VIR_DOMAIN_BLOCK_JOB_TYPE_UNKNOWN;