aboutsummaryrefslogtreecommitdiff
path: root/migration/migration.c
diff options
context:
space:
mode:
Diffstat (limited to 'migration/migration.c')
-rw-r--r--migration/migration.c268
1 files changed, 208 insertions, 60 deletions
diff --git a/migration/migration.c b/migration/migration.c
index a0db40d..7615391 100644
--- a/migration/migration.c
+++ b/migration/migration.c
@@ -102,14 +102,22 @@ enum mig_rp_message_type {
static MigrationState *current_migration;
+static bool migration_object_check(MigrationState *ms, Error **errp);
+
void migration_object_init(void)
{
MachineState *ms = MACHINE(qdev_get_machine());
+ Error *err = NULL;
/* This can only be called once. */
assert(!current_migration);
current_migration = MIGRATION_OBJ(object_new(TYPE_MIGRATION));
+ if (!migration_object_check(current_migration, &err)) {
+ error_report_err(err);
+ exit(1);
+ }
+
/*
* We cannot really do this in migration_instance_init() since at
* that time global properties are not yet applied, then this
@@ -348,6 +356,7 @@ static void process_incoming_migration_co(void *opaque)
migrate_set_state(&mis->state, MIGRATION_STATUS_ACTIVE,
MIGRATION_STATUS_FAILED);
error_report("load of migration failed: %s", strerror(-ret));
+ qemu_fclose(mis->from_src_file);
exit(EXIT_FAILURE);
}
mis->bh = qemu_bh_new(process_incoming_migration_bh, mis);
@@ -403,9 +412,6 @@ MigrationCapabilityStatusList *qmp_query_migrate_capabilities(Error **errp)
continue;
}
#endif
- if (i == MIGRATION_CAPABILITY_X_COLO && !colo_supported()) {
- continue;
- }
if (head == NULL) {
head = g_malloc0(sizeof(*caps));
caps = head;
@@ -582,51 +588,49 @@ MigrationInfo *qmp_query_migrate(Error **errp)
return info;
}
-void qmp_migrate_set_capabilities(MigrationCapabilityStatusList *params,
- Error **errp)
+/**
+ * @migration_caps_check - check capability validity
+ *
+ * @cap_list: old capability list, array of bool
+ * @params: new capabilities to be applied soon
+ * @errp: set *errp if the check failed, with reason
+ *
+ * Returns true if check passed, otherwise false.
+ */
+static bool migrate_caps_check(bool *cap_list,
+ MigrationCapabilityStatusList *params,
+ Error **errp)
{
- MigrationState *s = migrate_get_current();
MigrationCapabilityStatusList *cap;
- bool old_postcopy_cap = migrate_postcopy_ram();
+ bool old_postcopy_cap;
- if (migration_is_setup_or_active(s->state)) {
- error_setg(errp, QERR_MIGRATION_ACTIVE);
- return;
- }
+ old_postcopy_cap = cap_list[MIGRATION_CAPABILITY_POSTCOPY_RAM];
for (cap = params; cap; cap = cap->next) {
+ cap_list[cap->value->capability] = cap->value->state;
+ }
+
#ifndef CONFIG_LIVE_BLOCK_MIGRATION
- if (cap->value->capability == MIGRATION_CAPABILITY_BLOCK
- && cap->value->state) {
- error_setg(errp, "QEMU compiled without old-style (blk/-b, inc/-i) "
- "block migration");
- error_append_hint(errp, "Use drive_mirror+NBD instead.\n");
- continue;
- }
-#endif
- if (cap->value->capability == MIGRATION_CAPABILITY_X_COLO) {
- if (!colo_supported()) {
- error_setg(errp, "COLO is not currently supported, please"
- " configure with --enable-colo option in order to"
- " support COLO feature");
- continue;
- }
- }
- s->enabled_capabilities[cap->value->capability] = cap->value->state;
+ if (cap_list[MIGRATION_CAPABILITY_BLOCK]) {
+ error_setg(errp, "QEMU compiled without old-style (blk/-b, inc/-i) "
+ "block migration");
+ error_append_hint(errp, "Use drive_mirror+NBD instead.\n");
+ return false;
}
+#endif
- if (migrate_postcopy_ram()) {
- if (migrate_use_compression()) {
+ if (cap_list[MIGRATION_CAPABILITY_POSTCOPY_RAM]) {
+ if (cap_list[MIGRATION_CAPABILITY_COMPRESS]) {
/* The decompression threads asynchronously write into RAM
* rather than use the atomic copies needed to avoid
* userfaulting. It should be possible to fix the decompression
* threads for compatibility in future.
*/
- error_report("Postcopy is not currently compatible with "
- "compression");
- s->enabled_capabilities[MIGRATION_CAPABILITY_POSTCOPY_RAM] =
- false;
+ error_setg(errp, "Postcopy is not currently compatible "
+ "with compression");
+ return false;
}
+
/* This check is reasonably expensive, so only when it's being
* set the first time, also it's only the destination that needs
* special support.
@@ -636,96 +640,141 @@ void qmp_migrate_set_capabilities(MigrationCapabilityStatusList *params,
/* postcopy_ram_supported_by_host will have emitted a more
* detailed message
*/
- error_report("Postcopy is not supported");
- s->enabled_capabilities[MIGRATION_CAPABILITY_POSTCOPY_RAM] =
- false;
+ error_setg(errp, "Postcopy is not supported");
+ return false;
}
}
+
+ return true;
}
-void qmp_migrate_set_parameters(MigrationParameters *params, Error **errp)
+void qmp_migrate_set_capabilities(MigrationCapabilityStatusList *params,
+ Error **errp)
{
MigrationState *s = migrate_get_current();
+ MigrationCapabilityStatusList *cap;
+ if (migration_is_setup_or_active(s->state)) {
+ error_setg(errp, QERR_MIGRATION_ACTIVE);
+ return;
+ }
+
+ if (!migrate_caps_check(s->enabled_capabilities, params, errp)) {
+ return;
+ }
+
+ for (cap = params; cap; cap = cap->next) {
+ s->enabled_capabilities[cap->value->capability] = cap->value->state;
+ }
+}
+
+/*
+ * Check whether the parameters are valid. Error will be put into errp
+ * (if provided). Return true if valid, otherwise false.
+ */
+static bool migrate_params_check(MigrationParameters *params, Error **errp)
+{
if (params->has_compress_level &&
(params->compress_level < 0 || params->compress_level > 9)) {
error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "compress_level",
"is invalid, it should be in the range of 0 to 9");
- return;
+ return false;
}
+
if (params->has_compress_threads &&
(params->compress_threads < 1 || params->compress_threads > 255)) {
error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
"compress_threads",
"is invalid, it should be in the range of 1 to 255");
- return;
+ return false;
}
+
if (params->has_decompress_threads &&
(params->decompress_threads < 1 || params->decompress_threads > 255)) {
error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
"decompress_threads",
"is invalid, it should be in the range of 1 to 255");
- return;
+ return false;
}
+
if (params->has_cpu_throttle_initial &&
(params->cpu_throttle_initial < 1 ||
params->cpu_throttle_initial > 99)) {
error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
"cpu_throttle_initial",
"an integer in the range of 1 to 99");
- return;
+ return false;
}
+
if (params->has_cpu_throttle_increment &&
(params->cpu_throttle_increment < 1 ||
params->cpu_throttle_increment > 99)) {
error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
"cpu_throttle_increment",
"an integer in the range of 1 to 99");
- return;
+ return false;
}
+
if (params->has_max_bandwidth &&
(params->max_bandwidth < 0 || params->max_bandwidth > SIZE_MAX)) {
error_setg(errp, "Parameter 'max_bandwidth' expects an integer in the"
" range of 0 to %zu bytes/second", SIZE_MAX);
- return;
+ return false;
}
+
if (params->has_downtime_limit &&
(params->downtime_limit < 0 ||
params->downtime_limit > MAX_MIGRATE_DOWNTIME)) {
error_setg(errp, "Parameter 'downtime_limit' expects an integer in "
"the range of 0 to %d milliseconds",
MAX_MIGRATE_DOWNTIME);
- return;
+ return false;
}
+
if (params->has_x_checkpoint_delay && (params->x_checkpoint_delay < 0)) {
error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
"x_checkpoint_delay",
"is invalid, it should be positive");
+ return false;
}
+ return true;
+}
+
+static void migrate_params_apply(MigrationParameters *params)
+{
+ MigrationState *s = migrate_get_current();
+
if (params->has_compress_level) {
s->parameters.compress_level = params->compress_level;
}
+
if (params->has_compress_threads) {
s->parameters.compress_threads = params->compress_threads;
}
+
if (params->has_decompress_threads) {
s->parameters.decompress_threads = params->decompress_threads;
}
+
if (params->has_cpu_throttle_initial) {
s->parameters.cpu_throttle_initial = params->cpu_throttle_initial;
}
+
if (params->has_cpu_throttle_increment) {
s->parameters.cpu_throttle_increment = params->cpu_throttle_increment;
}
+
if (params->has_tls_creds) {
g_free(s->parameters.tls_creds);
s->parameters.tls_creds = g_strdup(params->tls_creds);
}
+
if (params->has_tls_hostname) {
g_free(s->parameters.tls_hostname);
s->parameters.tls_hostname = g_strdup(params->tls_hostname);
}
+
if (params->has_max_bandwidth) {
s->parameters.max_bandwidth = params->max_bandwidth;
if (s->to_dst_file) {
@@ -733,6 +782,7 @@ void qmp_migrate_set_parameters(MigrationParameters *params, Error **errp)
s->parameters.max_bandwidth / XFER_LIMIT_RATIO);
}
}
+
if (params->has_downtime_limit) {
s->parameters.downtime_limit = params->downtime_limit;
}
@@ -743,11 +793,22 @@ void qmp_migrate_set_parameters(MigrationParameters *params, Error **errp)
colo_checkpoint_notify(s);
}
}
+
if (params->has_block_incremental) {
s->parameters.block_incremental = params->block_incremental;
}
}
+void qmp_migrate_set_parameters(MigrationParameters *params, Error **errp)
+{
+ if (!migrate_params_check(params, errp)) {
+ /* Invalid parameter */
+ return;
+ }
+
+ migrate_params_apply(params);
+}
+
void qmp_migrate_start_postcopy(Error **errp)
{
@@ -781,14 +842,27 @@ void migrate_set_state(int *state, int old_state, int new_state)
}
}
-void migrate_set_block_enabled(bool value, Error **errp)
+static MigrationCapabilityStatusList *migrate_cap_add(
+ MigrationCapabilityStatusList *list,
+ MigrationCapability index,
+ bool state)
{
MigrationCapabilityStatusList *cap;
cap = g_new0(MigrationCapabilityStatusList, 1);
cap->value = g_new0(MigrationCapabilityStatus, 1);
- cap->value->capability = MIGRATION_CAPABILITY_BLOCK;
- cap->value->state = value;
+ cap->value->capability = index;
+ cap->value->state = state;
+ cap->next = list;
+
+ return cap;
+}
+
+void migrate_set_block_enabled(bool value, Error **errp)
+{
+ MigrationCapabilityStatusList *cap;
+
+ cap = migrate_cap_add(NULL, MIGRATION_CAPABILITY_BLOCK, value);
qmp_migrate_set_capabilities(cap, errp);
qapi_free_MigrationCapabilityStatusList(cap);
}
@@ -2001,6 +2075,9 @@ void migration_global_dump(Monitor *mon)
ms->send_configuration, ms->send_section_footer);
}
+#define DEFINE_PROP_MIG_CAP(name, x) \
+ DEFINE_PROP_BOOL(name, MigrationState, enabled_capabilities[x], false)
+
static Property migration_properties[] = {
DEFINE_PROP_BOOL("store-global-state", MigrationState,
store_global_state, true),
@@ -2009,6 +2086,45 @@ static Property migration_properties[] = {
send_configuration, true),
DEFINE_PROP_BOOL("send-section-footer", MigrationState,
send_section_footer, true),
+
+ /* Migration parameters */
+ DEFINE_PROP_INT64("x-compress-level", MigrationState,
+ parameters.compress_level,
+ DEFAULT_MIGRATE_COMPRESS_LEVEL),
+ DEFINE_PROP_INT64("x-compress-threads", MigrationState,
+ parameters.compress_threads,
+ DEFAULT_MIGRATE_COMPRESS_THREAD_COUNT),
+ DEFINE_PROP_INT64("x-decompress-threads", MigrationState,
+ parameters.decompress_threads,
+ DEFAULT_MIGRATE_DECOMPRESS_THREAD_COUNT),
+ DEFINE_PROP_INT64("x-cpu-throttle-initial", MigrationState,
+ parameters.cpu_throttle_initial,
+ DEFAULT_MIGRATE_CPU_THROTTLE_INITIAL),
+ DEFINE_PROP_INT64("x-cpu-throttle-increment", MigrationState,
+ parameters.cpu_throttle_increment,
+ DEFAULT_MIGRATE_CPU_THROTTLE_INCREMENT),
+ DEFINE_PROP_INT64("x-max-bandwidth", MigrationState,
+ parameters.max_bandwidth, MAX_THROTTLE),
+ DEFINE_PROP_INT64("x-downtime-limit", MigrationState,
+ parameters.downtime_limit,
+ DEFAULT_MIGRATE_SET_DOWNTIME),
+ DEFINE_PROP_INT64("x-checkpoint-delay", MigrationState,
+ parameters.x_checkpoint_delay,
+ DEFAULT_MIGRATE_X_CHECKPOINT_DELAY),
+
+ /* Migration capabilities */
+ DEFINE_PROP_MIG_CAP("x-xbzrle", MIGRATION_CAPABILITY_XBZRLE),
+ DEFINE_PROP_MIG_CAP("x-rdma-pin-all", MIGRATION_CAPABILITY_RDMA_PIN_ALL),
+ DEFINE_PROP_MIG_CAP("x-auto-converge", MIGRATION_CAPABILITY_AUTO_CONVERGE),
+ DEFINE_PROP_MIG_CAP("x-zero-blocks", MIGRATION_CAPABILITY_ZERO_BLOCKS),
+ DEFINE_PROP_MIG_CAP("x-compress", MIGRATION_CAPABILITY_COMPRESS),
+ DEFINE_PROP_MIG_CAP("x-events", MIGRATION_CAPABILITY_EVENTS),
+ DEFINE_PROP_MIG_CAP("x-postcopy-ram", MIGRATION_CAPABILITY_POSTCOPY_RAM),
+ DEFINE_PROP_MIG_CAP("x-colo", MIGRATION_CAPABILITY_X_COLO),
+ DEFINE_PROP_MIG_CAP("x-release-ram", MIGRATION_CAPABILITY_RELEASE_RAM),
+ DEFINE_PROP_MIG_CAP("x-block", MIGRATION_CAPABILITY_BLOCK),
+ DEFINE_PROP_MIG_CAP("x-return-path", MIGRATION_CAPABILITY_RETURN_PATH),
+
DEFINE_PROP_END_OF_LIST(),
};
@@ -2023,22 +2139,54 @@ static void migration_class_init(ObjectClass *klass, void *data)
static void migration_instance_init(Object *obj)
{
MigrationState *ms = MIGRATION_OBJ(obj);
+ MigrationParameters *params = &ms->parameters;
ms->state = MIGRATION_STATUS_NONE;
ms->xbzrle_cache_size = DEFAULT_MIGRATE_CACHE_SIZE;
ms->mbps = -1;
- ms->parameters = (MigrationParameters) {
- .compress_level = DEFAULT_MIGRATE_COMPRESS_LEVEL,
- .compress_threads = DEFAULT_MIGRATE_COMPRESS_THREAD_COUNT,
- .decompress_threads = DEFAULT_MIGRATE_DECOMPRESS_THREAD_COUNT,
- .cpu_throttle_initial = DEFAULT_MIGRATE_CPU_THROTTLE_INITIAL,
- .cpu_throttle_increment = DEFAULT_MIGRATE_CPU_THROTTLE_INCREMENT,
- .max_bandwidth = MAX_THROTTLE,
- .downtime_limit = DEFAULT_MIGRATE_SET_DOWNTIME,
- .x_checkpoint_delay = DEFAULT_MIGRATE_X_CHECKPOINT_DELAY,
- };
- ms->parameters.tls_creds = g_strdup("");
- ms->parameters.tls_hostname = g_strdup("");
+
+ params->tls_hostname = g_strdup("");
+ params->tls_creds = g_strdup("");
+
+ /* Set has_* up only for parameter checks */
+ params->has_compress_level = true;
+ params->has_compress_threads = true;
+ params->has_decompress_threads = true;
+ params->has_cpu_throttle_initial = true;
+ params->has_cpu_throttle_increment = true;
+ params->has_max_bandwidth = true;
+ params->has_downtime_limit = true;
+ params->has_x_checkpoint_delay = true;
+ params->has_block_incremental = true;
+}
+
+/*
+ * Return true if check pass, false otherwise. Error will be put
+ * inside errp if provided.
+ */
+static bool migration_object_check(MigrationState *ms, Error **errp)
+{
+ MigrationCapabilityStatusList *head = NULL;
+ /* Assuming all off */
+ bool cap_list[MIGRATION_CAPABILITY__MAX] = { 0 }, ret;
+ int i;
+
+ if (!migrate_params_check(&ms->parameters, errp)) {
+ return false;
+ }
+
+ for (i = 0; i < MIGRATION_CAPABILITY__MAX; i++) {
+ if (ms->enabled_capabilities[i]) {
+ head = migrate_cap_add(head, i, true);
+ }
+ }
+
+ ret = migrate_caps_check(cap_list, head, errp);
+
+ /* It works with head == NULL */
+ qapi_free_MigrationCapabilityStatusList(head);
+
+ return ret;
}
static const TypeInfo migration_type = {