diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2019-05-16 10:24:08 +0100 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2019-05-16 10:24:08 +0100 |
commit | c1497fba36465d0259d4d04f2bf09ea59ed42680 (patch) | |
tree | 80b616d06242e232762600f80b2d7745ea5015e2 | |
parent | e329ad2ab72c43b56df88b34954c2c7d839bb373 (diff) | |
parent | 9d3250d5ba8c4c5389530b861686e22e77fddcc7 (diff) |
Merge remote-tracking branch 'remotes/dgilbert/tags/pull-migration-20190514b' into staging
Migration pull 2019-05-14
Small fixes/cleanups
One HMP/monitor fix
# gpg: Signature made Tue 14 May 2019 19:03:53 BST
# gpg: using RSA key 45F5C71B4A0CB7FB977A9FA90516331EBC5BFDE7
# gpg: Good signature from "Dr. David Alan Gilbert (RH2) <dgilbert@redhat.com>" [full]
# Primary key fingerprint: 45F5 C71B 4A0C B7FB 977A 9FA9 0516 331E BC5B FDE7
* remotes/dgilbert/tags/pull-migration-20190514b:
monitor: Call mon_get_cpu() only once at hmp_gva2gpa()
migration/ram.c: fix typos in comments
migration: Fix use-after-free during process exit
migration/savevm: wrap into qemu_loadvm_state_header()
migration/savevm: load_header before load_setup
migration/savevm: remove duplicate check of migration_is_blocked
migration: update comments of migration bitmap
migration/ram.c: start of migration_bitmap_sync_range is always 0
qemu-option.hx: Update missed parameter for colo-compare
migration/colo.h: Remove obsolete codes
migration/colo.c: Remove redundant input parameter
migration: savevm: fix error code with migration blockers
vmstate: check subsection_found is enough
migration: remove not used field xfer_limit
migration: not necessary to check ops again
migration: comment VMSTATE_UNUSED*() properly
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
-rw-r--r-- | include/migration/colo.h | 4 | ||||
-rw-r--r-- | include/migration/vmstate.h | 14 | ||||
-rw-r--r-- | migration/colo-failover.c | 2 | ||||
-rw-r--r-- | migration/colo.c | 2 | ||||
-rw-r--r-- | migration/migration.c | 26 | ||||
-rw-r--r-- | migration/migration.h | 1 | ||||
-rw-r--r-- | migration/ram.c | 22 | ||||
-rw-r--r-- | migration/savevm.c | 89 | ||||
-rw-r--r-- | migration/vmstate.c | 8 | ||||
-rw-r--r-- | monitor.c | 3 | ||||
-rw-r--r-- | qemu-options.hx | 9 |
11 files changed, 105 insertions, 75 deletions
diff --git a/include/migration/colo.h b/include/migration/colo.h index 99ce17aca7..f6fbe23ec9 100644 --- a/include/migration/colo.h +++ b/include/migration/colo.h @@ -22,8 +22,6 @@ enum colo_event { COLO_EVENT_FAILOVER, }; -void colo_info_init(void); - void migrate_start_colo_process(MigrationState *s); bool migration_in_colo_state(void); @@ -37,7 +35,7 @@ bool migration_incoming_in_colo_state(void); COLOMode get_colo_mode(void); /* failover */ -void colo_do_failover(MigrationState *s); +void colo_do_failover(void); void colo_checkpoint_notify(void *opaque); #endif diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h index a668ec75b8..9224370ed5 100644 --- a/include/migration/vmstate.h +++ b/include/migration/vmstate.h @@ -1035,6 +1035,20 @@ extern const VMStateInfo vmstate_info_qtailq; #define VMSTATE_BUFFER_UNSAFE(_field, _state, _version, _size) \ VMSTATE_BUFFER_UNSAFE_INFO(_field, _state, _version, vmstate_info_buffer, _size) +/* + * These VMSTATE_UNUSED*() macros can be used to fill in the holes + * when some of the vmstate fields are obsolete to be compatible with + * migrations between new/old binaries. + * + * CAUTION: when using any of the VMSTATE_UNUSED*() macros please be + * sure that the size passed in is the size that was actually *sent* + * rather than the size of the *structure*. One example is the + * boolean type - the size of the structure can vary depending on the + * definition of boolean, however the size we actually sent is always + * 1 byte (please refer to implementation of VMSTATE_BOOL_V and + * vmstate_info_bool). So here we should always pass in size==1 + * rather than size==sizeof(bool). + */ #define VMSTATE_UNUSED_V(_v, _size) \ VMSTATE_UNUSED_BUFFER(NULL, _v, _size) diff --git a/migration/colo-failover.c b/migration/colo-failover.c index 4854a96c92..e9ca0b4774 100644 --- a/migration/colo-failover.c +++ b/migration/colo-failover.c @@ -39,7 +39,7 @@ static void colo_failover_bh(void *opaque) return; } - colo_do_failover(NULL); + colo_do_failover(); } void failover_request_active(Error **errp) diff --git a/migration/colo.c b/migration/colo.c index 238a6d62c7..8c1644091f 100644 --- a/migration/colo.c +++ b/migration/colo.c @@ -193,7 +193,7 @@ COLOMode get_colo_mode(void) } } -void colo_do_failover(MigrationState *s) +void colo_do_failover(void) { /* Make sure VM stopped while failover happened. */ if (!colo_runstate_is_stopped()) { diff --git a/migration/migration.c b/migration/migration.c index 609e0df5d0..d0a0f68f11 100644 --- a/migration/migration.c +++ b/migration/migration.c @@ -1495,10 +1495,8 @@ static void block_cleanup_parameters(MigrationState *s) } } -static void migrate_fd_cleanup(void *opaque) +static void migrate_fd_cleanup(MigrationState *s) { - MigrationState *s = opaque; - qemu_bh_delete(s->cleanup_bh); s->cleanup_bh = NULL; @@ -1543,6 +1541,23 @@ static void migrate_fd_cleanup(void *opaque) block_cleanup_parameters(s); } +static void migrate_fd_cleanup_schedule(MigrationState *s) +{ + /* + * Ref the state for bh, because it may be called when + * there're already no other refs + */ + object_ref(OBJECT(s)); + qemu_bh_schedule(s->cleanup_bh); +} + +static void migrate_fd_cleanup_bh(void *opaque) +{ + MigrationState *s = opaque; + migrate_fd_cleanup(s); + object_unref(OBJECT(s)); +} + void migrate_set_error(MigrationState *s, const Error *error) { qemu_mutex_lock(&s->error_mutex); @@ -1681,7 +1696,6 @@ void migrate_init(MigrationState *s) * locks. */ s->bytes_xfer = 0; - s->xfer_limit = 0; s->cleanup_bh = 0; s->to_dst_file = NULL; s->state = MIGRATION_STATUS_NONE; @@ -3144,7 +3158,7 @@ static void migration_iteration_finish(MigrationState *s) error_report("%s: Unknown ending state %d", __func__, s->state); break; } - qemu_bh_schedule(s->cleanup_bh); + migrate_fd_cleanup_schedule(s); qemu_mutex_unlock_iothread(); } @@ -3279,7 +3293,7 @@ void migrate_fd_connect(MigrationState *s, Error *error_in) bool resume = s->state == MIGRATION_STATUS_POSTCOPY_PAUSED; s->expected_downtime = s->parameters.downtime_limit; - s->cleanup_bh = qemu_bh_new(migrate_fd_cleanup, s); + s->cleanup_bh = qemu_bh_new(migrate_fd_cleanup_bh, s); if (error_in) { migrate_fd_error(s, error_in); migrate_fd_cleanup(s); diff --git a/migration/migration.h b/migration/migration.h index 438f17edad..780a096857 100644 --- a/migration/migration.h +++ b/migration/migration.h @@ -117,7 +117,6 @@ struct MigrationState /*< public >*/ size_t bytes_xfer; - size_t xfer_limit; QemuThread thread; QEMUBH *cleanup_bh; QEMUFile *to_dst_file; diff --git a/migration/ram.c b/migration/ram.c index 1ca9ba77b6..4c60869226 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -917,7 +917,7 @@ struct { * - to make easier to know what to free at the end of migration * * This way we always know who is the owner of each "pages" struct, - * and we don't need any loocking. It belongs to the migration thread + * and we don't need any locking. It belongs to the migration thread * or to the channel thread. Switching is safe because the migration * thread is using the channel mutex when changing it, and the channel * have to had finish with its own, otherwise pending_job can't be @@ -1630,9 +1630,7 @@ static int save_xbzrle_page(RAMState *rs, uint8_t **current_data, /** * migration_bitmap_find_dirty: find the next dirty page from start * - * Called with rcu_read_lock() to protect migration_bitmap - * - * Returns the byte offset within memory region of the start of a dirty page + * Returns the page offset within memory region of the start of a dirty page * * @rs: current RAM state * @rb: RAMBlock where to search for dirty pages @@ -1681,10 +1679,10 @@ static inline bool migration_bitmap_clear_dirty(RAMState *rs, } static void migration_bitmap_sync_range(RAMState *rs, RAMBlock *rb, - ram_addr_t start, ram_addr_t length) + ram_addr_t length) { rs->migration_dirty_pages += - cpu_physical_memory_sync_dirty_bitmap(rb, start, length, + cpu_physical_memory_sync_dirty_bitmap(rb, 0, length, &rs->num_dirty_pages_period); } @@ -1773,7 +1771,7 @@ static void migration_bitmap_sync(RAMState *rs) qemu_mutex_lock(&rs->bitmap_mutex); rcu_read_lock(); RAMBLOCK_FOREACH_NOT_IGNORED(block) { - migration_bitmap_sync_range(rs, block, 0, block->used_length); + migration_bitmap_sync_range(rs, block, block->used_length); } ram_counters.remaining = ram_bytes_remaining(); rcu_read_unlock(); @@ -2146,7 +2144,7 @@ retry: * find_dirty_block: find the next dirty page and update any state * associated with the search process. * - * Returns if a page is found + * Returns true if a page is found * * @rs: current RAM state * @pss: data about the state of the current dirty page scan @@ -2242,7 +2240,7 @@ static RAMBlock *unqueue_page(RAMState *rs, ram_addr_t *offset) * * Skips pages that are already sent (!dirty) * - * Returns if a queued page is found + * Returns true if a queued page is found * * @rs: current RAM state * @pss: data about the state of the current dirty page scan @@ -2681,7 +2679,7 @@ static void ram_save_cleanup(void *opaque) RAMBlock *block; /* caller have hold iothread lock or is in a bh, so there is - * no writing race against this migration_bitmap + * no writing race against the migration bitmap */ memory_global_dirty_log_stop(); @@ -3449,7 +3447,7 @@ static int ram_save_iterate(QEMUFile *f, void *opaque) /* we want to check in the 1st loop, just in case it was the 1st time and we had to sync the dirty bitmap. - qemu_get_clock_ns() is a bit expensive, so we only check each some + qemu_clock_get_ns() is a bit expensive, so we only check each some iterations */ if ((i & 63) == 0) { @@ -4196,7 +4194,7 @@ static void colo_flush_ram_cache(void) memory_global_dirty_log_sync(); rcu_read_lock(); RAMBLOCK_FOREACH_NOT_IGNORED(block) { - migration_bitmap_sync_range(ram_state, block, 0, block->used_length); + migration_bitmap_sync_range(ram_state, block, block->used_length); } rcu_read_unlock(); diff --git a/migration/savevm.c b/migration/savevm.c index 34bcad3807..c0e557b4c2 100644 --- a/migration/savevm.c +++ b/migration/savevm.c @@ -1157,15 +1157,13 @@ int qemu_savevm_state_iterate(QEMUFile *f, bool postcopy) if (!se->ops || !se->ops->save_live_iterate) { continue; } - if (se->ops && se->ops->is_active) { - if (!se->ops->is_active(se->opaque)) { - continue; - } + if (se->ops->is_active && + !se->ops->is_active(se->opaque)) { + continue; } - if (se->ops && se->ops->is_active_iterate) { - if (!se->ops->is_active_iterate(se->opaque)) { - continue; - } + if (se->ops->is_active_iterate && + !se->ops->is_active_iterate(se->opaque)) { + continue; } /* * In the postcopy phase, any device that doesn't know how to @@ -1420,10 +1418,6 @@ static int qemu_savevm_state(QEMUFile *f, Error **errp) return -EINVAL; } - if (migration_is_blocked(errp)) { - return -EINVAL; - } - if (migrate_use_block()) { error_setg(errp, "Block migration and snapshots are incompatible"); return -EINVAL; @@ -2268,6 +2262,43 @@ qemu_loadvm_section_part_end(QEMUFile *f, MigrationIncomingState *mis) return 0; } +static int qemu_loadvm_state_header(QEMUFile *f) +{ + unsigned int v; + int ret; + + v = qemu_get_be32(f); + if (v != QEMU_VM_FILE_MAGIC) { + error_report("Not a migration stream"); + return -EINVAL; + } + + v = qemu_get_be32(f); + if (v == QEMU_VM_FILE_VERSION_COMPAT) { + error_report("SaveVM v2 format is obsolete and don't work anymore"); + return -ENOTSUP; + } + if (v != QEMU_VM_FILE_VERSION) { + error_report("Unsupported migration stream version"); + return -ENOTSUP; + } + + if (migrate_get_current()->send_configuration) { + if (qemu_get_byte(f) != QEMU_VM_CONFIGURATION) { + error_report("Configuration section missing"); + qemu_loadvm_state_cleanup(); + return -EINVAL; + } + ret = vmstate_load_state(f, &vmstate_configuration, &savevm_state, 0); + + if (ret) { + qemu_loadvm_state_cleanup(); + return ret; + } + } + return 0; +} + static int qemu_loadvm_state_setup(QEMUFile *f) { SaveStateEntry *se; @@ -2416,7 +2447,6 @@ int qemu_loadvm_state(QEMUFile *f) { MigrationIncomingState *mis = migration_incoming_get_current(); Error *local_err = NULL; - unsigned int v; int ret; if (qemu_savevm_state_blocked(&local_err)) { @@ -2424,40 +2454,15 @@ int qemu_loadvm_state(QEMUFile *f) return -EINVAL; } - v = qemu_get_be32(f); - if (v != QEMU_VM_FILE_MAGIC) { - error_report("Not a migration stream"); - return -EINVAL; - } - - v = qemu_get_be32(f); - if (v == QEMU_VM_FILE_VERSION_COMPAT) { - error_report("SaveVM v2 format is obsolete and don't work anymore"); - return -ENOTSUP; - } - if (v != QEMU_VM_FILE_VERSION) { - error_report("Unsupported migration stream version"); - return -ENOTSUP; + ret = qemu_loadvm_state_header(f); + if (ret) { + return ret; } if (qemu_loadvm_state_setup(f) != 0) { return -EINVAL; } - if (migrate_get_current()->send_configuration) { - if (qemu_get_byte(f) != QEMU_VM_CONFIGURATION) { - error_report("Configuration section missing"); - qemu_loadvm_state_cleanup(); - return -EINVAL; - } - ret = vmstate_load_state(f, &vmstate_configuration, &savevm_state, 0); - - if (ret) { - qemu_loadvm_state_cleanup(); - return ret; - } - } - cpu_synchronize_all_pre_loadvm(); ret = qemu_loadvm_state_main(f, mis); @@ -2544,7 +2549,7 @@ int save_snapshot(const char *name, Error **errp) AioContext *aio_context; if (migration_is_blocked(errp)) { - return false; + return ret; } if (!replay_can_snapshot()) { diff --git a/migration/vmstate.c b/migration/vmstate.c index e2bbb7b5f7..1305d1a528 100644 --- a/migration/vmstate.c +++ b/migration/vmstate.c @@ -496,7 +496,7 @@ static int vmstate_subsection_save(QEMUFile *f, const VMStateDescription *vmsd, void *opaque, QJSON *vmdesc) { const VMStateDescription **sub = vmsd->subsections; - bool subsection_found = false; + bool vmdesc_has_subsections = false; int ret = 0; trace_vmstate_subsection_save_top(vmsd->name); @@ -508,9 +508,9 @@ static int vmstate_subsection_save(QEMUFile *f, const VMStateDescription *vmsd, trace_vmstate_subsection_save_loop(vmsd->name, vmsdsub->name); if (vmdesc) { /* Only create subsection array when we have any */ - if (!subsection_found) { + if (!vmdesc_has_subsections) { json_start_array(vmdesc, "subsections"); - subsection_found = true; + vmdesc_has_subsections = true; } json_start_object(vmdesc, NULL); @@ -533,7 +533,7 @@ static int vmstate_subsection_save(QEMUFile *f, const VMStateDescription *vmsd, sub++; } - if (vmdesc && subsection_found) { + if (vmdesc_has_subsections) { json_end_array(vmdesc); } @@ -1685,8 +1685,7 @@ static void hmp_gva2gpa(Monitor *mon, const QDict *qdict) return; } - gpa = cpu_get_phys_page_attrs_debug(mon_get_cpu(), - addr & TARGET_PAGE_MASK, &attrs); + gpa = cpu_get_phys_page_attrs_debug(cs, addr & TARGET_PAGE_MASK, &attrs); if (gpa == -1) { monitor_printf(mon, "Unmapped\n"); } else { diff --git a/qemu-options.hx b/qemu-options.hx index 51802cbb26..3faa935929 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -4425,13 +4425,15 @@ Dump the network traffic on netdev @var{dev} to the file specified by The file format is libpcap, so it can be analyzed with tools such as tcpdump or Wireshark. -@item -object colo-compare,id=@var{id},primary_in=@var{chardevid},secondary_in=@var{chardevid},outdev=@var{chardevid}[,vnet_hdr_support] +@item -object colo-compare,id=@var{id},primary_in=@var{chardevid},secondary_in=@var{chardevid},outdev=@var{chardevid},iothread=@var{id}[,vnet_hdr_support] Colo-compare gets packet from primary_in@var{chardevid} and secondary_in@var{chardevid}, than compare primary packet with secondary packet. If the packets are same, we will output primary packet to outdev@var{chardevid}, else we will notify colo-frame do checkpoint and send primary packet to outdev@var{chardevid}. -if it has the vnet_hdr_support flag, colo compare will send/recv packet with vnet_hdr_len. +In order to improve efficiency, we need to put the task of comparison +in another thread. If it has the vnet_hdr_support flag, colo compare +will send/recv packet with vnet_hdr_len. we must use it with the help of filter-mirror and filter-redirector. @@ -4446,10 +4448,11 @@ primary: -chardev socket,id=compare0-0,host=3.3.3.3,port=9001 -chardev socket,id=compare_out,host=3.3.3.3,port=9005,server,nowait -chardev socket,id=compare_out0,host=3.3.3.3,port=9005 +-object iothread,id=iothread1 -object filter-mirror,id=m0,netdev=hn0,queue=tx,outdev=mirror0 -object filter-redirector,netdev=hn0,id=redire0,queue=rx,indev=compare_out -object filter-redirector,netdev=hn0,id=redire1,queue=rx,outdev=compare0 --object colo-compare,id=comp0,primary_in=compare0-0,secondary_in=compare1,outdev=compare_out0 +-object colo-compare,id=comp0,primary_in=compare0-0,secondary_in=compare1,outdev=compare_out0,iothread=iothread1 secondary: -netdev tap,id=hn0,vhost=off,script=/etc/qemu-ifup,down script=/etc/qemu-ifdown |