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----- 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>
This commit is contained in:
commit
1eb95e1bae
@ -3154,6 +3154,8 @@ F: scripts/checkpatch.pl
|
||||
|
||||
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
|
||||
|
@ -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 @@ MigrationInfo *qmp_query_migrate(Error **errp)
|
||||
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 @@ void qmp_migrate_continue(MigrationStatus state, Error **errp)
|
||||
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
|
||||
|
@ -447,8 +447,6 @@ bool migration_is_blocked(Error **errp);
|
||||
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 */
|
||||
|
@ -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 @@ bool migrate_postcopy(void)
|
||||
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 @@ bool migrate_caps_check(bool *old_caps, bool *new_caps, Error **errp)
|
||||
{
|
||||
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 @@ bool migrate_caps_check(bool *old_caps, bool *new_caps, Error **errp)
|
||||
*/
|
||||
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 @@ bool migrate_caps_check(bool *old_caps, bool *new_caps, Error **errp)
|
||||
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 @@ bool migrate_caps_check(bool *old_caps, bool *new_caps, Error **errp)
|
||||
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 @@ MigrationParameters *qmp_query_migrate_parameters(Error **errp)
|
||||
|
||||
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);
|
||||
}
|
||||
|
@ -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_zero_copy_send(void);
|
||||
*/
|
||||
|
||||
bool migrate_postcopy(void);
|
||||
bool migrate_tls(void);
|
||||
|
||||
/* capabilities helpers */
|
||||
|
||||
@ -73,4 +81,8 @@ int migrate_multifd_zstd_level(void);
|
||||
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
|
||||
|
@ -283,11 +283,13 @@ static bool request_ufd_features(int ufd, uint64_t features)
|
||||
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 @@ static bool ufd_check_and_apply(int ufd, MigrationIncomingState *mis)
|
||||
*/
|
||||
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 @@ static bool ufd_check_and_apply(int ufd, MigrationIncomingState *mis)
|
||||
* 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 @@ static bool ufd_check_and_apply(int ufd, MigrationIncomingState *mis)
|
||||
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 @@ static bool ufd_check_and_apply(int ufd, MigrationIncomingState *mis)
|
||||
|
||||
/* 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 @@ static int test_ramblock_postcopiable(RAMBlock *rb)
|
||||
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 @@ static int test_ramblock_postcopiable(RAMBlock *rb)
|
||||
* 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 @@ bool postcopy_ram_supported_by_host(MigrationIncomingState *mis)
|
||||
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 @@ bool postcopy_ram_supported_by_host(MigrationIncomingState *mis)
|
||||
* 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 @@ bool postcopy_ram_supported_by_host(MigrationIncomingState *mis)
|
||||
* 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 @@ bool postcopy_ram_supported_by_host(MigrationIncomingState *mis)
|
||||
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 @@ bool postcopy_ram_supported_by_host(MigrationIncomingState *mis)
|
||||
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 @@ bool postcopy_ram_supported_by_host(MigrationIncomingState *mis)
|
||||
(__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 @@ static int postcopy_temp_pages_setup(MigrationIncomingState *mis)
|
||||
|
||||
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 @@ int postcopy_ram_incoming_setup(MigrationIncomingState *mis)
|
||||
* 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 @@ void fill_destination_postcopy_migration_info(MigrationInfo *info)
|
||||
{
|
||||
}
|
||||
|
||||
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;
|
||||
|
@ -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
|
||||
|
@ -536,6 +536,9 @@ static void dump_vmstate_vmsf(FILE *out_file, const VMStateField *field,
|
||||
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 @@ static int loadvm_postcopy_handle_advise(MigrationIncomingState *mis,
|
||||
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;
|
||||
}
|
||||
|
@ -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 @@ void migration_tls_channel_connect(MigrationState *s,
|
||||
|
||||
bool migrate_channel_requires_tls_upgrade(QIOChannel *ioc)
|
||||
{
|
||||
if (!migrate_use_tls()) {
|
||||
if (!migrate_tls()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -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=' ')
|
||||
|
Loading…
Reference in New Issue
Block a user