Merge tag 'migration-20230426-pull-request' of https://gitlab.com/juan.quintela/qemu into staging
Migration Pull request (take2)
With respect to the last PULL request:
- fix compilation on hosts without userfaultd.
Please, apply.
# -----BEGIN PGP SIGNATURE-----
#
# iQIzBAABCAAdFiEEGJn/jt6/WMzuA0uC9IfvGFhy1yMFAmRKMYYACgkQ9IfvGFhy
# 1yNoIBAAu4nyERXe7LuRcG02mXQ7N8NtKJXxlhvFGivmlZEzPPkI/SKSXVmzP47E
# uIq1+N+3couYlIof6mY3sjVDwv9Rk7AaGUNUsGv5ygLbXEd/3/qBnqcGV9pUBr3e
# Ls07l2bdb6QPSUGEfu3YATrYzEvWQOAA6AHEBJeqplPlIprgUM3qTlX3bSXrBb26
# J7+p+6A3xdH2koCwmBcWt7cO6IzM7t8pazOS+rJepFri/ZD9aVNr7E3QjXgMUeCs
# 4htBrFaCEXzb80n8O7yPCk90ei0PvGiYBdxI2MGCAy96MN0I5rfMLC/DDFQ+uMH2
# wMVpB5S5YiKrCkoP/ftiYZsSmfRMmQD9aVS6YHR8yt82kEbz616lkXIpvC5Zeads
# J9zTmFuI6fdaF/2PEDzFUACz3YDMtlqQZqKy+e9Ca8gVeoX+ZL4e5yQGNe5nx4BN
# wMr7tPjZenXUpDhuDMcw3/APqaPPZIPVKwYwSgiEL3mqVpU67pre5F4phERCVVVu
# GP/h9yhRa+dkBVNtkqIkK48vQvr7XXisukwSCWmFDA9kfDyDolN6IDaIjv5B7TdL
# DOAW+oz+O4QLVHQhbiQN9WGIc2OenhpKOJ9Rd6cUph6s9tBppaJTrTRRBTYNwPLv
# 8X5h/e7Q1Ee8xGWI1RhAsmD54/e8bu8zxczgf9iMIT8GskLoPco=
# =Ye0/
# -----END PGP SIGNATURE-----
# gpg: Signature made Thu 27 Apr 2023 09:25:42 AM BST
# gpg: using RSA key 1899FF8EDEBF58CCEE034B82F487EF185872D723
# gpg: Good signature from "Juan Quintela <quintela@redhat.com>" [undefined]
# gpg: aka "Juan Quintela <quintela@trasno.org>" [undefined]
# gpg: WARNING: This key is not certified with a trusted signature!
# gpg: There is no indication that the signature belongs to the owner.
# Primary key fingerprint: 1899 FF8E DEBF 58CC EE03 4B82 F487 EF18 5872 D723
* tag 'migration-20230426-pull-request' of https://gitlab.com/juan.quintela/qemu:
vmstate-static-checker: Recognize "num" field
migration/vmstate-dump: Dump array size too as "num"
migration: Allow postcopy_ram_supported_by_host() to report err
migration: Move qmp_migrate_set_parameters() to options.c
migration: Move migrate_use_tls() to options.c
MAINTAINERS: Add Leonardo and Peter as reviewers
migration: Disable postcopy + multifd migration
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
diff --git a/MAINTAINERS b/MAINTAINERS
index fc225e6..a8b942d 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -3154,6 +3154,8 @@
Migration
M: Juan Quintela <quintela@redhat.com>
+R: Peter Xu <peterx@redhat.com>
+R: Leonardo Bras <leobras@redhat.com>
S: Maintained
F: hw/core/vmstate-if.c
F: include/hw/vmstate-if.h
diff --git a/migration/migration.c b/migration/migration.c
index 53dd59f..22e8586 100644
--- a/migration/migration.c
+++ b/migration/migration.c
@@ -67,19 +67,10 @@
#define MAX_THROTTLE (128 << 20) /* Migration transfer speed throttling */
-/* Amount of time to allocate to each "chunk" of bandwidth-throttled
- * data. */
-#define BUFFER_DELAY 100
-#define XFER_LIMIT_RATIO (1000 / BUFFER_DELAY)
-
/* Time in milliseconds we are allowed to stop the source,
* for sending the last part */
#define DEFAULT_MIGRATE_SET_DOWNTIME 300
-/* Maximum migrate downtime set to 2000 seconds */
-#define MAX_MIGRATE_DOWNTIME_SECONDS 2000
-#define MAX_MIGRATE_DOWNTIME (MAX_MIGRATE_DOWNTIME_SECONDS * 1000)
-
/* Default compression thread count */
#define DEFAULT_MIGRATE_COMPRESS_THREAD_COUNT 8
/* Default decompression thread count, usually decompression is at
@@ -1140,417 +1131,6 @@
return info;
}
-/*
- * 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 > 9)) {
- error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "compress_level",
- "a value between 0 and 9");
- return false;
- }
-
- if (params->has_compress_threads && (params->compress_threads < 1)) {
- error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
- "compress_threads",
- "a value between 1 and 255");
- return false;
- }
-
- if (params->has_decompress_threads && (params->decompress_threads < 1)) {
- error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
- "decompress_threads",
- "a value between 1 and 255");
- return false;
- }
-
- if (params->has_throttle_trigger_threshold &&
- (params->throttle_trigger_threshold < 1 ||
- params->throttle_trigger_threshold > 100)) {
- error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
- "throttle_trigger_threshold",
- "an integer in the range of 1 to 100");
- 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 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 false;
- }
-
- if (params->has_max_bandwidth && (params->max_bandwidth > SIZE_MAX)) {
- error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
- "max_bandwidth",
- "an integer in the range of 0 to "stringify(SIZE_MAX)
- " bytes/second");
- return false;
- }
-
- if (params->has_downtime_limit &&
- (params->downtime_limit > MAX_MIGRATE_DOWNTIME)) {
- error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
- "downtime_limit",
- "an integer in the range of 0 to "
- stringify(MAX_MIGRATE_DOWNTIME)" ms");
- return false;
- }
-
- /* x_checkpoint_delay is now always positive */
-
- if (params->has_multifd_channels && (params->multifd_channels < 1)) {
- error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
- "multifd_channels",
- "a value between 1 and 255");
- return false;
- }
-
- if (params->has_multifd_zlib_level &&
- (params->multifd_zlib_level > 9)) {
- error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "multifd_zlib_level",
- "a value between 0 and 9");
- return false;
- }
-
- if (params->has_multifd_zstd_level &&
- (params->multifd_zstd_level > 20)) {
- error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "multifd_zstd_level",
- "a value between 0 and 20");
- return false;
- }
-
- if (params->has_xbzrle_cache_size &&
- (params->xbzrle_cache_size < qemu_target_page_size() ||
- !is_power_of_2(params->xbzrle_cache_size))) {
- error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
- "xbzrle_cache_size",
- "a power of two no less than the target page size");
- return false;
- }
-
- if (params->has_max_cpu_throttle &&
- (params->max_cpu_throttle < params->cpu_throttle_initial ||
- params->max_cpu_throttle > 99)) {
- error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
- "max_cpu_throttle",
- "an integer in the range of cpu_throttle_initial to 99");
- return false;
- }
-
- if (params->has_announce_initial &&
- params->announce_initial > 100000) {
- error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
- "announce_initial",
- "a value between 0 and 100000");
- return false;
- }
- if (params->has_announce_max &&
- params->announce_max > 100000) {
- error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
- "announce_max",
- "a value between 0 and 100000");
- return false;
- }
- if (params->has_announce_rounds &&
- params->announce_rounds > 1000) {
- error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
- "announce_rounds",
- "a value between 0 and 1000");
- return false;
- }
- if (params->has_announce_step &&
- (params->announce_step < 1 ||
- params->announce_step > 10000)) {
- error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
- "announce_step",
- "a value between 0 and 10000");
- return false;
- }
-
- if (params->has_block_bitmap_mapping &&
- !check_dirty_bitmap_mig_alias_map(params->block_bitmap_mapping, errp)) {
- error_prepend(errp, "Invalid mapping given for block-bitmap-mapping: ");
- return false;
- }
-
-#ifdef CONFIG_LINUX
- if (migrate_zero_copy_send() &&
- ((params->has_multifd_compression && params->multifd_compression) ||
- (params->tls_creds && *params->tls_creds))) {
- error_setg(errp,
- "Zero copy only available for non-compressed non-TLS multifd migration");
- return false;
- }
-#endif
-
- return true;
-}
-
-static void migrate_params_test_apply(MigrateSetParameters *params,
- MigrationParameters *dest)
-{
- *dest = migrate_get_current()->parameters;
-
- /* TODO use QAPI_CLONE() instead of duplicating it inline */
-
- if (params->has_compress_level) {
- dest->compress_level = params->compress_level;
- }
-
- if (params->has_compress_threads) {
- dest->compress_threads = params->compress_threads;
- }
-
- if (params->has_compress_wait_thread) {
- dest->compress_wait_thread = params->compress_wait_thread;
- }
-
- if (params->has_decompress_threads) {
- dest->decompress_threads = params->decompress_threads;
- }
-
- if (params->has_throttle_trigger_threshold) {
- dest->throttle_trigger_threshold = params->throttle_trigger_threshold;
- }
-
- if (params->has_cpu_throttle_initial) {
- dest->cpu_throttle_initial = params->cpu_throttle_initial;
- }
-
- if (params->has_cpu_throttle_increment) {
- dest->cpu_throttle_increment = params->cpu_throttle_increment;
- }
-
- if (params->has_cpu_throttle_tailslow) {
- dest->cpu_throttle_tailslow = params->cpu_throttle_tailslow;
- }
-
- if (params->tls_creds) {
- assert(params->tls_creds->type == QTYPE_QSTRING);
- dest->tls_creds = params->tls_creds->u.s;
- }
-
- if (params->tls_hostname) {
- assert(params->tls_hostname->type == QTYPE_QSTRING);
- dest->tls_hostname = params->tls_hostname->u.s;
- }
-
- if (params->has_max_bandwidth) {
- dest->max_bandwidth = params->max_bandwidth;
- }
-
- if (params->has_downtime_limit) {
- dest->downtime_limit = params->downtime_limit;
- }
-
- if (params->has_x_checkpoint_delay) {
- dest->x_checkpoint_delay = params->x_checkpoint_delay;
- }
-
- if (params->has_block_incremental) {
- dest->block_incremental = params->block_incremental;
- }
- if (params->has_multifd_channels) {
- dest->multifd_channels = params->multifd_channels;
- }
- if (params->has_multifd_compression) {
- dest->multifd_compression = params->multifd_compression;
- }
- if (params->has_xbzrle_cache_size) {
- dest->xbzrle_cache_size = params->xbzrle_cache_size;
- }
- if (params->has_max_postcopy_bandwidth) {
- dest->max_postcopy_bandwidth = params->max_postcopy_bandwidth;
- }
- if (params->has_max_cpu_throttle) {
- dest->max_cpu_throttle = params->max_cpu_throttle;
- }
- if (params->has_announce_initial) {
- dest->announce_initial = params->announce_initial;
- }
- if (params->has_announce_max) {
- dest->announce_max = params->announce_max;
- }
- if (params->has_announce_rounds) {
- dest->announce_rounds = params->announce_rounds;
- }
- if (params->has_announce_step) {
- dest->announce_step = params->announce_step;
- }
-
- if (params->has_block_bitmap_mapping) {
- dest->has_block_bitmap_mapping = true;
- dest->block_bitmap_mapping = params->block_bitmap_mapping;
- }
-}
-
-static void migrate_params_apply(MigrateSetParameters *params, Error **errp)
-{
- MigrationState *s = migrate_get_current();
-
- /* TODO use QAPI_CLONE() instead of duplicating it inline */
-
- 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_compress_wait_thread) {
- s->parameters.compress_wait_thread = params->compress_wait_thread;
- }
-
- if (params->has_decompress_threads) {
- s->parameters.decompress_threads = params->decompress_threads;
- }
-
- if (params->has_throttle_trigger_threshold) {
- s->parameters.throttle_trigger_threshold = params->throttle_trigger_threshold;
- }
-
- 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_cpu_throttle_tailslow) {
- s->parameters.cpu_throttle_tailslow = params->cpu_throttle_tailslow;
- }
-
- if (params->tls_creds) {
- g_free(s->parameters.tls_creds);
- assert(params->tls_creds->type == QTYPE_QSTRING);
- s->parameters.tls_creds = g_strdup(params->tls_creds->u.s);
- }
-
- if (params->tls_hostname) {
- g_free(s->parameters.tls_hostname);
- assert(params->tls_hostname->type == QTYPE_QSTRING);
- s->parameters.tls_hostname = g_strdup(params->tls_hostname->u.s);
- }
-
- if (params->tls_authz) {
- g_free(s->parameters.tls_authz);
- assert(params->tls_authz->type == QTYPE_QSTRING);
- s->parameters.tls_authz = g_strdup(params->tls_authz->u.s);
- }
-
- if (params->has_max_bandwidth) {
- s->parameters.max_bandwidth = params->max_bandwidth;
- if (s->to_dst_file && !migration_in_postcopy()) {
- qemu_file_set_rate_limit(s->to_dst_file,
- s->parameters.max_bandwidth / XFER_LIMIT_RATIO);
- }
- }
-
- if (params->has_downtime_limit) {
- s->parameters.downtime_limit = params->downtime_limit;
- }
-
- if (params->has_x_checkpoint_delay) {
- s->parameters.x_checkpoint_delay = params->x_checkpoint_delay;
- if (migration_in_colo_state()) {
- colo_checkpoint_notify(s);
- }
- }
-
- if (params->has_block_incremental) {
- s->parameters.block_incremental = params->block_incremental;
- }
- if (params->has_multifd_channels) {
- s->parameters.multifd_channels = params->multifd_channels;
- }
- if (params->has_multifd_compression) {
- s->parameters.multifd_compression = params->multifd_compression;
- }
- if (params->has_xbzrle_cache_size) {
- s->parameters.xbzrle_cache_size = params->xbzrle_cache_size;
- xbzrle_cache_resize(params->xbzrle_cache_size, errp);
- }
- if (params->has_max_postcopy_bandwidth) {
- s->parameters.max_postcopy_bandwidth = params->max_postcopy_bandwidth;
- if (s->to_dst_file && migration_in_postcopy()) {
- qemu_file_set_rate_limit(s->to_dst_file,
- s->parameters.max_postcopy_bandwidth / XFER_LIMIT_RATIO);
- }
- }
- if (params->has_max_cpu_throttle) {
- s->parameters.max_cpu_throttle = params->max_cpu_throttle;
- }
- if (params->has_announce_initial) {
- s->parameters.announce_initial = params->announce_initial;
- }
- if (params->has_announce_max) {
- s->parameters.announce_max = params->announce_max;
- }
- if (params->has_announce_rounds) {
- s->parameters.announce_rounds = params->announce_rounds;
- }
- if (params->has_announce_step) {
- s->parameters.announce_step = params->announce_step;
- }
-
- if (params->has_block_bitmap_mapping) {
- qapi_free_BitmapMigrationNodeAliasList(
- s->parameters.block_bitmap_mapping);
-
- s->parameters.has_block_bitmap_mapping = true;
- s->parameters.block_bitmap_mapping =
- QAPI_CLONE(BitmapMigrationNodeAliasList,
- params->block_bitmap_mapping);
- }
-}
-
-void qmp_migrate_set_parameters(MigrateSetParameters *params, Error **errp)
-{
- MigrationParameters tmp;
-
- /* TODO Rewrite "" to null instead */
- if (params->tls_creds
- && params->tls_creds->type == QTYPE_QNULL) {
- qobject_unref(params->tls_creds->u.n);
- params->tls_creds->type = QTYPE_QSTRING;
- params->tls_creds->u.s = strdup("");
- }
- /* TODO Rewrite "" to null instead */
- if (params->tls_hostname
- && params->tls_hostname->type == QTYPE_QNULL) {
- qobject_unref(params->tls_hostname->u.n);
- params->tls_hostname->type = QTYPE_QSTRING;
- params->tls_hostname->u.s = strdup("");
- }
-
- migrate_params_test_apply(params, &tmp);
-
- if (!migrate_params_check(&tmp, errp)) {
- /* Invalid parameter */
- return;
- }
-
- migrate_params_apply(params, errp);
-}
-
-
void qmp_migrate_start_postcopy(Error **errp)
{
MigrationState *s = migrate_get_current();
@@ -2177,15 +1757,6 @@
qemu_sem_post(&s->pause_sem);
}
-int migrate_use_tls(void)
-{
- MigrationState *s;
-
- s = migrate_get_current();
-
- return s->parameters.tls_creds && *s->parameters.tls_creds;
-}
-
/* migration thread support */
/*
* Something bad happened to the RP stream, mark an error
diff --git a/migration/migration.h b/migration/migration.h
index dcf9068..2b71df8 100644
--- a/migration/migration.h
+++ b/migration/migration.h
@@ -447,8 +447,6 @@
bool migration_in_postcopy(void);
MigrationState *migrate_get_current(void);
-int migrate_use_tls(void);
-
uint64_t ram_get_total_transferred_pages(void);
/* Sending on the return path - generic and then for each message type */
diff --git a/migration/options.c b/migration/options.c
index 8e8753d..c603058 100644
--- a/migration/options.c
+++ b/migration/options.c
@@ -12,17 +12,25 @@
*/
#include "qemu/osdep.h"
+#include "exec/target_page.h"
#include "qapi/clone-visitor.h"
#include "qapi/error.h"
#include "qapi/qapi-commands-migration.h"
#include "qapi/qapi-visit-migration.h"
#include "qapi/qmp/qerror.h"
+#include "qapi/qmp/qnull.h"
#include "sysemu/runstate.h"
+#include "migration/colo.h"
#include "migration/misc.h"
#include "migration.h"
+#include "qemu-file.h"
#include "ram.h"
#include "options.h"
+/* Maximum migrate downtime set to 2000 seconds */
+#define MAX_MIGRATE_DOWNTIME_SECONDS 2000
+#define MAX_MIGRATE_DOWNTIME (MAX_MIGRATE_DOWNTIME_SECONDS * 1000)
+
bool migrate_auto_converge(void)
{
MigrationState *s;
@@ -214,6 +222,15 @@
return migrate_postcopy_ram() || migrate_dirty_bitmaps();
}
+bool migrate_tls(void)
+{
+ MigrationState *s;
+
+ s = migrate_get_current();
+
+ return s->parameters.tls_creds && *s->parameters.tls_creds;
+}
+
typedef enum WriteTrackingSupport {
WT_SUPPORT_UNKNOWN = 0,
WT_SUPPORT_ABSENT,
@@ -285,6 +302,7 @@
{
MigrationIncomingState *mis = migration_incoming_get_current();
+ ERRP_GUARD();
#ifndef CONFIG_LIVE_BLOCK_MIGRATION
if (new_caps[MIGRATION_CAPABILITY_BLOCK]) {
error_setg(errp, "QEMU compiled without old-style (blk/-b, inc/-i) "
@@ -310,11 +328,8 @@
*/
if (!old_caps[MIGRATION_CAPABILITY_POSTCOPY_RAM] &&
runstate_check(RUN_STATE_INMIGRATE) &&
- !postcopy_ram_supported_by_host(mis)) {
- /* postcopy_ram_supported_by_host will have emitted a more
- * detailed message
- */
- error_setg(errp, "Postcopy is not supported");
+ !postcopy_ram_supported_by_host(mis, errp)) {
+ error_prepend(errp, "Postcopy is not supported: ");
return false;
}
@@ -322,6 +337,11 @@
error_setg(errp, "Postcopy is not compatible with ignore-shared");
return false;
}
+
+ if (new_caps[MIGRATION_CAPABILITY_MULTIFD]) {
+ error_setg(errp, "Postcopy is not yet compatible with multifd");
+ return false;
+ }
}
if (new_caps[MIGRATION_CAPABILITY_BACKGROUND_SNAPSHOT]) {
@@ -363,7 +383,7 @@
new_caps[MIGRATION_CAPABILITY_COMPRESS] ||
new_caps[MIGRATION_CAPABILITY_XBZRLE] ||
migrate_multifd_compression() ||
- migrate_use_tls())) {
+ migrate_tls())) {
error_setg(errp,
"Zero copy only available for non-compressed non-TLS multifd migration");
return false;
@@ -720,3 +740,413 @@
return params;
}
+
+/*
+ * Check whether the parameters are valid. Error will be put into errp
+ * (if provided). Return true if valid, otherwise false.
+ */
+bool migrate_params_check(MigrationParameters *params, Error **errp)
+{
+ if (params->has_compress_level &&
+ (params->compress_level > 9)) {
+ error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "compress_level",
+ "a value between 0 and 9");
+ return false;
+ }
+
+ if (params->has_compress_threads && (params->compress_threads < 1)) {
+ error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
+ "compress_threads",
+ "a value between 1 and 255");
+ return false;
+ }
+
+ if (params->has_decompress_threads && (params->decompress_threads < 1)) {
+ error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
+ "decompress_threads",
+ "a value between 1 and 255");
+ return false;
+ }
+
+ if (params->has_throttle_trigger_threshold &&
+ (params->throttle_trigger_threshold < 1 ||
+ params->throttle_trigger_threshold > 100)) {
+ error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
+ "throttle_trigger_threshold",
+ "an integer in the range of 1 to 100");
+ 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 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 false;
+ }
+
+ if (params->has_max_bandwidth && (params->max_bandwidth > SIZE_MAX)) {
+ error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
+ "max_bandwidth",
+ "an integer in the range of 0 to "stringify(SIZE_MAX)
+ " bytes/second");
+ return false;
+ }
+
+ if (params->has_downtime_limit &&
+ (params->downtime_limit > MAX_MIGRATE_DOWNTIME)) {
+ error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
+ "downtime_limit",
+ "an integer in the range of 0 to "
+ stringify(MAX_MIGRATE_DOWNTIME)" ms");
+ return false;
+ }
+
+ /* x_checkpoint_delay is now always positive */
+
+ if (params->has_multifd_channels && (params->multifd_channels < 1)) {
+ error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
+ "multifd_channels",
+ "a value between 1 and 255");
+ return false;
+ }
+
+ if (params->has_multifd_zlib_level &&
+ (params->multifd_zlib_level > 9)) {
+ error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "multifd_zlib_level",
+ "a value between 0 and 9");
+ return false;
+ }
+
+ if (params->has_multifd_zstd_level &&
+ (params->multifd_zstd_level > 20)) {
+ error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "multifd_zstd_level",
+ "a value between 0 and 20");
+ return false;
+ }
+
+ if (params->has_xbzrle_cache_size &&
+ (params->xbzrle_cache_size < qemu_target_page_size() ||
+ !is_power_of_2(params->xbzrle_cache_size))) {
+ error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
+ "xbzrle_cache_size",
+ "a power of two no less than the target page size");
+ return false;
+ }
+
+ if (params->has_max_cpu_throttle &&
+ (params->max_cpu_throttle < params->cpu_throttle_initial ||
+ params->max_cpu_throttle > 99)) {
+ error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
+ "max_cpu_throttle",
+ "an integer in the range of cpu_throttle_initial to 99");
+ return false;
+ }
+
+ if (params->has_announce_initial &&
+ params->announce_initial > 100000) {
+ error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
+ "announce_initial",
+ "a value between 0 and 100000");
+ return false;
+ }
+ if (params->has_announce_max &&
+ params->announce_max > 100000) {
+ error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
+ "announce_max",
+ "a value between 0 and 100000");
+ return false;
+ }
+ if (params->has_announce_rounds &&
+ params->announce_rounds > 1000) {
+ error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
+ "announce_rounds",
+ "a value between 0 and 1000");
+ return false;
+ }
+ if (params->has_announce_step &&
+ (params->announce_step < 1 ||
+ params->announce_step > 10000)) {
+ error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
+ "announce_step",
+ "a value between 0 and 10000");
+ return false;
+ }
+
+ if (params->has_block_bitmap_mapping &&
+ !check_dirty_bitmap_mig_alias_map(params->block_bitmap_mapping, errp)) {
+ error_prepend(errp, "Invalid mapping given for block-bitmap-mapping: ");
+ return false;
+ }
+
+#ifdef CONFIG_LINUX
+ if (migrate_zero_copy_send() &&
+ ((params->has_multifd_compression && params->multifd_compression) ||
+ (params->tls_creds && *params->tls_creds))) {
+ error_setg(errp,
+ "Zero copy only available for non-compressed non-TLS multifd migration");
+ return false;
+ }
+#endif
+
+ return true;
+}
+
+static void migrate_params_test_apply(MigrateSetParameters *params,
+ MigrationParameters *dest)
+{
+ *dest = migrate_get_current()->parameters;
+
+ /* TODO use QAPI_CLONE() instead of duplicating it inline */
+
+ if (params->has_compress_level) {
+ dest->compress_level = params->compress_level;
+ }
+
+ if (params->has_compress_threads) {
+ dest->compress_threads = params->compress_threads;
+ }
+
+ if (params->has_compress_wait_thread) {
+ dest->compress_wait_thread = params->compress_wait_thread;
+ }
+
+ if (params->has_decompress_threads) {
+ dest->decompress_threads = params->decompress_threads;
+ }
+
+ if (params->has_throttle_trigger_threshold) {
+ dest->throttle_trigger_threshold = params->throttle_trigger_threshold;
+ }
+
+ if (params->has_cpu_throttle_initial) {
+ dest->cpu_throttle_initial = params->cpu_throttle_initial;
+ }
+
+ if (params->has_cpu_throttle_increment) {
+ dest->cpu_throttle_increment = params->cpu_throttle_increment;
+ }
+
+ if (params->has_cpu_throttle_tailslow) {
+ dest->cpu_throttle_tailslow = params->cpu_throttle_tailslow;
+ }
+
+ if (params->tls_creds) {
+ assert(params->tls_creds->type == QTYPE_QSTRING);
+ dest->tls_creds = params->tls_creds->u.s;
+ }
+
+ if (params->tls_hostname) {
+ assert(params->tls_hostname->type == QTYPE_QSTRING);
+ dest->tls_hostname = params->tls_hostname->u.s;
+ }
+
+ if (params->has_max_bandwidth) {
+ dest->max_bandwidth = params->max_bandwidth;
+ }
+
+ if (params->has_downtime_limit) {
+ dest->downtime_limit = params->downtime_limit;
+ }
+
+ if (params->has_x_checkpoint_delay) {
+ dest->x_checkpoint_delay = params->x_checkpoint_delay;
+ }
+
+ if (params->has_block_incremental) {
+ dest->block_incremental = params->block_incremental;
+ }
+ if (params->has_multifd_channels) {
+ dest->multifd_channels = params->multifd_channels;
+ }
+ if (params->has_multifd_compression) {
+ dest->multifd_compression = params->multifd_compression;
+ }
+ if (params->has_xbzrle_cache_size) {
+ dest->xbzrle_cache_size = params->xbzrle_cache_size;
+ }
+ if (params->has_max_postcopy_bandwidth) {
+ dest->max_postcopy_bandwidth = params->max_postcopy_bandwidth;
+ }
+ if (params->has_max_cpu_throttle) {
+ dest->max_cpu_throttle = params->max_cpu_throttle;
+ }
+ if (params->has_announce_initial) {
+ dest->announce_initial = params->announce_initial;
+ }
+ if (params->has_announce_max) {
+ dest->announce_max = params->announce_max;
+ }
+ if (params->has_announce_rounds) {
+ dest->announce_rounds = params->announce_rounds;
+ }
+ if (params->has_announce_step) {
+ dest->announce_step = params->announce_step;
+ }
+
+ if (params->has_block_bitmap_mapping) {
+ dest->has_block_bitmap_mapping = true;
+ dest->block_bitmap_mapping = params->block_bitmap_mapping;
+ }
+}
+
+static void migrate_params_apply(MigrateSetParameters *params, Error **errp)
+{
+ MigrationState *s = migrate_get_current();
+
+ /* TODO use QAPI_CLONE() instead of duplicating it inline */
+
+ 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_compress_wait_thread) {
+ s->parameters.compress_wait_thread = params->compress_wait_thread;
+ }
+
+ if (params->has_decompress_threads) {
+ s->parameters.decompress_threads = params->decompress_threads;
+ }
+
+ if (params->has_throttle_trigger_threshold) {
+ s->parameters.throttle_trigger_threshold = params->throttle_trigger_threshold;
+ }
+
+ 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_cpu_throttle_tailslow) {
+ s->parameters.cpu_throttle_tailslow = params->cpu_throttle_tailslow;
+ }
+
+ if (params->tls_creds) {
+ g_free(s->parameters.tls_creds);
+ assert(params->tls_creds->type == QTYPE_QSTRING);
+ s->parameters.tls_creds = g_strdup(params->tls_creds->u.s);
+ }
+
+ if (params->tls_hostname) {
+ g_free(s->parameters.tls_hostname);
+ assert(params->tls_hostname->type == QTYPE_QSTRING);
+ s->parameters.tls_hostname = g_strdup(params->tls_hostname->u.s);
+ }
+
+ if (params->tls_authz) {
+ g_free(s->parameters.tls_authz);
+ assert(params->tls_authz->type == QTYPE_QSTRING);
+ s->parameters.tls_authz = g_strdup(params->tls_authz->u.s);
+ }
+
+ if (params->has_max_bandwidth) {
+ s->parameters.max_bandwidth = params->max_bandwidth;
+ if (s->to_dst_file && !migration_in_postcopy()) {
+ qemu_file_set_rate_limit(s->to_dst_file,
+ s->parameters.max_bandwidth / XFER_LIMIT_RATIO);
+ }
+ }
+
+ if (params->has_downtime_limit) {
+ s->parameters.downtime_limit = params->downtime_limit;
+ }
+
+ if (params->has_x_checkpoint_delay) {
+ s->parameters.x_checkpoint_delay = params->x_checkpoint_delay;
+ if (migration_in_colo_state()) {
+ colo_checkpoint_notify(s);
+ }
+ }
+
+ if (params->has_block_incremental) {
+ s->parameters.block_incremental = params->block_incremental;
+ }
+ if (params->has_multifd_channels) {
+ s->parameters.multifd_channels = params->multifd_channels;
+ }
+ if (params->has_multifd_compression) {
+ s->parameters.multifd_compression = params->multifd_compression;
+ }
+ if (params->has_xbzrle_cache_size) {
+ s->parameters.xbzrle_cache_size = params->xbzrle_cache_size;
+ xbzrle_cache_resize(params->xbzrle_cache_size, errp);
+ }
+ if (params->has_max_postcopy_bandwidth) {
+ s->parameters.max_postcopy_bandwidth = params->max_postcopy_bandwidth;
+ if (s->to_dst_file && migration_in_postcopy()) {
+ qemu_file_set_rate_limit(s->to_dst_file,
+ s->parameters.max_postcopy_bandwidth / XFER_LIMIT_RATIO);
+ }
+ }
+ if (params->has_max_cpu_throttle) {
+ s->parameters.max_cpu_throttle = params->max_cpu_throttle;
+ }
+ if (params->has_announce_initial) {
+ s->parameters.announce_initial = params->announce_initial;
+ }
+ if (params->has_announce_max) {
+ s->parameters.announce_max = params->announce_max;
+ }
+ if (params->has_announce_rounds) {
+ s->parameters.announce_rounds = params->announce_rounds;
+ }
+ if (params->has_announce_step) {
+ s->parameters.announce_step = params->announce_step;
+ }
+
+ if (params->has_block_bitmap_mapping) {
+ qapi_free_BitmapMigrationNodeAliasList(
+ s->parameters.block_bitmap_mapping);
+
+ s->parameters.has_block_bitmap_mapping = true;
+ s->parameters.block_bitmap_mapping =
+ QAPI_CLONE(BitmapMigrationNodeAliasList,
+ params->block_bitmap_mapping);
+ }
+}
+
+void qmp_migrate_set_parameters(MigrateSetParameters *params, Error **errp)
+{
+ MigrationParameters tmp;
+
+ /* TODO Rewrite "" to null instead */
+ if (params->tls_creds
+ && params->tls_creds->type == QTYPE_QNULL) {
+ qobject_unref(params->tls_creds->u.n);
+ params->tls_creds->type = QTYPE_QSTRING;
+ params->tls_creds->u.s = strdup("");
+ }
+ /* TODO Rewrite "" to null instead */
+ if (params->tls_hostname
+ && params->tls_hostname->type == QTYPE_QNULL) {
+ qobject_unref(params->tls_hostname->u.n);
+ params->tls_hostname->type = QTYPE_QSTRING;
+ params->tls_hostname->u.s = strdup("");
+ }
+
+ migrate_params_test_apply(params, &tmp);
+
+ if (!migrate_params_check(&tmp, errp)) {
+ /* Invalid parameter */
+ return;
+ }
+
+ migrate_params_apply(params, errp);
+}
diff --git a/migration/options.h b/migration/options.h
index 1b78fa9..89067e5 100644
--- a/migration/options.h
+++ b/migration/options.h
@@ -14,6 +14,13 @@
#ifndef QEMU_MIGRATION_OPTIONS_H
#define QEMU_MIGRATION_OPTIONS_H
+/* constants */
+
+/* Amount of time to allocate to each "chunk" of bandwidth-throttled
+ * data. */
+#define BUFFER_DELAY 100
+#define XFER_LIMIT_RATIO (1000 / BUFFER_DELAY)
+
/* capabilities */
bool migrate_auto_converge(void);
@@ -46,6 +53,7 @@
*/
bool migrate_postcopy(void);
+bool migrate_tls(void);
/* capabilities helpers */
@@ -73,4 +81,8 @@
uint8_t migrate_throttle_trigger_threshold(void);
uint64_t migrate_xbzrle_cache_size(void);
+/* parameters helpers */
+
+bool migrate_params_check(MigrationParameters *params, Error **errp);
+
#endif
diff --git a/migration/postcopy-ram.c b/migration/postcopy-ram.c
index 0711500..75aa276 100644
--- a/migration/postcopy-ram.c
+++ b/migration/postcopy-ram.c
@@ -283,11 +283,13 @@
return true;
}
-static bool ufd_check_and_apply(int ufd, MigrationIncomingState *mis)
+static bool ufd_check_and_apply(int ufd, MigrationIncomingState *mis,
+ Error **errp)
{
uint64_t asked_features = 0;
static uint64_t supported_features;
+ ERRP_GUARD();
/*
* it's not possible to
* request UFFD_API twice per one fd
@@ -295,7 +297,7 @@
*/
if (!supported_features) {
if (!receive_ufd_features(&supported_features)) {
- error_report("%s failed", __func__);
+ error_setg(errp, "Userfault feature detection failed");
return false;
}
}
@@ -317,8 +319,7 @@
* userfault file descriptor
*/
if (!request_ufd_features(ufd, asked_features)) {
- error_report("%s failed: features %" PRIu64, __func__,
- asked_features);
+ error_setg(errp, "Failed features %" PRIu64, asked_features);
return false;
}
@@ -329,7 +330,8 @@
have_hp = supported_features & UFFD_FEATURE_MISSING_HUGETLBFS;
#endif
if (!have_hp) {
- error_report("Userfault on this host does not support huge pages");
+ error_setg(errp,
+ "Userfault on this host does not support huge pages");
return false;
}
}
@@ -338,7 +340,7 @@
/* Callback from postcopy_ram_supported_by_host block iterator.
*/
-static int test_ramblock_postcopiable(RAMBlock *rb)
+static int test_ramblock_postcopiable(RAMBlock *rb, Error **errp)
{
const char *block_name = qemu_ram_get_idstr(rb);
ram_addr_t length = qemu_ram_get_used_length(rb);
@@ -346,16 +348,18 @@
QemuFsType fs;
if (length % pagesize) {
- error_report("Postcopy requires RAM blocks to be a page size multiple,"
- " block %s is 0x" RAM_ADDR_FMT " bytes with a "
- "page size of 0x%zx", block_name, length, pagesize);
+ error_setg(errp,
+ "Postcopy requires RAM blocks to be a page size multiple,"
+ " block %s is 0x" RAM_ADDR_FMT " bytes with a "
+ "page size of 0x%zx", block_name, length, pagesize);
return 1;
}
if (rb->fd >= 0) {
fs = qemu_fd_getfs(rb->fd);
if (fs != QEMU_FS_TYPE_TMPFS && fs != QEMU_FS_TYPE_HUGETLBFS) {
- error_report("Host backend files need to be TMPFS or HUGETLBFS only");
+ error_setg(errp,
+ "Host backend files need to be TMPFS or HUGETLBFS only");
return 1;
}
}
@@ -368,7 +372,7 @@
* normally fine since if the postcopy succeeds it gets turned back on at the
* end.
*/
-bool postcopy_ram_supported_by_host(MigrationIncomingState *mis)
+bool postcopy_ram_supported_by_host(MigrationIncomingState *mis, Error **errp)
{
long pagesize = qemu_real_host_page_size();
int ufd = -1;
@@ -377,29 +381,27 @@
struct uffdio_register reg_struct;
struct uffdio_range range_struct;
uint64_t feature_mask;
- Error *local_err = NULL;
RAMBlock *block;
+ ERRP_GUARD();
if (qemu_target_page_size() > pagesize) {
- error_report("Target page size bigger than host page size");
+ error_setg(errp, "Target page size bigger than host page size");
goto out;
}
ufd = uffd_open(O_CLOEXEC);
if (ufd == -1) {
- error_report("%s: userfaultfd not available: %s", __func__,
- strerror(errno));
+ error_setg(errp, "Userfaultfd not available: %s", strerror(errno));
goto out;
}
/* Give devices a chance to object */
- if (postcopy_notify(POSTCOPY_NOTIFY_PROBE, &local_err)) {
- error_report_err(local_err);
+ if (postcopy_notify(POSTCOPY_NOTIFY_PROBE, errp)) {
goto out;
}
/* Version and features check */
- if (!ufd_check_and_apply(ufd, mis)) {
+ if (!ufd_check_and_apply(ufd, mis, errp)) {
goto out;
}
@@ -417,7 +419,7 @@
* affect in reality, or we can revisit.
*/
RAMBLOCK_FOREACH(block) {
- if (test_ramblock_postcopiable(block)) {
+ if (test_ramblock_postcopiable(block, errp)) {
goto out;
}
}
@@ -427,7 +429,7 @@
* it was enabled.
*/
if (munlockall()) {
- error_report("%s: munlockall: %s", __func__, strerror(errno));
+ error_setg(errp, "munlockall() failed: %s", strerror(errno));
goto out;
}
@@ -439,8 +441,7 @@
testarea = mmap(NULL, pagesize, PROT_READ | PROT_WRITE, MAP_PRIVATE |
MAP_ANONYMOUS, -1, 0);
if (testarea == MAP_FAILED) {
- error_report("%s: Failed to map test area: %s", __func__,
- strerror(errno));
+ error_setg(errp, "Failed to map test area: %s", strerror(errno));
goto out;
}
g_assert(QEMU_PTR_IS_ALIGNED(testarea, pagesize));
@@ -450,14 +451,14 @@
reg_struct.mode = UFFDIO_REGISTER_MODE_MISSING;
if (ioctl(ufd, UFFDIO_REGISTER, ®_struct)) {
- error_report("%s userfault register: %s", __func__, strerror(errno));
+ error_setg(errp, "UFFDIO_REGISTER failed: %s", strerror(errno));
goto out;
}
range_struct.start = (uintptr_t)testarea;
range_struct.len = pagesize;
if (ioctl(ufd, UFFDIO_UNREGISTER, &range_struct)) {
- error_report("%s userfault unregister: %s", __func__, strerror(errno));
+ error_setg(errp, "UFFDIO_UNREGISTER failed: %s", strerror(errno));
goto out;
}
@@ -465,8 +466,8 @@
(__u64)1 << _UFFDIO_COPY |
(__u64)1 << _UFFDIO_ZEROPAGE;
if ((reg_struct.ioctls & feature_mask) != feature_mask) {
- error_report("Missing userfault map features: %" PRIx64,
- (uint64_t)(~reg_struct.ioctls & feature_mask));
+ error_setg(errp, "Missing userfault map features: %" PRIx64,
+ (uint64_t)(~reg_struct.ioctls & feature_mask));
goto out;
}
@@ -1188,6 +1189,8 @@
int postcopy_ram_incoming_setup(MigrationIncomingState *mis)
{
+ Error *local_err = NULL;
+
/* Open the fd for the kernel to give us userfaults */
mis->userfault_fd = uffd_open(O_CLOEXEC | O_NONBLOCK);
if (mis->userfault_fd == -1) {
@@ -1200,7 +1203,8 @@
* Although the host check already tested the API, we need to
* do the check again as an ABI handshake on the new fd.
*/
- if (!ufd_check_and_apply(mis->userfault_fd, mis)) {
+ if (!ufd_check_and_apply(mis->userfault_fd, mis, &local_err)) {
+ error_report_err(local_err);
return -1;
}
@@ -1360,7 +1364,7 @@
{
}
-bool postcopy_ram_supported_by_host(MigrationIncomingState *mis)
+bool postcopy_ram_supported_by_host(MigrationIncomingState *mis, Error **errp)
{
error_report("%s: No OS support", __func__);
return false;
diff --git a/migration/postcopy-ram.h b/migration/postcopy-ram.h
index b4867a3..442ab89 100644
--- a/migration/postcopy-ram.h
+++ b/migration/postcopy-ram.h
@@ -14,7 +14,8 @@
#define QEMU_POSTCOPY_RAM_H
/* Return true if the host supports everything we need to do postcopy-ram */
-bool postcopy_ram_supported_by_host(MigrationIncomingState *mis);
+bool postcopy_ram_supported_by_host(MigrationIncomingState *mis,
+ Error **errp);
/*
* Make all of RAM sensitive to accesses to areas that haven't yet been written
diff --git a/migration/savevm.c b/migration/savevm.c
index 9671211..a9181b4 100644
--- a/migration/savevm.c
+++ b/migration/savevm.c
@@ -536,6 +536,9 @@
field->version_id);
fprintf(out_file, "%*s\"field_exists\": %s,\n", indent, "",
field->field_exists ? "true" : "false");
+ if (field->flags & VMS_ARRAY) {
+ fprintf(out_file, "%*s\"num\": %d,\n", indent, "", field->num);
+ }
fprintf(out_file, "%*s\"size\": %zu", indent, "", field->size);
if (field->vmsd != NULL) {
fprintf(out_file, ",\n");
@@ -1753,7 +1756,8 @@
return -EINVAL;
}
- if (!postcopy_ram_supported_by_host(mis)) {
+ if (!postcopy_ram_supported_by_host(mis, &local_err)) {
+ error_report_err(local_err);
postcopy_state_set(POSTCOPY_INCOMING_NONE);
return -1;
}
diff --git a/migration/tls.c b/migration/tls.c
index 4d2166a..acd38e0 100644
--- a/migration/tls.c
+++ b/migration/tls.c
@@ -22,6 +22,7 @@
#include "channel.h"
#include "migration.h"
#include "tls.h"
+#include "options.h"
#include "crypto/tlscreds.h"
#include "qemu/error-report.h"
#include "qapi/error.h"
@@ -165,7 +166,7 @@
bool migrate_channel_requires_tls_upgrade(QIOChannel *ioc)
{
- if (!migrate_use_tls()) {
+ if (!migrate_tls()) {
return false;
}
diff --git a/scripts/vmstate-static-checker.py b/scripts/vmstate-static-checker.py
index dfeee82..9c0e6b8 100755
--- a/scripts/vmstate-static-checker.py
+++ b/scripts/vmstate-static-checker.py
@@ -134,6 +134,11 @@ def exists_in_substruct(fields, item):
return check_fields_match(fields["Description"]["name"],
substruct_fields[0]["field"], item)
+def size_total(entry):
+ size = entry["size"]
+ if "num" not in entry:
+ return size
+ return size * entry["num"]
def check_fields(src_fields, dest_fields, desc, sec):
# This function checks for all the fields in a section. If some
@@ -249,17 +254,19 @@ def check_fields(src_fields, dest_fields, desc, sec):
continue
if s_item["field"] == "unused" or d_item["field"] == "unused":
- if s_item["size"] == d_item["size"]:
+ s_size = size_total(s_item)
+ d_size = size_total(d_item)
+ if s_size == d_size:
continue
if d_item["field"] == "unused":
advance_dest = False
- unused_count = d_item["size"] - s_item["size"]
+ unused_count = d_size - s_size;
continue
if s_item["field"] == "unused":
advance_src = False
- unused_count = s_item["size"] - d_item["size"]
+ unused_count = s_size - d_size
continue
print("Section \"" + sec + "\",", end=' ')