Rewrite the doTunnelSendAll method so that it will process
job signals, and periodically ask QEMU for updated job status
* src/qemu/qemu_migration.c: Honour job signals/status during
tunnelled migration
---
src/qemu/qemu_migration.c | 72 +++++++++++++++++++++++++++++++++++++++++---
1 files changed, 67 insertions(+), 5 deletions(-)
diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c
index 3cff4d7..4fb4c83 100644
--- a/src/qemu/qemu_migration.c
+++ b/src/qemu/qemu_migration.c
@@ -1299,11 +1299,16 @@ cleanup:
#define TUNNEL_SEND_BUF_SIZE 65536
-static int doTunnelSendAll(virStreamPtr st,
+static int doTunnelSendAll(struct qemud_driver *driver,
+ virDomainObjPtr vm,
+ virStreamPtr st,
int sock)
{
+ qemuDomainObjPrivatePtr priv = vm->privateData;
char *buffer;
int nbytes = TUNNEL_SEND_BUF_SIZE;
+ struct timeval now, then;
+ unsigned long long delta;
if (VIR_ALLOC_N(buffer, TUNNEL_SEND_BUF_SIZE) < 0) {
virReportOOMError();
@@ -1311,13 +1316,28 @@ static int doTunnelSendAll(virStreamPtr st,
return -1;
}
- /* XXX should honour the 'resource' parameter here */
- for (;;) {
+ if (gettimeofday(&then, NULL) < 0) {
+ virReportSystemError(errno, "%s",
+ _("cannot get time of day"));
+ virStreamAbort(st);
+ return -1;
+ }
+
+ priv->jobInfo.type = VIR_DOMAIN_JOB_UNBOUNDED;
+
+ while (priv->jobInfo.type == VIR_DOMAIN_JOB_UNBOUNDED) {
+ virDomainObjUnlock(vm);
+ qemuDriverUnlock(driver);
nbytes = saferead(sock, buffer, nbytes);
+ qemuDriverLock(driver);
+ virDomainObjLock(vm);
+
if (nbytes < 0) {
virReportSystemError(errno, "%s",
_("tunnelled migration failed to read from
qemu"));
+ qemuDomainObjEnterRemoteWithDriver(driver, vm);
virStreamAbort(st);
+ qemuDomainObjExitRemoteWithDriver(driver, vm);
VIR_FREE(buffer);
return -1;
}
@@ -1325,19 +1345,56 @@ static int doTunnelSendAll(virStreamPtr st,
/* EOF; get out of here */
break;
+ qemuDomainObjEnterRemoteWithDriver(driver, vm);
if (virStreamSend(st, buffer, nbytes) < 0) {
+ qemuDomainObjExitRemoteWithDriver(driver, vm);
qemuReportError(VIR_ERR_OPERATION_FAILED, "%s",
_("Failed to write migration data to remote
libvirtd"));
VIR_FREE(buffer);
return -1;
}
+ qemuDomainObjExitRemoteWithDriver(driver, vm);
+
+ /* Process job signals on every loop */
+ if (qemuMigrationProcessJobSignals(driver, vm, "migration job") < 0)
{
+ virStreamAbort(st);
+ return -1;
+ }
+
+
+ if (gettimeofday(&now, NULL) < 0) {
+ priv->jobInfo.type = VIR_DOMAIN_JOB_FAILED;
+ virReportSystemError(errno, "%s",
+ _("cannot get time of day"));
+ virStreamAbort(st);
+ return -1;
+ }
+
+ delta = ((now.tv_sec * 1000ull) + (now.tv_usec / 1000ull)) -
+ ((then.tv_sec * 1000ull) + (then.tv_usec / 1000ull));
+
+ /* Only update QEMU monitor status once a second, since we
+ * detect failure quickly enough already, via the EOF on the
+ * pipe we're reading from */
+ if (delta > 1000) {
+ then = now;
+
+ if (qemuMigrationUpdateJobStatus(driver, vm, "migration job") <
0) {
+ virStreamAbort(st);
+ return -1;
+ }
+ }
}
VIR_FREE(buffer);
- if (virStreamFinish(st) < 0)
+ qemuDomainObjEnterRemoteWithDriver(driver, vm);
+ if (virStreamFinish(st) < 0) {
+ qemuDomainObjExitRemoteWithDriver(driver, vm);
/* virStreamFinish set the error for us */
return -1;
+ }
+ qemuDomainObjExitRemoteWithDriver(driver, vm);
return 0;
}
@@ -1434,6 +1491,11 @@ static int doTunnelMigrate(struct qemud_driver *driver,
/* 3. start migration on source */
qemuDomainObjEnterMonitorWithDriver(driver, vm);
+ if (resource > 0 &&
+ qemuMonitorSetMigrationSpeed(priv->mon, resource) < 0) {
+ qemuDomainObjExitMonitorWithDriver(driver, vm);
+ goto cleanup;
+ }
if (flags & VIR_MIGRATE_NON_SHARED_DISK)
background_flags |= QEMU_MONITOR_MIGRATE_NON_SHARED_DISK;
@@ -1495,7 +1557,7 @@ static int doTunnelMigrate(struct qemud_driver *driver,
goto cancel;
}
- ret = doTunnelSendAll(st, client_sock);
+ ret = doTunnelSendAll(driver, vm, st, client_sock);
if (ret == 0 &&
qemuMigrationBakeCookie(mig, driver, vm, cookieout, cookieoutlen, 0) < 0)
--
1.7.4.4