Migration Pull request

Everything that was reviewed since last PULL request:
 - fix to control flow (eric)
 - rearrange of hmp commands (juan)
 - Make capabilities more consistent and coherent (juan)
   Not all of them reviewed yet, so only the ones reviewed.
 
 Later, Juan.
 
 PD.  I am waiting to finish review of the compression fixes to send
 them.
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCAAdFiEEGJn/jt6/WMzuA0uC9IfvGFhy1yMFAmRGf0kACgkQ9IfvGFhy
 1yNojRAAhvOZoYRpTizbSo7wOr2TpO4F1R/opWECubBvw3/yTo3ifsVjovRo/nxe
 zmCXnY/ykqxskb/OMNyLZQYG4MPT24nyf7dhT3VxcFjTYsaNU59yvJoBtvy7Oq5h
 3Yk0459eKmsP39IXFlAMMRBwX+Hu3aE/8xAAHOowAhkmDkMFYjf7I1Lxpuarbhp+
 k9O5eqdNchG21YUzWXUe4ivAWqZmvzXtkwCp+XJ/KizjIEKgsm8HO1nwm5mtpmnu
 SS9Kkf957jYHqK73YXQhUV+iQ0kCVpclBPfZc2KuzudPi/aMG6LEVKfV//z5KIAz
 amME/6D1oSBfpgtqoCCPELdNfZOz+ZIa+XJzXlWkuiBDu9yNpUP339EVClmStwFu
 1UAOJIs8VUjPr9zTItgCDjZ17nh4Q0I04aMGuxgQIu82e8CTgS/QrnH2Tr2lUoMO
 QLgYAetVIDGVVFAA9Clba4C7AbS5hBeWMnd9Qd4cP93d6Z/C65xUv0a9mI7edpMb
 RNbvg73ZZCb6tye25cPSr07VaGTS+TELVMEh9RX3KZrfMTsHfGQ/ZHZv9wqJrQ04
 0wCidqBIbBk+BN8AtJ9vwqtPpL/Nf/BwDKPiwOVuZHCcrP+veXtlKb00SwNpJwkN
 x3Ld4cq22ZLeqO4dMueK16ij0ZpuXsF7jM/ptEvxrw6oxh/6xYQ=
 =g5gx
 -----END PGP SIGNATURE-----

Merge tag 'migration-20230424-pull-request' of https://gitlab.com/juan.quintela/qemu into staging

Migration Pull request

Everything that was reviewed since last PULL request:
- fix to control flow (eric)
- rearrange of hmp commands (juan)
- Make capabilities more consistent and coherent (juan)
  Not all of them reviewed yet, so only the ones reviewed.

Later, Juan.

PD.  I am waiting to finish review of the compression fixes to send
them.

# -----BEGIN PGP SIGNATURE-----
#
# iQIzBAABCAAdFiEEGJn/jt6/WMzuA0uC9IfvGFhy1yMFAmRGf0kACgkQ9IfvGFhy
# 1yNojRAAhvOZoYRpTizbSo7wOr2TpO4F1R/opWECubBvw3/yTo3ifsVjovRo/nxe
# zmCXnY/ykqxskb/OMNyLZQYG4MPT24nyf7dhT3VxcFjTYsaNU59yvJoBtvy7Oq5h
# 3Yk0459eKmsP39IXFlAMMRBwX+Hu3aE/8xAAHOowAhkmDkMFYjf7I1Lxpuarbhp+
# k9O5eqdNchG21YUzWXUe4ivAWqZmvzXtkwCp+XJ/KizjIEKgsm8HO1nwm5mtpmnu
# SS9Kkf957jYHqK73YXQhUV+iQ0kCVpclBPfZc2KuzudPi/aMG6LEVKfV//z5KIAz
# amME/6D1oSBfpgtqoCCPELdNfZOz+ZIa+XJzXlWkuiBDu9yNpUP339EVClmStwFu
# 1UAOJIs8VUjPr9zTItgCDjZ17nh4Q0I04aMGuxgQIu82e8CTgS/QrnH2Tr2lUoMO
# QLgYAetVIDGVVFAA9Clba4C7AbS5hBeWMnd9Qd4cP93d6Z/C65xUv0a9mI7edpMb
# RNbvg73ZZCb6tye25cPSr07VaGTS+TELVMEh9RX3KZrfMTsHfGQ/ZHZv9wqJrQ04
# 0wCidqBIbBk+BN8AtJ9vwqtPpL/Nf/BwDKPiwOVuZHCcrP+veXtlKb00SwNpJwkN
# x3Ld4cq22ZLeqO4dMueK16ij0ZpuXsF7jM/ptEvxrw6oxh/6xYQ=
# =g5gx
# -----END PGP SIGNATURE-----
# gpg: Signature made Mon 24 Apr 2023 02:08:25 PM 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-20230424-pull-request' of https://gitlab.com/juan.quintela/qemu: (30 commits)
  migration: Create migrate_max_bandwidth() function
  migration: Move migrate_postcopy() to options.c
  migration: Create migrate_cpu_throttle_tailslow() function
  migration: Create migrate_cpu_throttle_increment() function
  migration: Create  migrate_cpu_throttle_initial() to option.c
  migration: Move migrate_announce_params() to option.c
  migration: Create migrate_max_cpu_throttle()
  migration: Create migrate_checkpoint_delay()
  migration: Create migrate_throttle_trigger_threshold()
  migration: Move migrate_use_block_incremental() to option.c
  migration: Use migrate_max_postcopy_bandwidth()
  migration: Move parameters functions to option.c
  migration: Move migrate_cap_set() to options.c
  migration: Move qmp_migrate_set_capabilities() to options.c
  migration: Move qmp_query_migrate_capabilities() to options.c
  migration: Move migrate_caps_check() to options.c
  migration: Create migrate_rdma_pin_all() function
  migration: Move migrate_use_return() to options.c
  migration: Move migrate_use_block() to options.c
  migration: Move migrate_use_xbzrle() to options.c
  ...

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
Richard Henderson 2023-04-24 15:00:39 +01:00
commit ac5f7bf8e2
23 changed files with 971 additions and 832 deletions

View File

@ -32,6 +32,7 @@
#include "qemu/error-report.h" #include "qemu/error-report.h"
#include "migration/misc.h" #include "migration/misc.h"
#include "migration/migration.h" #include "migration/migration.h"
#include "migration/options.h"
#include "hw/virtio/virtio-bus.h" #include "hw/virtio/virtio-bus.h"
#include "hw/virtio/virtio-access.h" #include "hw/virtio/virtio-access.h"

View File

@ -66,7 +66,6 @@ bool migration_has_finished(MigrationState *);
bool migration_has_failed(MigrationState *); bool migration_has_failed(MigrationState *);
/* ...and after the device transmission */ /* ...and after the device transmission */
bool migration_in_postcopy_after_devices(MigrationState *); bool migration_in_postcopy_after_devices(MigrationState *);
void migration_global_dump(Monitor *mon);
/* True if incoming migration entered POSTCOPY_INCOMING_DISCARD */ /* True if incoming migration entered POSTCOPY_INCOMING_DISCARD */
bool migration_in_incoming_postcopy(void); bool migration_in_incoming_postcopy(void);
/* True if incoming migration entered POSTCOPY_INCOMING_ADVISE */ /* True if incoming migration entered POSTCOPY_INCOMING_ADVISE */

View File

@ -79,6 +79,7 @@
#include "qapi/qapi-visit-migration.h" #include "qapi/qapi-visit-migration.h"
#include "qapi/clone-visitor.h" #include "qapi/clone-visitor.h"
#include "trace.h" #include "trace.h"
#include "options.h"
#define CHUNK_SIZE (1 << 10) #define CHUNK_SIZE (1 << 10)

View File

@ -28,6 +28,7 @@
#include "migration/vmstate.h" #include "migration/vmstate.h"
#include "sysemu/block-backend.h" #include "sysemu/block-backend.h"
#include "trace.h" #include "trace.h"
#include "options.h"
#define BLK_MIG_BLOCK_SIZE (1ULL << 20) #define BLK_MIG_BLOCK_SIZE (1ULL << 20)
#define BDRV_SECTORS_PER_DIRTY_CHUNK (BLK_MIG_BLOCK_SIZE >> BDRV_SECTOR_BITS) #define BDRV_SECTORS_PER_DIRTY_CHUNK (BLK_MIG_BLOCK_SIZE >> BDRV_SECTOR_BITS)
@ -416,7 +417,7 @@ static int init_blk_migration(QEMUFile *f)
bmds->bulk_completed = 0; bmds->bulk_completed = 0;
bmds->total_sectors = sectors; bmds->total_sectors = sectors;
bmds->completed_sectors = 0; bmds->completed_sectors = 0;
bmds->shared_base = migrate_use_block_incremental(); bmds->shared_base = migrate_block_incremental();
assert(i < num_bs); assert(i < num_bs);
bmds_bs[i].bmds = bmds; bmds_bs[i].bmds = bmds;
@ -1000,7 +1001,7 @@ static int block_load(QEMUFile *f, void *opaque, int version_id)
static bool block_is_active(void *opaque) static bool block_is_active(void *opaque)
{ {
return migrate_use_block(); return migrate_block();
} }
static SaveVMHandlers savevm_block_handlers = { static SaveVMHandlers savevm_block_handlers = {

View File

@ -36,6 +36,7 @@
#include "sysemu/cpus.h" #include "sysemu/cpus.h"
#include "sysemu/runstate.h" #include "sysemu/runstate.h"
#include "net/filter.h" #include "net/filter.h"
#include "options.h"
static bool vmstate_loading; static bool vmstate_loading;
static Notifier packets_compare_notifier; static Notifier packets_compare_notifier;
@ -575,7 +576,7 @@ static void colo_process_checkpoint(MigrationState *s)
trace_colo_vm_state_change("stop", "run"); trace_colo_vm_state_change("stop", "run");
timer_mod(s->colo_delay_timer, qemu_clock_get_ms(QEMU_CLOCK_HOST) + timer_mod(s->colo_delay_timer, qemu_clock_get_ms(QEMU_CLOCK_HOST) +
s->parameters.x_checkpoint_delay); migrate_checkpoint_delay());
while (s->state == MIGRATION_STATUS_COLO) { while (s->state == MIGRATION_STATUS_COLO) {
if (failover_get_state() != FAILOVER_STATUS_NONE) { if (failover_get_state() != FAILOVER_STATUS_NONE) {
@ -650,8 +651,7 @@ void colo_checkpoint_notify(void *opaque)
qemu_event_set(&s->colo_checkpoint_event); qemu_event_set(&s->colo_checkpoint_event);
s->colo_checkpoint_time = qemu_clock_get_ms(QEMU_CLOCK_HOST); s->colo_checkpoint_time = qemu_clock_get_ms(QEMU_CLOCK_HOST);
next_notify_time = s->colo_checkpoint_time + next_notify_time = s->colo_checkpoint_time + migrate_checkpoint_delay();
s->parameters.x_checkpoint_delay;
timer_mod(s->colo_delay_timer, next_notify_time); timer_mod(s->colo_delay_timer, next_notify_time);
} }

View File

@ -22,6 +22,7 @@ softmmu_ss.add(files(
'migration.c', 'migration.c',
'multifd.c', 'multifd.c',
'multifd-zlib.c', 'multifd-zlib.c',
'options.c',
'postcopy-ram.c', 'postcopy-ram.c',
'savevm.c', 'savevm.c',
'socket.c', 'socket.c',

View File

@ -15,7 +15,6 @@
#include "qemu/osdep.h" #include "qemu/osdep.h"
#include "block/qapi.h" #include "block/qapi.h"
#include "migration/misc.h"
#include "migration/snapshot.h" #include "migration/snapshot.h"
#include "monitor/hmp.h" #include "monitor/hmp.h"
#include "monitor/monitor.h" #include "monitor/monitor.h"
@ -30,6 +29,27 @@
#include "qemu/sockets.h" #include "qemu/sockets.h"
#include "sysemu/runstate.h" #include "sysemu/runstate.h"
#include "ui/qemu-spice.h" #include "ui/qemu-spice.h"
#include "sysemu/sysemu.h"
#include "migration.h"
static void migration_global_dump(Monitor *mon)
{
MigrationState *ms = migrate_get_current();
monitor_printf(mon, "globals:\n");
monitor_printf(mon, "store-global-state: %s\n",
ms->store_global_state ? "on" : "off");
monitor_printf(mon, "only-migratable: %s\n",
only_migratable ? "on" : "off");
monitor_printf(mon, "send-configuration: %s\n",
ms->send_configuration ? "on" : "off");
monitor_printf(mon, "send-section-footer: %s\n",
ms->send_section_footer ? "on" : "off");
monitor_printf(mon, "decompress-error-check: %s\n",
ms->decompress_error_check ? "on" : "off");
monitor_printf(mon, "clear-bitmap-shift: %u\n",
ms->clear_bitmap_shift);
}
void hmp_info_migrate(Monitor *mon, const QDict *qdict) void hmp_info_migrate(Monitor *mon, const QDict *qdict)
{ {
@ -616,23 +636,6 @@ void hmp_migrate_set_parameter(Monitor *mon, const QDict *qdict)
hmp_handle_error(mon, err); hmp_handle_error(mon, err);
} }
void hmp_client_migrate_info(Monitor *mon, const QDict *qdict)
{
Error *err = NULL;
const char *protocol = qdict_get_str(qdict, "protocol");
const char *hostname = qdict_get_str(qdict, "hostname");
bool has_port = qdict_haskey(qdict, "port");
int port = qdict_get_try_int(qdict, "port", -1);
bool has_tls_port = qdict_haskey(qdict, "tls-port");
int tls_port = qdict_get_try_int(qdict, "tls-port", -1);
const char *cert_subject = qdict_get_try_str(qdict, "cert-subject");
qmp_client_migrate_info(protocol, hostname,
has_port, port, has_tls_port, tls_port,
cert_subject, &err);
hmp_handle_error(mon, err);
}
void hmp_migrate_start_postcopy(Monitor *mon, const QDict *qdict) void hmp_migrate_start_postcopy(Monitor *mon, const QDict *qdict)
{ {
Error *err = NULL; Error *err = NULL;

View File

@ -63,7 +63,7 @@
#include "sysemu/cpus.h" #include "sysemu/cpus.h"
#include "yank_functions.h" #include "yank_functions.h"
#include "sysemu/qtest.h" #include "sysemu/qtest.h"
#include "ui/qemu-spice.h" #include "options.h"
#define MAX_THROTTLE (128 << 20) /* Migration transfer speed throttling */ #define MAX_THROTTLE (128 << 20) /* Migration transfer speed throttling */
@ -136,39 +136,6 @@ enum mig_rp_message_type {
MIG_RP_MSG_MAX MIG_RP_MSG_MAX
}; };
/* Migration capabilities set */
struct MigrateCapsSet {
int size; /* Capability set size */
MigrationCapability caps[]; /* Variadic array of capabilities */
};
typedef struct MigrateCapsSet MigrateCapsSet;
/* Define and initialize MigrateCapsSet */
#define INITIALIZE_MIGRATE_CAPS_SET(_name, ...) \
MigrateCapsSet _name = { \
.size = sizeof((int []) { __VA_ARGS__ }) / sizeof(int), \
.caps = { __VA_ARGS__ } \
}
/* Background-snapshot compatibility check list */
static const
INITIALIZE_MIGRATE_CAPS_SET(check_caps_background_snapshot,
MIGRATION_CAPABILITY_POSTCOPY_RAM,
MIGRATION_CAPABILITY_DIRTY_BITMAPS,
MIGRATION_CAPABILITY_POSTCOPY_BLOCKTIME,
MIGRATION_CAPABILITY_LATE_BLOCK_ACTIVATE,
MIGRATION_CAPABILITY_RETURN_PATH,
MIGRATION_CAPABILITY_MULTIFD,
MIGRATION_CAPABILITY_PAUSE_BEFORE_SWITCHOVER,
MIGRATION_CAPABILITY_AUTO_CONVERGE,
MIGRATION_CAPABILITY_RELEASE_RAM,
MIGRATION_CAPABILITY_RDMA_PIN_ALL,
MIGRATION_CAPABILITY_COMPRESS,
MIGRATION_CAPABILITY_XBZRLE,
MIGRATION_CAPABILITY_X_COLO,
MIGRATION_CAPABILITY_VALIDATE_UUID,
MIGRATION_CAPABILITY_ZERO_COPY_SEND);
/* When we add fault tolerance, we could have several /* When we add fault tolerance, we could have several
migrations at once. For now we don't need to add migrations at once. For now we don't need to add
dynamic creation of migration */ dynamic creation of migration */
@ -186,7 +153,7 @@ static void migrate_fd_cancel(MigrationState *s);
static bool migration_needs_multiple_sockets(void) static bool migration_needs_multiple_sockets(void)
{ {
return migrate_use_multifd() || migrate_postcopy_preempt(); return migrate_multifd() || migrate_postcopy_preempt();
} }
static bool uri_supports_multi_channels(const char *uri) static bool uri_supports_multi_channels(const char *uri)
@ -353,20 +320,11 @@ void migration_incoming_state_destroy(void)
static void migrate_generate_event(int new_state) static void migrate_generate_event(int new_state)
{ {
if (migrate_use_events()) { if (migrate_events()) {
qapi_event_send_migration(new_state); qapi_event_send_migration(new_state);
} }
} }
static bool migrate_late_block_activate(void)
{
MigrationState *s;
s = migrate_get_current();
return s->capabilities[MIGRATION_CAPABILITY_LATE_BLOCK_ACTIVATE];
}
/* /*
* Send a message on the return channel back to the source * Send a message on the return channel back to the source
* of the migration. * of the migration.
@ -741,7 +699,7 @@ void migration_fd_process_incoming(QEMUFile *f, Error **errp)
static bool migration_should_start_incoming(bool main_channel) static bool migration_should_start_incoming(bool main_channel)
{ {
/* Multifd doesn't start unless all channels are established */ /* Multifd doesn't start unless all channels are established */
if (migrate_use_multifd()) { if (migrate_multifd()) {
return migration_has_all_channels(); return migration_has_all_channels();
} }
@ -768,7 +726,7 @@ void migration_ioc_process_incoming(QIOChannel *ioc, Error **errp)
uint32_t channel_magic = 0; uint32_t channel_magic = 0;
int ret = 0; int ret = 0;
if (migrate_use_multifd() && !migrate_postcopy_ram() && if (migrate_multifd() && !migrate_postcopy_ram() &&
qio_channel_has_feature(ioc, QIO_CHANNEL_FEATURE_READ_MSG_PEEK)) { qio_channel_has_feature(ioc, QIO_CHANNEL_FEATURE_READ_MSG_PEEK)) {
/* /*
* With multiple channels, it is possible that we receive channels * With multiple channels, it is possible that we receive channels
@ -807,7 +765,7 @@ void migration_ioc_process_incoming(QIOChannel *ioc, Error **errp)
} else { } else {
/* Multiple connections */ /* Multiple connections */
assert(migration_needs_multiple_sockets()); assert(migration_needs_multiple_sockets());
if (migrate_use_multifd()) { if (migrate_multifd()) {
multifd_recv_new_channel(ioc, &local_err); multifd_recv_new_channel(ioc, &local_err);
} else { } else {
assert(migrate_postcopy_preempt()); assert(migrate_postcopy_preempt());
@ -843,7 +801,7 @@ bool migration_has_all_channels(void)
return false; return false;
} }
if (migrate_use_multifd()) { if (migrate_multifd()) {
return multifd_recv_all_channels_created(); return multifd_recv_all_channels_created();
} }
@ -928,139 +886,6 @@ void migrate_send_rp_resume_ack(MigrationIncomingState *mis, uint32_t value)
migrate_send_rp_message(mis, MIG_RP_MSG_RESUME_ACK, sizeof(buf), &buf); migrate_send_rp_message(mis, MIG_RP_MSG_RESUME_ACK, sizeof(buf), &buf);
} }
MigrationCapabilityStatusList *qmp_query_migrate_capabilities(Error **errp)
{
MigrationCapabilityStatusList *head = NULL, **tail = &head;
MigrationCapabilityStatus *caps;
MigrationState *s = migrate_get_current();
int i;
for (i = 0; i < MIGRATION_CAPABILITY__MAX; i++) {
#ifndef CONFIG_LIVE_BLOCK_MIGRATION
if (i == MIGRATION_CAPABILITY_BLOCK) {
continue;
}
#endif
caps = g_malloc0(sizeof(*caps));
caps->capability = i;
caps->state = s->capabilities[i];
QAPI_LIST_APPEND(tail, caps);
}
return head;
}
MigrationParameters *qmp_query_migrate_parameters(Error **errp)
{
MigrationParameters *params;
MigrationState *s = migrate_get_current();
/* TODO use QAPI_CLONE() instead of duplicating it inline */
params = g_malloc0(sizeof(*params));
params->has_compress_level = true;
params->compress_level = s->parameters.compress_level;
params->has_compress_threads = true;
params->compress_threads = s->parameters.compress_threads;
params->has_compress_wait_thread = true;
params->compress_wait_thread = s->parameters.compress_wait_thread;
params->has_decompress_threads = true;
params->decompress_threads = s->parameters.decompress_threads;
params->has_throttle_trigger_threshold = true;
params->throttle_trigger_threshold = s->parameters.throttle_trigger_threshold;
params->has_cpu_throttle_initial = true;
params->cpu_throttle_initial = s->parameters.cpu_throttle_initial;
params->has_cpu_throttle_increment = true;
params->cpu_throttle_increment = s->parameters.cpu_throttle_increment;
params->has_cpu_throttle_tailslow = true;
params->cpu_throttle_tailslow = s->parameters.cpu_throttle_tailslow;
params->tls_creds = g_strdup(s->parameters.tls_creds);
params->tls_hostname = g_strdup(s->parameters.tls_hostname);
params->tls_authz = g_strdup(s->parameters.tls_authz ?
s->parameters.tls_authz : "");
params->has_max_bandwidth = true;
params->max_bandwidth = s->parameters.max_bandwidth;
params->has_downtime_limit = true;
params->downtime_limit = s->parameters.downtime_limit;
params->has_x_checkpoint_delay = true;
params->x_checkpoint_delay = s->parameters.x_checkpoint_delay;
params->has_block_incremental = true;
params->block_incremental = s->parameters.block_incremental;
params->has_multifd_channels = true;
params->multifd_channels = s->parameters.multifd_channels;
params->has_multifd_compression = true;
params->multifd_compression = s->parameters.multifd_compression;
params->has_multifd_zlib_level = true;
params->multifd_zlib_level = s->parameters.multifd_zlib_level;
params->has_multifd_zstd_level = true;
params->multifd_zstd_level = s->parameters.multifd_zstd_level;
params->has_xbzrle_cache_size = true;
params->xbzrle_cache_size = s->parameters.xbzrle_cache_size;
params->has_max_postcopy_bandwidth = true;
params->max_postcopy_bandwidth = s->parameters.max_postcopy_bandwidth;
params->has_max_cpu_throttle = true;
params->max_cpu_throttle = s->parameters.max_cpu_throttle;
params->has_announce_initial = true;
params->announce_initial = s->parameters.announce_initial;
params->has_announce_max = true;
params->announce_max = s->parameters.announce_max;
params->has_announce_rounds = true;
params->announce_rounds = s->parameters.announce_rounds;
params->has_announce_step = true;
params->announce_step = s->parameters.announce_step;
if (s->parameters.has_block_bitmap_mapping) {
params->has_block_bitmap_mapping = true;
params->block_bitmap_mapping =
QAPI_CLONE(BitmapMigrationNodeAliasList,
s->parameters.block_bitmap_mapping);
}
return params;
}
void qmp_client_migrate_info(const char *protocol, const char *hostname,
bool has_port, int64_t port,
bool has_tls_port, int64_t tls_port,
const char *cert_subject,
Error **errp)
{
if (strcmp(protocol, "spice") == 0) {
if (!qemu_using_spice(errp)) {
return;
}
if (!has_port && !has_tls_port) {
error_setg(errp, QERR_MISSING_PARAMETER, "port/tls-port");
return;
}
if (qemu_spice.migrate_info(hostname,
has_port ? port : -1,
has_tls_port ? tls_port : -1,
cert_subject)) {
error_setg(errp, "Could not set up display for migration");
return;
}
return;
}
error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "protocol", "'spice'");
}
AnnounceParameters *migrate_announce_params(void)
{
static AnnounceParameters ap;
MigrationState *s = migrate_get_current();
ap.initial = s->parameters.announce_initial;
ap.max = s->parameters.announce_max;
ap.rounds = s->parameters.announce_rounds;
ap.step = s->parameters.announce_step;
return &ap;
}
/* /*
* Return true if we're already in the middle of a migration * Return true if we're already in the middle of a migration
* (i.e. any of the active or setup states) * (i.e. any of the active or setup states)
@ -1160,7 +985,7 @@ static void populate_ram_info(MigrationInfo *info, MigrationState *s)
info->ram->downtime_bytes = stat64_get(&ram_counters.downtime_bytes); info->ram->downtime_bytes = stat64_get(&ram_counters.downtime_bytes);
info->ram->postcopy_bytes = stat64_get(&ram_counters.postcopy_bytes); info->ram->postcopy_bytes = stat64_get(&ram_counters.postcopy_bytes);
if (migrate_use_xbzrle()) { if (migrate_xbzrle()) {
info->xbzrle_cache = g_malloc0(sizeof(*info->xbzrle_cache)); info->xbzrle_cache = g_malloc0(sizeof(*info->xbzrle_cache));
info->xbzrle_cache->cache_size = migrate_xbzrle_cache_size(); info->xbzrle_cache->cache_size = migrate_xbzrle_cache_size();
info->xbzrle_cache->bytes = xbzrle_counters.bytes; info->xbzrle_cache->bytes = xbzrle_counters.bytes;
@ -1171,7 +996,7 @@ static void populate_ram_info(MigrationInfo *info, MigrationState *s)
info->xbzrle_cache->overflow = xbzrle_counters.overflow; info->xbzrle_cache->overflow = xbzrle_counters.overflow;
} }
if (migrate_use_compression()) { if (migrate_compress()) {
info->compression = g_malloc0(sizeof(*info->compression)); info->compression = g_malloc0(sizeof(*info->compression));
info->compression->pages = compression_counters.pages; info->compression->pages = compression_counters.pages;
info->compression->busy = compression_counters.busy; info->compression->busy = compression_counters.busy;
@ -1273,163 +1098,6 @@ static void fill_source_migration_info(MigrationInfo *info)
info->status = state; info->status = state;
} }
typedef enum WriteTrackingSupport {
WT_SUPPORT_UNKNOWN = 0,
WT_SUPPORT_ABSENT,
WT_SUPPORT_AVAILABLE,
WT_SUPPORT_COMPATIBLE
} WriteTrackingSupport;
static
WriteTrackingSupport migrate_query_write_tracking(void)
{
/* Check if kernel supports required UFFD features */
if (!ram_write_tracking_available()) {
return WT_SUPPORT_ABSENT;
}
/*
* Check if current memory configuration is
* compatible with required UFFD features.
*/
if (!ram_write_tracking_compatible()) {
return WT_SUPPORT_AVAILABLE;
}
return WT_SUPPORT_COMPATIBLE;
}
/**
* @migration_caps_check - check capability compatibility
*
* @old_caps: old capability list
* @new_caps: new capability list
* @errp: set *errp if the check failed, with reason
*
* Returns true if check passed, otherwise false.
*/
static bool migrate_caps_check(bool *old_caps, bool *new_caps, Error **errp)
{
MigrationIncomingState *mis = migration_incoming_get_current();
#ifndef CONFIG_LIVE_BLOCK_MIGRATION
if (new_caps[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
#ifndef CONFIG_REPLICATION
if (new_caps[MIGRATION_CAPABILITY_X_COLO]) {
error_setg(errp, "QEMU compiled without replication module"
" can't enable COLO");
error_append_hint(errp, "Please enable replication before COLO.\n");
return false;
}
#endif
if (new_caps[MIGRATION_CAPABILITY_POSTCOPY_RAM]) {
/* 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.
*/
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");
return false;
}
if (new_caps[MIGRATION_CAPABILITY_X_IGNORE_SHARED]) {
error_setg(errp, "Postcopy is not compatible with ignore-shared");
return false;
}
}
if (new_caps[MIGRATION_CAPABILITY_BACKGROUND_SNAPSHOT]) {
WriteTrackingSupport wt_support;
int idx;
/*
* Check if 'background-snapshot' capability is supported by
* host kernel and compatible with guest memory configuration.
*/
wt_support = migrate_query_write_tracking();
if (wt_support < WT_SUPPORT_AVAILABLE) {
error_setg(errp, "Background-snapshot is not supported by host kernel");
return false;
}
if (wt_support < WT_SUPPORT_COMPATIBLE) {
error_setg(errp, "Background-snapshot is not compatible "
"with guest memory configuration");
return false;
}
/*
* Check if there are any migration capabilities
* incompatible with 'background-snapshot'.
*/
for (idx = 0; idx < check_caps_background_snapshot.size; idx++) {
int incomp_cap = check_caps_background_snapshot.caps[idx];
if (new_caps[incomp_cap]) {
error_setg(errp,
"Background-snapshot is not compatible with %s",
MigrationCapability_str(incomp_cap));
return false;
}
}
}
#ifdef CONFIG_LINUX
if (new_caps[MIGRATION_CAPABILITY_ZERO_COPY_SEND] &&
(!new_caps[MIGRATION_CAPABILITY_MULTIFD] ||
new_caps[MIGRATION_CAPABILITY_COMPRESS] ||
new_caps[MIGRATION_CAPABILITY_XBZRLE] ||
migrate_multifd_compression() ||
migrate_use_tls())) {
error_setg(errp,
"Zero copy only available for non-compressed non-TLS multifd migration");
return false;
}
#else
if (new_caps[MIGRATION_CAPABILITY_ZERO_COPY_SEND]) {
error_setg(errp,
"Zero copy currently only available on Linux");
return false;
}
#endif
if (new_caps[MIGRATION_CAPABILITY_POSTCOPY_PREEMPT]) {
if (!new_caps[MIGRATION_CAPABILITY_POSTCOPY_RAM]) {
error_setg(errp, "Postcopy preempt requires postcopy-ram");
return false;
}
/*
* Preempt mode requires urgent pages to be sent in separate
* channel, OTOH compression logic will disorder all pages into
* different compression channels, which is not compatible with the
* preempt assumptions on channel assignments.
*/
if (new_caps[MIGRATION_CAPABILITY_COMPRESS]) {
error_setg(errp, "Postcopy preempt not compatible with compress");
return false;
}
}
if (new_caps[MIGRATION_CAPABILITY_MULTIFD]) {
if (new_caps[MIGRATION_CAPABILITY_COMPRESS]) {
error_setg(errp, "Multifd is not compatible with compress");
return false;
}
}
return true;
}
static void fill_destination_migration_info(MigrationInfo *info) static void fill_destination_migration_info(MigrationInfo *info)
{ {
MigrationIncomingState *mis = migration_incoming_get_current(); MigrationIncomingState *mis = migration_incoming_get_current();
@ -1472,32 +1140,6 @@ MigrationInfo *qmp_query_migrate(Error **errp)
return info; return info;
} }
void qmp_migrate_set_capabilities(MigrationCapabilityStatusList *params,
Error **errp)
{
MigrationState *s = migrate_get_current();
MigrationCapabilityStatusList *cap;
bool new_caps[MIGRATION_CAPABILITY__MAX];
if (migration_is_running(s->state)) {
error_setg(errp, QERR_MIGRATION_ACTIVE);
return;
}
memcpy(new_caps, s->capabilities, sizeof(new_caps));
for (cap = params; cap; cap = cap->next) {
new_caps[cap->value->capability] = cap->value->state;
}
if (!migrate_caps_check(s->capabilities, new_caps, errp)) {
return;
}
for (cap = params; cap; cap = cap->next) {
s->capabilities[cap->value->capability] = cap->value->state;
}
}
/* /*
* Check whether the parameters are valid. Error will be put into errp * Check whether the parameters are valid. Error will be put into errp
* (if provided). Return true if valid, otherwise false. * (if provided). Return true if valid, otherwise false.
@ -1647,7 +1289,7 @@ static bool migrate_params_check(MigrationParameters *params, Error **errp)
} }
#ifdef CONFIG_LINUX #ifdef CONFIG_LINUX
if (migrate_use_zero_copy_send() && if (migrate_zero_copy_send() &&
((params->has_multifd_compression && params->multifd_compression) || ((params->has_multifd_compression && params->multifd_compression) ||
(params->tls_creds && *params->tls_creds))) { (params->tls_creds && *params->tls_creds))) {
error_setg(errp, error_setg(errp,
@ -1942,27 +1584,6 @@ void migrate_set_state(int *state, int old_state, int new_state)
} }
} }
static MigrationCapabilityStatus *migrate_cap_add(MigrationCapability index,
bool state)
{
MigrationCapabilityStatus *cap;
cap = g_new0(MigrationCapabilityStatus, 1);
cap->capability = index;
cap->state = state;
return cap;
}
void migrate_set_block_enabled(bool value, Error **errp)
{
MigrationCapabilityStatusList *cap = NULL;
QAPI_LIST_PREPEND(cap, migrate_cap_add(MIGRATION_CAPABILITY_BLOCK, value));
qmp_migrate_set_capabilities(cap, errp);
qapi_free_MigrationCapabilityStatusList(cap);
}
static void migrate_set_block_incremental(MigrationState *s, bool value) static void migrate_set_block_incremental(MigrationState *s, bool value)
{ {
s->parameters.block_incremental = value; s->parameters.block_incremental = value;
@ -1972,7 +1593,7 @@ static void block_cleanup_parameters(MigrationState *s)
{ {
if (s->must_remove_block_options) { if (s->must_remove_block_options) {
/* setting to false can never fail */ /* setting to false can never fail */
migrate_set_block_enabled(false, &error_abort); migrate_cap_set(MIGRATION_CAPABILITY_BLOCK, false, &error_abort);
migrate_set_block_incremental(s, false); migrate_set_block_incremental(s, false);
s->must_remove_block_options = false; s->must_remove_block_options = false;
} }
@ -2450,17 +2071,16 @@ static bool migrate_prepare(MigrationState *s, bool blk, bool blk_inc,
} }
if (blk || blk_inc) { if (blk || blk_inc) {
if (migrate_colo_enabled()) { if (migrate_colo()) {
error_setg(errp, "No disk migration is required in COLO mode"); error_setg(errp, "No disk migration is required in COLO mode");
return false; return false;
} }
if (migrate_use_block() || migrate_use_block_incremental()) { if (migrate_block() || migrate_block_incremental()) {
error_setg(errp, "Command options are incompatible with " error_setg(errp, "Command options are incompatible with "
"current migration capabilities"); "current migration capabilities");
return false; return false;
} }
migrate_set_block_enabled(true, &local_err); if (!migrate_cap_set(MIGRATION_CAPABILITY_BLOCK, true, &local_err)) {
if (local_err) {
error_propagate(errp, local_err); error_propagate(errp, local_err);
return false; return false;
} }
@ -2557,203 +2177,6 @@ void qmp_migrate_continue(MigrationStatus state, Error **errp)
qemu_sem_post(&s->pause_sem); qemu_sem_post(&s->pause_sem);
} }
bool migrate_release_ram(void)
{
MigrationState *s;
s = migrate_get_current();
return s->capabilities[MIGRATION_CAPABILITY_RELEASE_RAM];
}
bool migrate_postcopy_ram(void)
{
MigrationState *s;
s = migrate_get_current();
return s->capabilities[MIGRATION_CAPABILITY_POSTCOPY_RAM];
}
bool migrate_postcopy(void)
{
return migrate_postcopy_ram() || migrate_dirty_bitmaps();
}
bool migrate_auto_converge(void)
{
MigrationState *s;
s = migrate_get_current();
return s->capabilities[MIGRATION_CAPABILITY_AUTO_CONVERGE];
}
bool migrate_zero_blocks(void)
{
MigrationState *s;
s = migrate_get_current();
return s->capabilities[MIGRATION_CAPABILITY_ZERO_BLOCKS];
}
bool migrate_postcopy_blocktime(void)
{
MigrationState *s;
s = migrate_get_current();
return s->capabilities[MIGRATION_CAPABILITY_POSTCOPY_BLOCKTIME];
}
bool migrate_use_compression(void)
{
MigrationState *s;
s = migrate_get_current();
return s->capabilities[MIGRATION_CAPABILITY_COMPRESS];
}
int migrate_compress_level(void)
{
MigrationState *s;
s = migrate_get_current();
return s->parameters.compress_level;
}
int migrate_compress_threads(void)
{
MigrationState *s;
s = migrate_get_current();
return s->parameters.compress_threads;
}
int migrate_compress_wait_thread(void)
{
MigrationState *s;
s = migrate_get_current();
return s->parameters.compress_wait_thread;
}
int migrate_decompress_threads(void)
{
MigrationState *s;
s = migrate_get_current();
return s->parameters.decompress_threads;
}
bool migrate_dirty_bitmaps(void)
{
MigrationState *s;
s = migrate_get_current();
return s->capabilities[MIGRATION_CAPABILITY_DIRTY_BITMAPS];
}
bool migrate_ignore_shared(void)
{
MigrationState *s;
s = migrate_get_current();
return s->capabilities[MIGRATION_CAPABILITY_X_IGNORE_SHARED];
}
bool migrate_validate_uuid(void)
{
MigrationState *s;
s = migrate_get_current();
return s->capabilities[MIGRATION_CAPABILITY_VALIDATE_UUID];
}
bool migrate_use_events(void)
{
MigrationState *s;
s = migrate_get_current();
return s->capabilities[MIGRATION_CAPABILITY_EVENTS];
}
bool migrate_use_multifd(void)
{
MigrationState *s;
s = migrate_get_current();
return s->capabilities[MIGRATION_CAPABILITY_MULTIFD];
}
bool migrate_pause_before_switchover(void)
{
MigrationState *s;
s = migrate_get_current();
return s->capabilities[MIGRATION_CAPABILITY_PAUSE_BEFORE_SWITCHOVER];
}
int migrate_multifd_channels(void)
{
MigrationState *s;
s = migrate_get_current();
return s->parameters.multifd_channels;
}
MultiFDCompression migrate_multifd_compression(void)
{
MigrationState *s;
s = migrate_get_current();
assert(s->parameters.multifd_compression < MULTIFD_COMPRESSION__MAX);
return s->parameters.multifd_compression;
}
int migrate_multifd_zlib_level(void)
{
MigrationState *s;
s = migrate_get_current();
return s->parameters.multifd_zlib_level;
}
int migrate_multifd_zstd_level(void)
{
MigrationState *s;
s = migrate_get_current();
return s->parameters.multifd_zstd_level;
}
#ifdef CONFIG_LINUX
bool migrate_use_zero_copy_send(void)
{
MigrationState *s;
s = migrate_get_current();
return s->capabilities[MIGRATION_CAPABILITY_ZERO_COPY_SEND];
}
#endif
int migrate_use_tls(void) int migrate_use_tls(void)
{ {
MigrationState *s; MigrationState *s;
@ -2763,78 +2186,6 @@ int migrate_use_tls(void)
return s->parameters.tls_creds && *s->parameters.tls_creds; return s->parameters.tls_creds && *s->parameters.tls_creds;
} }
int migrate_use_xbzrle(void)
{
MigrationState *s;
s = migrate_get_current();
return s->capabilities[MIGRATION_CAPABILITY_XBZRLE];
}
uint64_t migrate_xbzrle_cache_size(void)
{
MigrationState *s;
s = migrate_get_current();
return s->parameters.xbzrle_cache_size;
}
static int64_t migrate_max_postcopy_bandwidth(void)
{
MigrationState *s;
s = migrate_get_current();
return s->parameters.max_postcopy_bandwidth;
}
bool migrate_use_block(void)
{
MigrationState *s;
s = migrate_get_current();
return s->capabilities[MIGRATION_CAPABILITY_BLOCK];
}
bool migrate_use_return_path(void)
{
MigrationState *s;
s = migrate_get_current();
return s->capabilities[MIGRATION_CAPABILITY_RETURN_PATH];
}
bool migrate_use_block_incremental(void)
{
MigrationState *s;
s = migrate_get_current();
return s->parameters.block_incremental;
}
bool migrate_background_snapshot(void)
{
MigrationState *s;
s = migrate_get_current();
return s->capabilities[MIGRATION_CAPABILITY_BACKGROUND_SNAPSHOT];
}
bool migrate_postcopy_preempt(void)
{
MigrationState *s;
s = migrate_get_current();
return s->capabilities[MIGRATION_CAPABILITY_POSTCOPY_PREEMPT];
}
/* migration thread support */ /* migration thread support */
/* /*
* Something bad happened to the RP stream, mark an error * Something bad happened to the RP stream, mark an error
@ -3431,7 +2782,6 @@ static void migration_completion(MigrationState *s)
ret = global_state_store(); ret = global_state_store();
if (!ret) { if (!ret) {
bool inactivate = !migrate_colo_enabled();
ret = vm_stop_force_state(RUN_STATE_FINISH_MIGRATE); ret = vm_stop_force_state(RUN_STATE_FINISH_MIGRATE);
trace_migration_completion_vm_stop(ret); trace_migration_completion_vm_stop(ret);
if (ret >= 0) { if (ret >= 0) {
@ -3439,10 +2789,10 @@ static void migration_completion(MigrationState *s)
MIGRATION_STATUS_DEVICE); MIGRATION_STATUS_DEVICE);
} }
if (ret >= 0) { if (ret >= 0) {
s->block_inactive = inactivate; s->block_inactive = !migrate_colo();
qemu_file_set_rate_limit(s->to_dst_file, INT64_MAX); qemu_file_set_rate_limit(s->to_dst_file, INT64_MAX);
ret = qemu_savevm_state_complete_precopy(s->to_dst_file, false, ret = qemu_savevm_state_complete_precopy(s->to_dst_file, false,
inactivate); s->block_inactive);
} }
} }
qemu_mutex_unlock_iothread(); qemu_mutex_unlock_iothread();
@ -3492,7 +2842,7 @@ static void migration_completion(MigrationState *s)
goto fail_invalidate; goto fail_invalidate;
} }
if (migrate_colo_enabled() && s->state == MIGRATION_STATUS_ACTIVE) { if (migrate_colo() && s->state == MIGRATION_STATUS_ACTIVE) {
/* COLO does not support postcopy */ /* COLO does not support postcopy */
migrate_set_state(&s->state, MIGRATION_STATUS_ACTIVE, migrate_set_state(&s->state, MIGRATION_STATUS_ACTIVE,
MIGRATION_STATUS_COLO); MIGRATION_STATUS_COLO);
@ -3571,12 +2921,6 @@ fail:
MIGRATION_STATUS_FAILED); MIGRATION_STATUS_FAILED);
} }
bool migrate_colo_enabled(void)
{
MigrationState *s = migrate_get_current();
return s->capabilities[MIGRATION_CAPABILITY_X_COLO];
}
typedef enum MigThrError { typedef enum MigThrError {
/* No error detected */ /* No error detected */
MIG_THR_ERR_NONE = 0, MIG_THR_ERR_NONE = 0,
@ -3907,7 +3251,7 @@ static void migration_iteration_finish(MigrationState *s)
runstate_set(RUN_STATE_POSTMIGRATE); runstate_set(RUN_STATE_POSTMIGRATE);
break; break;
case MIGRATION_STATUS_COLO: case MIGRATION_STATUS_COLO:
if (!migrate_colo_enabled()) { if (!migrate_colo()) {
error_report("%s: critical error: calling COLO code without " error_report("%s: critical error: calling COLO code without "
"COLO enabled", __func__); "COLO enabled", __func__);
} }
@ -4103,7 +3447,7 @@ static void *migration_thread(void *opaque)
qemu_savevm_send_postcopy_advise(s->to_dst_file); qemu_savevm_send_postcopy_advise(s->to_dst_file);
} }
if (migrate_colo_enabled()) { if (migrate_colo()) {
/* Notify migration destination that we enable COLO */ /* Notify migration destination that we enable COLO */
qemu_savevm_send_colo_enable(s->to_dst_file); qemu_savevm_send_colo_enable(s->to_dst_file);
} }
@ -4355,11 +3699,11 @@ void migrate_fd_connect(MigrationState *s, Error *error_in)
if (resume) { if (resume) {
/* This is a resumed migration */ /* This is a resumed migration */
rate_limit = s->parameters.max_postcopy_bandwidth / rate_limit = migrate_max_postcopy_bandwidth() /
XFER_LIMIT_RATIO; XFER_LIMIT_RATIO;
} else { } else {
/* This is a fresh new migration */ /* This is a fresh new migration */
rate_limit = s->parameters.max_bandwidth / XFER_LIMIT_RATIO; rate_limit = migrate_max_bandwidth() / XFER_LIMIT_RATIO;
/* Notify before starting migration thread */ /* Notify before starting migration thread */
notifier_list_notify(&migration_state_notifiers, s); notifier_list_notify(&migration_state_notifiers, s);
@ -4373,7 +3717,7 @@ void migrate_fd_connect(MigrationState *s, Error *error_in)
* precopy, only if user specified "return-path" capability would * precopy, only if user specified "return-path" capability would
* QEMU uses the return path. * QEMU uses the return path.
*/ */
if (migrate_postcopy_ram() || migrate_use_return_path()) { if (migrate_postcopy_ram() || migrate_return_path()) {
if (open_return_path_on_source(s, !resume)) { if (open_return_path_on_source(s, !resume)) {
error_report("Unable to open return-path for postcopy"); error_report("Unable to open return-path for postcopy");
migrate_set_state(&s->state, s->state, MIGRATION_STATUS_FAILED); migrate_set_state(&s->state, s->state, MIGRATION_STATUS_FAILED);
@ -4417,25 +3761,6 @@ void migrate_fd_connect(MigrationState *s, Error *error_in)
s->migration_thread_running = true; s->migration_thread_running = true;
} }
void migration_global_dump(Monitor *mon)
{
MigrationState *ms = migrate_get_current();
monitor_printf(mon, "globals:\n");
monitor_printf(mon, "store-global-state: %s\n",
ms->store_global_state ? "on" : "off");
monitor_printf(mon, "only-migratable: %s\n",
only_migratable ? "on" : "off");
monitor_printf(mon, "send-configuration: %s\n",
ms->send_configuration ? "on" : "off");
monitor_printf(mon, "send-section-footer: %s\n",
ms->send_section_footer ? "on" : "off");
monitor_printf(mon, "decompress-error-check: %s\n",
ms->decompress_error_check ? "on" : "off");
monitor_printf(mon, "clear-bitmap-shift: %u\n",
ms->clear_bitmap_shift);
}
#define DEFINE_PROP_MIG_CAP(name, x) \ #define DEFINE_PROP_MIG_CAP(name, x) \
DEFINE_PROP_BOOL(name, MigrationState, capabilities[x], false) DEFINE_PROP_BOOL(name, MigrationState, capabilities[x], false)

View File

@ -447,50 +447,10 @@ bool migration_is_blocked(Error **errp);
bool migration_in_postcopy(void); bool migration_in_postcopy(void);
MigrationState *migrate_get_current(void); MigrationState *migrate_get_current(void);
bool migrate_postcopy(void);
bool migrate_release_ram(void);
bool migrate_postcopy_ram(void);
bool migrate_zero_blocks(void);
bool migrate_dirty_bitmaps(void);
bool migrate_ignore_shared(void);
bool migrate_validate_uuid(void);
bool migrate_auto_converge(void);
bool migrate_use_multifd(void);
bool migrate_pause_before_switchover(void);
int migrate_multifd_channels(void);
MultiFDCompression migrate_multifd_compression(void);
int migrate_multifd_zlib_level(void);
int migrate_multifd_zstd_level(void);
#ifdef CONFIG_LINUX
bool migrate_use_zero_copy_send(void);
#else
#define migrate_use_zero_copy_send() (false)
#endif
int migrate_use_tls(void); int migrate_use_tls(void);
int migrate_use_xbzrle(void);
uint64_t migrate_xbzrle_cache_size(void);
bool migrate_colo_enabled(void);
bool migrate_use_block(void);
bool migrate_use_block_incremental(void);
int migrate_max_cpu_throttle(void);
bool migrate_use_return_path(void);
uint64_t ram_get_total_transferred_pages(void); uint64_t ram_get_total_transferred_pages(void);
bool migrate_use_compression(void);
int migrate_compress_level(void);
int migrate_compress_threads(void);
int migrate_compress_wait_thread(void);
int migrate_decompress_threads(void);
bool migrate_use_events(void);
bool migrate_postcopy_blocktime(void);
bool migrate_background_snapshot(void);
bool migrate_postcopy_preempt(void);
/* Sending on the return path - generic and then for each message type */ /* Sending on the return path - generic and then for each message type */
void migrate_send_rp_shut(MigrationIncomingState *mis, void migrate_send_rp_shut(MigrationIncomingState *mis,
uint32_t value); uint32_t value);

View File

@ -18,6 +18,7 @@
#include "qapi/error.h" #include "qapi/error.h"
#include "migration.h" #include "migration.h"
#include "trace.h" #include "trace.h"
#include "options.h"
#include "multifd.h" #include "multifd.h"
struct zlib_data { struct zlib_data {

View File

@ -18,6 +18,7 @@
#include "qapi/error.h" #include "qapi/error.h"
#include "migration.h" #include "migration.h"
#include "trace.h" #include "trace.h"
#include "options.h"
#include "multifd.h" #include "multifd.h"
struct zstd_data { struct zstd_data {

View File

@ -25,7 +25,7 @@
#include "trace.h" #include "trace.h"
#include "multifd.h" #include "multifd.h"
#include "threadinfo.h" #include "threadinfo.h"
#include "options.h"
#include "qemu/yank.h" #include "qemu/yank.h"
#include "io/channel-socket.h" #include "io/channel-socket.h"
#include "yank_functions.h" #include "yank_functions.h"
@ -516,7 +516,7 @@ void multifd_save_cleanup(void)
{ {
int i; int i;
if (!migrate_use_multifd()) { if (!migrate_multifd()) {
return; return;
} }
multifd_send_terminate_threads(NULL); multifd_send_terminate_threads(NULL);
@ -587,7 +587,7 @@ int multifd_send_sync_main(QEMUFile *f)
int i; int i;
bool flush_zero_copy; bool flush_zero_copy;
if (!migrate_use_multifd()) { if (!migrate_multifd()) {
return 0; return 0;
} }
if (multifd_send_state->pages->num) { if (multifd_send_state->pages->num) {
@ -608,7 +608,7 @@ int multifd_send_sync_main(QEMUFile *f)
* all the dirty bitmaps. * all the dirty bitmaps.
*/ */
flush_zero_copy = migrate_use_zero_copy_send(); flush_zero_copy = migrate_zero_copy_send();
for (i = 0; i < migrate_multifd_channels(); i++) { for (i = 0; i < migrate_multifd_channels(); i++) {
MultiFDSendParams *p = &multifd_send_state->params[i]; MultiFDSendParams *p = &multifd_send_state->params[i];
@ -653,7 +653,7 @@ static void *multifd_send_thread(void *opaque)
MigrationThread *thread = NULL; MigrationThread *thread = NULL;
Error *local_err = NULL; Error *local_err = NULL;
int ret = 0; int ret = 0;
bool use_zero_copy_send = migrate_use_zero_copy_send(); bool use_zero_copy_send = migrate_zero_copy_send();
thread = MigrationThreadAdd(p->name, qemu_get_thread_id()); thread = MigrationThreadAdd(p->name, qemu_get_thread_id());
@ -911,7 +911,7 @@ int multifd_save_setup(Error **errp)
uint32_t page_count = MULTIFD_PACKET_SIZE / qemu_target_page_size(); uint32_t page_count = MULTIFD_PACKET_SIZE / qemu_target_page_size();
uint8_t i; uint8_t i;
if (!migrate_use_multifd()) { if (!migrate_multifd()) {
return 0; return 0;
} }
@ -945,7 +945,7 @@ int multifd_save_setup(Error **errp)
p->page_size = qemu_target_page_size(); p->page_size = qemu_target_page_size();
p->page_count = page_count; p->page_count = page_count;
if (migrate_use_zero_copy_send()) { if (migrate_zero_copy_send()) {
p->write_flags = QIO_CHANNEL_WRITE_FLAG_ZERO_COPY; p->write_flags = QIO_CHANNEL_WRITE_FLAG_ZERO_COPY;
} else { } else {
p->write_flags = 0; p->write_flags = 0;
@ -1016,7 +1016,7 @@ static void multifd_recv_terminate_threads(Error *err)
void multifd_load_shutdown(void) void multifd_load_shutdown(void)
{ {
if (migrate_use_multifd()) { if (migrate_multifd()) {
multifd_recv_terminate_threads(NULL); multifd_recv_terminate_threads(NULL);
} }
} }
@ -1025,7 +1025,7 @@ void multifd_load_cleanup(void)
{ {
int i; int i;
if (!migrate_use_multifd()) { if (!migrate_multifd()) {
return; return;
} }
multifd_recv_terminate_threads(NULL); multifd_recv_terminate_threads(NULL);
@ -1072,7 +1072,7 @@ void multifd_recv_sync_main(void)
{ {
int i; int i;
if (!migrate_use_multifd()) { if (!migrate_multifd()) {
return; return;
} }
for (i = 0; i < migrate_multifd_channels(); i++) { for (i = 0; i < migrate_multifd_channels(); i++) {
@ -1170,7 +1170,7 @@ int multifd_load_setup(Error **errp)
* Return successfully if multiFD recv state is already initialised * Return successfully if multiFD recv state is already initialised
* or multiFD is not enabled. * or multiFD is not enabled.
*/ */
if (multifd_recv_state || !migrate_use_multifd()) { if (multifd_recv_state || !migrate_multifd()) {
return 0; return 0;
} }
@ -1216,7 +1216,7 @@ bool multifd_recv_all_channels_created(void)
{ {
int thread_count = migrate_multifd_channels(); int thread_count = migrate_multifd_channels();
if (!migrate_use_multifd()) { if (!migrate_multifd()) {
return true; return true;
} }

722
migration/options.c Normal file
View File

@ -0,0 +1,722 @@
/*
* QEMU migration capabilities
*
* Copyright (c) 2012-2023 Red Hat Inc
*
* Authors:
* Orit Wasserman <owasserm@redhat.com>
* Juan Quintela <quintela@redhat.com>
*
* This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
*/
#include "qemu/osdep.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 "sysemu/runstate.h"
#include "migration/misc.h"
#include "migration.h"
#include "ram.h"
#include "options.h"
bool migrate_auto_converge(void)
{
MigrationState *s;
s = migrate_get_current();
return s->capabilities[MIGRATION_CAPABILITY_AUTO_CONVERGE];
}
bool migrate_background_snapshot(void)
{
MigrationState *s;
s = migrate_get_current();
return s->capabilities[MIGRATION_CAPABILITY_BACKGROUND_SNAPSHOT];
}
bool migrate_block(void)
{
MigrationState *s;
s = migrate_get_current();
return s->capabilities[MIGRATION_CAPABILITY_BLOCK];
}
bool migrate_colo(void)
{
MigrationState *s = migrate_get_current();
return s->capabilities[MIGRATION_CAPABILITY_X_COLO];
}
bool migrate_compress(void)
{
MigrationState *s;
s = migrate_get_current();
return s->capabilities[MIGRATION_CAPABILITY_COMPRESS];
}
bool migrate_dirty_bitmaps(void)
{
MigrationState *s;
s = migrate_get_current();
return s->capabilities[MIGRATION_CAPABILITY_DIRTY_BITMAPS];
}
bool migrate_events(void)
{
MigrationState *s;
s = migrate_get_current();
return s->capabilities[MIGRATION_CAPABILITY_EVENTS];
}
bool migrate_ignore_shared(void)
{
MigrationState *s;
s = migrate_get_current();
return s->capabilities[MIGRATION_CAPABILITY_X_IGNORE_SHARED];
}
bool migrate_late_block_activate(void)
{
MigrationState *s;
s = migrate_get_current();
return s->capabilities[MIGRATION_CAPABILITY_LATE_BLOCK_ACTIVATE];
}
bool migrate_multifd(void)
{
MigrationState *s;
s = migrate_get_current();
return s->capabilities[MIGRATION_CAPABILITY_MULTIFD];
}
bool migrate_pause_before_switchover(void)
{
MigrationState *s;
s = migrate_get_current();
return s->capabilities[MIGRATION_CAPABILITY_PAUSE_BEFORE_SWITCHOVER];
}
bool migrate_postcopy_blocktime(void)
{
MigrationState *s;
s = migrate_get_current();
return s->capabilities[MIGRATION_CAPABILITY_POSTCOPY_BLOCKTIME];
}
bool migrate_postcopy_preempt(void)
{
MigrationState *s;
s = migrate_get_current();
return s->capabilities[MIGRATION_CAPABILITY_POSTCOPY_PREEMPT];
}
bool migrate_postcopy_ram(void)
{
MigrationState *s;
s = migrate_get_current();
return s->capabilities[MIGRATION_CAPABILITY_POSTCOPY_RAM];
}
bool migrate_rdma_pin_all(void)
{
MigrationState *s = migrate_get_current();
return s->capabilities[MIGRATION_CAPABILITY_RDMA_PIN_ALL];
}
bool migrate_release_ram(void)
{
MigrationState *s;
s = migrate_get_current();
return s->capabilities[MIGRATION_CAPABILITY_RELEASE_RAM];
}
bool migrate_return_path(void)
{
MigrationState *s;
s = migrate_get_current();
return s->capabilities[MIGRATION_CAPABILITY_RETURN_PATH];
}
bool migrate_validate_uuid(void)
{
MigrationState *s;
s = migrate_get_current();
return s->capabilities[MIGRATION_CAPABILITY_VALIDATE_UUID];
}
bool migrate_xbzrle(void)
{
MigrationState *s;
s = migrate_get_current();
return s->capabilities[MIGRATION_CAPABILITY_XBZRLE];
}
bool migrate_zero_blocks(void)
{
MigrationState *s;
s = migrate_get_current();
return s->capabilities[MIGRATION_CAPABILITY_ZERO_BLOCKS];
}
bool migrate_zero_copy_send(void)
{
MigrationState *s;
s = migrate_get_current();
return s->capabilities[MIGRATION_CAPABILITY_ZERO_COPY_SEND];
}
/* pseudo capabilities */
bool migrate_postcopy(void)
{
return migrate_postcopy_ram() || migrate_dirty_bitmaps();
}
typedef enum WriteTrackingSupport {
WT_SUPPORT_UNKNOWN = 0,
WT_SUPPORT_ABSENT,
WT_SUPPORT_AVAILABLE,
WT_SUPPORT_COMPATIBLE
} WriteTrackingSupport;
static
WriteTrackingSupport migrate_query_write_tracking(void)
{
/* Check if kernel supports required UFFD features */
if (!ram_write_tracking_available()) {
return WT_SUPPORT_ABSENT;
}
/*
* Check if current memory configuration is
* compatible with required UFFD features.
*/
if (!ram_write_tracking_compatible()) {
return WT_SUPPORT_AVAILABLE;
}
return WT_SUPPORT_COMPATIBLE;
}
/* Migration capabilities set */
struct MigrateCapsSet {
int size; /* Capability set size */
MigrationCapability caps[]; /* Variadic array of capabilities */
};
typedef struct MigrateCapsSet MigrateCapsSet;
/* Define and initialize MigrateCapsSet */
#define INITIALIZE_MIGRATE_CAPS_SET(_name, ...) \
MigrateCapsSet _name = { \
.size = sizeof((int []) { __VA_ARGS__ }) / sizeof(int), \
.caps = { __VA_ARGS__ } \
}
/* Background-snapshot compatibility check list */
static const
INITIALIZE_MIGRATE_CAPS_SET(check_caps_background_snapshot,
MIGRATION_CAPABILITY_POSTCOPY_RAM,
MIGRATION_CAPABILITY_DIRTY_BITMAPS,
MIGRATION_CAPABILITY_POSTCOPY_BLOCKTIME,
MIGRATION_CAPABILITY_LATE_BLOCK_ACTIVATE,
MIGRATION_CAPABILITY_RETURN_PATH,
MIGRATION_CAPABILITY_MULTIFD,
MIGRATION_CAPABILITY_PAUSE_BEFORE_SWITCHOVER,
MIGRATION_CAPABILITY_AUTO_CONVERGE,
MIGRATION_CAPABILITY_RELEASE_RAM,
MIGRATION_CAPABILITY_RDMA_PIN_ALL,
MIGRATION_CAPABILITY_COMPRESS,
MIGRATION_CAPABILITY_XBZRLE,
MIGRATION_CAPABILITY_X_COLO,
MIGRATION_CAPABILITY_VALIDATE_UUID,
MIGRATION_CAPABILITY_ZERO_COPY_SEND);
/**
* @migration_caps_check - check capability compatibility
*
* @old_caps: old capability list
* @new_caps: new capability list
* @errp: set *errp if the check failed, with reason
*
* Returns true if check passed, otherwise false.
*/
bool migrate_caps_check(bool *old_caps, bool *new_caps, Error **errp)
{
MigrationIncomingState *mis = migration_incoming_get_current();
#ifndef CONFIG_LIVE_BLOCK_MIGRATION
if (new_caps[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
#ifndef CONFIG_REPLICATION
if (new_caps[MIGRATION_CAPABILITY_X_COLO]) {
error_setg(errp, "QEMU compiled without replication module"
" can't enable COLO");
error_append_hint(errp, "Please enable replication before COLO.\n");
return false;
}
#endif
if (new_caps[MIGRATION_CAPABILITY_POSTCOPY_RAM]) {
/* 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.
*/
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");
return false;
}
if (new_caps[MIGRATION_CAPABILITY_X_IGNORE_SHARED]) {
error_setg(errp, "Postcopy is not compatible with ignore-shared");
return false;
}
}
if (new_caps[MIGRATION_CAPABILITY_BACKGROUND_SNAPSHOT]) {
WriteTrackingSupport wt_support;
int idx;
/*
* Check if 'background-snapshot' capability is supported by
* host kernel and compatible with guest memory configuration.
*/
wt_support = migrate_query_write_tracking();
if (wt_support < WT_SUPPORT_AVAILABLE) {
error_setg(errp, "Background-snapshot is not supported by host kernel");
return false;
}
if (wt_support < WT_SUPPORT_COMPATIBLE) {
error_setg(errp, "Background-snapshot is not compatible "
"with guest memory configuration");
return false;
}
/*
* Check if there are any migration capabilities
* incompatible with 'background-snapshot'.
*/
for (idx = 0; idx < check_caps_background_snapshot.size; idx++) {
int incomp_cap = check_caps_background_snapshot.caps[idx];
if (new_caps[incomp_cap]) {
error_setg(errp,
"Background-snapshot is not compatible with %s",
MigrationCapability_str(incomp_cap));
return false;
}
}
}
#ifdef CONFIG_LINUX
if (new_caps[MIGRATION_CAPABILITY_ZERO_COPY_SEND] &&
(!new_caps[MIGRATION_CAPABILITY_MULTIFD] ||
new_caps[MIGRATION_CAPABILITY_COMPRESS] ||
new_caps[MIGRATION_CAPABILITY_XBZRLE] ||
migrate_multifd_compression() ||
migrate_use_tls())) {
error_setg(errp,
"Zero copy only available for non-compressed non-TLS multifd migration");
return false;
}
#else
if (new_caps[MIGRATION_CAPABILITY_ZERO_COPY_SEND]) {
error_setg(errp,
"Zero copy currently only available on Linux");
return false;
}
#endif
if (new_caps[MIGRATION_CAPABILITY_POSTCOPY_PREEMPT]) {
if (!new_caps[MIGRATION_CAPABILITY_POSTCOPY_RAM]) {
error_setg(errp, "Postcopy preempt requires postcopy-ram");
return false;
}
/*
* Preempt mode requires urgent pages to be sent in separate
* channel, OTOH compression logic will disorder all pages into
* different compression channels, which is not compatible with the
* preempt assumptions on channel assignments.
*/
if (new_caps[MIGRATION_CAPABILITY_COMPRESS]) {
error_setg(errp, "Postcopy preempt not compatible with compress");
return false;
}
}
if (new_caps[MIGRATION_CAPABILITY_MULTIFD]) {
if (new_caps[MIGRATION_CAPABILITY_COMPRESS]) {
error_setg(errp, "Multifd is not compatible with compress");
return false;
}
}
return true;
}
bool migrate_cap_set(int cap, bool value, Error **errp)
{
MigrationState *s = migrate_get_current();
bool new_caps[MIGRATION_CAPABILITY__MAX];
if (migration_is_running(s->state)) {
error_setg(errp, QERR_MIGRATION_ACTIVE);
return false;
}
memcpy(new_caps, s->capabilities, sizeof(new_caps));
new_caps[cap] = value;
if (!migrate_caps_check(s->capabilities, new_caps, errp)) {
return false;
}
s->capabilities[cap] = value;
return true;
}
MigrationCapabilityStatusList *qmp_query_migrate_capabilities(Error **errp)
{
MigrationCapabilityStatusList *head = NULL, **tail = &head;
MigrationCapabilityStatus *caps;
MigrationState *s = migrate_get_current();
int i;
for (i = 0; i < MIGRATION_CAPABILITY__MAX; i++) {
#ifndef CONFIG_LIVE_BLOCK_MIGRATION
if (i == MIGRATION_CAPABILITY_BLOCK) {
continue;
}
#endif
caps = g_malloc0(sizeof(*caps));
caps->capability = i;
caps->state = s->capabilities[i];
QAPI_LIST_APPEND(tail, caps);
}
return head;
}
void qmp_migrate_set_capabilities(MigrationCapabilityStatusList *params,
Error **errp)
{
MigrationState *s = migrate_get_current();
MigrationCapabilityStatusList *cap;
bool new_caps[MIGRATION_CAPABILITY__MAX];
if (migration_is_running(s->state)) {
error_setg(errp, QERR_MIGRATION_ACTIVE);
return;
}
memcpy(new_caps, s->capabilities, sizeof(new_caps));
for (cap = params; cap; cap = cap->next) {
new_caps[cap->value->capability] = cap->value->state;
}
if (!migrate_caps_check(s->capabilities, new_caps, errp)) {
return;
}
for (cap = params; cap; cap = cap->next) {
s->capabilities[cap->value->capability] = cap->value->state;
}
}
/* parameters */
bool migrate_block_incremental(void)
{
MigrationState *s;
s = migrate_get_current();
return s->parameters.block_incremental;
}
uint32_t migrate_checkpoint_delay(void)
{
MigrationState *s;
s = migrate_get_current();
return s->parameters.x_checkpoint_delay;
}
int migrate_compress_level(void)
{
MigrationState *s;
s = migrate_get_current();
return s->parameters.compress_level;
}
int migrate_compress_threads(void)
{
MigrationState *s;
s = migrate_get_current();
return s->parameters.compress_threads;
}
int migrate_compress_wait_thread(void)
{
MigrationState *s;
s = migrate_get_current();
return s->parameters.compress_wait_thread;
}
uint8_t migrate_cpu_throttle_increment(void)
{
MigrationState *s;
s = migrate_get_current();
return s->parameters.cpu_throttle_increment;
}
uint8_t migrate_cpu_throttle_initial(void)
{
MigrationState *s;
s = migrate_get_current();
return s->parameters.cpu_throttle_initial;
}
bool migrate_cpu_throttle_tailslow(void)
{
MigrationState *s;
s = migrate_get_current();
return s->parameters.cpu_throttle_tailslow;
}
int migrate_decompress_threads(void)
{
MigrationState *s;
s = migrate_get_current();
return s->parameters.decompress_threads;
}
uint8_t migrate_max_cpu_throttle(void)
{
MigrationState *s;
s = migrate_get_current();
return s->parameters.max_cpu_throttle;
}
uint64_t migrate_max_bandwidth(void)
{
MigrationState *s;
s = migrate_get_current();
return s->parameters.max_bandwidth;
}
int64_t migrate_max_postcopy_bandwidth(void)
{
MigrationState *s;
s = migrate_get_current();
return s->parameters.max_postcopy_bandwidth;
}
int migrate_multifd_channels(void)
{
MigrationState *s;
s = migrate_get_current();
return s->parameters.multifd_channels;
}
MultiFDCompression migrate_multifd_compression(void)
{
MigrationState *s;
s = migrate_get_current();
assert(s->parameters.multifd_compression < MULTIFD_COMPRESSION__MAX);
return s->parameters.multifd_compression;
}
int migrate_multifd_zlib_level(void)
{
MigrationState *s;
s = migrate_get_current();
return s->parameters.multifd_zlib_level;
}
int migrate_multifd_zstd_level(void)
{
MigrationState *s;
s = migrate_get_current();
return s->parameters.multifd_zstd_level;
}
uint8_t migrate_throttle_trigger_threshold(void)
{
MigrationState *s;
s = migrate_get_current();
return s->parameters.throttle_trigger_threshold;
}
uint64_t migrate_xbzrle_cache_size(void)
{
MigrationState *s;
s = migrate_get_current();
return s->parameters.xbzrle_cache_size;
}
/* parameters helpers */
AnnounceParameters *migrate_announce_params(void)
{
static AnnounceParameters ap;
MigrationState *s = migrate_get_current();
ap.initial = s->parameters.announce_initial;
ap.max = s->parameters.announce_max;
ap.rounds = s->parameters.announce_rounds;
ap.step = s->parameters.announce_step;
return &ap;
}
MigrationParameters *qmp_query_migrate_parameters(Error **errp)
{
MigrationParameters *params;
MigrationState *s = migrate_get_current();
/* TODO use QAPI_CLONE() instead of duplicating it inline */
params = g_malloc0(sizeof(*params));
params->has_compress_level = true;
params->compress_level = s->parameters.compress_level;
params->has_compress_threads = true;
params->compress_threads = s->parameters.compress_threads;
params->has_compress_wait_thread = true;
params->compress_wait_thread = s->parameters.compress_wait_thread;
params->has_decompress_threads = true;
params->decompress_threads = s->parameters.decompress_threads;
params->has_throttle_trigger_threshold = true;
params->throttle_trigger_threshold = s->parameters.throttle_trigger_threshold;
params->has_cpu_throttle_initial = true;
params->cpu_throttle_initial = s->parameters.cpu_throttle_initial;
params->has_cpu_throttle_increment = true;
params->cpu_throttle_increment = s->parameters.cpu_throttle_increment;
params->has_cpu_throttle_tailslow = true;
params->cpu_throttle_tailslow = s->parameters.cpu_throttle_tailslow;
params->tls_creds = g_strdup(s->parameters.tls_creds);
params->tls_hostname = g_strdup(s->parameters.tls_hostname);
params->tls_authz = g_strdup(s->parameters.tls_authz ?
s->parameters.tls_authz : "");
params->has_max_bandwidth = true;
params->max_bandwidth = s->parameters.max_bandwidth;
params->has_downtime_limit = true;
params->downtime_limit = s->parameters.downtime_limit;
params->has_x_checkpoint_delay = true;
params->x_checkpoint_delay = s->parameters.x_checkpoint_delay;
params->has_block_incremental = true;
params->block_incremental = s->parameters.block_incremental;
params->has_multifd_channels = true;
params->multifd_channels = s->parameters.multifd_channels;
params->has_multifd_compression = true;
params->multifd_compression = s->parameters.multifd_compression;
params->has_multifd_zlib_level = true;
params->multifd_zlib_level = s->parameters.multifd_zlib_level;
params->has_multifd_zstd_level = true;
params->multifd_zstd_level = s->parameters.multifd_zstd_level;
params->has_xbzrle_cache_size = true;
params->xbzrle_cache_size = s->parameters.xbzrle_cache_size;
params->has_max_postcopy_bandwidth = true;
params->max_postcopy_bandwidth = s->parameters.max_postcopy_bandwidth;
params->has_max_cpu_throttle = true;
params->max_cpu_throttle = s->parameters.max_cpu_throttle;
params->has_announce_initial = true;
params->announce_initial = s->parameters.announce_initial;
params->has_announce_max = true;
params->announce_max = s->parameters.announce_max;
params->has_announce_rounds = true;
params->announce_rounds = s->parameters.announce_rounds;
params->has_announce_step = true;
params->announce_step = s->parameters.announce_step;
if (s->parameters.has_block_bitmap_mapping) {
params->has_block_bitmap_mapping = true;
params->block_bitmap_mapping =
QAPI_CLONE(BitmapMigrationNodeAliasList,
s->parameters.block_bitmap_mapping);
}
return params;
}

76
migration/options.h Normal file
View File

@ -0,0 +1,76 @@
/*
* QEMU migration capabilities
*
* Copyright (c) 2012-2023 Red Hat Inc
*
* Authors:
* Orit Wasserman <owasserm@redhat.com>
* Juan Quintela <quintela@redhat.com>
*
* This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
*/
#ifndef QEMU_MIGRATION_OPTIONS_H
#define QEMU_MIGRATION_OPTIONS_H
/* capabilities */
bool migrate_auto_converge(void);
bool migrate_background_snapshot(void);
bool migrate_block(void);
bool migrate_colo(void);
bool migrate_compress(void);
bool migrate_dirty_bitmaps(void);
bool migrate_events(void);
bool migrate_ignore_shared(void);
bool migrate_late_block_activate(void);
bool migrate_multifd(void);
bool migrate_pause_before_switchover(void);
bool migrate_postcopy_blocktime(void);
bool migrate_postcopy_preempt(void);
bool migrate_postcopy_ram(void);
bool migrate_rdma_pin_all(void);
bool migrate_release_ram(void);
bool migrate_return_path(void);
bool migrate_validate_uuid(void);
bool migrate_xbzrle(void);
bool migrate_zero_blocks(void);
bool migrate_zero_copy_send(void);
/*
* pseudo capabilities
*
* These are functions that are used in a similar way to capabilities
* check, but they are not a capability.
*/
bool migrate_postcopy(void);
/* capabilities helpers */
bool migrate_caps_check(bool *old_caps, bool *new_caps, Error **errp);
bool migrate_cap_set(int cap, bool value, Error **errp);
/* parameters */
bool migrate_block_incremental(void);
uint32_t migrate_checkpoint_delay(void);
int migrate_compress_level(void);
int migrate_compress_threads(void);
int migrate_compress_wait_thread(void);
uint8_t migrate_cpu_throttle_increment(void);
uint8_t migrate_cpu_throttle_initial(void);
bool migrate_cpu_throttle_tailslow(void);
int migrate_decompress_threads(void);
uint8_t migrate_max_cpu_throttle(void);
uint64_t migrate_max_bandwidth(void);
int64_t migrate_max_postcopy_bandwidth(void);
int migrate_multifd_channels(void);
MultiFDCompression migrate_multifd_compression(void);
int migrate_multifd_zlib_level(void);
int migrate_multifd_zstd_level(void);
uint8_t migrate_throttle_trigger_threshold(void);
uint64_t migrate_xbzrle_cache_size(void);
#endif

View File

@ -37,6 +37,7 @@
#include "tls.h" #include "tls.h"
#include "qemu/userfaultfd.h" #include "qemu/userfaultfd.h"
#include "qemu/mmap-alloc.h" #include "qemu/mmap-alloc.h"
#include "options.h"
/* Arbitrary limit on size of each discard command, /* Arbitrary limit on size of each discard command,
* keeps them around ~200 bytes * keeps them around ~200 bytes

View File

@ -57,6 +57,7 @@
#include "qemu/iov.h" #include "qemu/iov.h"
#include "multifd.h" #include "multifd.h"
#include "sysemu/runstate.h" #include "sysemu/runstate.h"
#include "options.h"
#include "hw/boards.h" /* for machine_dump_guest_core() */ #include "hw/boards.h" /* for machine_dump_guest_core() */
@ -155,14 +156,14 @@ static struct {
static void XBZRLE_cache_lock(void) static void XBZRLE_cache_lock(void)
{ {
if (migrate_use_xbzrle()) { if (migrate_xbzrle()) {
qemu_mutex_lock(&XBZRLE.lock); qemu_mutex_lock(&XBZRLE.lock);
} }
} }
static void XBZRLE_cache_unlock(void) static void XBZRLE_cache_unlock(void)
{ {
if (migrate_use_xbzrle()) { if (migrate_xbzrle()) {
qemu_mutex_unlock(&XBZRLE.lock); qemu_mutex_unlock(&XBZRLE.lock);
} }
} }
@ -585,7 +586,7 @@ static void compress_threads_save_cleanup(void)
{ {
int i, thread_count; int i, thread_count;
if (!migrate_use_compression() || !comp_param) { if (!migrate_compress() || !comp_param) {
return; return;
} }
@ -624,7 +625,7 @@ static int compress_threads_save_setup(void)
{ {
int i, thread_count; int i, thread_count;
if (!migrate_use_compression()) { if (!migrate_compress()) {
return 0; return 0;
} }
thread_count = migrate_compress_threads(); thread_count = migrate_compress_threads();
@ -710,11 +711,10 @@ static size_t save_page_header(PageSearchStatus *pss, QEMUFile *f,
static void mig_throttle_guest_down(uint64_t bytes_dirty_period, static void mig_throttle_guest_down(uint64_t bytes_dirty_period,
uint64_t bytes_dirty_threshold) uint64_t bytes_dirty_threshold)
{ {
MigrationState *s = migrate_get_current(); uint64_t pct_initial = migrate_cpu_throttle_initial();
uint64_t pct_initial = s->parameters.cpu_throttle_initial; uint64_t pct_increment = migrate_cpu_throttle_increment();
uint64_t pct_increment = s->parameters.cpu_throttle_increment; bool pct_tailslow = migrate_cpu_throttle_tailslow();
bool pct_tailslow = s->parameters.cpu_throttle_tailslow; int pct_max = migrate_max_cpu_throttle();
int pct_max = s->parameters.max_cpu_throttle;
uint64_t throttle_now = cpu_throttle_get_percentage(); uint64_t throttle_now = cpu_throttle_get_percentage();
uint64_t cpu_now, cpu_ideal, throttle_inc; uint64_t cpu_now, cpu_ideal, throttle_inc;
@ -1136,7 +1136,7 @@ static void migration_update_rates(RAMState *rs, int64_t end_time)
return; return;
} }
if (migrate_use_xbzrle()) { if (migrate_xbzrle()) {
double encoded_size, unencoded_size; double encoded_size, unencoded_size;
xbzrle_counters.cache_miss_rate = (double)(xbzrle_counters.cache_miss - xbzrle_counters.cache_miss_rate = (double)(xbzrle_counters.cache_miss -
@ -1154,7 +1154,7 @@ static void migration_update_rates(RAMState *rs, int64_t end_time)
rs->xbzrle_bytes_prev = xbzrle_counters.bytes; rs->xbzrle_bytes_prev = xbzrle_counters.bytes;
} }
if (migrate_use_compression()) { if (migrate_compress()) {
compression_counters.busy_rate = (double)(compression_counters.busy - compression_counters.busy_rate = (double)(compression_counters.busy -
rs->compress_thread_busy_prev) / page_count; rs->compress_thread_busy_prev) / page_count;
rs->compress_thread_busy_prev = compression_counters.busy; rs->compress_thread_busy_prev = compression_counters.busy;
@ -1177,8 +1177,7 @@ static void migration_update_rates(RAMState *rs, int64_t end_time)
static void migration_trigger_throttle(RAMState *rs) static void migration_trigger_throttle(RAMState *rs)
{ {
MigrationState *s = migrate_get_current(); uint64_t threshold = migrate_throttle_trigger_threshold();
uint64_t threshold = s->parameters.throttle_trigger_threshold;
uint64_t bytes_xfer_period = uint64_t bytes_xfer_period =
stat64_get(&ram_counters.transferred) - rs->bytes_xfer_prev; stat64_get(&ram_counters.transferred) - rs->bytes_xfer_prev;
uint64_t bytes_dirty_period = rs->num_dirty_pages_period * TARGET_PAGE_SIZE; uint64_t bytes_dirty_period = rs->num_dirty_pages_period * TARGET_PAGE_SIZE;
@ -1245,7 +1244,7 @@ static void migration_bitmap_sync(RAMState *rs)
rs->num_dirty_pages_period = 0; rs->num_dirty_pages_period = 0;
rs->bytes_xfer_prev = stat64_get(&ram_counters.transferred); rs->bytes_xfer_prev = stat64_get(&ram_counters.transferred);
} }
if (migrate_use_events()) { if (migrate_events()) {
uint64_t generation = stat64_get(&ram_counters.dirty_sync_count); uint64_t generation = stat64_get(&ram_counters.dirty_sync_count);
qapi_event_send_migration_pass(generation); qapi_event_send_migration_pass(generation);
} }
@ -1625,7 +1624,7 @@ static int find_dirty_block(RAMState *rs, PageSearchStatus *pss)
/* Flag that we've looped */ /* Flag that we've looped */
pss->complete_round = true; pss->complete_round = true;
/* After the first round, enable XBZRLE. */ /* After the first round, enable XBZRLE. */
if (migrate_use_xbzrle()) { if (migrate_xbzrle()) {
rs->xbzrle_enabled = true; rs->xbzrle_enabled = true;
} }
} }
@ -2269,7 +2268,7 @@ int ram_save_queue_pages(const char *rbname, ram_addr_t start, ram_addr_t len)
static bool save_page_use_compression(RAMState *rs) static bool save_page_use_compression(RAMState *rs)
{ {
if (!migrate_use_compression()) { if (!migrate_compress()) {
return false; return false;
} }
@ -2361,7 +2360,7 @@ static int ram_save_target_page_legacy(RAMState *rs, PageSearchStatus *pss)
* if host page size == guest page size the dest guest during run may * if host page size == guest page size the dest guest during run may
* still see partially copied pages which is data corruption. * still see partially copied pages which is data corruption.
*/ */
if (migrate_use_multifd() && !migration_in_postcopy()) { if (migrate_multifd() && !migration_in_postcopy()) {
return ram_save_multifd_page(pss->pss_channel, block, offset); return ram_save_multifd_page(pss->pss_channel, block, offset);
} }
@ -2978,7 +2977,7 @@ static int xbzrle_init(void)
{ {
Error *local_err = NULL; Error *local_err = NULL;
if (!migrate_use_xbzrle()) { if (!migrate_xbzrle()) {
return 0; return 0;
} }
@ -3733,7 +3732,7 @@ static int wait_for_decompress_done(void)
{ {
int idx, thread_count; int idx, thread_count;
if (!migrate_use_compression()) { if (!migrate_compress()) {
return 0; return 0;
} }
@ -3752,7 +3751,7 @@ static void compress_threads_load_cleanup(void)
{ {
int i, thread_count; int i, thread_count;
if (!migrate_use_compression()) { if (!migrate_compress()) {
return; return;
} }
thread_count = migrate_decompress_threads(); thread_count = migrate_decompress_threads();
@ -3793,7 +3792,7 @@ static int compress_threads_load_setup(QEMUFile *f)
{ {
int i, thread_count; int i, thread_count;
if (!migrate_use_compression()) { if (!migrate_compress()) {
return 0; return 0;
} }
@ -4259,7 +4258,7 @@ static int ram_load_precopy(QEMUFile *f)
int flags = 0, ret = 0, invalid_flags = 0, len = 0, i = 0; int flags = 0, ret = 0, invalid_flags = 0, len = 0, i = 0;
/* ADVISE is earlier, it shows the source has the postcopy capability on */ /* ADVISE is earlier, it shows the source has the postcopy capability on */
bool postcopy_advised = migration_incoming_postcopy_advised(); bool postcopy_advised = migration_incoming_postcopy_advised();
if (!migrate_use_compression()) { if (!migrate_compress()) {
invalid_flags |= RAM_SAVE_FLAG_COMPRESS_PAGE; invalid_flags |= RAM_SAVE_FLAG_COMPRESS_PAGE;
} }

View File

@ -35,6 +35,7 @@
#include <rdma/rdma_cma.h> #include <rdma/rdma_cma.h>
#include "trace.h" #include "trace.h"
#include "qom/object.h" #include "qom/object.h"
#include "options.h"
#include <poll.h> #include <poll.h>
/* /*
@ -3373,7 +3374,7 @@ static int qemu_rdma_accept(RDMAContext *rdma)
* initialize the RDMAContext for return path for postcopy after first * initialize the RDMAContext for return path for postcopy after first
* connection request reached. * connection request reached.
*/ */
if ((migrate_postcopy() || migrate_use_return_path()) if ((migrate_postcopy() || migrate_return_path())
&& !rdma->is_return_path) { && !rdma->is_return_path) {
rdma_return_path = qemu_rdma_data_init(rdma->host_port, NULL); rdma_return_path = qemu_rdma_data_init(rdma->host_port, NULL);
if (rdma_return_path == NULL) { if (rdma_return_path == NULL) {
@ -3456,7 +3457,7 @@ static int qemu_rdma_accept(RDMAContext *rdma)
} }
/* Accept the second connection request for return path */ /* Accept the second connection request for return path */
if ((migrate_postcopy() || migrate_use_return_path()) if ((migrate_postcopy() || migrate_return_path())
&& !rdma->is_return_path) { && !rdma->is_return_path) {
qemu_set_fd_handler(rdma->channel->fd, rdma_accept_incoming_migration, qemu_set_fd_handler(rdma->channel->fd, rdma_accept_incoming_migration,
NULL, NULL,
@ -4178,8 +4179,7 @@ void rdma_start_outgoing_migration(void *opaque,
goto err; goto err;
} }
ret = qemu_rdma_source_init(rdma, ret = qemu_rdma_source_init(rdma, migrate_rdma_pin_all(), errp);
s->capabilities[MIGRATION_CAPABILITY_RDMA_PIN_ALL], errp);
if (ret) { if (ret) {
goto err; goto err;
@ -4193,7 +4193,7 @@ void rdma_start_outgoing_migration(void *opaque,
} }
/* RDMA postcopy need a separate queue pair for return path */ /* RDMA postcopy need a separate queue pair for return path */
if (migrate_postcopy() || migrate_use_return_path()) { if (migrate_postcopy() || migrate_return_path()) {
rdma_return_path = qemu_rdma_data_init(host_port, errp); rdma_return_path = qemu_rdma_data_init(host_port, errp);
if (rdma_return_path == NULL) { if (rdma_return_path == NULL) {
@ -4201,7 +4201,7 @@ void rdma_start_outgoing_migration(void *opaque,
} }
ret = qemu_rdma_source_init(rdma_return_path, ret = qemu_rdma_source_init(rdma_return_path,
s->capabilities[MIGRATION_CAPABILITY_RDMA_PIN_ALL], errp); migrate_rdma_pin_all(), errp);
if (ret) { if (ret) {
goto return_path_err; goto return_path_err;

View File

@ -67,6 +67,7 @@
#include "qemu/yank.h" #include "qemu/yank.h"
#include "yank_functions.h" #include "yank_functions.h"
#include "sysemu/qtest.h" #include "sysemu/qtest.h"
#include "options.h"
const unsigned int postcopy_ram_discard_version; const unsigned int postcopy_ram_discard_version;
@ -1611,7 +1612,7 @@ static int qemu_savevm_state(QEMUFile *f, Error **errp)
return -EINVAL; return -EINVAL;
} }
if (migrate_use_block()) { if (migrate_block()) {
error_setg(errp, "Block migration and snapshots are incompatible"); error_setg(errp, "Block migration and snapshots are incompatible");
return -EINVAL; return -EINVAL;
} }

View File

@ -27,6 +27,7 @@
#include "io/net-listener.h" #include "io/net-listener.h"
#include "trace.h" #include "trace.h"
#include "postcopy-ram.h" #include "postcopy-ram.h"
#include "options.h"
struct SocketOutgoingArgs { struct SocketOutgoingArgs {
SocketAddress *saddr; SocketAddress *saddr;
@ -97,7 +98,7 @@ static void socket_outgoing_migration(QIOTask *task,
trace_migration_socket_outgoing_connected(data->hostname); trace_migration_socket_outgoing_connected(data->hostname);
if (migrate_use_zero_copy_send() && if (migrate_zero_copy_send() &&
!qio_channel_has_feature(sioc, QIO_CHANNEL_FEATURE_WRITE_ZERO_COPY)) { !qio_channel_has_feature(sioc, QIO_CHANNEL_FEATURE_WRITE_ZERO_COPY)) {
error_setg(&err, "Zero copy send feature not detected in host kernel"); error_setg(&err, "Zero copy send feature not detected in host kernel");
} }
@ -182,7 +183,7 @@ socket_start_incoming_migration_internal(SocketAddress *saddr,
qio_net_listener_set_name(listener, "migration-socket-listener"); qio_net_listener_set_name(listener, "migration-socket-listener");
if (migrate_use_multifd()) { if (migrate_multifd()) {
num = migrate_multifd_channels(); num = migrate_multifd_channels();
} else if (migrate_postcopy_preempt()) { } else if (migrate_postcopy_preempt()) {
num = RAM_CHANNEL_MAX; num = RAM_CHANNEL_MAX;

View File

@ -1203,34 +1203,6 @@
{ 'command': 'query-migrate-parameters', { 'command': 'query-migrate-parameters',
'returns': 'MigrationParameters' } 'returns': 'MigrationParameters' }
##
# @client_migrate_info:
#
# Set migration information for remote display. This makes the server
# ask the client to automatically reconnect using the new parameters
# once migration finished successfully. Only implemented for SPICE.
#
# @protocol: must be "spice"
# @hostname: migration target hostname
# @port: spice tcp port for plaintext channels
# @tls-port: spice tcp port for tls-secured channels
# @cert-subject: server certificate subject
#
# Since: 0.14
#
# Example:
#
# -> { "execute": "client_migrate_info",
# "arguments": { "protocol": "spice",
# "hostname": "virt42.lab.kraxel.org",
# "port": 1234 } }
# <- { "return": {} }
#
##
{ 'command': 'client_migrate_info',
'data': { 'protocol': 'str', 'hostname': 'str', '*port': 'int',
'*tls-port': 'int', '*cert-subject': 'str' } }
## ##
# @migrate-start-postcopy: # @migrate-start-postcopy:
# #

View File

@ -1554,3 +1554,31 @@
{ 'command': 'display-update', { 'command': 'display-update',
'data': 'DisplayUpdateOptions', 'data': 'DisplayUpdateOptions',
'boxed' : true } 'boxed' : true }
##
# @client_migrate_info:
#
# Set migration information for remote display. This makes the server
# ask the client to automatically reconnect using the new parameters
# once migration finished successfully. Only implemented for SPICE.
#
# @protocol: must be "spice"
# @hostname: migration target hostname
# @port: spice tcp port for plaintext channels
# @tls-port: spice tcp port for tls-secured channels
# @cert-subject: server certificate subject
#
# Since: 0.14
#
# Example:
#
# -> { "execute": "client_migrate_info",
# "arguments": { "protocol": "spice",
# "hostname": "virt42.lab.kraxel.org",
# "port": 1234 } }
# <- { "return": {} }
#
##
{ 'command': 'client_migrate_info',
'data': { 'protocol': 'str', 'hostname': 'str', '*port': 'int',
'*tls-port': 'int', '*cert-subject': 'str' } }

View File

@ -458,3 +458,20 @@ hmp_screendump(Monitor *mon, const QDict *qdict)
end: end:
hmp_handle_error(mon, err); hmp_handle_error(mon, err);
} }
void hmp_client_migrate_info(Monitor *mon, const QDict *qdict)
{
Error *err = NULL;
const char *protocol = qdict_get_str(qdict, "protocol");
const char *hostname = qdict_get_str(qdict, "hostname");
bool has_port = qdict_haskey(qdict, "port");
int port = qdict_get_try_int(qdict, "port", -1);
bool has_tls_port = qdict_haskey(qdict, "tls-port");
int tls_port = qdict_get_try_int(qdict, "tls-port", -1);
const char *cert_subject = qdict_get_try_str(qdict, "cert-subject");
qmp_client_migrate_info(protocol, hostname,
has_port, port, has_tls_port, tls_port,
cert_subject, &err);
hmp_handle_error(mon, err);
}

View File

@ -175,3 +175,32 @@ void qmp_display_update(DisplayUpdateOptions *arg, Error **errp)
abort(); abort();
} }
} }
void qmp_client_migrate_info(const char *protocol, const char *hostname,
bool has_port, int64_t port,
bool has_tls_port, int64_t tls_port,
const char *cert_subject,
Error **errp)
{
if (strcmp(protocol, "spice") == 0) {
if (!qemu_using_spice(errp)) {
return;
}
if (!has_port && !has_tls_port) {
error_setg(errp, QERR_MISSING_PARAMETER, "port/tls-port");
return;
}
if (qemu_spice.migrate_info(hostname,
has_port ? port : -1,
has_tls_port ? tls_port : -1,
cert_subject)) {
error_setg(errp, "Could not set up display for migration");
return;
}
return;
}
error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "protocol", "'spice'");
}