mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2025-01-27 18:03:50 +03: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
|
||||
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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user