* abort with pivot; this updates the VM definition as appropriate, on
* either success or failure. */
static int
-qemuDomainBlockPivot(struct qemud_driver *driver, virDomainObjPtr vm,
+qemuDomainBlockPivot(virConnectPtr conn,
+ struct qemud_driver *driver, virDomainObjPtr vm,
const char *device, virDomainDiskDefPtr disk)
{
int ret = -1;
qemuDomainObjPrivatePtr priv = vm->privateData;
virDomainBlockJobInfo info;
const char *format = virStorageFileFormatTypeToString(disk->mirrorFormat);
+ bool resume = false;
/* Probe the status, if needed. */
if (!disk->mirroring) {
goto cleanup;
}
+ /* If we are using the older 'drive-reopen', we want to make sure
+ * that management apps can tell whether the command succeeded,
+ * even if libvirtd is restarted at the wrong time. To accomplish
+ * that, we pause the guest before drive-reopen, and resume it
+ * only when we know the outcome; if libvirtd restarts, then
+ * management will see the guest still paused, and know that no
+ * guest I/O has caused the source and mirror to diverge. XXX
+ * With the newer 'block-job-complete', we need to use a
+ * persistent bitmap to make things safe; so for now, we just
+ * blindly pause the guest. */
+ if (virDomainObjGetState(vm, NULL) == VIR_DOMAIN_RUNNING) {
+ if (qemuProcessStopCPUs(driver, vm, VIR_DOMAIN_PAUSED_SAVE,
+ QEMU_ASYNC_JOB_NONE) < 0)
+ goto cleanup;
+
+ resume = true;
+ if (!virDomainObjIsActive(vm)) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("guest unexpectedly quit"));
+ goto cleanup;
+ }
+ }
+
/* Attempt the pivot. */
qemuDomainObjEnterMonitorWithDriver(driver, vm);
ret = qemuMonitorDrivePivot(priv->mon, device, disk->mirror, format);
}
cleanup:
+ if (resume && virDomainObjIsActive(vm) &&
+ qemuProcessStartCPUs(driver, vm, conn,
+ VIR_DOMAIN_RUNNING_UNPAUSED,
+ QEMU_ASYNC_JOB_NONE) < 0 &&
+ virGetLastError() == NULL) {
+ virReportError(VIR_ERR_OPERATION_FAILED, "%s",
+ _("resuming after drive-reopen failed"));
+ }
return ret;
}
if (disk->mirror && mode == BLOCK_JOB_ABORT &&
(flags & VIR_DOMAIN_BLOCK_JOB_ABORT_PIVOT)) {
- ret = qemuDomainBlockPivot(driver, vm, device, disk);
+ ret = qemuDomainBlockPivot(dom->conn, driver, vm, device, disk);
goto endjob;
}