We need to start NBD server and feed it with all non-<shared/>,
RW and source-full disks. Moreover, with new virPortAllocator we
must ensure the borrowed port for NBD server will be returned if
either migration completes or qemu process is teared down.
---
src/qemu/qemu_migration.c | 84 ++++++++++++++++++++++++++++++++++++++++++++++-
src/qemu/qemu_process.c | 5 +++
2 files changed, 88 insertions(+), 1 deletion(-)
diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c
index 82c3f97..876e81b 100644
--- a/src/qemu/qemu_migration.c
+++ b/src/qemu/qemu_migration.c
@@ -35,6 +35,7 @@
#include "qemu_domain.h"
#include "qemu_process.h"
#include "qemu_capabilities.h"
+#include "qemu_command.h"
#include "qemu_cgroup.h"
#include "domain_audit.h"
@@ -1097,6 +1098,80 @@ error:
return NULL;
}
+/**
+ * qemuMigrationStartNBDServer:
+ * @driver: qemu driver
+ * @vm: domain
+ *
+ * Starts NBD server. This is a newer method to copy
+ * storage during migration than using 'blk' and 'inc'
+ * arguments in 'migrate' monitor command.
+ * Error is reported here.
+ *
+ * Returns 0 on success, -1 otherwise.
+ */
+static int
+qemuMigrationStartNBDServer(virQEMUDriverPtr driver,
+ virDomainObjPtr vm)
+{
+ int ret = -1;
+ qemuDomainObjPrivatePtr priv = vm->privateData;
+ unsigned short port = 0;
+ const char *listen = "0.0.0.0";
+ char *diskAlias = NULL;
+ size_t i;
+
+ for (i = 0; i < vm->def->ndisks; i++) {
+ virDomainDiskDefPtr disk = vm->def->disks[i];
+
+ /* skip shared, RO and source-less disks */
+ if (disk->shared || disk->readonly || !disk->src)
+ continue;
+
+ VIR_FREE(diskAlias);
+ if (virAsprintf(&diskAlias, "%s%s",
+ QEMU_DRIVE_HOST_PREFIX, disk->info.alias) < 0) {
+ virReportOOMError();
+ goto cleanup;
+ }
+
+ if (qemuDomainObjEnterMonitorAsync(driver, vm,
+ QEMU_ASYNC_JOB_MIGRATION_IN) < 0)
+ goto cleanup;
+
+ if (!port) {
+ if (virPortAllocatorAcquire(driver->remotePorts, &port) < 0)
+ goto cleanup;
+
+ if (qemuMonitorNBDServerStart(priv->mon, listen, port) < 0) {
+ qemuDomainObjExitMonitor(driver, vm);
+ virReportError(VIR_ERR_OPERATION_FAILED, "%s",
+ _("Unable to start nbd server"));
+ goto cleanup;
+ }
+ }
+
+ if (qemuMonitorNBDServerAdd(priv->mon, diskAlias, true) < 0) {
+ qemuDomainObjExitMonitor(driver, vm);
+
+ virReportError(VIR_ERR_OPERATION_FAILED,
+ _("Unable to add '%s' to NDB server"),
diskAlias);
+ goto cleanup;
+ }
+ qemuDomainObjExitMonitor(driver, vm);
+ }
+
+ priv->nbdPort = port;
+ ret = 0;
+
+cleanup:
+ VIR_FREE(diskAlias);
+ if (ret < 0)
+ virPortAllocatorRelease(driver->remotePorts, port);
+ return ret;
+}
+
+
/* Validate whether the domain is safe to migrate. If vm is NULL,
* then this is being run in the v2 Prepare stage on the destination
* (where we only have the target xml); if vm is provided, then this
@@ -1822,8 +1897,11 @@ done:
if (flags & VIR_MIGRATE_TUNNELLED)
VIR_DEBUG("NBD in tunnelled migration is currently not
supported");
else {
+ if (qemuMigrationStartNBDServer(driver, vm) < 0) {
+ /* error already reported */
+ goto endjob;
+ }
cookieFlags |= QEMU_MIGRATION_COOKIE_NBD;
- priv->nbdPort = 0;
}
}
@@ -1870,6 +1948,10 @@ cleanup:
virObjectUnlock(vm);
else
qemuDomainRemoveInactive(driver, vm);
+ if (ret < 0 && priv->nbdPort) {
+ virPortAllocatorRelease(driver->remotePorts, priv->nbdPort);
+ priv->nbdPort = 0;
+ }
}
if (event)
qemuDomainEventQueue(driver, event);
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
index 4251c34..e6874e2 100644
--- a/src/qemu/qemu_process.c
+++ b/src/qemu/qemu_process.c
@@ -4237,6 +4237,11 @@ void qemuProcessStop(virQEMUDriverPtr driver,
}
}
+ if (priv->nbdPort) {
+ virPortAllocatorRelease(driver->remotePorts, priv->nbdPort);
+ priv->nbdPort = 0;
+ }
+
if (priv->agent) {
qemuAgentClose(priv->agent);
priv->agent = NULL;
--
1.8.0.2