提交 94f59b9e 编写于 作者: J Jiri Denemark

qemu: Add support for compressed migration

上级 ecfff1da
......@@ -1149,6 +1149,47 @@ qemuMigrationSetOffline(virQEMUDriverPtr driver,
}
static int
qemuMigrationSetCompression(virQEMUDriverPtr driver,
virDomainObjPtr vm,
enum qemuDomainAsyncJob job)
{
qemuDomainObjPrivatePtr priv = vm->privateData;
int ret;
if (qemuDomainObjEnterMonitorAsync(driver, vm, job) < 0)
return -1;
ret = qemuMonitorGetMigrationCapability(
priv->mon,
QEMU_MONITOR_MIGRATION_CAPS_XBZRLE);
if (ret < 0) {
goto cleanup;
} else if (ret == 0) {
if (job == QEMU_ASYNC_JOB_MIGRATION_IN) {
virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
_("Compressed migration is not supported by "
"target QEMU binary"));
} else {
virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
_("Compressed migration is not supported by "
"source QEMU binary"));
}
ret = -1;
goto cleanup;
}
ret = qemuMonitorSetMigrationCapability(
priv->mon,
QEMU_MONITOR_MIGRATION_CAPS_XBZRLE);
cleanup:
qemuDomainObjExitMonitor(driver, vm);
return ret;
}
static int
qemuMigrationUpdateJobStatus(virQEMUDriverPtr driver,
virDomainObjPtr vm,
......@@ -1704,13 +1745,16 @@ qemuMigrationPrepareAny(virQEMUDriverPtr driver,
if (virFDStreamOpen(st, dataFD[1]) < 0) {
virReportSystemError(errno, "%s",
_("cannot pass pipe for tunnelled migration"));
virDomainAuditStart(vm, "migrated", false);
qemuProcessStop(driver, vm, VIR_DOMAIN_SHUTOFF_FAILED, 0);
goto endjob;
goto stop;
}
dataFD[1] = -1; /* 'st' owns the FD now & will close it */
}
if (flags & VIR_MIGRATE_COMPRESSED &&
qemuMigrationSetCompression(driver, vm,
QEMU_ASYNC_JOB_MIGRATION_IN) < 0)
goto stop;
if (mig->lockState) {
VIR_DEBUG("Received lockstate %s", mig->lockState);
VIR_FREE(priv->lockState);
......@@ -1776,6 +1820,10 @@ cleanup:
virObjectUnref(caps);
return ret;
stop:
virDomainAuditStart(vm, "migrated", false);
qemuProcessStop(driver, vm, VIR_DOMAIN_SHUTOFF_FAILED, 0);
endjob:
if (!qemuMigrationJobFinish(driver, vm)) {
vm = NULL;
......@@ -2255,6 +2303,11 @@ qemuMigrationRun(virQEMUDriverPtr driver,
goto cleanup;
}
if (flags & VIR_MIGRATE_COMPRESSED &&
qemuMigrationSetCompression(driver, vm,
QEMU_ASYNC_JOB_MIGRATION_OUT) < 0)
goto cleanup;
if (qemuDomainObjEnterMonitorAsync(driver, vm,
QEMU_ASYNC_JOB_MIGRATION_OUT) < 0)
goto cleanup;
......
......@@ -37,7 +37,8 @@
VIR_MIGRATE_NON_SHARED_INC | \
VIR_MIGRATE_CHANGE_PROTECTION | \
VIR_MIGRATE_UNSAFE | \
VIR_MIGRATE_OFFLINE)
VIR_MIGRATE_OFFLINE | \
VIR_MIGRATE_COMPRESSED)
enum qemuMigrationJobPhase {
QEMU_MIGRATION_PHASE_NONE = 0,
......
......@@ -101,6 +101,10 @@ VIR_ENUM_IMPL(qemuMonitorMigrationStatus,
QEMU_MONITOR_MIGRATION_STATUS_LAST,
"inactive", "active", "completed", "failed", "cancelled")
VIR_ENUM_IMPL(qemuMonitorMigrationCaps,
QEMU_MONITOR_MIGRATION_CAPS_LAST,
"xbzrle")
VIR_ENUM_IMPL(qemuMonitorVMStatus,
QEMU_MONITOR_VM_STATUS_LAST,
"debug", "inmigrate", "internal-error", "io-error", "paused",
......@@ -3383,3 +3387,45 @@ char *qemuMonitorGetTargetArch(qemuMonitorPtr mon)
return qemuMonitorJSONGetTargetArch(mon);
}
/**
* Returns 1 if @capability is supported, 0 if it's not, or -1 on error.
*/
int qemuMonitorGetMigrationCapability(qemuMonitorPtr mon,
qemuMonitorMigrationCaps capability)
{
VIR_DEBUG("mon=%p capability=%d", mon, capability);
if (!mon) {
virReportError(VIR_ERR_INVALID_ARG, "%s",
_("monitor must not be NULL"));
return -1;
}
/* No capability is supported without JSON monitor */
if (!mon->json)
return 0;
return qemuMonitorJSONGetMigrationCapability(mon, capability);
}
int qemuMonitorSetMigrationCapability(qemuMonitorPtr mon,
qemuMonitorMigrationCaps capability)
{
VIR_DEBUG("mon=%p capability=%d", mon, capability);
if (!mon) {
virReportError(VIR_ERR_INVALID_ARG, "%s",
_("monitor must not be NULL"));
return -1;
}
if (!mon->json) {
virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
_("JSON monitor is required"));
return -1;
}
return qemuMonitorJSONSetMigrationCapability(mon, capability);
}
......@@ -346,6 +346,19 @@ int qemuMonitorGetMigrationStatus(qemuMonitorPtr mon,
int qemuMonitorGetSpiceMigrationStatus(qemuMonitorPtr mon,
bool *spice_migrated);
typedef enum {
QEMU_MONITOR_MIGRATION_CAPS_XBZRLE,
QEMU_MONITOR_MIGRATION_CAPS_LAST
} qemuMonitorMigrationCaps;
VIR_ENUM_DECL(qemuMonitorMigrationCaps);
int qemuMonitorGetMigrationCapability(qemuMonitorPtr mon,
qemuMonitorMigrationCaps capability);
int qemuMonitorSetMigrationCapability(qemuMonitorPtr mon,
qemuMonitorMigrationCaps capability);
typedef enum {
QEMU_MONITOR_MIGRATE_BACKGROUND = 1 << 0,
QEMU_MONITOR_MIGRATE_NON_SHARED_DISK = 1 << 1, /* migration with non-shared storage with full disk copy */
......
......@@ -4359,3 +4359,124 @@ cleanup:
virJSONValueFree(reply);
return ret;
}
int
qemuMonitorJSONGetMigrationCapability(qemuMonitorPtr mon,
qemuMonitorMigrationCaps capability)
{
int ret;
virJSONValuePtr cmd;
virJSONValuePtr reply = NULL;
virJSONValuePtr caps;
int i;
if (!(cmd = qemuMonitorJSONMakeCommand("query-migrate-capabilities",
NULL)))
return -1;
ret = qemuMonitorJSONCommand(mon, cmd, &reply);
if (ret == 0) {
if (qemuMonitorJSONHasError(reply, "CommandNotFound"))
goto cleanup;
ret = qemuMonitorJSONCheckError(cmd, reply);
}
if (ret < 0)
goto cleanup;
ret = -1;
caps = virJSONValueObjectGet(reply, "return");
if (!caps || caps->type != VIR_JSON_TYPE_ARRAY) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("missing migration capabilities"));
goto cleanup;
}
for (i = 0; i < virJSONValueArraySize(caps); i++) {
virJSONValuePtr cap = virJSONValueArrayGet(caps, i);
const char *name;
if (!cap || cap->type != VIR_JSON_TYPE_OBJECT) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("missing entry in migration capabilities list"));
goto cleanup;
}
if (!(name = virJSONValueObjectGetString(cap, "capability"))) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("missing migration capability name"));
goto cleanup;
}
if (qemuMonitorMigrationCapsTypeFromString(name) == capability) {
ret = 1;
goto cleanup;
}
}
ret = 0;
cleanup:
virJSONValueFree(cmd);
virJSONValueFree(reply);
return ret;
}
int
qemuMonitorJSONSetMigrationCapability(qemuMonitorPtr mon,
qemuMonitorMigrationCaps capability)
{
int ret = -1;
virJSONValuePtr cmd = NULL;
virJSONValuePtr reply = NULL;
virJSONValuePtr cap = NULL;
virJSONValuePtr caps;
if (!(caps = virJSONValueNewArray()))
goto cleanup;
if (!(cap = virJSONValueNewObject()))
goto no_memory;
if (virJSONValueObjectAppendString(
cap, "capability",
qemuMonitorMigrationCapsTypeToString(capability)) < 0)
goto no_memory;
if (virJSONValueObjectAppendBoolean(cap, "state", 1) < 0)
goto no_memory;
if (virJSONValueArrayAppend(caps, cap) < 0)
goto no_memory;
cap = NULL;
cmd = qemuMonitorJSONMakeCommand("migrate-set-capabilities",
"a:capabilities", caps,
NULL);
if (!cmd)
goto cleanup;
caps = NULL;
if ((ret = qemuMonitorJSONCommand(mon, cmd, &reply)) < 0)
goto cleanup;
ret = qemuMonitorJSONCheckError(cmd, reply);
cleanup:
virJSONValueFree(caps);
virJSONValueFree(cap);
virJSONValueFree(cmd);
virJSONValueFree(reply);
return ret;
no_memory:
virReportOOMError();
goto cleanup;
}
......@@ -126,6 +126,11 @@ int qemuMonitorJSONGetMigrationStatus(qemuMonitorPtr mon,
unsigned long long *remaining,
unsigned long long *total);
int qemuMonitorJSONGetMigrationCapability(qemuMonitorPtr mon,
qemuMonitorMigrationCaps capability);
int qemuMonitorJSONSetMigrationCapability(qemuMonitorPtr mon,
qemuMonitorMigrationCaps capability);
int qemuMonitorJSONMigrate(qemuMonitorPtr mon,
unsigned int flags,
const char *uri);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册