diff options
-rw-r--r-- | hw/net/vmxnet3.c | 52 | ||||
-rw-r--r-- | include/migration/qemu-file-types.h | 4 | ||||
-rw-r--r-- | migration/migration.c | 79 | ||||
-rw-r--r-- | migration/migration.h | 1 | ||||
-rw-r--r-- | migration/postcopy-ram.c | 70 | ||||
-rw-r--r-- | migration/postcopy-ram.h | 13 | ||||
-rw-r--r-- | migration/qemu-file-channel.c | 30 | ||||
-rw-r--r-- | migration/qemu-file.c | 68 | ||||
-rw-r--r-- | migration/qemu-file.h | 20 | ||||
-rw-r--r-- | migration/ram.c | 217 | ||||
-rw-r--r-- | migration/rdma.c | 6 | ||||
-rw-r--r-- | migration/savevm.c | 96 | ||||
-rw-r--r-- | migration/trace-events | 6 | ||||
-rw-r--r-- | monitor/hmp-cmds.c | 14 |
14 files changed, 348 insertions, 328 deletions
diff --git a/hw/net/vmxnet3.c b/hw/net/vmxnet3.c index 10d01d0058..8b17548b02 100644 --- a/hw/net/vmxnet3.c +++ b/hw/net/vmxnet3.c @@ -2141,21 +2141,6 @@ vmxnet3_cleanup_msi(VMXNET3State *s) msi_uninit(d); } -static void -vmxnet3_msix_save(QEMUFile *f, void *opaque) -{ - PCIDevice *d = PCI_DEVICE(opaque); - msix_save(d, f); -} - -static int -vmxnet3_msix_load(QEMUFile *f, void *opaque, int version_id) -{ - PCIDevice *d = PCI_DEVICE(opaque); - msix_load(d, f); - return 0; -} - static const MemoryRegionOps b0_ops = { .read = vmxnet3_io_bar0_read, .write = vmxnet3_io_bar0_write, @@ -2176,11 +2161,6 @@ static const MemoryRegionOps b1_ops = { }, }; -static SaveVMHandlers savevm_vmxnet3_msix = { - .save_state = vmxnet3_msix_save, - .load_state = vmxnet3_msix_load, -}; - static uint64_t vmxnet3_device_serial_num(VMXNET3State *s) { uint64_t dsn_payload; @@ -2203,7 +2183,6 @@ static uint64_t vmxnet3_device_serial_num(VMXNET3State *s) static void vmxnet3_pci_realize(PCIDevice *pci_dev, Error **errp) { - DeviceState *dev = DEVICE(pci_dev); VMXNET3State *s = VMXNET3(pci_dev); int ret; @@ -2249,8 +2228,6 @@ static void vmxnet3_pci_realize(PCIDevice *pci_dev, Error **errp) pcie_dev_ser_num_init(pci_dev, VMXNET3_DSN_OFFSET, vmxnet3_device_serial_num(s)); } - - register_savevm_live(dev, "vmxnet3-msix", -1, 1, &savevm_vmxnet3_msix, s); } static void vmxnet3_instance_init(Object *obj) @@ -2440,29 +2417,6 @@ static const VMStateDescription vmstate_vmxnet3_int_state = { } }; -static bool vmxnet3_vmstate_need_pcie_device(void *opaque) -{ - VMXNET3State *s = VMXNET3(opaque); - - return !(s->compat_flags & VMXNET3_COMPAT_FLAG_DISABLE_PCIE); -} - -static bool vmxnet3_vmstate_test_pci_device(void *opaque, int version_id) -{ - return !vmxnet3_vmstate_need_pcie_device(opaque); -} - -static const VMStateDescription vmstate_vmxnet3_pcie_device = { - .name = "vmxnet3/pcie", - .version_id = 1, - .minimum_version_id = 1, - .needed = vmxnet3_vmstate_need_pcie_device, - .fields = (VMStateField[]) { - VMSTATE_PCI_DEVICE(parent_obj, VMXNET3State), - VMSTATE_END_OF_LIST() - } -}; - static const VMStateDescription vmstate_vmxnet3 = { .name = "vmxnet3", .version_id = 1, @@ -2470,9 +2424,8 @@ static const VMStateDescription vmstate_vmxnet3 = { .pre_save = vmxnet3_pre_save, .post_load = vmxnet3_post_load, .fields = (VMStateField[]) { - VMSTATE_STRUCT_TEST(parent_obj, VMXNET3State, - vmxnet3_vmstate_test_pci_device, 0, - vmstate_pci_device, PCIDevice), + VMSTATE_PCI_DEVICE(parent_obj, VMXNET3State), + VMSTATE_MSIX(parent_obj, VMXNET3State), VMSTATE_BOOL(rx_packets_compound, VMXNET3State), VMSTATE_BOOL(rx_vlan_stripping, VMXNET3State), VMSTATE_BOOL(lro_supported, VMXNET3State), @@ -2508,7 +2461,6 @@ static const VMStateDescription vmstate_vmxnet3 = { }, .subsections = (const VMStateDescription*[]) { &vmxstate_vmxnet3_mcast_list, - &vmstate_vmxnet3_pcie_device, NULL } }; diff --git a/include/migration/qemu-file-types.h b/include/migration/qemu-file-types.h index c0a1988155..2867e3da84 100644 --- a/include/migration/qemu-file-types.h +++ b/include/migration/qemu-file-types.h @@ -161,6 +161,10 @@ static inline void qemu_get_sbe64s(QEMUFile *f, int64_t *pv) qemu_get_be64s(f, (uint64_t *)pv); } +size_t qemu_get_counted_string(QEMUFile *f, char buf[256]); + +void qemu_put_counted_string(QEMUFile *f, const char *name); + int qemu_file_rate_limit(QEMUFile *f); #endif diff --git a/migration/migration.c b/migration/migration.c index 8a607fe1e2..c49e9dc035 100644 --- a/migration/migration.c +++ b/migration/migration.c @@ -823,6 +823,25 @@ bool migration_is_setup_or_active(int state) } } +static void populate_time_info(MigrationInfo *info, MigrationState *s) +{ + info->has_status = true; + info->has_setup_time = true; + info->setup_time = s->setup_time; + if (s->state == MIGRATION_STATUS_COMPLETED) { + info->has_total_time = true; + info->total_time = s->total_time; + info->has_downtime = true; + info->downtime = s->downtime; + } else { + info->has_total_time = true; + info->total_time = qemu_clock_get_ms(QEMU_CLOCK_REALTIME) - + s->start_time; + info->has_expected_downtime = true; + info->expected_downtime = s->expected_downtime; + } +} + static void populate_ram_info(MigrationInfo *info, MigrationState *s) { info->has_ram = true; @@ -908,16 +927,8 @@ static void fill_source_migration_info(MigrationInfo *info) case MIGRATION_STATUS_DEVICE: case MIGRATION_STATUS_POSTCOPY_PAUSED: case MIGRATION_STATUS_POSTCOPY_RECOVER: - /* TODO add some postcopy stats */ - info->has_status = true; - info->has_total_time = true; - info->total_time = qemu_clock_get_ms(QEMU_CLOCK_REALTIME) - - s->start_time; - info->has_expected_downtime = true; - info->expected_downtime = s->expected_downtime; - info->has_setup_time = true; - info->setup_time = s->setup_time; - + /* TODO add some postcopy stats */ + populate_time_info(info, s); populate_ram_info(info, s); populate_disk_info(info); break; @@ -926,14 +937,7 @@ static void fill_source_migration_info(MigrationInfo *info) /* TODO: display COLO specific information (checkpoint info etc.) */ break; case MIGRATION_STATUS_COMPLETED: - info->has_status = true; - info->has_total_time = true; - info->total_time = s->total_time; - info->has_downtime = true; - info->downtime = s->downtime; - info->has_setup_time = true; - info->setup_time = s->setup_time; - + populate_time_info(info, s); populate_ram_info(info, s); break; case MIGRATION_STATUS_FAILED: @@ -1695,7 +1699,6 @@ void migrate_init(MigrationState *s) * parameters/capabilities that the user set, and * locks. */ - s->bytes_xfer = 0; s->cleanup_bh = 0; s->to_dst_file = NULL; s->state = MIGRATION_STATUS_NONE; @@ -1908,6 +1911,11 @@ static bool migrate_prepare(MigrationState *s, bool blk, bool blk_inc, } migrate_init(s); + /* + * set ram_counters memory to zero for a + * new migration + */ + memset(&ram_counters, 0, sizeof(ram_counters)); return true; } @@ -2963,6 +2971,7 @@ static MigThrError migration_detect_error(MigrationState *s) { int ret; int state = s->state; + Error *local_error = NULL; if (state == MIGRATION_STATUS_CANCELLING || state == MIGRATION_STATUS_CANCELLED) { @@ -2971,13 +2980,18 @@ static MigThrError migration_detect_error(MigrationState *s) } /* Try to detect any file errors */ - ret = qemu_file_get_error(s->to_dst_file); - + ret = qemu_file_get_error_obj(s->to_dst_file, &local_error); if (!ret) { /* Everything is fine */ + assert(!local_error); return MIG_THR_ERR_NONE; } + if (local_error) { + migrate_set_error(s, local_error); + error_free(local_error); + } + if (state == MIGRATION_STATUS_POSTCOPY_ACTIVE && ret == -EIO) { /* * For postcopy, we allow the network to be down for a @@ -3025,6 +3039,17 @@ static void migration_calculate_complete(MigrationState *s) } } +static void update_iteration_initial_status(MigrationState *s) +{ + /* + * Update these three fields at the same time to avoid mismatch info lead + * wrong speed calculation. + */ + s->iteration_start_time = qemu_clock_get_ms(QEMU_CLOCK_REALTIME); + s->iteration_initial_bytes = migration_total_bytes(s); + s->iteration_initial_pages = ram_get_total_transferred_pages(); +} + static void migration_update_counters(MigrationState *s, int64_t current_time) { @@ -3060,9 +3085,7 @@ static void migration_update_counters(MigrationState *s, qemu_file_reset_rate_limit(s->to_dst_file); - s->iteration_start_time = current_time; - s->iteration_initial_bytes = current_bytes; - s->iteration_initial_pages = ram_get_total_transferred_pages(); + update_iteration_initial_status(s); trace_migrate_transferred(transferred, time_spent, bandwidth, s->threshold_size); @@ -3093,8 +3116,7 @@ static MigIterateState migration_iteration_run(MigrationState *s) if (pending_size && pending_size >= s->threshold_size) { /* Still a significant amount to transfer */ - if (migrate_postcopy() && !in_postcopy && - pend_pre <= s->threshold_size && + if (!in_postcopy && pend_pre <= s->threshold_size && atomic_read(&s->start_postcopy)) { if (postcopy_start(s)) { error_report("%s: postcopy failed to start", __func__); @@ -3186,7 +3208,7 @@ static void *migration_thread(void *opaque) rcu_register_thread(); object_ref(OBJECT(s)); - s->iteration_start_time = qemu_clock_get_ms(QEMU_CLOCK_REALTIME); + update_iteration_initial_status(s); qemu_savevm_state_header(s->to_dst_file); @@ -3251,8 +3273,7 @@ static void *migration_thread(void *opaque) * the local variables. This is important to avoid * breaking transferred_bytes and bandwidth calculation */ - s->iteration_start_time = qemu_clock_get_ms(QEMU_CLOCK_REALTIME); - s->iteration_initial_bytes = 0; + update_iteration_initial_status(s); } current_time = qemu_clock_get_ms(QEMU_CLOCK_REALTIME); diff --git a/migration/migration.h b/migration/migration.h index 1fdd7b21fd..5bc60709db 100644 --- a/migration/migration.h +++ b/migration/migration.h @@ -132,7 +132,6 @@ struct MigrationState DeviceState parent_obj; /*< public >*/ - size_t bytes_xfer; QemuThread thread; QEMUBH *cleanup_bh; QEMUFile *to_dst_file; diff --git a/migration/postcopy-ram.c b/migration/postcopy-ram.c index 9faacacc9e..2cb1a69752 100644 --- a/migration/postcopy-ram.c +++ b/migration/postcopy-ram.c @@ -1377,22 +1377,16 @@ void postcopy_fault_thread_notify(MigrationIncomingState *mis) * asking to discard individual ranges. * * @ms: The current migration state. - * @offset: the bitmap offset of the named RAMBlock in the migration - * bitmap. + * @offset: the bitmap offset of the named RAMBlock in the migration bitmap. * @name: RAMBlock that discards will operate on. - * - * returns: a new PDS. */ -PostcopyDiscardState *postcopy_discard_send_init(MigrationState *ms, - const char *name) +static PostcopyDiscardState pds = {0}; +void postcopy_discard_send_init(MigrationState *ms, const char *name) { - PostcopyDiscardState *res = g_malloc0(sizeof(PostcopyDiscardState)); - - if (res) { - res->ramblock_name = name; - } - - return res; + pds.ramblock_name = name; + pds.cur_entry = 0; + pds.nsentwords = 0; + pds.nsentcmds = 0; } /** @@ -1401,30 +1395,29 @@ PostcopyDiscardState *postcopy_discard_send_init(MigrationState *ms, * be sent later. * * @ms: Current migration state. - * @pds: Structure initialised by postcopy_discard_send_init(). * @start,@length: a range of pages in the migration bitmap in the * RAM block passed to postcopy_discard_send_init() (length=1 is one page) */ -void postcopy_discard_send_range(MigrationState *ms, PostcopyDiscardState *pds, - unsigned long start, unsigned long length) +void postcopy_discard_send_range(MigrationState *ms, unsigned long start, + unsigned long length) { size_t tp_size = qemu_target_page_size(); /* Convert to byte offsets within the RAM block */ - pds->start_list[pds->cur_entry] = start * tp_size; - pds->length_list[pds->cur_entry] = length * tp_size; - trace_postcopy_discard_send_range(pds->ramblock_name, start, length); - pds->cur_entry++; - pds->nsentwords++; + pds.start_list[pds.cur_entry] = start * tp_size; + pds.length_list[pds.cur_entry] = length * tp_size; + trace_postcopy_discard_send_range(pds.ramblock_name, start, length); + pds.cur_entry++; + pds.nsentwords++; - if (pds->cur_entry == MAX_DISCARDS_PER_COMMAND) { + if (pds.cur_entry == MAX_DISCARDS_PER_COMMAND) { /* Full set, ship it! */ qemu_savevm_send_postcopy_ram_discard(ms->to_dst_file, - pds->ramblock_name, - pds->cur_entry, - pds->start_list, - pds->length_list); - pds->nsentcmds++; - pds->cur_entry = 0; + pds.ramblock_name, + pds.cur_entry, + pds.start_list, + pds.length_list); + pds.nsentcmds++; + pds.cur_entry = 0; } } @@ -1433,24 +1426,21 @@ void postcopy_discard_send_range(MigrationState *ms, PostcopyDiscardState *pds, * bitmap code. Sends any outstanding discard messages, frees the PDS * * @ms: Current migration state. - * @pds: Structure initialised by postcopy_discard_send_init(). */ -void postcopy_discard_send_finish(MigrationState *ms, PostcopyDiscardState *pds) +void postcopy_discard_send_finish(MigrationState *ms) { /* Anything unsent? */ - if (pds->cur_entry) { + if (pds.cur_entry) { qemu_savevm_send_postcopy_ram_discard(ms->to_dst_file, - pds->ramblock_name, - pds->cur_entry, - pds->start_list, - pds->length_list); - pds->nsentcmds++; + pds.ramblock_name, + pds.cur_entry, + pds.start_list, + pds.length_list); + pds.nsentcmds++; } - trace_postcopy_discard_send_finish(pds->ramblock_name, pds->nsentwords, - pds->nsentcmds); - - g_free(pds); + trace_postcopy_discard_send_finish(pds.ramblock_name, pds.nsentwords, + pds.nsentcmds); } /* diff --git a/migration/postcopy-ram.h b/migration/postcopy-ram.h index 9d55536fd1..9c8bd2bae0 100644 --- a/migration/postcopy-ram.h +++ b/migration/postcopy-ram.h @@ -43,10 +43,8 @@ int postcopy_ram_prepare_discard(MigrationIncomingState *mis); /* * Called at the start of each RAMBlock by the bitmap code. - * Returns a new PDS */ -PostcopyDiscardState *postcopy_discard_send_init(MigrationState *ms, - const char *name); +void postcopy_discard_send_init(MigrationState *ms, const char *name); /* * Called by the bitmap code for each chunk to discard. @@ -55,15 +53,14 @@ PostcopyDiscardState *postcopy_discard_send_init(MigrationState *ms, * @start,@length: a range of pages in the migration bitmap in the * RAM block passed to postcopy_discard_send_init() (length=1 is one page) */ -void postcopy_discard_send_range(MigrationState *ms, PostcopyDiscardState *pds, - unsigned long start, unsigned long length); +void postcopy_discard_send_range(MigrationState *ms, unsigned long start, + unsigned long length); /* * Called at the end of each RAMBlock by the bitmap code. - * Sends any outstanding discard messages, frees the PDS. + * Sends any outstanding discard messages. */ -void postcopy_discard_send_finish(MigrationState *ms, - PostcopyDiscardState *pds); +void postcopy_discard_send_finish(MigrationState *ms); /* * Place a page (from) at (host) efficiently diff --git a/migration/qemu-file-channel.c b/migration/qemu-file-channel.c index 8e639eb496..c382ea2d78 100644 --- a/migration/qemu-file-channel.c +++ b/migration/qemu-file-channel.c @@ -33,7 +33,8 @@ static ssize_t channel_writev_buffer(void *opaque, struct iovec *iov, int iovcnt, - int64_t pos) + int64_t pos, + Error **errp) { QIOChannel *ioc = QIO_CHANNEL(opaque); ssize_t done = 0; @@ -47,7 +48,7 @@ static ssize_t channel_writev_buffer(void *opaque, while (nlocal_iov > 0) { ssize_t len; - len = qio_channel_writev(ioc, local_iov, nlocal_iov, NULL); + len = qio_channel_writev(ioc, local_iov, nlocal_iov, errp); if (len == QIO_CHANNEL_ERR_BLOCK) { if (qemu_in_coroutine()) { qio_channel_yield(ioc, G_IO_OUT); @@ -57,7 +58,6 @@ static ssize_t channel_writev_buffer(void *opaque, continue; } if (len < 0) { - /* XXX handle Error objects */ done = -EIO; goto cleanup; } @@ -75,13 +75,14 @@ static ssize_t channel_writev_buffer(void *opaque, static ssize_t channel_get_buffer(void *opaque, uint8_t *buf, int64_t pos, - size_t size) + size_t size, + Error **errp) { QIOChannel *ioc = QIO_CHANNEL(opaque); ssize_t ret; do { - ret = qio_channel_read(ioc, (char *)buf, size, NULL); + ret = qio_channel_read(ioc, (char *)buf, size, errp); if (ret < 0) { if (ret == QIO_CHANNEL_ERR_BLOCK) { if (qemu_in_coroutine()) { @@ -90,7 +91,6 @@ static ssize_t channel_get_buffer(void *opaque, qio_channel_wait(ioc, G_IO_IN); } } else { - /* XXX handle Error * object */ return -EIO; } } @@ -100,18 +100,20 @@ static ssize_t channel_get_buffer(void *opaque, } -static int channel_close(void *opaque) +static int channel_close(void *opaque, Error **errp) { + int ret; QIOChannel *ioc = QIO_CHANNEL(opaque); - qio_channel_close(ioc, NULL); + ret = qio_channel_close(ioc, errp); object_unref(OBJECT(ioc)); - return 0; + return ret; } static int channel_shutdown(void *opaque, bool rd, - bool wr) + bool wr, + Error **errp) { QIOChannel *ioc = QIO_CHANNEL(opaque); @@ -125,8 +127,7 @@ static int channel_shutdown(void *opaque, } else { mode = QIO_CHANNEL_SHUTDOWN_WRITE; } - if (qio_channel_shutdown(ioc, mode, NULL) < 0) { - /* XXX handler Error * object */ + if (qio_channel_shutdown(ioc, mode, errp) < 0) { return -EIO; } } @@ -135,11 +136,12 @@ static int channel_shutdown(void *opaque, static int channel_set_blocking(void *opaque, - bool enabled) + bool enabled, + Error **errp) { QIOChannel *ioc = QIO_CHANNEL(opaque); - if (qio_channel_set_blocking(ioc, enabled, NULL) < 0) { + if (qio_channel_set_blocking(ioc, enabled, errp) < 0) { return -1; } return 0; diff --git a/migration/qemu-file.c b/migration/qemu-file.c index 0431585502..e33c46764f 100644 --- a/migration/qemu-file.c +++ b/migration/qemu-file.c @@ -28,6 +28,7 @@ #include "migration.h" #include "qemu-file.h" #include "trace.h" +#include "qapi/error.h" #define IO_BUF_SIZE 32768 #define MAX_IOV_SIZE MIN(IOV_MAX, 64) @@ -51,6 +52,7 @@ struct QEMUFile { unsigned int iovcnt; int last_error; + Error *last_error_obj; }; /* @@ -62,7 +64,7 @@ int qemu_file_shutdown(QEMUFile *f) if (!f->ops->shut_down) { return -ENOSYS; } - return f->ops->shut_down(f->opaque, true, true); + return f->ops->shut_down(f->opaque, true, true, NULL); } /* @@ -107,24 +109,55 @@ void qemu_file_set_hooks(QEMUFile *f, const QEMUFileHooks *hooks) } /* - * Get last error for stream f + * Get last error for stream f with optional Error* * * Return negative error value if there has been an error on previous * operations, return 0 if no error happened. + * Optional, it returns Error* in errp, but it may be NULL even if return value + * is not 0. * */ -int qemu_file_get_error(QEMUFile *f) +int qemu_file_get_error_obj(QEMUFile *f, Error **errp) { + if (errp) { + *errp = f->last_error_obj ? error_copy(f->last_error_obj) : NULL; + } return f->last_error; } -void qemu_file_set_error(QEMUFile *f, int ret) +/* + * Set the last error for stream f with optional Error* + */ +void qemu_file_set_error_obj(QEMUFile *f, int ret, Error *err) { - if (f->last_error == 0) { + if (f->last_error == 0 && ret) { f->last_error = ret; + error_propagate(&f->last_error_obj, err); + } else if (err) { + error_report_err(err); } } +/* + * Get last error for stream f + * + * Return negative error value if there has been an error on previous + * operations, return 0 if no error happened. + * + */ +int qemu_file_get_error(QEMUFile *f) +{ + return qemu_file_get_error_obj(f, NULL); +} + +/* + * Set the last error for stream f + */ +void qemu_file_set_error(QEMUFile *f, int ret) +{ + qemu_file_set_error_obj(f, ret, NULL); +} + bool qemu_file_is_writable(QEMUFile *f) { return f->ops->writev_buffer; @@ -176,6 +209,7 @@ void qemu_fflush(QEMUFile *f) { ssize_t ret = 0; ssize_t expect = 0; + Error *local_error = NULL; if (!qemu_file_is_writable(f)) { return; @@ -183,7 +217,8 @@ void qemu_fflush(QEMUFile *f) if (f->iovcnt > 0) { expect = iov_size(f->iov, f->iovcnt); - ret = f->ops->writev_buffer(f->opaque, f->iov, f->iovcnt, f->pos); + ret = f->ops->writev_buffer(f->opaque, f->iov, f->iovcnt, f->pos, + &local_error); qemu_iovec_release_ram(f); } @@ -195,7 +230,7 @@ void qemu_fflush(QEMUFile *f) * data set we requested, so sanity check that. */ if (ret != expect) { - qemu_file_set_error(f, ret < 0 ? ret : -EIO); + qemu_file_set_error_obj(f, ret < 0 ? ret : -EIO, local_error); } f->buf_index = 0; f->iovcnt = 0; @@ -283,6 +318,7 @@ static ssize_t qemu_fill_buffer(QEMUFile *f) { int len; int pending; + Error *local_error = NULL; assert(!qemu_file_is_writable(f)); @@ -294,14 +330,16 @@ static ssize_t qemu_fill_buffer(QEMUFile *f) f->buf_size = pending; len = f->ops->get_buffer(f->opaque, f->buf + pending, f->pos, - IO_BUF_SIZE - pending); + IO_BUF_SIZE - pending, &local_error); if (len > 0) { f->buf_size += len; f->pos += len; } else if (len == 0) { - qemu_file_set_error(f, -EIO); + qemu_file_set_error_obj(f, -EIO, local_error); } else if (len != -EAGAIN) { - qemu_file_set_error(f, len); + qemu_file_set_error_obj(f, len, local_error); + } else { + error_free(local_error); } return len; @@ -327,7 +365,7 @@ int qemu_fclose(QEMUFile *f) ret = qemu_file_get_error(f); if (f->ops->close) { - int ret2 = f->ops->close(f->opaque); + int ret2 = f->ops->close(f->opaque, NULL); if (ret >= 0) { ret = ret2; } @@ -338,6 +376,7 @@ int qemu_fclose(QEMUFile *f) if (f->last_error) { ret = f->last_error; } + error_free(f->last_error_obj); g_free(f); trace_qemu_file_fclose(); return ret; @@ -615,6 +654,11 @@ void qemu_file_reset_rate_limit(QEMUFile *f) f->bytes_xfer = 0; } +void qemu_file_update_transfer(QEMUFile *f, int64_t len) +{ + f->bytes_xfer += len; +} + void qemu_put_be16(QEMUFile *f, unsigned int v) { qemu_put_byte(f, v >> 8); @@ -783,6 +827,6 @@ void qemu_put_counted_string(QEMUFile *f, const char *str) void qemu_file_set_blocking(QEMUFile *f, bool block) { if (f->ops->set_blocking) { - f->ops->set_blocking(f->opaque, block); + f->ops->set_blocking(f->opaque, block, NULL); } } diff --git a/migration/qemu-file.h b/migration/qemu-file.h index 13baf896bd..b6303dbeef 100644 --- a/migration/qemu-file.h +++ b/migration/qemu-file.h @@ -32,7 +32,8 @@ * bytes actually read should be returned. */ typedef ssize_t (QEMUFileGetBufferFunc)(void *opaque, uint8_t *buf, - int64_t pos, size_t size); + int64_t pos, size_t size, + Error **errp); /* Close a file * @@ -41,7 +42,7 @@ typedef ssize_t (QEMUFileGetBufferFunc)(void *opaque, uint8_t *buf, * The meaning of return value on success depends on the specific back-end being * used. */ -typedef int (QEMUFileCloseFunc)(void *opaque); +typedef int (QEMUFileCloseFunc)(void *opaque, Error **errp); /* Called to return the OS file descriptor associated to the QEMUFile. */ @@ -49,14 +50,15 @@ typedef int (QEMUFileGetFD)(void *opaque); /* Called to change the blocking mode of the file */ -typedef int (QEMUFileSetBlocking)(void *opaque, bool enabled); +typedef int (QEMUFileSetBlocking)(void *opaque, bool enabled, Error **errp); /* * This function writes an iovec to file. The handler must write all * of the data or return a negative errno value. */ typedef ssize_t (QEMUFileWritevBufferFunc)(void *opaque, struct iovec *iov, - int iovcnt, int64_t pos); + int iovcnt, int64_t pos, + Error **errp); /* * This function provides hooks around different @@ -97,7 +99,8 @@ typedef QEMUFile *(QEMURetPathFunc)(void *opaque); * Existing blocking reads/writes must be woken * Returns 0 on success, -err on error */ -typedef int (QEMUFileShutdownFunc)(void *opaque, bool rd, bool wr); +typedef int (QEMUFileShutdownFunc)(void *opaque, bool rd, bool wr, + Error **errp); typedef struct QEMUFileOps { QEMUFileGetBufferFunc *get_buffer; @@ -147,16 +150,17 @@ int qemu_peek_byte(QEMUFile *f, int offset); void qemu_file_skip(QEMUFile *f, int size); void qemu_update_position(QEMUFile *f, size_t size); void qemu_file_reset_rate_limit(QEMUFile *f); +void qemu_file_update_transfer(QEMUFile *f, int64_t len); void qemu_file_set_rate_limit(QEMUFile *f, int64_t new_rate); int64_t qemu_file_get_rate_limit(QEMUFile *f); +int qemu_file_get_error_obj(QEMUFile *f, Error **errp); +void qemu_file_set_error_obj(QEMUFile *f, int ret, Error *err); void qemu_file_set_error(QEMUFile *f, int ret); int qemu_file_shutdown(QEMUFile *f); QEMUFile *qemu_file_get_return_path(QEMUFile *f); void qemu_fflush(QEMUFile *f); void qemu_file_set_blocking(QEMUFile *f, bool block); -size_t qemu_get_counted_string(QEMUFile *f, char buf[256]); - void ram_control_before_iterate(QEMUFile *f, uint64_t flags); void ram_control_after_iterate(QEMUFile *f, uint64_t flags); void ram_control_load_hook(QEMUFile *f, uint64_t flags, void *data); @@ -175,6 +179,4 @@ size_t ram_control_save_page(QEMUFile *f, ram_addr_t block_offset, ram_addr_t offset, size_t size, uint64_t *bytes_sent); -void qemu_put_counted_string(QEMUFile *f, const char *name); - #endif diff --git a/migration/ram.c b/migration/ram.c index 889148dd84..35552c090b 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -661,6 +661,8 @@ typedef struct { uint64_t num_packets; /* pages sent through this channel */ uint64_t num_pages; + /* syncs main thread and channels */ + QemuSemaphore sem_sync; } MultiFDSendParams; typedef struct { @@ -896,8 +898,6 @@ struct { MultiFDSendParams *params; /* array of pages to sent */ MultiFDPages_t *pages; - /* syncs main thread and channels */ - QemuSemaphore sem_sync; /* global number of generated multifd packets */ uint64_t packet_num; /* send channels ready */ @@ -922,7 +922,7 @@ struct { * false. */ -static int multifd_send_pages(void) +static int multifd_send_pages(RAMState *rs) { int i; static int next_channel; @@ -954,6 +954,7 @@ static int multifd_send_pages(void) multifd_send_state->pages = p->pages; p->pages = pages; transferred = ((uint64_t) pages->used) * TARGET_PAGE_SIZE + p->packet_len; + qemu_file_update_transfer(rs->f, transferred); ram_counters.multifd_bytes += transferred; ram_counters.transferred += transferred;; qemu_mutex_unlock(&p->mutex); @@ -962,7 +963,7 @@ static int multifd_send_pages(void) return 1; } -static int multifd_queue_page(RAMBlock *block, ram_addr_t offset) +static int multifd_queue_page(RAMState *rs, RAMBlock *block, ram_addr_t offset) { MultiFDPages_t *pages = multifd_send_state->pages; @@ -981,12 +982,12 @@ static int multifd_queue_page(RAMBlock *block, ram_addr_t offset) } } - if (multifd_send_pages() < 0) { + if (multifd_send_pages(rs) < 0) { return -1; } if (pages->block != block) { - return multifd_queue_page(block, offset); + return multifd_queue_page(rs, block, offset); } return 1; @@ -996,6 +997,8 @@ static void multifd_send_terminate_threads(Error *err) { int i; + trace_multifd_send_terminate_threads(err != NULL); + if (err) { MigrationState *s = migrate_get_current(); migrate_set_error(s, err); @@ -1036,6 +1039,7 @@ void multifd_save_cleanup(void) p->c = NULL; qemu_mutex_destroy(&p->mutex); qemu_sem_destroy(&p->sem); + qemu_sem_destroy(&p->sem_sync); g_free(p->name); p->name = NULL; multifd_pages_clear(p->pages); @@ -1045,7 +1049,6 @@ void multifd_save_cleanup(void) p->packet = NULL; } qemu_sem_destroy(&multifd_send_state->channels_ready); - qemu_sem_destroy(&multifd_send_state->sem_sync); g_free(multifd_send_state->params); multifd_send_state->params = NULL; multifd_pages_clear(multifd_send_state->pages); @@ -1054,7 +1057,7 @@ void multifd_save_cleanup(void) multifd_send_state = NULL; } -static void multifd_send_sync_main(void) +static void multifd_send_sync_main(RAMState *rs) { int i; @@ -1062,7 +1065,7 @@ static void multifd_send_sync_main(void) return; } if (multifd_send_state->pages->used) { - if (multifd_send_pages() < 0) { + if (multifd_send_pages(rs) < 0) { error_report("%s: multifd_send_pages fail", __func__); return; } @@ -1083,6 +1086,9 @@ static void multifd_send_sync_main(void) p->packet_num = multifd_send_state->packet_num++; p->flags |= MULTIFD_FLAG_SYNC; p->pending_job++; + qemu_file_update_transfer(rs->f, p->packet_len); + ram_counters.multifd_bytes += p->packet_len; + ram_counters.transferred += p->packet_len; qemu_mutex_unlock(&p->mutex); qemu_sem_post(&p->sem); } @@ -1090,7 +1096,7 @@ static void multifd_send_sync_main(void) MultiFDSendParams *p = &multifd_send_state->params[i]; trace_multifd_send_sync_main_wait(p->id); - qemu_sem_wait(&multifd_send_state->sem_sync); + qemu_sem_wait(&p->sem_sync); } trace_multifd_send_sync_main(multifd_send_state->packet_num); } @@ -1150,7 +1156,7 @@ static void *multifd_send_thread(void *opaque) qemu_mutex_unlock(&p->mutex); if (flags & MULTIFD_FLAG_SYNC) { - qemu_sem_post(&multifd_send_state->sem_sync); + qemu_sem_post(&p->sem_sync); } qemu_sem_post(&multifd_send_state->channels_ready); } else if (p->quit) { @@ -1164,6 +1170,7 @@ static void *multifd_send_thread(void *opaque) out: if (local_err) { + trace_multifd_send_error(p->id); multifd_send_terminate_threads(local_err); } @@ -1173,7 +1180,7 @@ out: */ if (ret != 0) { if (flags & MULTIFD_FLAG_SYNC) { - qemu_sem_post(&multifd_send_state->sem_sync); + qemu_sem_post(&p->sem_sync); } qemu_sem_post(&multifd_send_state->channels_ready); } @@ -1194,6 +1201,7 @@ static void multifd_new_send_channel_async(QIOTask *task, gpointer opaque) QIOChannel *sioc = QIO_CHANNEL(qio_task_get_source(task)); Error *local_err = NULL; + trace_multifd_new_send_channel_async(p->id); if (qio_task_propagate_error(task, &local_err)) { migrate_set_error(migrate_get_current(), local_err); multifd_save_cleanup(); @@ -1219,7 +1227,6 @@ int multifd_save_setup(void) multifd_send_state = g_malloc0(sizeof(*multifd_send_state)); multifd_send_state->params = g_new0(MultiFDSendParams, thread_count); multifd_send_state->pages = multifd_pages_init(page_count); - qemu_sem_init(&multifd_send_state->sem_sync, 0); qemu_sem_init(&multifd_send_state->channels_ready, 0); for (i = 0; i < thread_count; i++) { @@ -1227,6 +1234,7 @@ int multifd_save_setup(void) qemu_mutex_init(&p->mutex); qemu_sem_init(&p->sem, 0); + qemu_sem_init(&p->sem_sync, 0); p->quit = false; p->pending_job = 0; p->id = i; @@ -1254,6 +1262,8 @@ static void multifd_recv_terminate_threads(Error *err) { int i; + trace_multifd_recv_terminate_threads(err != NULL); + if (err) { MigrationState *s = migrate_get_current(); migrate_set_error(s, err); @@ -1478,6 +1488,7 @@ bool multifd_recv_new_channel(QIOChannel *ioc, Error **errp) atomic_read(&multifd_recv_state->count)); return false; } + trace_multifd_recv_new_channel(id); p = &multifd_recv_state->params[id]; if (p->c != NULL) { @@ -1748,11 +1759,10 @@ static inline bool migration_bitmap_clear_dirty(RAMState *rs, } /* Called with RCU critical section */ -static void migration_bitmap_sync_range(RAMState *rs, RAMBlock *rb, - ram_addr_t length) +static void ramblock_sync_dirty_bitmap(RAMState *rs, RAMBlock *rb) { rs->migration_dirty_pages += - cpu_physical_memory_sync_dirty_bitmap(rb, 0, length, + cpu_physical_memory_sync_dirty_bitmap(rb, 0, rb->used_length, &rs->num_dirty_pages_period); } @@ -1841,7 +1851,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, block->used_length); + ramblock_sync_dirty_bitmap(rs, block); } ram_counters.remaining = ram_bytes_remaining(); rcu_read_unlock(); @@ -2079,7 +2089,7 @@ static int ram_save_page(RAMState *rs, PageSearchStatus *pss, bool last_stage) static int ram_save_multifd_page(RAMState *rs, RAMBlock *block, ram_addr_t offset) { - if (multifd_queue_page(block, offset) < 0) { + if (multifd_queue_page(rs, block, offset) < 0) { return -1; } ram_counters.normal++; @@ -2851,12 +2861,9 @@ void ram_postcopy_migrated_memory_release(MigrationState *ms) * with the dirtymap; so a '1' means it's either dirty or unsent. * * @ms: current migration state - * @pds: state for postcopy * @block: RAMBlock to discard */ -static int postcopy_send_discard_bm_ram(MigrationState *ms, - PostcopyDiscardState *pds, - RAMBlock *block) +static int postcopy_send_discard_bm_ram(MigrationState *ms, RAMBlock *block) { unsigned long end = block->used_length >> TARGET_PAGE_BITS; unsigned long current; @@ -2864,23 +2871,21 @@ static int postcopy_send_discard_bm_ram(MigrationState *ms, for (current = 0; current < end; ) { unsigned long one = find_next_bit(unsentmap, end, current); + unsigned long zero, discard_length; + + if (one >= end) { + break; + } - if (one <= end) { - unsigned long zero = find_next_zero_bit(unsentmap, end, one + 1); - unsigned long discard_length; + zero = find_next_zero_bit(unsentmap, end, one + 1); - if (zero >= end) { - discard_length = end - one; - } else { - discard_length = zero - one; - } - if (discard_length) { - postcopy_discard_send_range(ms, pds, one, discard_length); - } - current = one + discard_length; + if (zero >= end) { + discard_length = end - one; } else { - current = one; + discard_length = zero - one; } + postcopy_discard_send_range(ms, one, discard_length); + current = one + discard_length; } return 0; @@ -2905,16 +2910,15 @@ static int postcopy_each_ram_send_discard(MigrationState *ms) int ret; RAMBLOCK_FOREACH_NOT_IGNORED(block) { - PostcopyDiscardState *pds = - postcopy_discard_send_init(ms, block->idstr); + postcopy_discard_send_init(ms, block->idstr); /* * Postcopy sends chunks of bitmap over the wire, but it * just needs indexes at this point, avoids it having * target page specific code. */ - ret = postcopy_send_discard_bm_ram(ms, pds, block); - postcopy_discard_send_finish(ms, pds); + ret = postcopy_send_discard_bm_ram(ms, block); + postcopy_discard_send_finish(ms); if (ret) { return ret; } @@ -2937,11 +2941,9 @@ static int postcopy_each_ram_send_discard(MigrationState *ms) * @unsent_pass: if true we need to canonicalize partially unsent host pages * otherwise we need to canonicalize partially dirty host pages * @block: block that contains the page we want to canonicalize - * @pds: state for postcopy */ static void postcopy_chunk_hostpages_pass(MigrationState *ms, bool unsent_pass, - RAMBlock *block, - PostcopyDiscardState *pds) + RAMBlock *block) { RAMState *rs = ram_state; unsigned long *bitmap = block->bmap; @@ -2964,54 +2966,30 @@ static void postcopy_chunk_hostpages_pass(MigrationState *ms, bool unsent_pass, } while (run_start < pages) { - bool do_fixup = false; - unsigned long fixup_start_addr; - unsigned long host_offset; /* * If the start of this run of pages is in the middle of a host * page, then we need to fixup this host page. */ - host_offset = run_start % host_ratio; - if (host_offset) { - do_fixup = true; - run_start -= host_offset; - fixup_start_addr = run_start; - /* For the next pass */ - run_start = run_start + host_ratio; - } else { + if (QEMU_IS_ALIGNED(run_start, host_ratio)) { /* Find the end of this run */ - unsigned long run_end; if (unsent_pass) { - run_end = find_next_bit(unsentmap, pages, run_start + 1); + run_start = find_next_bit(unsentmap, pages, run_start + 1); } else { - run_end = find_next_zero_bit(bitmap, pages, run_start + 1); + run_start = find_next_zero_bit(bitmap, pages, run_start + 1); } /* * If the end isn't at the start of a host page, then the * run doesn't finish at the end of a host page * and we need to discard. */ - host_offset = run_end % host_ratio; - if (host_offset) { - do_fixup = true; - fixup_start_addr = run_end - host_offset; - /* - * This host page has gone, the next loop iteration starts - * from after the fixup - */ - run_start = fixup_start_addr + host_ratio; - } else { - /* - * No discards on this iteration, next loop starts from - * next sent/dirty page - */ - run_start = run_end + 1; - } } - if (do_fixup) { + if (!QEMU_IS_ALIGNED(run_start, host_ratio)) { unsigned long page; + unsigned long fixup_start_addr = QEMU_ALIGN_DOWN(run_start, + host_ratio); + run_start = QEMU_ALIGN_UP(run_start, host_ratio); /* Tell the destination to discard this page */ if (unsent_pass || !test_bit(fixup_start_addr, unsentmap)) { @@ -3022,8 +3000,7 @@ static void postcopy_chunk_hostpages_pass(MigrationState *ms, bool unsent_pass, * (any partially sent pages were already discarded * by the previous unsent_pass) */ - postcopy_discard_send_range(ms, pds, fixup_start_addr, - host_ratio); + postcopy_discard_send_range(ms, fixup_start_addr, host_ratio); } /* Clean up the bitmap */ @@ -3066,18 +3043,17 @@ static void postcopy_chunk_hostpages_pass(MigrationState *ms, bool unsent_pass, */ static int postcopy_chunk_hostpages(MigrationState *ms, RAMBlock *block) { - PostcopyDiscardState *pds = - postcopy_discard_send_init(ms, block->idstr); + postcopy_discard_send_init(ms, block->idstr); /* First pass: Discard all partially sent host pages */ - postcopy_chunk_hostpages_pass(ms, true, block, pds); + postcopy_chunk_hostpages_pass(ms, true, block); /* * Second pass: Ensure that all partially dirty host pages are made * fully dirty. */ - postcopy_chunk_hostpages_pass(ms, false, block, pds); + postcopy_chunk_hostpages_pass(ms, false, block); - postcopy_discard_send_finish(ms, pds); + postcopy_discard_send_finish(ms); return 0; } @@ -3482,7 +3458,7 @@ static int ram_save_setup(QEMUFile *f, void *opaque) ram_control_before_iterate(f, RAM_CONTROL_SETUP); ram_control_after_iterate(f, RAM_CONTROL_SETUP); - multifd_send_sync_main(); + multifd_send_sync_main(*rsp); qemu_put_be64(f, RAM_SAVE_FLAG_EOS); qemu_fflush(f); @@ -3570,7 +3546,7 @@ static int ram_save_iterate(QEMUFile *f, void *opaque) ram_control_after_iterate(f, RAM_CONTROL_ROUND); out: - multifd_send_sync_main(); + multifd_send_sync_main(rs); qemu_put_be64(f, RAM_SAVE_FLAG_EOS); qemu_fflush(f); ram_counters.transferred += 8; @@ -3629,7 +3605,7 @@ static int ram_save_complete(QEMUFile *f, void *opaque) rcu_read_unlock(); - multifd_send_sync_main(); + multifd_send_sync_main(rs); qemu_put_be64(f, RAM_SAVE_FLAG_EOS); qemu_fflush(f); @@ -4296,7 +4272,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, block->used_length); + ramblock_sync_dirty_bitmap(ram_state, block); } rcu_read_unlock(); @@ -4322,40 +4298,26 @@ static void colo_flush_ram_cache(void) trace_colo_flush_ram_cache_end(); } -static int ram_load(QEMUFile *f, void *opaque, int version_id) +/** + * ram_load_precopy: load pages in precopy case + * + * Returns 0 for success or -errno in case of error + * + * Called in precopy mode by ram_load(). + * rcu_read_lock is taken prior to this being called. + * + * @f: QEMUFile where to send the data + */ +static int ram_load_precopy(QEMUFile *f) { - int flags = 0, ret = 0, invalid_flags = 0; - static uint64_t seq_iter; - int len = 0; - /* - * If system is running in postcopy mode, page inserts to host memory must - * be atomic - */ - bool postcopy_running = postcopy_is_running(); + int flags = 0, ret = 0, invalid_flags = 0, len = 0; /* ADVISE is earlier, it shows the source has the postcopy capability on */ bool postcopy_advised = postcopy_is_advised(); - - seq_iter++; - - if (version_id != 4) { - ret = -EINVAL; - } - if (!migrate_use_compression()) { invalid_flags |= RAM_SAVE_FLAG_COMPRESS_PAGE; } - /* This RCU critical section can be very long running. - * When RCU reclaims in the code start to become numerous, - * it will be necessary to reduce the granularity of this - * critical section. - */ - rcu_read_lock(); - - if (postcopy_running) { - ret = ram_load_postcopy(f); - } - while (!postcopy_running && !ret && !(flags & RAM_SAVE_FLAG_EOS)) { + while (!ret && !(flags & RAM_SAVE_FLAG_EOS)) { ram_addr_t addr, total_ram_bytes; void *host = NULL; uint8_t ch; @@ -4506,6 +4468,39 @@ static int ram_load(QEMUFile *f, void *opaque, int version_id) } } + return ret; +} + +static int ram_load(QEMUFile *f, void *opaque, int version_id) +{ + int ret = 0; + static uint64_t seq_iter; + /* + * If system is running in postcopy mode, page inserts to host memory must + * be atomic + */ + bool postcopy_running = postcopy_is_running(); + + seq_iter++; + + if (version_id != 4) { + return -EINVAL; + } + + /* + * This RCU critical section can be very long running. + * When RCU reclaims in the code start to become numerous, + * it will be necessary to reduce the granularity of this + * critical section. + */ + rcu_read_lock(); + + if (postcopy_running) { + ret = ram_load_postcopy(f); + } else { + ret = ram_load_precopy(f); + } + ret |= wait_for_decompress_done(); rcu_read_unlock(); trace_ram_load_complete(ret, seq_iter); diff --git a/migration/rdma.c b/migration/rdma.c index 3036221ee8..0e73e759ca 100644 --- a/migration/rdma.c +++ b/migration/rdma.c @@ -3140,7 +3140,7 @@ static size_t qemu_rdma_save_page(QEMUFile *f, void *opaque, CHECK_ERROR_STATE(); - if (migrate_get_current()->state == MIGRATION_STATUS_POSTCOPY_ACTIVE) { + if (migration_in_postcopy()) { rcu_read_unlock(); return RAM_SAVE_CONTROL_NOT_SUPP; } @@ -3775,7 +3775,7 @@ static int qemu_rdma_registration_start(QEMUFile *f, void *opaque, CHECK_ERROR_STATE(); - if (migrate_get_current()->state == MIGRATION_STATUS_POSTCOPY_ACTIVE) { + if (migration_in_postcopy()) { rcu_read_unlock(); return 0; } @@ -3810,7 +3810,7 @@ static int qemu_rdma_registration_stop(QEMUFile *f, void *opaque, CHECK_ERROR_STATE(); - if (migrate_get_current()->state == MIGRATION_STATUS_POSTCOPY_ACTIVE) { + if (migration_in_postcopy()) { rcu_read_unlock(); return 0; } diff --git a/migration/savevm.c b/migration/savevm.c index 79ed44d475..6369a4ff7a 100644 --- a/migration/savevm.c +++ b/migration/savevm.c @@ -124,7 +124,7 @@ static struct mig_cmd_args { /* savevm/loadvm support */ static ssize_t block_writev_buffer(void *opaque, struct iovec *iov, int iovcnt, - int64_t pos) + int64_t pos, Error **errp) { int ret; QEMUIOVector qiov; @@ -139,12 +139,12 @@ static ssize_t block_writev_buffer(void *opaque, struct iovec *iov, int iovcnt, } static ssize_t block_get_buffer(void *opaque, uint8_t *buf, int64_t pos, - size_t size) + size_t size, Error **errp) { return bdrv_load_vmstate(opaque, buf, pos, size); } -static int bdrv_fclose(void *opaque) +static int bdrv_fclose(void *opaque, Error **errp) { return bdrv_flush(opaque); } @@ -1246,29 +1246,16 @@ void qemu_savevm_state_complete_postcopy(QEMUFile *f) qemu_fflush(f); } -int qemu_savevm_state_complete_precopy(QEMUFile *f, bool iterable_only, - bool inactivate_disks) +static +int qemu_savevm_state_complete_precopy_iterable(QEMUFile *f, bool in_postcopy) { - QJSON *vmdesc; - int vmdesc_len; SaveStateEntry *se; int ret; - bool in_postcopy = migration_in_postcopy(); - Error *local_err = NULL; - - if (precopy_notify(PRECOPY_NOTIFY_COMPLETE, &local_err)) { - error_report_err(local_err); - } - - trace_savevm_state_complete_precopy(); - - cpu_synchronize_all_states(); QTAILQ_FOREACH(se, &savevm_state.handlers, entry) { if (!se->ops || (in_postcopy && se->ops->has_postcopy && se->ops->has_postcopy(se->opaque)) || - (in_postcopy && !iterable_only) || !se->ops->save_live_complete_precopy) { continue; } @@ -1291,9 +1278,18 @@ int qemu_savevm_state_complete_precopy(QEMUFile *f, bool iterable_only, } } - if (iterable_only) { - return 0; - } + return 0; +} + +static +int qemu_savevm_state_complete_precopy_non_iterable(QEMUFile *f, + bool in_postcopy, + bool inactivate_disks) +{ + QJSON *vmdesc; + int vmdesc_len; + SaveStateEntry *se; + int ret; vmdesc = qjson_new(); json_prop_int(vmdesc, "page_size", qemu_target_page_size()); @@ -1353,6 +1349,42 @@ int qemu_savevm_state_complete_precopy(QEMUFile *f, bool iterable_only, } qjson_destroy(vmdesc); + return 0; +} + +int qemu_savevm_state_complete_precopy(QEMUFile *f, bool iterable_only, + bool inactivate_disks) +{ + int ret; + Error *local_err = NULL; + bool in_postcopy = migration_in_postcopy(); + + if (precopy_notify(PRECOPY_NOTIFY_COMPLETE, &local_err)) { + error_report_err(local_err); + } + + trace_savevm_state_complete_precopy(); + + cpu_synchronize_all_states(); + + if (!in_postcopy || iterable_only) { + ret = qemu_savevm_state_complete_precopy_iterable(f, in_postcopy); + if (ret) { + return ret; + } + } + + if (iterable_only) { + goto flush; + } + + ret = qemu_savevm_state_complete_precopy_non_iterable(f, in_postcopy, + inactivate_disks); + if (ret) { + return ret; + } + +flush: qemu_fflush(f); return 0; } @@ -1424,6 +1456,7 @@ static int qemu_savevm_state(QEMUFile *f, Error **errp) } migrate_init(ms); + memset(&ram_counters, 0, sizeof(ram_counters)); ms->to_dst_file = f; qemu_mutex_unlock_iothread(); @@ -1616,8 +1649,6 @@ static int loadvm_postcopy_handle_advise(MigrationIncomingState *mis, return -1; } - postcopy_state_set(POSTCOPY_INCOMING_ADVISE); - return 0; } @@ -1835,16 +1866,10 @@ static int loadvm_postcopy_handle_listen(MigrationIncomingState *mis) return 0; } - -typedef struct { - QEMUBH *bh; -} HandleRunBhData; - static void loadvm_postcopy_handle_run_bh(void *opaque) { Error *local_err = NULL; - HandleRunBhData *data = opaque; - MigrationIncomingState *mis = migration_incoming_get_current(); + MigrationIncomingState *mis = opaque; /* TODO we should move all of this lot into postcopy_ram.c or a shared code * in migration.c @@ -1876,15 +1901,13 @@ static void loadvm_postcopy_handle_run_bh(void *opaque) runstate_set(RUN_STATE_PAUSED); } - qemu_bh_delete(data->bh); - g_free(data); + qemu_bh_delete(mis->bh); } /* After all discards we can start running and asking for pages */ static int loadvm_postcopy_handle_run(MigrationIncomingState *mis) { PostcopyState ps = postcopy_state_set(POSTCOPY_INCOMING_RUNNING); - HandleRunBhData *data; trace_loadvm_postcopy_handle_run(); if (ps != POSTCOPY_INCOMING_LISTENING) { @@ -1892,9 +1915,8 @@ static int loadvm_postcopy_handle_run(MigrationIncomingState *mis) return -1; } - data = g_new(HandleRunBhData, 1); - data->bh = qemu_bh_new(loadvm_postcopy_handle_run_bh, data); - qemu_bh_schedule(data->bh); + mis->bh = qemu_bh_new(loadvm_postcopy_handle_run_bh, mis); + qemu_bh_schedule(mis->bh); /* We need to finish reading the stream from the package * and also stop reading anything more from the stream that loaded the @@ -2407,7 +2429,7 @@ retry: case QEMU_VM_COMMAND: ret = loadvm_process_command(f); trace_qemu_loadvm_state_section_command(ret); - if ((ret < 0) || (ret & LOADVM_QUIT)) { + if ((ret < 0) || (ret == LOADVM_QUIT)) { goto out; } break; diff --git a/migration/trace-events b/migration/trace-events index d8e54c367a..00ffcd5930 100644 --- a/migration/trace-events +++ b/migration/trace-events @@ -81,16 +81,22 @@ migration_bitmap_sync_start(void) "" migration_bitmap_sync_end(uint64_t dirty_pages) "dirty_pages %" PRIu64 migration_bitmap_clear_dirty(char *str, uint64_t start, uint64_t size, unsigned long page) "rb %s start 0x%"PRIx64" size 0x%"PRIx64" page 0x%lx" migration_throttle(void) "" +multifd_new_send_channel_async(uint8_t id) "channel %d" multifd_recv(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_recv_new_channel(uint8_t id) "channel %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_terminate_threads(bool error) "error %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_save_setup_wait(uint8_t id) "%d" 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_error(uint8_t id) "channel %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" +multifd_send_terminate_threads(bool error) "error %d" multifd_send_thread_end(uint8_t id, uint64_t packets, uint64_t pages) "channel %d packets %" PRIu64 " pages %" PRIu64 multifd_send_thread_start(uint8_t id) "%d" ram_discard_range(const char *rbname, uint64_t start, size_t len) "%s: start: %" PRIx64 " %zx" diff --git a/monitor/hmp-cmds.c b/monitor/hmp-cmds.c index 5ca3ebe942..35788c0645 100644 --- a/monitor/hmp-cmds.c +++ b/monitor/hmp-cmds.c @@ -220,24 +220,11 @@ static char *SocketAddress_to_str(SocketAddress *addr) void hmp_info_migrate(Monitor *mon, const QDict *qdict) { MigrationInfo *info; - MigrationCapabilityStatusList *caps, *cap; info = qmp_query_migrate(NULL); - caps = qmp_query_migrate_capabilities(NULL); migration_global_dump(mon); - /* do not display parameters during setup */ - if (info->has_status && caps) { - monitor_printf(mon, "capabilities: "); - for (cap = caps; cap; cap = cap->next) { - monitor_printf(mon, "%s: %s ", - MigrationCapability_str(cap->value->capability), - cap->value->state ? "on" : "off"); - } - monitor_printf(mon, "\n"); - } - if (info->has_status) { monitor_printf(mon, "Migration status: %s", MigrationStatus_str(info->status)); @@ -370,7 +357,6 @@ void hmp_info_migrate(Monitor *mon, const QDict *qdict) monitor_printf(mon, "]\n"); } qapi_free_MigrationInfo(info); - qapi_free_MigrationCapabilityStatusList(caps); } void hmp_info_migrate_capabilities(Monitor *mon, const QDict *qdict) |