From ad24c7cb595e7ff3df17f7db790e2a7dfaf8040c Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Fri, 4 Jan 2019 19:12:35 +0100 Subject: multifd: Only send pages when packet are not empty We send packages without pages sometimes for sysnchronizanion. The iov functions do the right thing, but we will be changing this code in future patches. Signed-off-by: Juan Quintela Reviewed-by: Dr. David Alan Gilbert Signed-off-by: Juan Quintela --- migration/ram.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) (limited to 'migration') diff --git a/migration/ram.c b/migration/ram.c index 35bd6213e9..3034f862c1 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -1088,9 +1088,12 @@ static void *multifd_send_thread(void *opaque) break; } - ret = qio_channel_writev_all(p->c, p->pages->iov, used, &local_err); - if (ret != 0) { - break; + if (used) { + ret = qio_channel_writev_all(p->c, p->pages->iov, + used, &local_err); + if (ret != 0) { + break; + } } qemu_mutex_lock(&p->mutex); @@ -1317,9 +1320,12 @@ static void *multifd_recv_thread(void *opaque) p->num_pages += used; qemu_mutex_unlock(&p->mutex); - ret = qio_channel_readv_all(p->c, p->pages->iov, used, &local_err); - if (ret != 0) { - break; + if (used) { + ret = qio_channel_readv_all(p->c, p->pages->iov, + used, &local_err); + if (ret != 0) { + break; + } } if (flags & MULTIFD_FLAG_SYNC) { -- cgit v1.2.3 From 6f862692951ad6f31c1c8ea686bd1b85365d36d8 Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Wed, 20 Feb 2019 12:04:04 +0100 Subject: multifd: Rename "size" member to pages_alloc It really indicates what is the number of allocated pages for one packet. Once there rename "used" to "pages_used". Signed-off-by: Juan Quintela Reviewed-by: Dr. David Alan Gilbert Signed-off-by: Juan Quintela --- migration/ram.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) (limited to 'migration') diff --git a/migration/ram.c b/migration/ram.c index 3034f862c1..dc73829e25 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -594,8 +594,9 @@ typedef struct { uint32_t magic; uint32_t version; uint32_t flags; - uint32_t size; - uint32_t used; + /* maximum number of allocated pages */ + uint32_t pages_alloc; + uint32_t pages_used; uint64_t packet_num; char ramblock[256]; uint64_t offset[]; @@ -781,8 +782,8 @@ static void multifd_send_fill_packet(MultiFDSendParams *p) packet->magic = cpu_to_be32(MULTIFD_MAGIC); packet->version = cpu_to_be32(MULTIFD_VERSION); packet->flags = cpu_to_be32(p->flags); - packet->size = cpu_to_be32(migrate_multifd_page_count()); - packet->used = cpu_to_be32(p->pages->used); + packet->pages_alloc = cpu_to_be32(migrate_multifd_page_count()); + packet->pages_used = cpu_to_be32(p->pages->used); packet->packet_num = cpu_to_be64(p->packet_num); if (p->pages->block) { @@ -818,19 +819,19 @@ static int multifd_recv_unfill_packet(MultiFDRecvParams *p, Error **errp) p->flags = be32_to_cpu(packet->flags); - packet->size = be32_to_cpu(packet->size); - if (packet->size > migrate_multifd_page_count()) { + packet->pages_alloc = be32_to_cpu(packet->pages_alloc); + if (packet->pages_alloc > migrate_multifd_page_count()) { error_setg(errp, "multifd: received packet " "with size %d and expected maximum size %d", - packet->size, migrate_multifd_page_count()) ; + packet->pages_alloc, migrate_multifd_page_count()) ; return -1; } - p->pages->used = be32_to_cpu(packet->used); - if (p->pages->used > packet->size) { + p->pages->used = be32_to_cpu(packet->pages_used); + if (p->pages->used > packet->pages_alloc) { error_setg(errp, "multifd: received packet " - "with size %d and expected maximum size %d", - p->pages->used, packet->size) ; + "with %d pages and expected maximum pages are %d", + p->pages->used, packet->pages_alloc) ; return -1; } -- cgit v1.2.3 From 2a34ee593bb08570fe29420d2309ece9f319014b Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Fri, 4 Jan 2019 19:45:39 +0100 Subject: multifd: Create new next_packet_size field We need to send this field when we add compression support. As we are still on x- stage, we can do this kind of changes. Signed-off-by: Juan Quintela --- migration/ram.c | 15 +++++++++++++-- migration/trace-events | 4 ++-- 2 files changed, 15 insertions(+), 4 deletions(-) (limited to 'migration') diff --git a/migration/ram.c b/migration/ram.c index dc73829e25..29f2823939 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -597,6 +597,8 @@ typedef struct { /* maximum number of allocated pages */ uint32_t pages_alloc; uint32_t pages_used; + /* size of the next packet that contains pages */ + uint32_t next_packet_size; uint64_t packet_num; char ramblock[256]; uint64_t offset[]; @@ -644,6 +646,8 @@ typedef struct { MultiFDPacket_t *packet; /* multifd flags for each packet */ uint32_t flags; + /* size of the next packet that contains pages */ + uint32_t next_packet_size; /* global number of generated multifd packets */ uint64_t packet_num; /* thread local variables */ @@ -680,6 +684,8 @@ typedef struct { /* global number of generated multifd packets */ uint64_t packet_num; /* thread local variables */ + /* size of the next packet that contains pages */ + uint32_t next_packet_size; /* packets sent through this channel */ uint64_t num_packets; /* pages sent through this channel */ @@ -784,6 +790,7 @@ static void multifd_send_fill_packet(MultiFDSendParams *p) packet->flags = cpu_to_be32(p->flags); packet->pages_alloc = cpu_to_be32(migrate_multifd_page_count()); packet->pages_used = cpu_to_be32(p->pages->used); + packet->next_packet_size = cpu_to_be32(p->next_packet_size); packet->packet_num = cpu_to_be64(p->packet_num); if (p->pages->block) { @@ -835,6 +842,7 @@ static int multifd_recv_unfill_packet(MultiFDRecvParams *p, Error **errp) return -1; } + p->next_packet_size = be32_to_cpu(packet->next_packet_size); p->packet_num = be64_to_cpu(packet->packet_num); if (p->pages->used) { @@ -1074,6 +1082,7 @@ static void *multifd_send_thread(void *opaque) uint64_t packet_num = p->packet_num; uint32_t flags = p->flags; + p->next_packet_size = used * qemu_target_page_size(); multifd_send_fill_packet(p); p->flags = 0; p->num_packets++; @@ -1081,7 +1090,8 @@ static void *multifd_send_thread(void *opaque) p->pages->used = 0; qemu_mutex_unlock(&p->mutex); - trace_multifd_send(p->id, packet_num, used, flags); + trace_multifd_send(p->id, packet_num, used, flags, + p->next_packet_size); ret = qio_channel_write_all(p->c, (void *)p->packet, p->packet_len, &local_err); @@ -1316,7 +1326,8 @@ static void *multifd_recv_thread(void *opaque) used = p->pages->used; flags = p->flags; - trace_multifd_recv(p->id, p->packet_num, used, flags); + trace_multifd_recv(p->id, p->packet_num, used, flags, + p->next_packet_size); p->num_packets++; p->num_pages += used; qemu_mutex_unlock(&p->mutex); diff --git a/migration/trace-events b/migration/trace-events index 72e3fcb885..ef78dc21f8 100644 --- a/migration/trace-events +++ b/migration/trace-events @@ -76,13 +76,13 @@ get_queued_page_not_dirty(const char *block_name, uint64_t tmp_offset, unsigned migration_bitmap_sync_start(void) "" migration_bitmap_sync_end(uint64_t dirty_pages) "dirty_pages %" PRIu64 migration_throttle(void) "" -multifd_recv(uint8_t id, uint64_t packet_num, uint32_t used, uint32_t flags) "channel %d packet number %" PRIu64 " pages %d flags 0x%x" +multifd_recv(uint8_t id, uint64_t packet_num, uint32_t used, uint32_t flags, uint32_t next_packet_size) "channel %d packet number %" PRIu64 " pages %d flags 0x%x next packet size %d" multifd_recv_sync_main(long packet_num) "packet num %ld" multifd_recv_sync_main_signal(uint8_t id) "channel %d" multifd_recv_sync_main_wait(uint8_t id) "channel %d" multifd_recv_thread_end(uint8_t id, uint64_t packets, uint64_t pages) "channel %d packets %" PRIu64 " pages %" PRIu64 multifd_recv_thread_start(uint8_t id) "%d" -multifd_send(uint8_t id, uint64_t packet_num, uint32_t used, uint32_t flags) "channel %d packet_num %" PRIu64 " pages %d flags 0x%x" +multifd_send(uint8_t id, uint64_t packet_num, uint32_t used, uint32_t flags, uint32_t next_packet_size) "channel %d packet_num %" PRIu64 " pages %d flags 0x%x next packet size %d" multifd_send_sync_main(long packet_num) "packet num %ld" multifd_send_sync_main_signal(uint8_t id) "channel %d" multifd_send_sync_main_wait(uint8_t id) "channel %d" -- cgit v1.2.3 From efd1a1d6407f73565cf3b4089a2baa4bad0650f8 Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Wed, 20 Feb 2019 12:06:03 +0100 Subject: multifd: Drop x-multifd-page-count parameter Libvirt don't want to expose (and explain it). From now on we measure the number of packages in bytes instead of pages, so it is the same independently of architecture. We choose the page size of x86. Notice that in the following patch we make this variable. Signed-off-by: Juan Quintela Reviewed-by: Dr. David Alan Gilbert Reviewed-by: Markus Armbruster Signed-off-by: Juan Quintela --- migration/migration.c | 30 ------------------------------ migration/migration.h | 1 - migration/ram.c | 15 ++++++++++----- 3 files changed, 10 insertions(+), 36 deletions(-) (limited to 'migration') diff --git a/migration/migration.c b/migration/migration.c index df6fd8e0e5..52c8121628 100644 --- a/migration/migration.c +++ b/migration/migration.c @@ -82,7 +82,6 @@ /* 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_PAGE_COUNT 16 /* Background transfer rate for postcopy, 0 means unlimited, note * that page requests can still exceed this limit. @@ -768,8 +767,6 @@ MigrationParameters *qmp_query_migrate_parameters(Error **errp) params->block_incremental = s->parameters.block_incremental; params->has_x_multifd_channels = true; params->x_multifd_channels = s->parameters.x_multifd_channels; - params->has_x_multifd_page_count = true; - params->x_multifd_page_count = s->parameters.x_multifd_page_count; params->has_xbzrle_cache_size = true; params->xbzrle_cache_size = s->parameters.xbzrle_cache_size; params->has_max_postcopy_bandwidth = true; @@ -1158,14 +1155,6 @@ static bool migrate_params_check(MigrationParameters *params, Error **errp) "is invalid, it should be in the range of 1 to 255"); return false; } - if (params->has_x_multifd_page_count && - (params->x_multifd_page_count < 1 || - params->x_multifd_page_count > 10000)) { - error_setg(errp, QERR_INVALID_PARAMETER_VALUE, - "multifd_page_count", - "is invalid, it should be in the range of 1 to 10000"); - return false; - } if (params->has_xbzrle_cache_size && (params->xbzrle_cache_size < qemu_target_page_size() || @@ -1277,9 +1266,6 @@ static void migrate_params_test_apply(MigrateSetParameters *params, if (params->has_x_multifd_channels) { dest->x_multifd_channels = params->x_multifd_channels; } - if (params->has_x_multifd_page_count) { - dest->x_multifd_page_count = params->x_multifd_page_count; - } if (params->has_xbzrle_cache_size) { dest->xbzrle_cache_size = params->xbzrle_cache_size; } @@ -1370,9 +1356,6 @@ static void migrate_params_apply(MigrateSetParameters *params, Error **errp) if (params->has_x_multifd_channels) { s->parameters.x_multifd_channels = params->x_multifd_channels; } - if (params->has_x_multifd_page_count) { - s->parameters.x_multifd_page_count = params->x_multifd_page_count; - } if (params->has_xbzrle_cache_size) { s->parameters.xbzrle_cache_size = params->xbzrle_cache_size; xbzrle_cache_resize(params->xbzrle_cache_size, errp); @@ -2152,15 +2135,6 @@ int migrate_multifd_channels(void) return s->parameters.x_multifd_channels; } -int migrate_multifd_page_count(void) -{ - MigrationState *s; - - s = migrate_get_current(); - - return s->parameters.x_multifd_page_count; -} - int migrate_use_xbzrle(void) { MigrationState *s; @@ -3403,9 +3377,6 @@ static Property migration_properties[] = { DEFINE_PROP_UINT8("x-multifd-channels", MigrationState, parameters.x_multifd_channels, DEFAULT_MIGRATE_MULTIFD_CHANNELS), - DEFINE_PROP_UINT32("x-multifd-page-count", MigrationState, - parameters.x_multifd_page_count, - DEFAULT_MIGRATE_MULTIFD_PAGE_COUNT), DEFINE_PROP_SIZE("xbzrle-cache-size", MigrationState, parameters.xbzrle_cache_size, DEFAULT_MIGRATE_XBZRLE_CACHE_SIZE), @@ -3495,7 +3466,6 @@ static void migration_instance_init(Object *obj) params->has_x_checkpoint_delay = true; params->has_block_incremental = true; params->has_x_multifd_channels = true; - params->has_x_multifd_page_count = true; params->has_xbzrle_cache_size = true; params->has_max_postcopy_bandwidth = true; params->has_max_cpu_throttle = true; diff --git a/migration/migration.h b/migration/migration.h index 99e99e56bd..0f986935e1 100644 --- a/migration/migration.h +++ b/migration/migration.h @@ -274,7 +274,6 @@ bool migrate_auto_converge(void); bool migrate_use_multifd(void); bool migrate_pause_before_switchover(void); int migrate_multifd_channels(void); -int migrate_multifd_page_count(void); int migrate_use_xbzrle(void); int64_t migrate_xbzrle_cache_size(void); diff --git a/migration/ram.c b/migration/ram.c index 29f2823939..454d3eb539 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -583,6 +583,9 @@ exit: #define MULTIFD_FLAG_SYNC (1 << 0) +/* This value needs to be a multiple of qemu_target_page_size() */ +#define MULTIFD_PACKET_SIZE (64 * 1024) + typedef struct { uint32_t magic; uint32_t version; @@ -783,12 +786,13 @@ static void multifd_pages_clear(MultiFDPages_t *pages) static void multifd_send_fill_packet(MultiFDSendParams *p) { MultiFDPacket_t *packet = p->packet; + uint32_t page_count = MULTIFD_PACKET_SIZE / qemu_target_page_size(); int i; packet->magic = cpu_to_be32(MULTIFD_MAGIC); packet->version = cpu_to_be32(MULTIFD_VERSION); packet->flags = cpu_to_be32(p->flags); - packet->pages_alloc = cpu_to_be32(migrate_multifd_page_count()); + packet->pages_alloc = cpu_to_be32(page_count); packet->pages_used = cpu_to_be32(p->pages->used); packet->next_packet_size = cpu_to_be32(p->next_packet_size); packet->packet_num = cpu_to_be64(p->packet_num); @@ -805,6 +809,7 @@ static void multifd_send_fill_packet(MultiFDSendParams *p) static int multifd_recv_unfill_packet(MultiFDRecvParams *p, Error **errp) { MultiFDPacket_t *packet = p->packet; + uint32_t page_count = MULTIFD_PACKET_SIZE / qemu_target_page_size(); RAMBlock *block; int i; @@ -827,10 +832,10 @@ static int multifd_recv_unfill_packet(MultiFDRecvParams *p, Error **errp) p->flags = be32_to_cpu(packet->flags); packet->pages_alloc = be32_to_cpu(packet->pages_alloc); - if (packet->pages_alloc > migrate_multifd_page_count()) { + if (packet->pages_alloc > page_count) { error_setg(errp, "multifd: received packet " "with size %d and expected maximum size %d", - packet->pages_alloc, migrate_multifd_page_count()) ; + packet->pages_alloc, page_count) ; return -1; } @@ -1162,7 +1167,7 @@ static void multifd_new_send_channel_async(QIOTask *task, gpointer opaque) int multifd_save_setup(void) { int thread_count; - uint32_t page_count = migrate_multifd_page_count(); + uint32_t page_count = MULTIFD_PACKET_SIZE / qemu_target_page_size(); uint8_t i; if (!migrate_use_multifd()) { @@ -1362,7 +1367,7 @@ static void *multifd_recv_thread(void *opaque) int multifd_load_setup(void) { int thread_count; - uint32_t page_count = migrate_multifd_page_count(); + uint32_t page_count = MULTIFD_PACKET_SIZE / qemu_target_page_size(); uint8_t i; if (!migrate_use_multifd()) { -- cgit v1.2.3 From 7ed379b286dc6d3942ae851bdfa87b45b99ae9ff Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Wed, 20 Feb 2019 12:44:07 +0100 Subject: multifd: Be flexible about packet size This way we can change the packet size in the future and everything will work. We choose an arbitrary big number (100 times configured size) as a limit about how big we will reallocate. Signed-off-by: Juan Quintela Reviewed-by: Dr. David Alan Gilbert Signed-off-by: Juan Quintela --- migration/ram.c | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) (limited to 'migration') diff --git a/migration/ram.c b/migration/ram.c index 454d3eb539..77c1878292 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -786,13 +786,13 @@ static void multifd_pages_clear(MultiFDPages_t *pages) static void multifd_send_fill_packet(MultiFDSendParams *p) { MultiFDPacket_t *packet = p->packet; - uint32_t page_count = MULTIFD_PACKET_SIZE / qemu_target_page_size(); + uint32_t page_max = MULTIFD_PACKET_SIZE / qemu_target_page_size(); int i; packet->magic = cpu_to_be32(MULTIFD_MAGIC); packet->version = cpu_to_be32(MULTIFD_VERSION); packet->flags = cpu_to_be32(p->flags); - packet->pages_alloc = cpu_to_be32(page_count); + packet->pages_alloc = cpu_to_be32(page_max); packet->pages_used = cpu_to_be32(p->pages->used); packet->next_packet_size = cpu_to_be32(p->next_packet_size); packet->packet_num = cpu_to_be64(p->packet_num); @@ -809,7 +809,7 @@ static void multifd_send_fill_packet(MultiFDSendParams *p) static int multifd_recv_unfill_packet(MultiFDRecvParams *p, Error **errp) { MultiFDPacket_t *packet = p->packet; - uint32_t page_count = MULTIFD_PACKET_SIZE / qemu_target_page_size(); + uint32_t pages_max = MULTIFD_PACKET_SIZE / qemu_target_page_size(); RAMBlock *block; int i; @@ -832,12 +832,24 @@ static int multifd_recv_unfill_packet(MultiFDRecvParams *p, Error **errp) p->flags = be32_to_cpu(packet->flags); packet->pages_alloc = be32_to_cpu(packet->pages_alloc); - if (packet->pages_alloc > page_count) { + /* + * If we recevied a packet that is 100 times bigger than expected + * just stop migration. It is a magic number. + */ + if (packet->pages_alloc > pages_max * 100) { error_setg(errp, "multifd: received packet " - "with size %d and expected maximum size %d", - packet->pages_alloc, page_count) ; + "with size %d and expected a maximum size of %d", + packet->pages_alloc, pages_max * 100) ; return -1; } + /* + * We received a packet that is bigger than expected but inside + * reasonable limits (see previous comment). Just reallocate. + */ + if (packet->pages_alloc > p->pages->allocated) { + multifd_pages_clear(p->pages); + multifd_pages_init(packet->pages_alloc); + } p->pages->used = be32_to_cpu(packet->pages_used); if (p->pages->used > packet->pages_alloc) { -- cgit v1.2.3 From 4b0c72645c468827dbdf04594fcb274741fecbb1 Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Wed, 20 Feb 2019 12:45:57 +0100 Subject: multifd: Change default packet size We moved from 64KB to 512KB, as it makes less locking contention without any downside in testing. Signed-off-by: Juan Quintela Reviewed-by: Dr. David Alan Gilbert Signed-off-by: Juan Quintela --- migration/ram.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'migration') diff --git a/migration/ram.c b/migration/ram.c index 77c1878292..700c345ec5 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -584,7 +584,7 @@ exit: #define MULTIFD_FLAG_SYNC (1 << 0) /* This value needs to be a multiple of qemu_target_page_size() */ -#define MULTIFD_PACKET_SIZE (64 * 1024) +#define MULTIFD_PACKET_SIZE (512 * 1024) typedef struct { uint32_t magic; -- cgit v1.2.3 From 5fbd8b4bbb959cc5534bf488505ce85455fa4271 Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Wed, 13 Mar 2019 10:54:58 +0100 Subject: multifd: Add some padding Add some padding. MultifdInit_t is padded to 64 bytes. MultiFDPacket_t is padded to 320bytes (64 * 5). Signed-off-by: Juan Quintela --- migration/ram.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'migration') diff --git a/migration/ram.c b/migration/ram.c index 700c345ec5..d7f8fe45a8 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -591,6 +591,8 @@ typedef struct { uint32_t version; unsigned char uuid[16]; /* QemuUUID */ uint8_t id; + uint8_t unused1[7]; /* Reserved for future use */ + uint64_t unused2[4]; /* Reserved for future use */ } __attribute__((packed)) MultiFDInit_t; typedef struct { @@ -603,6 +605,7 @@ typedef struct { /* size of the next packet that contains pages */ uint32_t next_packet_size; uint64_t packet_num; + uint64_t unused[4]; /* Reserved for future use */ char ramblock[256]; uint64_t offset[]; } __attribute__((packed)) MultiFDPacket_t; -- cgit v1.2.3 From cbfd6c957a4437d4759ca660e621daa381bf2898 Mon Sep 17 00:00:00 2001 From: Juan Quintela Date: Wed, 6 Feb 2019 13:54:06 +0100 Subject: multifd: Drop x- We make it supported from now on. Reviewed-by: Dr. David Alan Gilbert Reviewed-by: Markus Armbruster Signed-off-by: Juan Quintela --- migration/migration.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) (limited to 'migration') diff --git a/migration/migration.c b/migration/migration.c index 52c8121628..b36cf9c9a0 100644 --- a/migration/migration.c +++ b/migration/migration.c @@ -765,8 +765,8 @@ MigrationParameters *qmp_query_migrate_parameters(Error **errp) params->x_checkpoint_delay = s->parameters.x_checkpoint_delay; params->has_block_incremental = true; params->block_incremental = s->parameters.block_incremental; - params->has_x_multifd_channels = true; - params->x_multifd_channels = s->parameters.x_multifd_channels; + params->has_multifd_channels = true; + params->multifd_channels = s->parameters.multifd_channels; params->has_xbzrle_cache_size = true; params->xbzrle_cache_size = s->parameters.xbzrle_cache_size; params->has_max_postcopy_bandwidth = true; @@ -1149,7 +1149,7 @@ static bool migrate_params_check(MigrationParameters *params, Error **errp) /* x_checkpoint_delay is now always positive */ - if (params->has_x_multifd_channels && (params->x_multifd_channels < 1)) { + if (params->has_multifd_channels && (params->multifd_channels < 1)) { error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "multifd_channels", "is invalid, it should be in the range of 1 to 255"); @@ -1263,8 +1263,8 @@ static void migrate_params_test_apply(MigrateSetParameters *params, if (params->has_block_incremental) { dest->block_incremental = params->block_incremental; } - if (params->has_x_multifd_channels) { - dest->x_multifd_channels = params->x_multifd_channels; + if (params->has_multifd_channels) { + dest->multifd_channels = params->multifd_channels; } if (params->has_xbzrle_cache_size) { dest->xbzrle_cache_size = params->xbzrle_cache_size; @@ -1353,8 +1353,8 @@ static void migrate_params_apply(MigrateSetParameters *params, Error **errp) if (params->has_block_incremental) { s->parameters.block_incremental = params->block_incremental; } - if (params->has_x_multifd_channels) { - s->parameters.x_multifd_channels = params->x_multifd_channels; + if (params->has_multifd_channels) { + s->parameters.multifd_channels = params->multifd_channels; } if (params->has_xbzrle_cache_size) { s->parameters.xbzrle_cache_size = params->xbzrle_cache_size; @@ -2113,7 +2113,7 @@ bool migrate_use_multifd(void) s = migrate_get_current(); - return s->enabled_capabilities[MIGRATION_CAPABILITY_X_MULTIFD]; + return s->enabled_capabilities[MIGRATION_CAPABILITY_MULTIFD]; } bool migrate_pause_before_switchover(void) @@ -2132,7 +2132,7 @@ int migrate_multifd_channels(void) s = migrate_get_current(); - return s->parameters.x_multifd_channels; + return s->parameters.multifd_channels; } int migrate_use_xbzrle(void) @@ -3374,8 +3374,8 @@ static Property migration_properties[] = { DEFINE_PROP_UINT32("x-checkpoint-delay", MigrationState, parameters.x_checkpoint_delay, DEFAULT_MIGRATE_X_CHECKPOINT_DELAY), - DEFINE_PROP_UINT8("x-multifd-channels", MigrationState, - parameters.x_multifd_channels, + DEFINE_PROP_UINT8("multifd-channels", MigrationState, + parameters.multifd_channels, DEFAULT_MIGRATE_MULTIFD_CHANNELS), DEFINE_PROP_SIZE("xbzrle-cache-size", MigrationState, parameters.xbzrle_cache_size, @@ -3411,7 +3411,7 @@ static Property migration_properties[] = { 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_X_MULTIFD), + DEFINE_PROP_MIG_CAP("x-multifd", MIGRATION_CAPABILITY_MULTIFD), DEFINE_PROP_END_OF_LIST(), }; @@ -3465,7 +3465,7 @@ static void migration_instance_init(Object *obj) params->has_downtime_limit = true; params->has_x_checkpoint_delay = true; params->has_block_incremental = true; - params->has_x_multifd_channels = true; + params->has_multifd_channels = true; params->has_xbzrle_cache_size = true; params->has_max_postcopy_bandwidth = true; params->has_max_cpu_throttle = true; -- cgit v1.2.3 From d2f1d29b95aa45d13262b39153ff501ed6b1ac95 Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Wed, 27 Feb 2019 14:53:24 +0000 Subject: migration: add support for a "tls-authz" migration parameter The QEMU instance that runs as the server for the migration data transport (ie the target QEMU) needs to be able to configure access control so it can prevent unauthorized clients initiating an incoming migration. This adds a new 'tls-authz' migration parameter that is used to provide the QOM ID of a QAuthZ subclass instance that provides the access control check. This is checked against the x509 certificate obtained during the TLS handshake. For example, when starting a QEMU for incoming migration, it is possible to give an example identity of the source QEMU that is intended to be connecting later: $QEMU \ -monitor stdio \ -incoming defer \ ...other args... (qemu) object_add tls-creds-x509,id=tls0,dir=/home/berrange/qemutls,\ endpoint=server,verify-peer=yes \ (qemu) object_add authz-simple,id=auth0,identity=CN=laptop.example.com,,\ O=Example Org,,L=London,,ST=London,,C=GB \ (qemu) migrate_incoming tcp:localhost:9000 Reviewed-by: Juan Quintela Signed-off-by: Daniel P. Berrange Signed-off-by: Juan Quintela --- migration/migration.c | 8 ++++++++ migration/tls.c | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) (limited to 'migration') diff --git a/migration/migration.c b/migration/migration.c index b36cf9c9a0..d5c218a22b 100644 --- a/migration/migration.c +++ b/migration/migration.c @@ -757,6 +757,8 @@ MigrationParameters *qmp_query_migrate_parameters(Error **errp) params->tls_creds = g_strdup(s->parameters.tls_creds); params->has_tls_hostname = true; params->tls_hostname = g_strdup(s->parameters.tls_hostname); + params->has_tls_authz = true; + params->tls_authz = g_strdup(s->parameters.tls_authz); params->has_max_bandwidth = true; params->max_bandwidth = s->parameters.max_bandwidth; params->has_downtime_limit = true; @@ -1331,6 +1333,12 @@ static void migrate_params_apply(MigrateSetParameters *params, Error **errp) s->parameters.tls_hostname = g_strdup(params->tls_hostname->u.s); } + if (params->has_tls_authz) { + g_free(s->parameters.tls_authz); + assert(params->tls_authz->type == QTYPE_QSTRING); + s->parameters.tls_authz = g_strdup(params->tls_authz->u.s); + } + if (params->has_max_bandwidth) { s->parameters.max_bandwidth = params->max_bandwidth; if (s->to_dst_file) { diff --git a/migration/tls.c b/migration/tls.c index 3b9e8c9263..5171afc6c4 100644 --- a/migration/tls.c +++ b/migration/tls.c @@ -94,7 +94,7 @@ void migration_tls_channel_process_incoming(MigrationState *s, tioc = qio_channel_tls_new_server( ioc, creds, - NULL, /* XXX pass ACL name */ + s->parameters.tls_authz, errp); if (!tioc) { return; -- cgit v1.2.3 From 281496bb8aaa36093625d459ac6f5cdcf5fa7c00 Mon Sep 17 00:00:00 2001 From: "Dr. David Alan Gilbert" Date: Fri, 8 Mar 2019 18:51:24 +0000 Subject: migration/rdma: Check qemu_rdma_init_one_block Actually it can't fail at the moment, but Coverity moans that it's the only place it's not checked, and it's an easy check. Reported-by: Coverity (CID 1399413) Signed-off-by: Dr. David Alan Gilbert Reviewed-by: Juan Quintela Signed-off-by: Juan Quintela --- migration/rdma.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'migration') diff --git a/migration/rdma.c b/migration/rdma.c index 63c118af09..c1bcece53b 100644 --- a/migration/rdma.c +++ b/migration/rdma.c @@ -641,10 +641,14 @@ static int qemu_rdma_init_one_block(RAMBlock *rb, void *opaque) static int qemu_rdma_init_ram_blocks(RDMAContext *rdma) { RDMALocalBlocks *local = &rdma->local_ram_blocks; + int ret; assert(rdma->blockmap == NULL); memset(local, 0, sizeof *local); - foreach_not_ignored_block(qemu_rdma_init_one_block, rdma); + ret = foreach_not_ignored_block(qemu_rdma_init_one_block, rdma); + if (ret) { + return ret; + } trace_qemu_rdma_init_ram_blocks(local->nb_blocks); rdma->dest_blocks = g_new0(RDMADestBlock, rdma->local_ram_blocks.nb_blocks); -- cgit v1.2.3 From 1fe6ab267fa6c7f75466063763370ef877465a87 Mon Sep 17 00:00:00 2001 From: Zhang Chen Date: Fri, 22 Mar 2019 18:13:30 +0800 Subject: Migration/colo.c: Fix COLO failover status error When finished COLO failover, the status is FAILOVER_STATUS_COMPLETED. The origin codes misunderstand the FAILOVER_STATUS_REQUIRE. Signed-off-by: Zhang Chen Reviewed-by: Dr. David Alan Gilbert Reviewed-by: Juan Quintela Signed-off-by: Juan Quintela --- migration/colo.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'migration') diff --git a/migration/colo.c b/migration/colo.c index 5ba610dc01..89325952c7 100644 --- a/migration/colo.c +++ b/migration/colo.c @@ -121,6 +121,7 @@ static void secondary_vm_do_failover(void) } /* Notify COLO incoming thread that failover work is finished */ qemu_sem_post(&mis->colo_incoming_sem); + /* For Secondary VM, jump to incoming co */ if (mis->migration_incoming_co) { qemu_coroutine_enter(mis->migration_incoming_co); @@ -262,7 +263,7 @@ COLOStatus *qmp_query_colo_status(Error **errp) case FAILOVER_STATUS_NONE: s->reason = COLO_EXIT_REASON_NONE; break; - case FAILOVER_STATUS_REQUIRE: + case FAILOVER_STATUS_COMPLETED: s->reason = COLO_EXIT_REASON_REQUEST; break; default: @@ -582,7 +583,7 @@ out: qapi_event_send_colo_exit(COLO_MODE_PRIMARY, COLO_EXIT_REASON_ERROR); break; - case FAILOVER_STATUS_REQUIRE: + case FAILOVER_STATUS_COMPLETED: qapi_event_send_colo_exit(COLO_MODE_PRIMARY, COLO_EXIT_REASON_REQUEST); break; @@ -854,7 +855,7 @@ out: qapi_event_send_colo_exit(COLO_MODE_SECONDARY, COLO_EXIT_REASON_ERROR); break; - case FAILOVER_STATUS_REQUIRE: + case FAILOVER_STATUS_COMPLETED: qapi_event_send_colo_exit(COLO_MODE_SECONDARY, COLO_EXIT_REASON_REQUEST); break; -- cgit v1.2.3 From 3a43ac4757b70dfc2964c12ca1ac82f61128cc04 Mon Sep 17 00:00:00 2001 From: Zhang Chen Date: Fri, 22 Mar 2019 18:13:31 +0800 Subject: Migration/colo.c: Add new COLOExitReason to handle all failover state In this patch we add the processing state for COLOExitReason, because we have to identify COLO in the failover processing state or failover error state. In the way, we can handle all the failover state. We have improved the description of the COLOExitReason by the way. Signed-off-by: Zhang Chen Reviewed-by: Dr. David Alan Gilbert Reviewed-by: Juan Quintela Signed-off-by: Juan Quintela --- migration/colo.c | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) (limited to 'migration') diff --git a/migration/colo.c b/migration/colo.c index 89325952c7..dbe2b88807 100644 --- a/migration/colo.c +++ b/migration/colo.c @@ -267,7 +267,11 @@ COLOStatus *qmp_query_colo_status(Error **errp) s->reason = COLO_EXIT_REASON_REQUEST; break; default: - s->reason = COLO_EXIT_REASON_ERROR; + if (migration_in_colo_state()) { + s->reason = COLO_EXIT_REASON_PROCESSING; + } else { + s->reason = COLO_EXIT_REASON_ERROR; + } } return s; @@ -579,16 +583,13 @@ out: * or the user triggered failover. */ switch (failover_get_state()) { - case FAILOVER_STATUS_NONE: - qapi_event_send_colo_exit(COLO_MODE_PRIMARY, - COLO_EXIT_REASON_ERROR); - break; case FAILOVER_STATUS_COMPLETED: qapi_event_send_colo_exit(COLO_MODE_PRIMARY, COLO_EXIT_REASON_REQUEST); break; default: - abort(); + qapi_event_send_colo_exit(COLO_MODE_PRIMARY, + COLO_EXIT_REASON_ERROR); } /* Hope this not to be too long to wait here */ @@ -850,17 +851,18 @@ out: error_report_err(local_err); } + /* + * There are only two reasons we can get here, some error happened + * or the user triggered failover. + */ switch (failover_get_state()) { - case FAILOVER_STATUS_NONE: - qapi_event_send_colo_exit(COLO_MODE_SECONDARY, - COLO_EXIT_REASON_ERROR); - break; case FAILOVER_STATUS_COMPLETED: qapi_event_send_colo_exit(COLO_MODE_SECONDARY, COLO_EXIT_REASON_REQUEST); break; default: - abort(); + qapi_event_send_colo_exit(COLO_MODE_SECONDARY, + COLO_EXIT_REASON_ERROR); } if (fb) { -- cgit v1.2.3 From 82cd368ccd0a962f1f141e0e529abc54d5ab504e Mon Sep 17 00:00:00 2001 From: Zhang Chen Date: Fri, 22 Mar 2019 18:13:32 +0800 Subject: Migration/colo.c: Add the necessary checks for colo_do_failover Signed-off-by: Zhang Chen Reviewed-by: Dr. David Alan Gilbert Reviewed-by: Juan Quintela Signed-off-by: Juan Quintela --- migration/colo.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'migration') diff --git a/migration/colo.c b/migration/colo.c index dbe2b88807..d1ae2e6d11 100644 --- a/migration/colo.c +++ b/migration/colo.c @@ -197,10 +197,16 @@ void colo_do_failover(MigrationState *s) vm_stop_force_state(RUN_STATE_COLO); } - if (get_colo_mode() == COLO_MODE_PRIMARY) { + switch (get_colo_mode()) { + case COLO_MODE_PRIMARY: primary_vm_do_failover(); - } else { + break; + case COLO_MODE_SECONDARY: secondary_vm_do_failover(); + break; + default: + error_report("colo_do_failover failed because the colo mode" + " could not be obtained"); } } -- cgit v1.2.3 From 5ed0deca41b201a66d858d7296fe6b780d757404 Mon Sep 17 00:00:00 2001 From: Zhang Chen Date: Fri, 22 Mar 2019 18:13:33 +0800 Subject: Migration/colo.c: Make user obtain the last COLO mode info after failover Add the last_colo_mode to save the status after failover. This patch can solve the issue that user want to get last colo mode use query_colo_status after failover. Signed-off-by: Zhang Chen Reviewed-by: Juan Quintela Signed-off-by: Juan Quintela --- migration/colo.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'migration') diff --git a/migration/colo.c b/migration/colo.c index d1ae2e6d11..238a6d62c7 100644 --- a/migration/colo.c +++ b/migration/colo.c @@ -38,6 +38,9 @@ static bool vmstate_loading; static Notifier packets_compare_notifier; +/* User need to know colo mode after COLO failover */ +static COLOMode last_colo_mode; + #define COLO_BUFFER_BASE_SIZE (4 * 1024 * 1024) bool migration_in_colo_state(void) @@ -264,6 +267,7 @@ COLOStatus *qmp_query_colo_status(Error **errp) COLOStatus *s = g_new0(COLOStatus, 1); s->mode = get_colo_mode(); + s->last_mode = last_colo_mode; switch (failover_get_state()) { case FAILOVER_STATUS_NONE: @@ -515,6 +519,12 @@ static void colo_process_checkpoint(MigrationState *s) Error *local_err = NULL; int ret; + last_colo_mode = get_colo_mode(); + if (last_colo_mode != COLO_MODE_PRIMARY) { + error_report("COLO mode must be COLO_MODE_PRIMARY"); + return; + } + failover_init_state(); s->rp_state.from_dst_file = qemu_file_get_return_path(s->to_dst_file); @@ -688,6 +698,12 @@ void *colo_process_incoming_thread(void *opaque) migrate_set_state(&mis->state, MIGRATION_STATUS_ACTIVE, MIGRATION_STATUS_COLO); + last_colo_mode = get_colo_mode(); + if (last_colo_mode != COLO_MODE_SECONDARY) { + error_report("COLO mode must be COLO_MODE_SECONDARY"); + return NULL; + } + failover_init_state(); mis->to_src_file = qemu_file_get_return_path(mis->from_src_file); -- cgit v1.2.3 From c38c1c142e64901b09f5ac000695071ed8c0e3a5 Mon Sep 17 00:00:00 2001 From: "Dr. David Alan Gilbert" Date: Fri, 8 Mar 2019 10:12:10 +0000 Subject: migration/postcopy: Update the bandwidth during postcopy The recently added max-postcopy-bandwidth parameter is only read at the transition from precopy->postcopy where as the older max-bandwidth parameter updates the migration bandwidth when changed even if the migration is already running. Fix this discrepency so that: a) You can change the bandwidth during postcopy by setting max-postcopy-bandwidth b) Changing max-bandwidth during postcopy has no effect (it currently changes the postcopy bandwidth which isn't expected). Fixes: 7e555c6c bz: https://bugzilla.redhat.com/show_bug.cgi?id=1686321 Signed-off-by: Dr. David Alan Gilbert Reviewed-by: Juan Quintela Signed-off-by: Juan Quintela --- migration/migration.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'migration') diff --git a/migration/migration.c b/migration/migration.c index d5c218a22b..69f75124c9 100644 --- a/migration/migration.c +++ b/migration/migration.c @@ -1341,7 +1341,7 @@ static void migrate_params_apply(MigrateSetParameters *params, Error **errp) if (params->has_max_bandwidth) { s->parameters.max_bandwidth = params->max_bandwidth; - if (s->to_dst_file) { + if (s->to_dst_file && !migration_in_postcopy()) { qemu_file_set_rate_limit(s->to_dst_file, s->parameters.max_bandwidth / XFER_LIMIT_RATIO); } @@ -1370,6 +1370,10 @@ static void migrate_params_apply(MigrateSetParameters *params, Error **errp) } if (params->has_max_postcopy_bandwidth) { s->parameters.max_postcopy_bandwidth = params->max_postcopy_bandwidth; + if (s->to_dst_file && migration_in_postcopy()) { + qemu_file_set_rate_limit(s->to_dst_file, + s->parameters.max_postcopy_bandwidth / XFER_LIMIT_RATIO); + } } if (params->has_max_cpu_throttle) { s->parameters.max_cpu_throttle = params->max_cpu_throttle; -- cgit v1.2.3