Migration pull 2019-01-23

New pages-per-second stat, a new test, and a bunch
 of fixes and tidy ups.
 -----BEGIN PGP SIGNATURE-----
 
 iQIcBAABAgAGBQJcSI5IAAoJEAUWMx68W/3nQuoQAKvaW/g+EMEHBXeXkSttCTpz
 n5hDhiIwj+sW6BXDqjS9r9zBbAeUvmlJELO+N35ELgZKZKAfymYjcP7MT3bHlnW+
 8/AZdIuuVBBWvGS4iCgiScvBVwbj7HqeVynEk4Z2DudGckJpypNnfjx8ssBKs5Gt
 DGGKcqrT3DGo5VxMbR/gYXCvsFtbqxVM3Taud4ReZNyuNQmMxRLe+O3JPQ2AHYbZ
 lSWVp9R0AZx71ynpI5K2bZDe5f1Y6Ag9Ziitz+H0WOpiEcDdS5NHmnfq8Bm7x/Ef
 0K/D2V2T9EVyiuGs6XAuyMV0n7RfpVN7OpMMH41SW6UzvS88YoXqLPuSPYPV5TGH
 JhpenX/5ELAGEO/B7ITeaeKi9q4aQ4Fxbtpr/lWqStodCARzI7QS6arrUCOF0UhH
 EGuKV/qoX7UMmz1KRA7vr6npSOZkdVVbdnRjG6zrTJpSBwCzZufUYKPaDDjc8pSD
 +RY4rrFU1bMuQF5e8xyjKu8VWWN1YhN+uzWzf5OhTsW6josocSCzC3FTJPJStpbs
 2hbXDptznfZw77W3qvKPX1hNMwl08im79NLyDo+PxniVilclMQ11GKyaWAGRggmQ
 49012bWozON6pK2JIzv1GXLHNOAyLcTHdUfpywU100srBEkchrdq/SlEX49IiDW7
 yh+a4BmwHjN4FDwCkufR
 =xxTj
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/dgilbert/tags/pull-migration-20190123a' into staging

Migration pull 2019-01-23

New pages-per-second stat, a new test, and a bunch
of fixes and tidy ups.

# gpg: Signature made Wed 23 Jan 2019 15:54:48 GMT
# gpg:                using RSA key 0516331EBC5BFDE7
# gpg: Good signature from "Dr. David Alan Gilbert (RH2) <dgilbert@redhat.com>"
# Primary key fingerprint: 45F5 C71B 4A0C B7FB 977A  9FA9 0516 331E BC5B FDE7

* remotes/dgilbert/tags/pull-migration-20190123a:
  migration: introduce pages-per-second
  vmstate: constify SaveVMHandlers
  tests: add /vmstate/simple/array
  migration/rdma: unregister fd handler
  migration: unify error handling for process_incoming_migration_co
  migration: add more error handling for postcopy_ram_enable_notify
  migration: multifd_save_cleanup() can't fail, simplify
  migration: fix the multifd code when receiving less channels
  Fix segmentation fault when qemu_signal_init fails

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2019-01-24 13:28:26 +00:00
commit b6b2308113
13 changed files with 139 additions and 47 deletions

2
hmp.c
View File

@ -236,6 +236,8 @@ void hmp_info_migrate(Monitor *mon, const QDict *qdict)
info->ram->page_size >> 10);
monitor_printf(mon, "multifd bytes: %" PRIu64 " kbytes\n",
info->ram->multifd_bytes >> 10);
monitor_printf(mon, "pages-per-second: %" PRIu64 "\n",
info->ram->pages_per_second);
if (info->ram->dirty_pages_rate) {
monitor_printf(mon, "dirty pages rate: %" PRIu64 " pages\n",

View File

@ -72,7 +72,7 @@ int register_savevm_live(DeviceState *dev,
const char *idstr,
int instance_id,
int version_id,
SaveVMHandlers *ops,
const SaveVMHandlers *ops,
void *opaque);
void unregister_savevm(DeviceState *dev, const char *idstr, void *opaque);

View File

@ -30,6 +30,7 @@
void migration_channel_process_incoming(QIOChannel *ioc)
{
MigrationState *s = migrate_get_current();
Error *local_err = NULL;
trace_migration_set_incoming_channel(
ioc, object_get_typename(OBJECT(ioc)));
@ -38,13 +39,13 @@ void migration_channel_process_incoming(QIOChannel *ioc)
*s->parameters.tls_creds &&
!object_dynamic_cast(OBJECT(ioc),
TYPE_QIO_CHANNEL_TLS)) {
Error *local_err = NULL;
migration_tls_channel_process_incoming(s, ioc, &local_err);
if (local_err) {
error_report_err(local_err);
}
} else {
migration_ioc_process_incoming(ioc);
migration_ioc_process_incoming(ioc, &local_err);
}
if (local_err) {
error_report_err(local_err);
}
}

View File

@ -438,15 +438,13 @@ static void process_incoming_migration_co(void *opaque)
/* Make sure all file formats flush their mutable metadata */
bdrv_invalidate_cache_all(&local_err);
if (local_err) {
migrate_set_state(&mis->state, MIGRATION_STATUS_ACTIVE,
MIGRATION_STATUS_FAILED);
error_report_err(local_err);
exit(EXIT_FAILURE);
goto fail;
}
if (colo_init_ram_cache() < 0) {
error_report("Init ram cache failed");
exit(EXIT_FAILURE);
goto fail;
}
qemu_thread_create(&mis->colo_incoming_thread, "COLO incoming",
@ -461,20 +459,22 @@ static void process_incoming_migration_co(void *opaque)
}
if (ret < 0) {
Error *local_err = NULL;
migrate_set_state(&mis->state, MIGRATION_STATUS_ACTIVE,
MIGRATION_STATUS_FAILED);
error_report("load of migration failed: %s", strerror(-ret));
qemu_fclose(mis->from_src_file);
if (multifd_load_cleanup(&local_err) != 0) {
error_report_err(local_err);
}
exit(EXIT_FAILURE);
goto fail;
}
mis->bh = qemu_bh_new(process_incoming_migration_bh, mis);
qemu_bh_schedule(mis->bh);
mis->migration_incoming_co = NULL;
return;
fail:
local_err = NULL;
migrate_set_state(&mis->state, MIGRATION_STATUS_ACTIVE,
MIGRATION_STATUS_FAILED);
qemu_fclose(mis->from_src_file);
if (multifd_load_cleanup(&local_err) != 0) {
error_report_err(local_err);
}
exit(EXIT_FAILURE);
}
static void migration_incoming_setup(QEMUFile *f)
@ -541,7 +541,7 @@ void migration_fd_process_incoming(QEMUFile *f)
migration_incoming_process();
}
void migration_ioc_process_incoming(QIOChannel *ioc)
void migration_ioc_process_incoming(QIOChannel *ioc, Error **errp)
{
MigrationIncomingState *mis = migration_incoming_get_current();
bool start_migration;
@ -563,9 +563,14 @@ void migration_ioc_process_incoming(QIOChannel *ioc)
*/
start_migration = !migrate_use_multifd();
} else {
Error *local_err = NULL;
/* Multiple connections */
assert(migrate_use_multifd());
start_migration = multifd_recv_new_channel(ioc);
start_migration = multifd_recv_new_channel(ioc, &local_err);
if (local_err) {
error_propagate(errp, local_err);
return;
}
}
if (start_migration) {
@ -777,6 +782,7 @@ static void populate_ram_info(MigrationInfo *info, MigrationState *s)
info->ram->postcopy_requests = ram_counters.postcopy_requests;
info->ram->page_size = qemu_target_page_size();
info->ram->multifd_bytes = ram_counters.multifd_bytes;
info->ram->pages_per_second = s->pages_per_second;
if (migrate_use_xbzrle()) {
info->has_xbzrle_cache = true;
@ -1381,7 +1387,6 @@ static void migrate_fd_cleanup(void *opaque)
qemu_savevm_state_cleanup();
if (s->to_dst_file) {
Error *local_err = NULL;
QEMUFile *tmp;
trace_migrate_fd_cleanup();
@ -1392,9 +1397,7 @@ static void migrate_fd_cleanup(void *opaque)
}
qemu_mutex_lock_iothread();
if (multifd_save_cleanup(&local_err) != 0) {
error_report_err(local_err);
}
multifd_save_cleanup();
qemu_mutex_lock(&s->qemu_file_lock);
tmp = s->to_dst_file;
s->to_dst_file = NULL;
@ -1563,6 +1566,7 @@ void migrate_init(MigrationState *s)
s->rp_state.from_dst_file = NULL;
s->rp_state.error = false;
s->mbps = 0.0;
s->pages_per_second = 0.0;
s->downtime = 0;
s->expected_downtime = 0;
s->setup_time = 0;
@ -2881,7 +2885,7 @@ static void migration_calculate_complete(MigrationState *s)
static void migration_update_counters(MigrationState *s,
int64_t current_time)
{
uint64_t transferred, time_spent;
uint64_t transferred, transferred_pages, time_spent;
uint64_t current_bytes; /* bytes transferred since the beginning */
double bandwidth;
@ -2898,6 +2902,11 @@ static void migration_update_counters(MigrationState *s,
s->mbps = (((double) transferred * 8.0) /
((double) time_spent / 1000.0)) / 1000.0 / 1000.0;
transferred_pages = ram_get_total_transferred_pages() -
s->iteration_initial_pages;
s->pages_per_second = (double) transferred_pages /
(((double) time_spent / 1000.0));
/*
* if we haven't sent anything, we don't want to
* recalculate. 10000 is a small enough number for our purposes
@ -2910,6 +2919,7 @@ static void migration_update_counters(MigrationState *s,
s->iteration_start_time = current_time;
s->iteration_initial_bytes = current_bytes;
s->iteration_initial_pages = ram_get_total_transferred_pages();
trace_migrate_transferred(transferred, time_spent,
bandwidth, s->threshold_size);
@ -3314,6 +3324,7 @@ static void migration_instance_init(Object *obj)
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);

View File

@ -126,7 +126,13 @@ struct MigrationState
*/
QemuSemaphore rate_limit_sem;
/* bytes already send at the beggining of current interation */
/* pages already send at the beginning of current iteration */
uint64_t iteration_initial_pages;
/* pages transferred per second */
double pages_per_second;
/* bytes already send at the beginning of current iteration */
uint64_t iteration_initial_bytes;
/* time at the start of current iteration */
int64_t iteration_start_time;
@ -229,7 +235,7 @@ struct MigrationState
void migrate_set_state(int *state, int old_state, int new_state);
void migration_fd_process_incoming(QEMUFile *f);
void migration_ioc_process_incoming(QIOChannel *ioc);
void migration_ioc_process_incoming(QIOChannel *ioc, Error **errp);
void migration_incoming_process(void);
bool migration_has_all_channels(void);
@ -271,6 +277,8 @@ 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);

View File

@ -1117,6 +1117,7 @@ int postcopy_ram_enable_notify(MigrationIncomingState *mis)
/* Mark so that we get notified of accesses to unwritten areas */
if (qemu_ram_foreach_migratable_block(ram_block_enable_notify, mis)) {
error_report("ram_block_enable_notify failed");
return -1;
}

View File

@ -917,13 +917,12 @@ static void multifd_send_terminate_threads(Error *err)
}
}
int multifd_save_cleanup(Error **errp)
void multifd_save_cleanup(void)
{
int i;
int ret = 0;
if (!migrate_use_multifd()) {
return 0;
return;
}
multifd_send_terminate_threads(NULL);
for (i = 0; i < migrate_multifd_channels(); i++) {
@ -953,7 +952,6 @@ int multifd_save_cleanup(Error **errp)
multifd_send_state->pages = NULL;
g_free(multifd_send_state);
multifd_send_state = NULL;
return ret;
}
static void multifd_send_sync_main(void)
@ -1071,9 +1069,8 @@ static void multifd_new_send_channel_async(QIOTask *task, gpointer opaque)
Error *local_err = NULL;
if (qio_task_propagate_error(task, &local_err)) {
if (multifd_save_cleanup(&local_err) != 0) {
migrate_set_error(migrate_get_current(), local_err);
}
migrate_set_error(migrate_get_current(), local_err);
multifd_save_cleanup();
} else {
p->c = QIO_CHANNEL(sioc);
qio_channel_set_delay(p->c, false);
@ -1322,8 +1319,13 @@ bool multifd_recv_all_channels_created(void)
return thread_count == atomic_read(&multifd_recv_state->count);
}
/* Return true if multifd is ready for the migration, otherwise false */
bool multifd_recv_new_channel(QIOChannel *ioc)
/*
* Try to receive all multifd channels to get ready for the migration.
* - Return true and do not set @errp when correctly receving all channels;
* - Return false and do not set @errp when correctly receiving the current one;
* - Return false and set @errp when failing to receive the current channel.
*/
bool multifd_recv_new_channel(QIOChannel *ioc, Error **errp)
{
MultiFDRecvParams *p;
Error *local_err = NULL;
@ -1332,6 +1334,10 @@ bool multifd_recv_new_channel(QIOChannel *ioc)
id = multifd_recv_initial_packet(ioc, &local_err);
if (id < 0) {
multifd_recv_terminate_threads(local_err);
error_propagate_prepend(errp, local_err,
"failed to receive packet"
" via multifd channel %d: ",
atomic_read(&multifd_recv_state->count));
return false;
}
@ -1340,6 +1346,7 @@ bool multifd_recv_new_channel(QIOChannel *ioc)
error_setg(&local_err, "multifd: received id '%d' already setup'",
id);
multifd_recv_terminate_threads(local_err);
error_propagate(errp, local_err);
return false;
}
p->c = ioc;
@ -1351,7 +1358,8 @@ bool multifd_recv_new_channel(QIOChannel *ioc)
qemu_thread_create(&p->thread, p->name, multifd_recv_thread, p,
QEMU_THREAD_JOINABLE);
atomic_inc(&multifd_recv_state->count);
return multifd_recv_state->count == migrate_multifd_channels();
return atomic_read(&multifd_recv_state->count) ==
migrate_multifd_channels();
}
/**
@ -1593,6 +1601,12 @@ uint64_t ram_pagesize_summary(void)
return summary;
}
uint64_t ram_get_total_transferred_pages(void)
{
return ram_counters.normal + ram_counters.duplicate +
compression_counters.pages + xbzrle_counters.pages;
}
static void migration_update_rates(RAMState *rs, int64_t end_time)
{
uint64_t page_count = rs->target_page_count - rs->target_page_count_prev;

View File

@ -43,11 +43,11 @@ uint64_t ram_bytes_remaining(void);
uint64_t ram_bytes_total(void);
int multifd_save_setup(void);
int multifd_save_cleanup(Error **errp);
void multifd_save_cleanup(void);
int multifd_load_setup(void);
int multifd_load_cleanup(Error **errp);
bool multifd_recv_all_channels_created(void);
bool multifd_recv_new_channel(QIOChannel *ioc);
bool multifd_recv_new_channel(QIOChannel *ioc, Error **errp);
uint64_t ram_pagesize_summary(void);
int ram_save_queue_pages(const char *rbname, ram_addr_t start, ram_addr_t len);

View File

@ -2321,6 +2321,7 @@ static void qemu_rdma_cleanup(RDMAContext *rdma)
rdma->connected = false;
}
qemu_set_fd_handler(rdma->channel->fd, NULL, NULL, NULL);
g_free(rdma->dest_blocks);
rdma->dest_blocks = NULL;

View File

@ -303,7 +303,7 @@ typedef struct SaveStateEntry {
int section_id;
/* section id read from the stream */
int load_section_id;
SaveVMHandlers *ops;
const SaveVMHandlers *ops;
const VMStateDescription *vmsd;
void *opaque;
CompatEntry *compat;
@ -614,7 +614,7 @@ int register_savevm_live(DeviceState *dev,
const char *idstr,
int instance_id,
int version_id,
SaveVMHandlers *ops,
const SaveVMHandlers *ops,
void *opaque)
{
SaveStateEntry *se;
@ -1729,6 +1729,7 @@ static int loadvm_postcopy_handle_listen(MigrationIncomingState *mis)
*/
if (migrate_postcopy_ram()) {
if (postcopy_ram_enable_notify(mis)) {
postcopy_ram_incoming_cleanup(mis);
return -1;
}
}

View File

@ -41,6 +41,9 @@
#
# @multifd-bytes: The number of bytes sent through multifd (since 3.0)
#
# @pages-per-second: the number of memory pages transferred per second
# (Since 4.0)
#
# Since: 0.14.0
##
{ 'struct': 'MigrationStats',
@ -49,7 +52,7 @@
'normal-bytes': 'int', 'dirty-pages-rate' : 'int',
'mbps' : 'number', 'dirty-sync-count' : 'int',
'postcopy-requests' : 'int', 'page-size' : 'int',
'multifd-bytes' : 'uint64' } }
'multifd-bytes' : 'uint64', 'pages-per-second' : 'uint64' } }
##
# @XBZRLECacheStats:

View File

@ -284,6 +284,55 @@ static void test_simple_primitive(void)
FIELD_EQUAL(i64_2);
}
typedef struct TestSimpleArray {
uint16_t u16_1[3];
} TestSimpleArray;
/* Object instantiation, we are going to use it in more than one test */
TestSimpleArray obj_simple_arr = {
.u16_1 = { 0x42, 0x43, 0x44 },
};
/* Description of the values. If you add a primitive type
you are expected to add a test here */
static const VMStateDescription vmstate_simple_arr = {
.name = "simple/array",
.version_id = 1,
.minimum_version_id = 1,
.fields = (VMStateField[]) {
VMSTATE_UINT16_ARRAY(u16_1, TestSimpleArray, 3),
VMSTATE_END_OF_LIST()
}
};
uint8_t wire_simple_arr[] = {
/* u16_1 */ 0x00, 0x42,
/* u16_1 */ 0x00, 0x43,
/* u16_1 */ 0x00, 0x44,
QEMU_VM_EOF, /* just to ensure we won't get EOF reported prematurely */
};
static void obj_simple_arr_copy(void *target, void *source)
{
memcpy(target, source, sizeof(TestSimpleArray));
}
static void test_simple_array(void)
{
TestSimpleArray obj, obj_clone;
memset(&obj, 0, sizeof(obj));
save_vmstate(&vmstate_simple_arr, &obj_simple_arr);
compare_vmstate(wire_simple_arr, sizeof(wire_simple_arr));
SUCCESS(load_vmstate(&vmstate_simple_arr, &obj, &obj_clone,
obj_simple_arr_copy, 1, wire_simple_arr,
sizeof(wire_simple_arr)));
}
typedef struct TestStruct {
uint32_t a, b, c, e;
uint64_t d, f;
@ -863,6 +912,7 @@ int main(int argc, char **argv)
g_test_init(&argc, &argv, NULL);
g_test_add_func("/vmstate/simple/primitive", test_simple_primitive);
g_test_add_func("/vmstate/simple/array", test_simple_array);
g_test_add_func("/vmstate/versioned/load/v1", test_load_v1);
g_test_add_func("/vmstate/versioned/load/v2", test_load_v2);
g_test_add_func("/vmstate/field_exists/load/noskip", test_load_noskip);

View File

@ -71,7 +71,7 @@ static void sigfd_handler(void *opaque)
}
}
static int qemu_signal_init(void)
static int qemu_signal_init(Error **errp)
{
int sigfd;
sigset_t set;
@ -96,7 +96,7 @@ static int qemu_signal_init(void)
sigdelset(&set, SIG_IPI);
sigfd = qemu_signalfd(&set);
if (sigfd == -1) {
fprintf(stderr, "failed to create signalfd\n");
error_setg_errno(errp, errno, "failed to create signalfd");
return -errno;
}
@ -109,7 +109,7 @@ static int qemu_signal_init(void)
#else /* _WIN32 */
static int qemu_signal_init(void)
static int qemu_signal_init(Error **errp)
{
return 0;
}
@ -148,7 +148,7 @@ int qemu_init_main_loop(Error **errp)
init_clocks(qemu_timer_notify_cb);
ret = qemu_signal_init();
ret = qemu_signal_init(errp);
if (ret) {
return ret;
}