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:
commit
ac5f7bf8e2
@ -32,6 +32,7 @@
|
||||
#include "qemu/error-report.h"
|
||||
#include "migration/misc.h"
|
||||
#include "migration/migration.h"
|
||||
#include "migration/options.h"
|
||||
|
||||
#include "hw/virtio/virtio-bus.h"
|
||||
#include "hw/virtio/virtio-access.h"
|
||||
|
@ -66,7 +66,6 @@ bool migration_has_finished(MigrationState *);
|
||||
bool migration_has_failed(MigrationState *);
|
||||
/* ...and after the device transmission */
|
||||
bool migration_in_postcopy_after_devices(MigrationState *);
|
||||
void migration_global_dump(Monitor *mon);
|
||||
/* True if incoming migration entered POSTCOPY_INCOMING_DISCARD */
|
||||
bool migration_in_incoming_postcopy(void);
|
||||
/* True if incoming migration entered POSTCOPY_INCOMING_ADVISE */
|
||||
|
@ -79,6 +79,7 @@
|
||||
#include "qapi/qapi-visit-migration.h"
|
||||
#include "qapi/clone-visitor.h"
|
||||
#include "trace.h"
|
||||
#include "options.h"
|
||||
|
||||
#define CHUNK_SIZE (1 << 10)
|
||||
|
||||
|
@ -28,6 +28,7 @@
|
||||
#include "migration/vmstate.h"
|
||||
#include "sysemu/block-backend.h"
|
||||
#include "trace.h"
|
||||
#include "options.h"
|
||||
|
||||
#define BLK_MIG_BLOCK_SIZE (1ULL << 20)
|
||||
#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->total_sectors = sectors;
|
||||
bmds->completed_sectors = 0;
|
||||
bmds->shared_base = migrate_use_block_incremental();
|
||||
bmds->shared_base = migrate_block_incremental();
|
||||
|
||||
assert(i < num_bs);
|
||||
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)
|
||||
{
|
||||
return migrate_use_block();
|
||||
return migrate_block();
|
||||
}
|
||||
|
||||
static SaveVMHandlers savevm_block_handlers = {
|
||||
|
@ -36,6 +36,7 @@
|
||||
#include "sysemu/cpus.h"
|
||||
#include "sysemu/runstate.h"
|
||||
#include "net/filter.h"
|
||||
#include "options.h"
|
||||
|
||||
static bool vmstate_loading;
|
||||
static Notifier packets_compare_notifier;
|
||||
@ -575,7 +576,7 @@ static void colo_process_checkpoint(MigrationState *s)
|
||||
trace_colo_vm_state_change("stop", "run");
|
||||
|
||||
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) {
|
||||
if (failover_get_state() != FAILOVER_STATUS_NONE) {
|
||||
@ -650,8 +651,7 @@ void colo_checkpoint_notify(void *opaque)
|
||||
|
||||
qemu_event_set(&s->colo_checkpoint_event);
|
||||
s->colo_checkpoint_time = qemu_clock_get_ms(QEMU_CLOCK_HOST);
|
||||
next_notify_time = s->colo_checkpoint_time +
|
||||
s->parameters.x_checkpoint_delay;
|
||||
next_notify_time = s->colo_checkpoint_time + migrate_checkpoint_delay();
|
||||
timer_mod(s->colo_delay_timer, next_notify_time);
|
||||
}
|
||||
|
||||
|
@ -22,6 +22,7 @@ softmmu_ss.add(files(
|
||||
'migration.c',
|
||||
'multifd.c',
|
||||
'multifd-zlib.c',
|
||||
'options.c',
|
||||
'postcopy-ram.c',
|
||||
'savevm.c',
|
||||
'socket.c',
|
||||
|
@ -15,7 +15,6 @@
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "block/qapi.h"
|
||||
#include "migration/misc.h"
|
||||
#include "migration/snapshot.h"
|
||||
#include "monitor/hmp.h"
|
||||
#include "monitor/monitor.h"
|
||||
@ -30,6 +29,27 @@
|
||||
#include "qemu/sockets.h"
|
||||
#include "sysemu/runstate.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)
|
||||
{
|
||||
@ -616,23 +636,6 @@ void hmp_migrate_set_parameter(Monitor *mon, const QDict *qdict)
|
||||
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)
|
||||
{
|
||||
Error *err = NULL;
|
||||
|
@ -63,7 +63,7 @@
|
||||
#include "sysemu/cpus.h"
|
||||
#include "yank_functions.h"
|
||||
#include "sysemu/qtest.h"
|
||||
#include "ui/qemu-spice.h"
|
||||
#include "options.h"
|
||||
|
||||
#define MAX_THROTTLE (128 << 20) /* Migration transfer speed throttling */
|
||||
|
||||
@ -136,39 +136,6 @@ enum mig_rp_message_type {
|
||||
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
|
||||
migrations at once. For now we don't need to add
|
||||
dynamic creation of migration */
|
||||
@ -186,7 +153,7 @@ static void migrate_fd_cancel(MigrationState *s);
|
||||
|
||||
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)
|
||||
@ -353,20 +320,11 @@ void migration_incoming_state_destroy(void)
|
||||
|
||||
static void migrate_generate_event(int new_state)
|
||||
{
|
||||
if (migrate_use_events()) {
|
||||
if (migrate_events()) {
|
||||
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
|
||||
* 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)
|
||||
{
|
||||
/* Multifd doesn't start unless all channels are established */
|
||||
if (migrate_use_multifd()) {
|
||||
if (migrate_multifd()) {
|
||||
return migration_has_all_channels();
|
||||
}
|
||||
|
||||
@ -768,7 +726,7 @@ void migration_ioc_process_incoming(QIOChannel *ioc, Error **errp)
|
||||
uint32_t channel_magic = 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)) {
|
||||
/*
|
||||
* With multiple channels, it is possible that we receive channels
|
||||
@ -807,7 +765,7 @@ void migration_ioc_process_incoming(QIOChannel *ioc, Error **errp)
|
||||
} else {
|
||||
/* Multiple connections */
|
||||
assert(migration_needs_multiple_sockets());
|
||||
if (migrate_use_multifd()) {
|
||||
if (migrate_multifd()) {
|
||||
multifd_recv_new_channel(ioc, &local_err);
|
||||
} else {
|
||||
assert(migrate_postcopy_preempt());
|
||||
@ -843,7 +801,7 @@ bool migration_has_all_channels(void)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (migrate_use_multifd()) {
|
||||
if (migrate_multifd()) {
|
||||
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);
|
||||
}
|
||||
|
||||
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 ≈
|
||||
}
|
||||
|
||||
/*
|
||||
* Return true if we're already in the middle of a migration
|
||||
* (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->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->cache_size = migrate_xbzrle_cache_size();
|
||||
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;
|
||||
}
|
||||
|
||||
if (migrate_use_compression()) {
|
||||
if (migrate_compress()) {
|
||||
info->compression = g_malloc0(sizeof(*info->compression));
|
||||
info->compression->pages = compression_counters.pages;
|
||||
info->compression->busy = compression_counters.busy;
|
||||
@ -1273,163 +1098,6 @@ static void fill_source_migration_info(MigrationInfo *info)
|
||||
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)
|
||||
{
|
||||
MigrationIncomingState *mis = migration_incoming_get_current();
|
||||
@ -1472,32 +1140,6 @@ MigrationInfo *qmp_query_migrate(Error **errp)
|
||||
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
|
||||
* (if provided). Return true if valid, otherwise false.
|
||||
@ -1647,7 +1289,7 @@ static bool migrate_params_check(MigrationParameters *params, Error **errp)
|
||||
}
|
||||
|
||||
#ifdef CONFIG_LINUX
|
||||
if (migrate_use_zero_copy_send() &&
|
||||
if (migrate_zero_copy_send() &&
|
||||
((params->has_multifd_compression && params->multifd_compression) ||
|
||||
(params->tls_creds && *params->tls_creds))) {
|
||||
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)
|
||||
{
|
||||
s->parameters.block_incremental = value;
|
||||
@ -1972,7 +1593,7 @@ static void block_cleanup_parameters(MigrationState *s)
|
||||
{
|
||||
if (s->must_remove_block_options) {
|
||||
/* 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);
|
||||
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 (migrate_colo_enabled()) {
|
||||
if (migrate_colo()) {
|
||||
error_setg(errp, "No disk migration is required in COLO mode");
|
||||
return false;
|
||||
}
|
||||
if (migrate_use_block() || migrate_use_block_incremental()) {
|
||||
if (migrate_block() || migrate_block_incremental()) {
|
||||
error_setg(errp, "Command options are incompatible with "
|
||||
"current migration capabilities");
|
||||
return false;
|
||||
}
|
||||
migrate_set_block_enabled(true, &local_err);
|
||||
if (local_err) {
|
||||
if (!migrate_cap_set(MIGRATION_CAPABILITY_BLOCK, true, &local_err)) {
|
||||
error_propagate(errp, local_err);
|
||||
return false;
|
||||
}
|
||||
@ -2557,203 +2177,6 @@ void qmp_migrate_continue(MigrationStatus state, Error **errp)
|
||||
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)
|
||||
{
|
||||
MigrationState *s;
|
||||
@ -2763,78 +2186,6 @@ int migrate_use_tls(void)
|
||||
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 */
|
||||
/*
|
||||
* Something bad happened to the RP stream, mark an error
|
||||
@ -3431,7 +2782,6 @@ static void migration_completion(MigrationState *s)
|
||||
ret = global_state_store();
|
||||
|
||||
if (!ret) {
|
||||
bool inactivate = !migrate_colo_enabled();
|
||||
ret = vm_stop_force_state(RUN_STATE_FINISH_MIGRATE);
|
||||
trace_migration_completion_vm_stop(ret);
|
||||
if (ret >= 0) {
|
||||
@ -3439,10 +2789,10 @@ static void migration_completion(MigrationState *s)
|
||||
MIGRATION_STATUS_DEVICE);
|
||||
}
|
||||
if (ret >= 0) {
|
||||
s->block_inactive = inactivate;
|
||||
s->block_inactive = !migrate_colo();
|
||||
qemu_file_set_rate_limit(s->to_dst_file, INT64_MAX);
|
||||
ret = qemu_savevm_state_complete_precopy(s->to_dst_file, false,
|
||||
inactivate);
|
||||
s->block_inactive);
|
||||
}
|
||||
}
|
||||
qemu_mutex_unlock_iothread();
|
||||
@ -3492,7 +2842,7 @@ static void migration_completion(MigrationState *s)
|
||||
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 */
|
||||
migrate_set_state(&s->state, MIGRATION_STATUS_ACTIVE,
|
||||
MIGRATION_STATUS_COLO);
|
||||
@ -3571,12 +2921,6 @@ fail:
|
||||
MIGRATION_STATUS_FAILED);
|
||||
}
|
||||
|
||||
bool migrate_colo_enabled(void)
|
||||
{
|
||||
MigrationState *s = migrate_get_current();
|
||||
return s->capabilities[MIGRATION_CAPABILITY_X_COLO];
|
||||
}
|
||||
|
||||
typedef enum MigThrError {
|
||||
/* No error detected */
|
||||
MIG_THR_ERR_NONE = 0,
|
||||
@ -3907,7 +3251,7 @@ static void migration_iteration_finish(MigrationState *s)
|
||||
runstate_set(RUN_STATE_POSTMIGRATE);
|
||||
break;
|
||||
case MIGRATION_STATUS_COLO:
|
||||
if (!migrate_colo_enabled()) {
|
||||
if (!migrate_colo()) {
|
||||
error_report("%s: critical error: calling COLO code without "
|
||||
"COLO enabled", __func__);
|
||||
}
|
||||
@ -4103,7 +3447,7 @@ static void *migration_thread(void *opaque)
|
||||
qemu_savevm_send_postcopy_advise(s->to_dst_file);
|
||||
}
|
||||
|
||||
if (migrate_colo_enabled()) {
|
||||
if (migrate_colo()) {
|
||||
/* Notify migration destination that we enable COLO */
|
||||
qemu_savevm_send_colo_enable(s->to_dst_file);
|
||||
}
|
||||
@ -4355,11 +3699,11 @@ void migrate_fd_connect(MigrationState *s, Error *error_in)
|
||||
|
||||
if (resume) {
|
||||
/* This is a resumed migration */
|
||||
rate_limit = s->parameters.max_postcopy_bandwidth /
|
||||
rate_limit = migrate_max_postcopy_bandwidth() /
|
||||
XFER_LIMIT_RATIO;
|
||||
} else {
|
||||
/* 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 */
|
||||
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
|
||||
* 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)) {
|
||||
error_report("Unable to open return-path for postcopy");
|
||||
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;
|
||||
}
|
||||
|
||||
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_PROP_BOOL(name, MigrationState, capabilities[x], false)
|
||||
|
||||
|
@ -447,50 +447,10 @@ bool migration_is_blocked(Error **errp);
|
||||
bool migration_in_postcopy(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_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);
|
||||
|
||||
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 */
|
||||
void migrate_send_rp_shut(MigrationIncomingState *mis,
|
||||
uint32_t value);
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include "qapi/error.h"
|
||||
#include "migration.h"
|
||||
#include "trace.h"
|
||||
#include "options.h"
|
||||
#include "multifd.h"
|
||||
|
||||
struct zlib_data {
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include "qapi/error.h"
|
||||
#include "migration.h"
|
||||
#include "trace.h"
|
||||
#include "options.h"
|
||||
#include "multifd.h"
|
||||
|
||||
struct zstd_data {
|
||||
|
@ -25,7 +25,7 @@
|
||||
#include "trace.h"
|
||||
#include "multifd.h"
|
||||
#include "threadinfo.h"
|
||||
|
||||
#include "options.h"
|
||||
#include "qemu/yank.h"
|
||||
#include "io/channel-socket.h"
|
||||
#include "yank_functions.h"
|
||||
@ -516,7 +516,7 @@ void multifd_save_cleanup(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!migrate_use_multifd()) {
|
||||
if (!migrate_multifd()) {
|
||||
return;
|
||||
}
|
||||
multifd_send_terminate_threads(NULL);
|
||||
@ -587,7 +587,7 @@ int multifd_send_sync_main(QEMUFile *f)
|
||||
int i;
|
||||
bool flush_zero_copy;
|
||||
|
||||
if (!migrate_use_multifd()) {
|
||||
if (!migrate_multifd()) {
|
||||
return 0;
|
||||
}
|
||||
if (multifd_send_state->pages->num) {
|
||||
@ -608,7 +608,7 @@ int multifd_send_sync_main(QEMUFile *f)
|
||||
* 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++) {
|
||||
MultiFDSendParams *p = &multifd_send_state->params[i];
|
||||
@ -653,7 +653,7 @@ static void *multifd_send_thread(void *opaque)
|
||||
MigrationThread *thread = NULL;
|
||||
Error *local_err = NULL;
|
||||
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());
|
||||
|
||||
@ -911,7 +911,7 @@ int multifd_save_setup(Error **errp)
|
||||
uint32_t page_count = MULTIFD_PACKET_SIZE / qemu_target_page_size();
|
||||
uint8_t i;
|
||||
|
||||
if (!migrate_use_multifd()) {
|
||||
if (!migrate_multifd()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -945,7 +945,7 @@ int multifd_save_setup(Error **errp)
|
||||
p->page_size = qemu_target_page_size();
|
||||
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;
|
||||
} else {
|
||||
p->write_flags = 0;
|
||||
@ -1016,7 +1016,7 @@ static void multifd_recv_terminate_threads(Error *err)
|
||||
|
||||
void multifd_load_shutdown(void)
|
||||
{
|
||||
if (migrate_use_multifd()) {
|
||||
if (migrate_multifd()) {
|
||||
multifd_recv_terminate_threads(NULL);
|
||||
}
|
||||
}
|
||||
@ -1025,7 +1025,7 @@ void multifd_load_cleanup(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!migrate_use_multifd()) {
|
||||
if (!migrate_multifd()) {
|
||||
return;
|
||||
}
|
||||
multifd_recv_terminate_threads(NULL);
|
||||
@ -1072,7 +1072,7 @@ void multifd_recv_sync_main(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!migrate_use_multifd()) {
|
||||
if (!migrate_multifd()) {
|
||||
return;
|
||||
}
|
||||
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
|
||||
* or multiFD is not enabled.
|
||||
*/
|
||||
if (multifd_recv_state || !migrate_use_multifd()) {
|
||||
if (multifd_recv_state || !migrate_multifd()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1216,7 +1216,7 @@ bool multifd_recv_all_channels_created(void)
|
||||
{
|
||||
int thread_count = migrate_multifd_channels();
|
||||
|
||||
if (!migrate_use_multifd()) {
|
||||
if (!migrate_multifd()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
722
migration/options.c
Normal file
722
migration/options.c
Normal 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 ≈
|
||||
}
|
||||
|
||||
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
76
migration/options.h
Normal 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
|
@ -37,6 +37,7 @@
|
||||
#include "tls.h"
|
||||
#include "qemu/userfaultfd.h"
|
||||
#include "qemu/mmap-alloc.h"
|
||||
#include "options.h"
|
||||
|
||||
/* Arbitrary limit on size of each discard command,
|
||||
* keeps them around ~200 bytes
|
||||
|
@ -57,6 +57,7 @@
|
||||
#include "qemu/iov.h"
|
||||
#include "multifd.h"
|
||||
#include "sysemu/runstate.h"
|
||||
#include "options.h"
|
||||
|
||||
#include "hw/boards.h" /* for machine_dump_guest_core() */
|
||||
|
||||
@ -155,14 +156,14 @@ static struct {
|
||||
|
||||
static void XBZRLE_cache_lock(void)
|
||||
{
|
||||
if (migrate_use_xbzrle()) {
|
||||
if (migrate_xbzrle()) {
|
||||
qemu_mutex_lock(&XBZRLE.lock);
|
||||
}
|
||||
}
|
||||
|
||||
static void XBZRLE_cache_unlock(void)
|
||||
{
|
||||
if (migrate_use_xbzrle()) {
|
||||
if (migrate_xbzrle()) {
|
||||
qemu_mutex_unlock(&XBZRLE.lock);
|
||||
}
|
||||
}
|
||||
@ -585,7 +586,7 @@ static void compress_threads_save_cleanup(void)
|
||||
{
|
||||
int i, thread_count;
|
||||
|
||||
if (!migrate_use_compression() || !comp_param) {
|
||||
if (!migrate_compress() || !comp_param) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -624,7 +625,7 @@ static int compress_threads_save_setup(void)
|
||||
{
|
||||
int i, thread_count;
|
||||
|
||||
if (!migrate_use_compression()) {
|
||||
if (!migrate_compress()) {
|
||||
return 0;
|
||||
}
|
||||
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,
|
||||
uint64_t bytes_dirty_threshold)
|
||||
{
|
||||
MigrationState *s = migrate_get_current();
|
||||
uint64_t pct_initial = s->parameters.cpu_throttle_initial;
|
||||
uint64_t pct_increment = s->parameters.cpu_throttle_increment;
|
||||
bool pct_tailslow = s->parameters.cpu_throttle_tailslow;
|
||||
int pct_max = s->parameters.max_cpu_throttle;
|
||||
uint64_t pct_initial = migrate_cpu_throttle_initial();
|
||||
uint64_t pct_increment = migrate_cpu_throttle_increment();
|
||||
bool pct_tailslow = migrate_cpu_throttle_tailslow();
|
||||
int pct_max = migrate_max_cpu_throttle();
|
||||
|
||||
uint64_t throttle_now = cpu_throttle_get_percentage();
|
||||
uint64_t cpu_now, cpu_ideal, throttle_inc;
|
||||
@ -1136,7 +1136,7 @@ static void migration_update_rates(RAMState *rs, int64_t end_time)
|
||||
return;
|
||||
}
|
||||
|
||||
if (migrate_use_xbzrle()) {
|
||||
if (migrate_xbzrle()) {
|
||||
double encoded_size, unencoded_size;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if (migrate_use_compression()) {
|
||||
if (migrate_compress()) {
|
||||
compression_counters.busy_rate = (double)(compression_counters.busy -
|
||||
rs->compress_thread_busy_prev) / page_count;
|
||||
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)
|
||||
{
|
||||
MigrationState *s = migrate_get_current();
|
||||
uint64_t threshold = s->parameters.throttle_trigger_threshold;
|
||||
uint64_t threshold = migrate_throttle_trigger_threshold();
|
||||
uint64_t bytes_xfer_period =
|
||||
stat64_get(&ram_counters.transferred) - rs->bytes_xfer_prev;
|
||||
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->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);
|
||||
qapi_event_send_migration_pass(generation);
|
||||
}
|
||||
@ -1625,7 +1624,7 @@ static int find_dirty_block(RAMState *rs, PageSearchStatus *pss)
|
||||
/* Flag that we've looped */
|
||||
pss->complete_round = true;
|
||||
/* After the first round, enable XBZRLE. */
|
||||
if (migrate_use_xbzrle()) {
|
||||
if (migrate_xbzrle()) {
|
||||
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)
|
||||
{
|
||||
if (!migrate_use_compression()) {
|
||||
if (!migrate_compress()) {
|
||||
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
|
||||
* 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);
|
||||
}
|
||||
|
||||
@ -2978,7 +2977,7 @@ static int xbzrle_init(void)
|
||||
{
|
||||
Error *local_err = NULL;
|
||||
|
||||
if (!migrate_use_xbzrle()) {
|
||||
if (!migrate_xbzrle()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -3733,7 +3732,7 @@ static int wait_for_decompress_done(void)
|
||||
{
|
||||
int idx, thread_count;
|
||||
|
||||
if (!migrate_use_compression()) {
|
||||
if (!migrate_compress()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -3752,7 +3751,7 @@ static void compress_threads_load_cleanup(void)
|
||||
{
|
||||
int i, thread_count;
|
||||
|
||||
if (!migrate_use_compression()) {
|
||||
if (!migrate_compress()) {
|
||||
return;
|
||||
}
|
||||
thread_count = migrate_decompress_threads();
|
||||
@ -3793,7 +3792,7 @@ static int compress_threads_load_setup(QEMUFile *f)
|
||||
{
|
||||
int i, thread_count;
|
||||
|
||||
if (!migrate_use_compression()) {
|
||||
if (!migrate_compress()) {
|
||||
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;
|
||||
/* ADVISE is earlier, it shows the source has the postcopy capability on */
|
||||
bool postcopy_advised = migration_incoming_postcopy_advised();
|
||||
if (!migrate_use_compression()) {
|
||||
if (!migrate_compress()) {
|
||||
invalid_flags |= RAM_SAVE_FLAG_COMPRESS_PAGE;
|
||||
}
|
||||
|
||||
|
@ -35,6 +35,7 @@
|
||||
#include <rdma/rdma_cma.h>
|
||||
#include "trace.h"
|
||||
#include "qom/object.h"
|
||||
#include "options.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
|
||||
* connection request reached.
|
||||
*/
|
||||
if ((migrate_postcopy() || migrate_use_return_path())
|
||||
if ((migrate_postcopy() || migrate_return_path())
|
||||
&& !rdma->is_return_path) {
|
||||
rdma_return_path = qemu_rdma_data_init(rdma->host_port, 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 */
|
||||
if ((migrate_postcopy() || migrate_use_return_path())
|
||||
if ((migrate_postcopy() || migrate_return_path())
|
||||
&& !rdma->is_return_path) {
|
||||
qemu_set_fd_handler(rdma->channel->fd, rdma_accept_incoming_migration,
|
||||
NULL,
|
||||
@ -4178,8 +4179,7 @@ void rdma_start_outgoing_migration(void *opaque,
|
||||
goto err;
|
||||
}
|
||||
|
||||
ret = qemu_rdma_source_init(rdma,
|
||||
s->capabilities[MIGRATION_CAPABILITY_RDMA_PIN_ALL], errp);
|
||||
ret = qemu_rdma_source_init(rdma, migrate_rdma_pin_all(), errp);
|
||||
|
||||
if (ret) {
|
||||
goto err;
|
||||
@ -4193,7 +4193,7 @@ void rdma_start_outgoing_migration(void *opaque,
|
||||
}
|
||||
|
||||
/* 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);
|
||||
|
||||
if (rdma_return_path == NULL) {
|
||||
@ -4201,7 +4201,7 @@ void rdma_start_outgoing_migration(void *opaque,
|
||||
}
|
||||
|
||||
ret = qemu_rdma_source_init(rdma_return_path,
|
||||
s->capabilities[MIGRATION_CAPABILITY_RDMA_PIN_ALL], errp);
|
||||
migrate_rdma_pin_all(), errp);
|
||||
|
||||
if (ret) {
|
||||
goto return_path_err;
|
||||
|
@ -67,6 +67,7 @@
|
||||
#include "qemu/yank.h"
|
||||
#include "yank_functions.h"
|
||||
#include "sysemu/qtest.h"
|
||||
#include "options.h"
|
||||
|
||||
const unsigned int postcopy_ram_discard_version;
|
||||
|
||||
@ -1611,7 +1612,7 @@ static int qemu_savevm_state(QEMUFile *f, Error **errp)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (migrate_use_block()) {
|
||||
if (migrate_block()) {
|
||||
error_setg(errp, "Block migration and snapshots are incompatible");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include "io/net-listener.h"
|
||||
#include "trace.h"
|
||||
#include "postcopy-ram.h"
|
||||
#include "options.h"
|
||||
|
||||
struct SocketOutgoingArgs {
|
||||
SocketAddress *saddr;
|
||||
@ -97,7 +98,7 @@ static void socket_outgoing_migration(QIOTask *task,
|
||||
|
||||
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)) {
|
||||
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");
|
||||
|
||||
if (migrate_use_multifd()) {
|
||||
if (migrate_multifd()) {
|
||||
num = migrate_multifd_channels();
|
||||
} else if (migrate_postcopy_preempt()) {
|
||||
num = RAM_CHANNEL_MAX;
|
||||
|
@ -1203,34 +1203,6 @@
|
||||
{ 'command': 'query-migrate-parameters',
|
||||
'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:
|
||||
#
|
||||
|
28
qapi/ui.json
28
qapi/ui.json
@ -1554,3 +1554,31 @@
|
||||
{ 'command': 'display-update',
|
||||
'data': 'DisplayUpdateOptions',
|
||||
'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' } }
|
||||
|
@ -458,3 +458,20 @@ hmp_screendump(Monitor *mon, const QDict *qdict)
|
||||
end:
|
||||
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);
|
||||
}
|
||||
|
@ -175,3 +175,32 @@ void qmp_display_update(DisplayUpdateOptions *arg, Error **errp)
|
||||
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'");
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user