mirror of
https://github.com/libvirt/libvirt.git
synced 2025-02-25 18:55:26 -06:00
qemu: Add support for compressed migration
This commit is contained in:
parent
ecfff1dab3
commit
94f59b9ece
@ -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
|
static int
|
||||||
qemuMigrationUpdateJobStatus(virQEMUDriverPtr driver,
|
qemuMigrationUpdateJobStatus(virQEMUDriverPtr driver,
|
||||||
virDomainObjPtr vm,
|
virDomainObjPtr vm,
|
||||||
@ -1704,13 +1745,16 @@ qemuMigrationPrepareAny(virQEMUDriverPtr driver,
|
|||||||
if (virFDStreamOpen(st, dataFD[1]) < 0) {
|
if (virFDStreamOpen(st, dataFD[1]) < 0) {
|
||||||
virReportSystemError(errno, "%s",
|
virReportSystemError(errno, "%s",
|
||||||
_("cannot pass pipe for tunnelled migration"));
|
_("cannot pass pipe for tunnelled migration"));
|
||||||
virDomainAuditStart(vm, "migrated", false);
|
goto stop;
|
||||||
qemuProcessStop(driver, vm, VIR_DOMAIN_SHUTOFF_FAILED, 0);
|
|
||||||
goto endjob;
|
|
||||||
}
|
}
|
||||||
dataFD[1] = -1; /* 'st' owns the FD now & will close it */
|
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) {
|
if (mig->lockState) {
|
||||||
VIR_DEBUG("Received lockstate %s", mig->lockState);
|
VIR_DEBUG("Received lockstate %s", mig->lockState);
|
||||||
VIR_FREE(priv->lockState);
|
VIR_FREE(priv->lockState);
|
||||||
@ -1776,6 +1820,10 @@ cleanup:
|
|||||||
virObjectUnref(caps);
|
virObjectUnref(caps);
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
stop:
|
||||||
|
virDomainAuditStart(vm, "migrated", false);
|
||||||
|
qemuProcessStop(driver, vm, VIR_DOMAIN_SHUTOFF_FAILED, 0);
|
||||||
|
|
||||||
endjob:
|
endjob:
|
||||||
if (!qemuMigrationJobFinish(driver, vm)) {
|
if (!qemuMigrationJobFinish(driver, vm)) {
|
||||||
vm = NULL;
|
vm = NULL;
|
||||||
@ -2255,6 +2303,11 @@ qemuMigrationRun(virQEMUDriverPtr driver,
|
|||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (flags & VIR_MIGRATE_COMPRESSED &&
|
||||||
|
qemuMigrationSetCompression(driver, vm,
|
||||||
|
QEMU_ASYNC_JOB_MIGRATION_OUT) < 0)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
if (qemuDomainObjEnterMonitorAsync(driver, vm,
|
if (qemuDomainObjEnterMonitorAsync(driver, vm,
|
||||||
QEMU_ASYNC_JOB_MIGRATION_OUT) < 0)
|
QEMU_ASYNC_JOB_MIGRATION_OUT) < 0)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
@ -37,7 +37,8 @@
|
|||||||
VIR_MIGRATE_NON_SHARED_INC | \
|
VIR_MIGRATE_NON_SHARED_INC | \
|
||||||
VIR_MIGRATE_CHANGE_PROTECTION | \
|
VIR_MIGRATE_CHANGE_PROTECTION | \
|
||||||
VIR_MIGRATE_UNSAFE | \
|
VIR_MIGRATE_UNSAFE | \
|
||||||
VIR_MIGRATE_OFFLINE)
|
VIR_MIGRATE_OFFLINE | \
|
||||||
|
VIR_MIGRATE_COMPRESSED)
|
||||||
|
|
||||||
enum qemuMigrationJobPhase {
|
enum qemuMigrationJobPhase {
|
||||||
QEMU_MIGRATION_PHASE_NONE = 0,
|
QEMU_MIGRATION_PHASE_NONE = 0,
|
||||||
|
@ -101,6 +101,10 @@ VIR_ENUM_IMPL(qemuMonitorMigrationStatus,
|
|||||||
QEMU_MONITOR_MIGRATION_STATUS_LAST,
|
QEMU_MONITOR_MIGRATION_STATUS_LAST,
|
||||||
"inactive", "active", "completed", "failed", "cancelled")
|
"inactive", "active", "completed", "failed", "cancelled")
|
||||||
|
|
||||||
|
VIR_ENUM_IMPL(qemuMonitorMigrationCaps,
|
||||||
|
QEMU_MONITOR_MIGRATION_CAPS_LAST,
|
||||||
|
"xbzrle")
|
||||||
|
|
||||||
VIR_ENUM_IMPL(qemuMonitorVMStatus,
|
VIR_ENUM_IMPL(qemuMonitorVMStatus,
|
||||||
QEMU_MONITOR_VM_STATUS_LAST,
|
QEMU_MONITOR_VM_STATUS_LAST,
|
||||||
"debug", "inmigrate", "internal-error", "io-error", "paused",
|
"debug", "inmigrate", "internal-error", "io-error", "paused",
|
||||||
@ -3383,3 +3387,45 @@ char *qemuMonitorGetTargetArch(qemuMonitorPtr mon)
|
|||||||
|
|
||||||
return qemuMonitorJSONGetTargetArch(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,
|
int qemuMonitorGetSpiceMigrationStatus(qemuMonitorPtr mon,
|
||||||
bool *spice_migrated);
|
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 {
|
typedef enum {
|
||||||
QEMU_MONITOR_MIGRATE_BACKGROUND = 1 << 0,
|
QEMU_MONITOR_MIGRATE_BACKGROUND = 1 << 0,
|
||||||
QEMU_MONITOR_MIGRATE_NON_SHARED_DISK = 1 << 1, /* migration with non-shared storage with full disk copy */
|
QEMU_MONITOR_MIGRATE_NON_SHARED_DISK = 1 << 1, /* migration with non-shared storage with full disk copy */
|
||||||
|
@ -4359,3 +4359,124 @@ cleanup:
|
|||||||
virJSONValueFree(reply);
|
virJSONValueFree(reply);
|
||||||
return ret;
|
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 *remaining,
|
||||||
unsigned long long *total);
|
unsigned long long *total);
|
||||||
|
|
||||||
|
int qemuMonitorJSONGetMigrationCapability(qemuMonitorPtr mon,
|
||||||
|
qemuMonitorMigrationCaps capability);
|
||||||
|
int qemuMonitorJSONSetMigrationCapability(qemuMonitorPtr mon,
|
||||||
|
qemuMonitorMigrationCaps capability);
|
||||||
|
|
||||||
int qemuMonitorJSONMigrate(qemuMonitorPtr mon,
|
int qemuMonitorJSONMigrate(qemuMonitorPtr mon,
|
||||||
unsigned int flags,
|
unsigned int flags,
|
||||||
const char *uri);
|
const char *uri);
|
||||||
|
Loading…
Reference in New Issue
Block a user