Showing with 414 additions and 352 deletions.
  1. +3 −1 hw/core/machine.c
  2. +6 −0 include/qemu/stats64.h
  3. +8 −6 migration/block-dirty-bitmap.c
  4. +12 −208 migration/migration.c
  5. +11 −0 migration/migration.h
  6. +2 −1 migration/multifd.c
  7. +290 −114 migration/options.c
  8. +19 −0 migration/options.h
  9. +42 −9 migration/ram.c
  10. +2 −2 migration/ram.h
  11. +8 −11 migration/tls.c
  12. +11 −0 util/stats64.c
4 changes: 3 additions & 1 deletion hw/core/machine.c
Expand Up @@ -39,7 +39,9 @@
#include "hw/virtio/virtio.h"
#include "hw/virtio/virtio-pci.h"

GlobalProperty hw_compat_8_0[] = {};
GlobalProperty hw_compat_8_0[] = {
{ "migration", "multifd-flush-after-each-section", "on"},
};
const size_t hw_compat_8_0_len = G_N_ELEMENTS(hw_compat_8_0);

GlobalProperty hw_compat_7_2[] = {
Expand Down
6 changes: 6 additions & 0 deletions include/qemu/stats64.h
Expand Up @@ -40,6 +40,11 @@ static inline uint64_t stat64_get(const Stat64 *s)
return qatomic_read__nocheck(&s->value);
}

static inline void stat64_set(Stat64 *s, uint64_t value)
{
qatomic_set__nocheck(&s->value, value);
}

static inline void stat64_add(Stat64 *s, uint64_t value)
{
qatomic_add(&s->value, value);
Expand All @@ -62,6 +67,7 @@ static inline void stat64_max(Stat64 *s, uint64_t value)
}
#else
uint64_t stat64_get(const Stat64 *s);
void stat64_set(Stat64 *s, uint64_t value);
bool stat64_min_slow(Stat64 *s, uint64_t value);
bool stat64_max_slow(Stat64 *s, uint64_t value);
bool stat64_add32_carry(Stat64 *s, uint32_t low, uint32_t high);
Expand Down
14 changes: 8 additions & 6 deletions migration/block-dirty-bitmap.c
Expand Up @@ -605,11 +605,12 @@ static int init_dirty_bitmap_migration(DBMSaveState *s)
SaveBitmapState *dbms;
GHashTable *handled_by_blk = g_hash_table_new(NULL, NULL);
BlockBackend *blk;
const MigrationParameters *mig_params = &migrate_get_current()->parameters;
GHashTable *alias_map = NULL;
const BitmapMigrationNodeAliasList *block_bitmap_mapping =
migrate_block_bitmap_mapping();

if (mig_params->has_block_bitmap_mapping) {
alias_map = construct_alias_map(mig_params->block_bitmap_mapping, true,
if (block_bitmap_mapping) {
alias_map = construct_alias_map(block_bitmap_mapping, true,
&error_abort);
}

Expand Down Expand Up @@ -1158,7 +1159,8 @@ static int dirty_bitmap_load_header(QEMUFile *f, DBMLoadState *s,
static int dirty_bitmap_load(QEMUFile *f, void *opaque, int version_id)
{
GHashTable *alias_map = NULL;
const MigrationParameters *mig_params = &migrate_get_current()->parameters;
const BitmapMigrationNodeAliasList *block_bitmap_mapping =
migrate_block_bitmap_mapping();
DBMLoadState *s = &((DBMState *)opaque)->load;
int ret = 0;

Expand All @@ -1170,8 +1172,8 @@ static int dirty_bitmap_load(QEMUFile *f, void *opaque, int version_id)
return -EINVAL;
}

if (mig_params->has_block_bitmap_mapping) {
alias_map = construct_alias_map(mig_params->block_bitmap_mapping,
if (block_bitmap_mapping) {
alias_map = construct_alias_map(block_bitmap_mapping,
false, &error_abort);
}

Expand Down
220 changes: 12 additions & 208 deletions migration/migration.c
Expand Up @@ -52,8 +52,6 @@
#include "io/channel-tls.h"
#include "migration/colo.h"
#include "hw/boards.h"
#include "hw/qdev-properties.h"
#include "hw/qdev-properties-system.h"
#include "monitor/monitor.h"
#include "net/announce.h"
#include "qemu/queue.h"
Expand All @@ -65,51 +63,6 @@
#include "sysemu/qtest.h"
#include "options.h"

#define MAX_THROTTLE (128 << 20) /* Migration transfer speed throttling */

/* Time in milliseconds we are allowed to stop the source,
* for sending the last part */
#define DEFAULT_MIGRATE_SET_DOWNTIME 300

/* Default compression thread count */
#define DEFAULT_MIGRATE_COMPRESS_THREAD_COUNT 8
/* Default decompression thread count, usually decompression is at
* least 4 times as fast as compression.*/
#define DEFAULT_MIGRATE_DECOMPRESS_THREAD_COUNT 2
/*0: means nocompress, 1: best speed, ... 9: best compress ratio */
#define DEFAULT_MIGRATE_COMPRESS_LEVEL 1
/* Define default autoconverge cpu throttle migration parameters */
#define DEFAULT_MIGRATE_THROTTLE_TRIGGER_THRESHOLD 50
#define DEFAULT_MIGRATE_CPU_THROTTLE_INITIAL 20
#define DEFAULT_MIGRATE_CPU_THROTTLE_INCREMENT 10
#define DEFAULT_MIGRATE_MAX_CPU_THROTTLE 99

/* Migration XBZRLE default cache size */
#define DEFAULT_MIGRATE_XBZRLE_CACHE_SIZE (64 * 1024 * 1024)

/* The delay time (in ms) between two COLO checkpoints */
#define DEFAULT_MIGRATE_X_CHECKPOINT_DELAY (200 * 100)
#define DEFAULT_MIGRATE_MULTIFD_CHANNELS 2
#define DEFAULT_MIGRATE_MULTIFD_COMPRESSION MULTIFD_COMPRESSION_NONE
/* 0: means nocompress, 1: best speed, ... 9: best compress ratio */
#define DEFAULT_MIGRATE_MULTIFD_ZLIB_LEVEL 1
/* 0: means nocompress, 1: best speed, ... 20: best compress ratio */
#define DEFAULT_MIGRATE_MULTIFD_ZSTD_LEVEL 1

/* Background transfer rate for postcopy, 0 means unlimited, note
* that page requests can still exceed this limit.
*/
#define DEFAULT_MIGRATE_MAX_POSTCOPY_BANDWIDTH 0

/*
* Parameters for self_announce_delay giving a stream of RARP/ARP
* packets after migration.
*/
#define DEFAULT_MIGRATE_ANNOUNCE_INITIAL 50
#define DEFAULT_MIGRATE_ANNOUNCE_MAX 550
#define DEFAULT_MIGRATE_ANNOUNCE_ROUNDS 5
#define DEFAULT_MIGRATE_ANNOUNCE_STEP 100

static NotifierList migration_state_notifiers =
NOTIFIER_LIST_INITIALIZER(migration_state_notifiers);

Expand Down Expand Up @@ -1005,7 +958,8 @@ static void populate_ram_info(MigrationInfo *info, MigrationState *s)

if (s->state != MIGRATION_STATUS_COMPLETED) {
info->ram->remaining = ram_bytes_remaining();
info->ram->dirty_pages_rate = ram_counters.dirty_pages_rate;
info->ram->dirty_pages_rate =
stat64_get(&ram_counters.dirty_pages_rate);
}
}

Expand Down Expand Up @@ -1164,21 +1118,6 @@ void migrate_set_state(int *state, int old_state, int new_state)
}
}

static void migrate_set_block_incremental(MigrationState *s, bool value)
{
s->parameters.block_incremental = value;
}

static void block_cleanup_parameters(MigrationState *s)
{
if (s->must_remove_block_options) {
/* setting to false can never fail */
migrate_cap_set(MIGRATION_CAPABILITY_BLOCK, false, &error_abort);
migrate_set_block_incremental(s, false);
s->must_remove_block_options = false;
}
}

static void migrate_fd_cleanup(MigrationState *s)
{
qemu_bh_delete(s->cleanup_bh);
Expand Down Expand Up @@ -1233,7 +1172,7 @@ static void migrate_fd_cleanup(MigrationState *s)
error_report_err(error_copy(s->error));
}
notifier_list_notify(&migration_state_notifiers, s);
block_cleanup_parameters(s);
block_cleanup_parameters();
yank_unregister_instance(MIGRATION_YANK_INSTANCE);
}

Expand Down Expand Up @@ -1668,7 +1607,7 @@ static bool migrate_prepare(MigrationState *s, bool blk, bool blk_inc,
}

if (blk_inc) {
migrate_set_block_incremental(s, true);
migrate_set_block_incremental(true);
}

migrate_init(s);
Expand Down Expand Up @@ -1727,7 +1666,7 @@ void qmp_migrate(const char *uri, bool has_blk, bool blk,
"a valid migration protocol");
migrate_set_state(&s->state, MIGRATION_STATUS_SETUP,
MIGRATION_STATUS_FAILED);
block_cleanup_parameters(s);
block_cleanup_parameters();
return;
}

Expand Down Expand Up @@ -2737,7 +2676,7 @@ static void migration_update_counters(MigrationState *s,
transferred = current_bytes - s->iteration_initial_bytes;
time_spent = current_time - s->iteration_start_time;
bandwidth = (double)transferred / time_spent;
s->threshold_size = bandwidth * s->parameters.downtime_limit;
s->threshold_size = bandwidth * migrate_downtime_limit();

s->mbps = (((double) transferred * 8.0) /
((double) time_spent / 1000.0)) / 1000.0 / 1000.0;
Expand All @@ -2751,8 +2690,10 @@ static void migration_update_counters(MigrationState *s,
* if we haven't sent anything, we don't want to
* recalculate. 10000 is a small enough number for our purposes
*/
if (ram_counters.dirty_pages_rate && transferred > 10000) {
s->expected_downtime = ram_counters.remaining / bandwidth;
if (stat64_get(&ram_counters.dirty_pages_rate) &&
transferred > 10000) {
s->expected_downtime =
stat64_get(&ram_counters.dirty_bytes_last_sync) / bandwidth;
}

qemu_file_reset_rate_limit(s->to_dst_file);
Expand Down Expand Up @@ -3244,7 +3185,7 @@ void migrate_fd_connect(MigrationState *s, Error *error_in)
*/
migrate_error_free(s);

s->expected_downtime = s->parameters.downtime_limit;
s->expected_downtime = migrate_downtime_limit();
if (resume) {
assert(s->cleanup_bh);
} else {
Expand Down Expand Up @@ -3332,116 +3273,6 @@ void migrate_fd_connect(MigrationState *s, Error *error_in)
s->migration_thread_running = true;
}

#define DEFINE_PROP_MIG_CAP(name, x) \
DEFINE_PROP_BOOL(name, MigrationState, capabilities[x], false)

static Property migration_properties[] = {
DEFINE_PROP_BOOL("store-global-state", MigrationState,
store_global_state, true),
DEFINE_PROP_BOOL("send-configuration", MigrationState,
send_configuration, true),
DEFINE_PROP_BOOL("send-section-footer", MigrationState,
send_section_footer, true),
DEFINE_PROP_BOOL("decompress-error-check", MigrationState,
decompress_error_check, true),
DEFINE_PROP_UINT8("x-clear-bitmap-shift", MigrationState,
clear_bitmap_shift, CLEAR_BITMAP_SHIFT_DEFAULT),
DEFINE_PROP_BOOL("x-preempt-pre-7-2", MigrationState,
preempt_pre_7_2, false),

/* Migration parameters */
DEFINE_PROP_UINT8("x-compress-level", MigrationState,
parameters.compress_level,
DEFAULT_MIGRATE_COMPRESS_LEVEL),
DEFINE_PROP_UINT8("x-compress-threads", MigrationState,
parameters.compress_threads,
DEFAULT_MIGRATE_COMPRESS_THREAD_COUNT),
DEFINE_PROP_BOOL("x-compress-wait-thread", MigrationState,
parameters.compress_wait_thread, true),
DEFINE_PROP_UINT8("x-decompress-threads", MigrationState,
parameters.decompress_threads,
DEFAULT_MIGRATE_DECOMPRESS_THREAD_COUNT),
DEFINE_PROP_UINT8("x-throttle-trigger-threshold", MigrationState,
parameters.throttle_trigger_threshold,
DEFAULT_MIGRATE_THROTTLE_TRIGGER_THRESHOLD),
DEFINE_PROP_UINT8("x-cpu-throttle-initial", MigrationState,
parameters.cpu_throttle_initial,
DEFAULT_MIGRATE_CPU_THROTTLE_INITIAL),
DEFINE_PROP_UINT8("x-cpu-throttle-increment", MigrationState,
parameters.cpu_throttle_increment,
DEFAULT_MIGRATE_CPU_THROTTLE_INCREMENT),
DEFINE_PROP_BOOL("x-cpu-throttle-tailslow", MigrationState,
parameters.cpu_throttle_tailslow, false),
DEFINE_PROP_SIZE("x-max-bandwidth", MigrationState,
parameters.max_bandwidth, MAX_THROTTLE),
DEFINE_PROP_UINT64("x-downtime-limit", MigrationState,
parameters.downtime_limit,
DEFAULT_MIGRATE_SET_DOWNTIME),
DEFINE_PROP_UINT32("x-checkpoint-delay", MigrationState,
parameters.x_checkpoint_delay,
DEFAULT_MIGRATE_X_CHECKPOINT_DELAY),
DEFINE_PROP_UINT8("multifd-channels", MigrationState,
parameters.multifd_channels,
DEFAULT_MIGRATE_MULTIFD_CHANNELS),
DEFINE_PROP_MULTIFD_COMPRESSION("multifd-compression", MigrationState,
parameters.multifd_compression,
DEFAULT_MIGRATE_MULTIFD_COMPRESSION),
DEFINE_PROP_UINT8("multifd-zlib-level", MigrationState,
parameters.multifd_zlib_level,
DEFAULT_MIGRATE_MULTIFD_ZLIB_LEVEL),
DEFINE_PROP_UINT8("multifd-zstd-level", MigrationState,
parameters.multifd_zstd_level,
DEFAULT_MIGRATE_MULTIFD_ZSTD_LEVEL),
DEFINE_PROP_SIZE("xbzrle-cache-size", MigrationState,
parameters.xbzrle_cache_size,
DEFAULT_MIGRATE_XBZRLE_CACHE_SIZE),
DEFINE_PROP_SIZE("max-postcopy-bandwidth", MigrationState,
parameters.max_postcopy_bandwidth,
DEFAULT_MIGRATE_MAX_POSTCOPY_BANDWIDTH),
DEFINE_PROP_UINT8("max-cpu-throttle", MigrationState,
parameters.max_cpu_throttle,
DEFAULT_MIGRATE_MAX_CPU_THROTTLE),
DEFINE_PROP_SIZE("announce-initial", MigrationState,
parameters.announce_initial,
DEFAULT_MIGRATE_ANNOUNCE_INITIAL),
DEFINE_PROP_SIZE("announce-max", MigrationState,
parameters.announce_max,
DEFAULT_MIGRATE_ANNOUNCE_MAX),
DEFINE_PROP_SIZE("announce-rounds", MigrationState,
parameters.announce_rounds,
DEFAULT_MIGRATE_ANNOUNCE_ROUNDS),
DEFINE_PROP_SIZE("announce-step", MigrationState,
parameters.announce_step,
DEFAULT_MIGRATE_ANNOUNCE_STEP),
DEFINE_PROP_STRING("tls-creds", MigrationState, parameters.tls_creds),
DEFINE_PROP_STRING("tls-hostname", MigrationState, parameters.tls_hostname),
DEFINE_PROP_STRING("tls-authz", MigrationState, parameters.tls_authz),

/* Migration capabilities */
DEFINE_PROP_MIG_CAP("x-xbzrle", MIGRATION_CAPABILITY_XBZRLE),
DEFINE_PROP_MIG_CAP("x-rdma-pin-all", MIGRATION_CAPABILITY_RDMA_PIN_ALL),
DEFINE_PROP_MIG_CAP("x-auto-converge", MIGRATION_CAPABILITY_AUTO_CONVERGE),
DEFINE_PROP_MIG_CAP("x-zero-blocks", MIGRATION_CAPABILITY_ZERO_BLOCKS),
DEFINE_PROP_MIG_CAP("x-compress", MIGRATION_CAPABILITY_COMPRESS),
DEFINE_PROP_MIG_CAP("x-events", MIGRATION_CAPABILITY_EVENTS),
DEFINE_PROP_MIG_CAP("x-postcopy-ram", MIGRATION_CAPABILITY_POSTCOPY_RAM),
DEFINE_PROP_MIG_CAP("x-postcopy-preempt",
MIGRATION_CAPABILITY_POSTCOPY_PREEMPT),
DEFINE_PROP_MIG_CAP("x-colo", MIGRATION_CAPABILITY_X_COLO),
DEFINE_PROP_MIG_CAP("x-release-ram", MIGRATION_CAPABILITY_RELEASE_RAM),
DEFINE_PROP_MIG_CAP("x-block", MIGRATION_CAPABILITY_BLOCK),
DEFINE_PROP_MIG_CAP("x-return-path", MIGRATION_CAPABILITY_RETURN_PATH),
DEFINE_PROP_MIG_CAP("x-multifd", MIGRATION_CAPABILITY_MULTIFD),
DEFINE_PROP_MIG_CAP("x-background-snapshot",
MIGRATION_CAPABILITY_BACKGROUND_SNAPSHOT),
#ifdef CONFIG_LINUX
DEFINE_PROP_MIG_CAP("x-zero-copy-send",
MIGRATION_CAPABILITY_ZERO_COPY_SEND),
#endif

DEFINE_PROP_END_OF_LIST(),
};

static void migration_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
Expand Down Expand Up @@ -3470,41 +3301,14 @@ static void migration_instance_finalize(Object *obj)
static void migration_instance_init(Object *obj)
{
MigrationState *ms = MIGRATION_OBJ(obj);
MigrationParameters *params = &ms->parameters;

ms->state = MIGRATION_STATUS_NONE;
ms->mbps = -1;
ms->pages_per_second = -1;
qemu_sem_init(&ms->pause_sem, 0);
qemu_mutex_init(&ms->error_mutex);

params->tls_hostname = g_strdup("");
params->tls_creds = g_strdup("");

/* Set has_* up only for parameter checks */
params->has_compress_level = true;
params->has_compress_threads = true;
params->has_compress_wait_thread = true;
params->has_decompress_threads = true;
params->has_throttle_trigger_threshold = true;
params->has_cpu_throttle_initial = true;
params->has_cpu_throttle_increment = true;
params->has_cpu_throttle_tailslow = true;
params->has_max_bandwidth = true;
params->has_downtime_limit = true;
params->has_x_checkpoint_delay = true;
params->has_block_incremental = true;
params->has_multifd_channels = true;
params->has_multifd_compression = true;
params->has_multifd_zlib_level = true;
params->has_multifd_zstd_level = true;
params->has_xbzrle_cache_size = true;
params->has_max_postcopy_bandwidth = true;
params->has_max_cpu_throttle = true;
params->has_announce_initial = true;
params->has_announce_max = true;
params->has_announce_rounds = true;
params->has_announce_step = true;
migrate_params_init(&ms->parameters);

qemu_sem_init(&ms->postcopy_pause_sem, 0);
qemu_sem_init(&ms->postcopy_pause_rp_sem, 0);
Expand Down
11 changes: 11 additions & 0 deletions migration/migration.h
Expand Up @@ -404,6 +404,17 @@ struct MigrationState {
*/
bool preempt_pre_7_2;

/*
* flush every channel after each section sent.
*
* This assures that we can't mix pages from one iteration through
* ram pages with pages for the following iteration. We really
* only need to do this flush after we have go through all the
* dirty pages. For historical reasons, we do that after each
* section. This is suboptimal (we flush too many times).
* Default value is false. (since 8.1)
*/
bool multifd_flush_after_each_section;
/*
* This decides the size of guest memory chunk that will be used
* to track dirty bitmap clearing. The size of memory chunk will
Expand Down