3 changes: 2 additions & 1 deletion migration/multifd.c
Expand Up @@ -635,6 +635,7 @@ int multifd_send_sync_main(QEMUFile *f)
for (i = 0; i < migrate_multifd_channels(); i++) {
MultiFDSendParams *p = &multifd_send_state->params[i];

qemu_sem_wait(&multifd_send_state->channels_ready);
trace_multifd_send_sync_main_wait(p->id);
qemu_sem_wait(&p->sem_sync);

Expand Down Expand Up @@ -668,6 +669,7 @@ static void *multifd_send_thread(void *opaque)
p->num_packets = 1;

while (true) {
qemu_sem_post(&multifd_send_state->channels_ready);
qemu_sem_wait(&p->sem);

if (qatomic_read(&multifd_send_state->exiting)) {
Expand Down Expand Up @@ -736,7 +738,6 @@ static void *multifd_send_thread(void *opaque)
if (flags & MULTIFD_FLAG_SYNC) {
qemu_sem_post(&p->sem_sync);
}
qemu_sem_post(&multifd_send_state->channels_ready);
} else if (p->quit) {
qemu_mutex_unlock(&p->mutex);
break;
Expand Down
404 changes: 290 additions & 114 deletions migration/options.c

Large diffs are not rendered by default.

19 changes: 19 additions & 0 deletions migration/options.h
Expand Up @@ -14,13 +14,20 @@
#ifndef QEMU_MIGRATION_OPTIONS_H
#define QEMU_MIGRATION_OPTIONS_H

#include "hw/qdev-properties.h"
#include "hw/qdev-properties-system.h"

/* constants */

/* Amount of time to allocate to each "chunk" of bandwidth-throttled
* data. */
#define BUFFER_DELAY 100
#define XFER_LIMIT_RATIO (1000 / BUFFER_DELAY)

/* migration properties */

extern Property migration_properties[];

/* capabilities */

bool migrate_auto_converge(void);
Expand Down Expand Up @@ -52,6 +59,7 @@ bool migrate_zero_copy_send(void);
* check, but they are not a capability.
*/

bool migrate_multifd_flush_after_each_section(void);
bool migrate_postcopy(void);
bool migrate_tls(void);

Expand All @@ -62,6 +70,7 @@ bool migrate_cap_set(int cap, bool value, Error **errp);

/* parameters */

const BitmapMigrationNodeAliasList *migrate_block_bitmap_mapping(void);
bool migrate_block_incremental(void);
uint32_t migrate_checkpoint_delay(void);
int migrate_compress_level(void);
Expand All @@ -71,6 +80,7 @@ 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);
uint64_t migrate_downtime_limit(void);
uint8_t migrate_max_cpu_throttle(void);
uint64_t migrate_max_bandwidth(void);
int64_t migrate_max_postcopy_bandwidth(void);
Expand All @@ -79,10 +89,19 @@ MultiFDCompression migrate_multifd_compression(void);
int migrate_multifd_zlib_level(void);
int migrate_multifd_zstd_level(void);
uint8_t migrate_throttle_trigger_threshold(void);
const char *migrate_tls_authz(void);
const char *migrate_tls_creds(void);
const char *migrate_tls_hostname(void);
uint64_t migrate_xbzrle_cache_size(void);

/* parameters setters */

void migrate_set_block_incremental(bool value);

/* parameters helpers */

bool migrate_params_check(MigrationParameters *params, Error **errp);
void migrate_params_init(MigrationParameters *params);
void block_cleanup_parameters(void);

#endif
51 changes: 42 additions & 9 deletions migration/ram.c
Expand Up @@ -86,6 +86,7 @@
#define RAM_SAVE_FLAG_XBZRLE 0x40
/* 0x80 is reserved in qemu-file.h for RAM_SAVE_FLAG_HOOK */
#define RAM_SAVE_FLAG_COMPRESS_PAGE 0x100
#define RAM_SAVE_FLAG_MULTIFD_FLUSH 0x200
/* We can't use any flag that is bigger than 0x200 */

int (*xbzrle_encode_buffer_func)(uint8_t *, uint8_t *, int,
Expand Down Expand Up @@ -1129,8 +1130,9 @@ static void migration_update_rates(RAMState *rs, int64_t end_time)
double compressed_size;

/* calculate period counters */
ram_counters.dirty_pages_rate = rs->num_dirty_pages_period * 1000
/ (end_time - rs->time_last_bitmap_sync);
stat64_set(&ram_counters.dirty_pages_rate,
rs->num_dirty_pages_period * 1000 /
(end_time - rs->time_last_bitmap_sync));

if (!page_count) {
return;
Expand Down Expand Up @@ -1222,7 +1224,7 @@ static void migration_bitmap_sync(RAMState *rs)
RAMBLOCK_FOREACH_NOT_IGNORED(block) {
ramblock_sync_dirty_bitmap(rs, block);
}
ram_counters.remaining = ram_bytes_remaining();
stat64_set(&ram_counters.dirty_bytes_last_sync, ram_bytes_remaining());
}
qemu_mutex_unlock(&rs->bitmap_mutex);

Expand Down Expand Up @@ -1581,6 +1583,7 @@ static int compress_page_with_multi_thread(RAMBlock *block, ram_addr_t offset)
* associated with the search process.
*
* Returns:
* <0: An error happened
* PAGE_ALL_CLEAN: no dirty page found, give up
* PAGE_TRY_AGAIN: no dirty page found, retry for next block
* PAGE_DIRTY_FOUND: dirty page found
Expand Down Expand Up @@ -1608,6 +1611,15 @@ static int find_dirty_block(RAMState *rs, PageSearchStatus *pss)
pss->page = 0;
pss->block = QLIST_NEXT_RCU(pss->block, next);
if (!pss->block) {
if (!migrate_multifd_flush_after_each_section()) {
QEMUFile *f = rs->pss[RAM_CHANNEL_PRECOPY].pss_channel;
int ret = multifd_send_sync_main(f);
if (ret < 0) {
return ret;
}
qemu_put_be64(f, RAM_SAVE_FLAG_MULTIFD_FLUSH);
qemu_fflush(f);
}
/*
* If memory migration starts over, we will meet a dirtied page
* which may still exists in compression threads's ring, so we
Expand Down Expand Up @@ -2600,6 +2612,9 @@ static int ram_find_and_save_block(RAMState *rs)
break;
} else if (res == PAGE_TRY_AGAIN) {
continue;
} else if (res < 0) {
pages = res;
break;
}
}
}
Expand Down Expand Up @@ -3286,6 +3301,10 @@ static int ram_save_setup(QEMUFile *f, void *opaque)
return ret;
}

if (!migrate_multifd_flush_after_each_section()) {
qemu_put_be64(f, RAM_SAVE_FLAG_MULTIFD_FLUSH);
}

qemu_put_be64(f, RAM_SAVE_FLAG_EOS);
qemu_fflush(f);

Expand Down Expand Up @@ -3394,9 +3413,11 @@ static int ram_save_iterate(QEMUFile *f, void *opaque)
out:
if (ret >= 0
&& migration_is_setup_or_active(migrate_get_current()->state)) {
ret = multifd_send_sync_main(rs->pss[RAM_CHANNEL_PRECOPY].pss_channel);
if (ret < 0) {
return ret;
if (migrate_multifd_flush_after_each_section()) {
ret = multifd_send_sync_main(rs->pss[RAM_CHANNEL_PRECOPY].pss_channel);
if (ret < 0) {
return ret;
}
}

qemu_put_be64(f, RAM_SAVE_FLAG_EOS);
Expand Down Expand Up @@ -3469,6 +3490,9 @@ static int ram_save_complete(QEMUFile *f, void *opaque)
return ret;
}

if (!migrate_multifd_flush_after_each_section()) {
qemu_put_be64(f, RAM_SAVE_FLAG_MULTIFD_FLUSH);
}
qemu_put_be64(f, RAM_SAVE_FLAG_EOS);
qemu_fflush(f);

Expand Down Expand Up @@ -4150,10 +4174,14 @@ int ram_load_postcopy(QEMUFile *f, int channel)
}
decompress_data_with_multi_threads(f, page_buffer, len);
break;

case RAM_SAVE_FLAG_MULTIFD_FLUSH:
multifd_recv_sync_main();
break;
case RAM_SAVE_FLAG_EOS:
/* normal exit */
multifd_recv_sync_main();
if (migrate_multifd_flush_after_each_section()) {
multifd_recv_sync_main();
}
break;
default:
error_report("Unknown combination of migration flags: 0x%x"
Expand Down Expand Up @@ -4422,9 +4450,14 @@ static int ram_load_precopy(QEMUFile *f)
break;
}
break;
case RAM_SAVE_FLAG_MULTIFD_FLUSH:
multifd_recv_sync_main();
break;
case RAM_SAVE_FLAG_EOS:
/* normal exit */
multifd_recv_sync_main();
if (migrate_multifd_flush_after_each_section()) {
multifd_recv_sync_main();
}
break;
default:
if (flags & RAM_SAVE_FLAG_HOOK) {
Expand Down
4 changes: 2 additions & 2 deletions migration/ram.h
Expand Up @@ -41,7 +41,8 @@
* one thread).
*/
typedef struct {
int64_t dirty_pages_rate;
Stat64 dirty_bytes_last_sync;
Stat64 dirty_pages_rate;
Stat64 dirty_sync_count;
Stat64 dirty_sync_missed_zero_copy;
Stat64 downtime_bytes;
Expand All @@ -51,7 +52,6 @@ typedef struct {
Stat64 postcopy_bytes;
Stat64 postcopy_requests;
Stat64 precopy_bytes;
int64_t remaining;
Stat64 transferred;
} RAMStats;

Expand Down
19 changes: 8 additions & 11 deletions migration/tls.c
Expand Up @@ -34,20 +34,19 @@ migration_tls_get_creds(MigrationState *s,
Error **errp)
{
Object *creds;
const char *tls_creds = migrate_tls_creds();
QCryptoTLSCreds *ret;

creds = object_resolve_path_component(
object_get_objects_root(), s->parameters.tls_creds);
creds = object_resolve_path_component(object_get_objects_root(), tls_creds);
if (!creds) {
error_setg(errp, "No TLS credentials with id '%s'",
s->parameters.tls_creds);
error_setg(errp, "No TLS credentials with id '%s'", tls_creds);
return NULL;
}
ret = (QCryptoTLSCreds *)object_dynamic_cast(
creds, TYPE_QCRYPTO_TLS_CREDS);
if (!ret) {
error_setg(errp, "Object with id '%s' is not TLS credentials",
s->parameters.tls_creds);
tls_creds);
return NULL;
}
if (!qcrypto_tls_creds_check_endpoint(ret, endpoint, errp)) {
Expand Down Expand Up @@ -87,10 +86,7 @@ void migration_tls_channel_process_incoming(MigrationState *s,
return;
}

tioc = qio_channel_tls_new_server(
ioc, creds,
s->parameters.tls_authz,
errp);
tioc = qio_channel_tls_new_server(ioc, creds, migrate_tls_authz(), errp);
if (!tioc) {
return;
}
Expand Down Expand Up @@ -134,8 +130,9 @@ QIOChannelTLS *migration_tls_client_create(MigrationState *s,
return NULL;
}

if (s->parameters.tls_hostname && *s->parameters.tls_hostname) {
hostname = s->parameters.tls_hostname;
const char *tls_hostname = migrate_tls_hostname();
if (tls_hostname && *tls_hostname) {
hostname = tls_hostname;
}

return qio_channel_tls_new_client(ioc, creds, hostname, errp);
Expand Down
11 changes: 11 additions & 0 deletions util/stats64.c
Expand Up @@ -57,6 +57,17 @@ uint64_t stat64_get(const Stat64 *s)
return ((uint64_t)high << 32) | low;
}

void stat64_set(Stat64 *s, uint64_t val)
{
while (!stat64_wrtrylock(s)) {
cpu_relax();
}

qatomic_set(&s->high, val >> 32);
qatomic_set(&s->low, val);
stat64_wrunlock(s);
}

bool stat64_add32_carry(Stat64 *s, uint32_t low, uint32_t high)
{
uint32_t old;
Expand Down