diff options
46 files changed, 648 insertions, 583 deletions
diff --git a/hw/net/vmxnet3.c b/hw/net/vmxnet3.c index 17b420b2a8..b07adeed9c 100644 --- a/hw/net/vmxnet3.c +++ b/hw/net/vmxnet3.c @@ -2143,21 +2143,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, @@ -2178,11 +2163,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; @@ -2205,7 +2185,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; @@ -2251,8 +2230,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) @@ -2442,29 +2419,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, @@ -2472,9 +2426,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), @@ -2510,7 +2463,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/include/sysemu/qtest.h b/include/sysemu/qtest.h index cd114b8d80..5ed09c80b1 100644 --- a/include/sysemu/qtest.h +++ b/include/sysemu/qtest.h @@ -24,6 +24,6 @@ static inline bool qtest_enabled(void) bool qtest_driver(void); -void qtest_init(const char *qtest_chrdev, const char *qtest_log, Error **errp); +void qtest_server_init(const char *qtest_chrdev, const char *qtest_log, Error **errp); #endif diff --git a/migration/migration.c b/migration/migration.c index c1600c395f..8b9f2fe30a 100644 --- a/migration/migration.c +++ b/migration/migration.c @@ -827,6 +827,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; @@ -912,16 +931,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; @@ -930,14 +941,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: @@ -1699,7 +1703,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; @@ -1912,6 +1915,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; } @@ -2967,6 +2975,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) { @@ -2975,13 +2984,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 @@ -3029,6 +3043,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) { @@ -3064,9 +3089,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); @@ -3097,8 +3120,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__); @@ -3190,7 +3212,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); @@ -3255,8 +3277,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 b150937180..3e1ea2b5dc 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 56054d0a73..1f63e65ed7 100644 --- a/migration/postcopy-ram.c +++ b/migration/postcopy-ram.c @@ -1378,22 +1378,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; } /** @@ -1402,30 +1396,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; } } @@ -1434,24 +1427,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 78ef248820..d2ce32f4b9 100644 --- a/migration/qemu-file-channel.c +++ b/migration/qemu-file-channel.c @@ -32,7 +32,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; @@ -46,7 +47,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); @@ -56,7 +57,6 @@ static ssize_t channel_writev_buffer(void *opaque, continue; } if (len < 0) { - /* XXX handle Error objects */ done = -EIO; goto cleanup; } @@ -74,13 +74,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()) { @@ -89,7 +90,6 @@ static ssize_t channel_get_buffer(void *opaque, qio_channel_wait(ioc, G_IO_IN); } } else { - /* XXX handle Error * object */ return -EIO; } } @@ -99,18 +99,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); @@ -124,8 +126,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; } } @@ -134,11 +135,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 21f3ae4be2..a9b6d6ccb7 100644 --- a/migration/qemu-file.h +++ b/migration/qemu-file.h @@ -33,7 +33,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 * @@ -42,7 +43,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. */ @@ -50,14 +51,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 @@ -98,7 +100,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; @@ -148,16 +151,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); @@ -176,6 +180,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 b0e27b6174..78e6b72bac 100644 --- a/migration/rdma.c +++ b/migration/rdma.c @@ -3141,7 +3141,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; } @@ -3776,7 +3776,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; } @@ -3811,7 +3811,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 fd3c39dc39..4a86128ac4 100644 --- a/migration/savevm.c +++ b/migration/savevm.c @@ -128,7 +128,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; @@ -143,12 +143,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); } @@ -1250,29 +1250,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; } @@ -1295,9 +1282,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()); @@ -1357,6 +1353,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; } @@ -1428,6 +1460,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(); @@ -1620,8 +1653,6 @@ static int loadvm_postcopy_handle_advise(MigrationIncomingState *mis, return -1; } - postcopy_state_set(POSTCOPY_INCOMING_ADVISE); - return 0; } @@ -1839,16 +1870,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 @@ -1880,15 +1905,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) { @@ -1896,9 +1919,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 @@ -2411,7 +2433,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 5ed82387ea..e4d4043a3b 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) @@ -747,8 +747,7 @@ static void qtest_event(void *opaque, int event) break; } } - -void qtest_init(const char *qtest_chrdev, const char *qtest_log, Error **errp) +void qtest_server_init(const char *qtest_chrdev, const char *qtest_log, Error **errp) { Chardev *chr; diff --git a/tests/cpu-plug-test.c b/tests/cpu-plug-test.c index 668f00144e..3049620854 100644 --- a/tests/cpu-plug-test.c +++ b/tests/cpu-plug-test.c @@ -77,18 +77,19 @@ static void test_plug_with_device_add_x86(gconstpointer data) const PlugTestData *td = data; char *args; unsigned int s, c, t; + QTestState *qts; args = g_strdup_printf("-machine %s -cpu %s " "-smp 1,sockets=%u,cores=%u,threads=%u,maxcpus=%u", td->machine, td->cpu_model, td->sockets, td->cores, td->threads, td->maxcpus); - qtest_start(args); + qts = qtest_init(args); for (s = 1; s < td->sockets; s++) { for (c = 0; c < td->cores; c++) { for (t = 0; t < td->threads; t++) { char *id = g_strdup_printf("id-%i-%i-%i", s, c, t); - qtest_qmp_device_add(td->device_model, id, + qtest_qmp_device_add(qts, td->device_model, id, "{'socket-id':%u, 'core-id':%u," " 'thread-id':%u}", s, c, t); @@ -97,7 +98,7 @@ static void test_plug_with_device_add_x86(gconstpointer data) } } - qtest_end(); + qtest_quit(qts); g_free(args); } @@ -106,20 +107,22 @@ static void test_plug_with_device_add_coreid(gconstpointer data) const PlugTestData *td = data; char *args; unsigned int c; + QTestState *qts; args = g_strdup_printf("-machine %s -cpu %s " "-smp 1,sockets=%u,cores=%u,threads=%u,maxcpus=%u", td->machine, td->cpu_model, td->sockets, td->cores, td->threads, td->maxcpus); - qtest_start(args); + qts = qtest_init(args); for (c = 1; c < td->cores; c++) { char *id = g_strdup_printf("id-%i", c); - qtest_qmp_device_add(td->device_model, id, "{'core-id':%u}", c); + qtest_qmp_device_add(qts, td->device_model, id, + "{'core-id':%u}", c); g_free(id); } - qtest_end(); + qtest_quit(qts); g_free(args); } diff --git a/tests/drive_del-test.c b/tests/drive_del-test.c index b56b223fc2..5f8839b232 100644 --- a/tests/drive_del-test.c +++ b/tests/drive_del-test.c @@ -121,7 +121,8 @@ static void test_drive_del_device_del(void) QTestState *qts; /* Start with a drive used by a device that unplugs instantaneously */ - qts = qtest_initf("-drive if=none,id=drive0,file=null-co://,format=raw" + qts = qtest_initf("-drive if=none,id=drive0,file=null-co://," + "file.read-zeroes=on,format=raw" " -device virtio-scsi-%s" " -device scsi-hd,drive=drive0,id=dev0", qvirtio_get_dev_type()); diff --git a/tests/e1000e-test.c b/tests/e1000e-test.c index 445787a7e4..93628c588d 100644 --- a/tests/e1000e-test.c +++ b/tests/e1000e-test.c @@ -235,7 +235,7 @@ static void test_e1000e_hotplug(void *obj, void *data, QGuestAllocator * alloc) { QTestState *qts = global_qtest; /* TODO: get rid of global_qtest here */ - qtest_qmp_device_add("e1000e", "e1000e_net", "{'addr': '0x06'}"); + qtest_qmp_device_add(qts, "e1000e", "e1000e_net", "{'addr': '0x06'}"); qpci_unplug_acpi_device_test(qts, "e1000e_net", 0x06); } diff --git a/tests/ivshmem-test.c b/tests/ivshmem-test.c index a467b8c03d..b76457948b 100644 --- a/tests/ivshmem-test.c +++ b/tests/ivshmem-test.c @@ -389,7 +389,7 @@ static void test_ivshmem_hotplug(void) qts = qtest_init("-object memory-backend-ram,size=1M,id=mb1"); global_qtest = qts; /* TODO: Get rid of global_qtest here */ - qtest_qmp_device_add("ivshmem-plain", "iv1", + qtest_qmp_device_add(qts, "ivshmem-plain", "iv1", "{'addr': %s, 'memdev': 'mb1'}", stringify(PCI_SLOT_HP)); if (strcmp(arch, "ppc64") != 0) { diff --git a/tests/libqos/usb.c b/tests/libqos/usb.c index 49e2f4bc0a..d7a9cb3c72 100644 --- a/tests/libqos/usb.c +++ b/tests/libqos/usb.c @@ -37,20 +37,20 @@ void uhci_port_test(struct qhc *hc, int port, uint16_t expect) g_assert((value & mask) == (expect & mask)); } -void usb_test_hotplug(const char *hcd_id, const char *port, +void usb_test_hotplug(QTestState *qts, const char *hcd_id, const char *port, void (*port_check)(void)) { char *id = g_strdup_printf("usbdev%s", port); char *bus = g_strdup_printf("%s.0", hcd_id); - qtest_qmp_device_add("usb-tablet", id, "{'port': %s, 'bus': %s}", + qtest_qmp_device_add(qts, "usb-tablet", id, "{'port': %s, 'bus': %s}", port, bus); if (port_check) { port_check(); } - qtest_qmp_device_del(id); + qtest_qmp_device_del(qts, id); g_free(bus); g_free(id); diff --git a/tests/libqos/usb.h b/tests/libqos/usb.h index c506418a13..eeced39a2f 100644 --- a/tests/libqos/usb.h +++ b/tests/libqos/usb.h @@ -13,6 +13,6 @@ void qusb_pci_init_one(QPCIBus *pcibus, struct qhc *hc, void uhci_port_test(struct qhc *hc, int port, uint16_t expect); void uhci_deinit(struct qhc *hc); -void usb_test_hotplug(const char *bus_name, const char *port, +void usb_test_hotplug(QTestState *qts, const char *bus_name, const char *port, void (*port_check)(void)); #endif diff --git a/tests/libqos/virtio-net.c b/tests/libqos/virtio-net.c index 66405b646e..6567beb553 100644 --- a/tests/libqos/virtio-net.c +++ b/tests/libqos/virtio-net.c @@ -53,6 +53,7 @@ static void virtio_net_setup(QVirtioNet *interface) } else { interface->n_queues = 2; } + interface->n_queues++; /* Account for the ctrl queue */ interface->queues = g_new(QVirtQueue *, interface->n_queues); for (i = 0; i < interface->n_queues; i++) { diff --git a/tests/libqos/virtio-net.h b/tests/libqos/virtio-net.h index a5697d7326..855c67d00f 100644 --- a/tests/libqos/virtio-net.h +++ b/tests/libqos/virtio-net.h @@ -29,7 +29,7 @@ typedef struct QVirtioNetDevice QVirtioNetDevice; struct QVirtioNet { QVirtioDevice *vdev; - int n_queues; + int n_queues; /* total number of virtqueues (rx, tx, ctrl) */ QVirtQueue **queues; }; diff --git a/tests/libqos/virtio-pci.c b/tests/libqos/virtio-pci.c index a622ca26ca..3f55c047a0 100644 --- a/tests/libqos/virtio-pci.c +++ b/tests/libqos/virtio-pci.c @@ -138,9 +138,9 @@ static bool qvirtio_pci_get_queue_isr_status(QVirtioDevice *d, QVirtQueue *vq) /* No ISR checking should be done if masked, but read anyway */ return qpci_msix_pending(dev->pdev, vqpci->msix_entry); } else { - data = readl(vqpci->msix_addr); + data = qtest_readl(dev->pdev->bus->qts, vqpci->msix_addr); if (data == vqpci->msix_data) { - writel(vqpci->msix_addr, 0); + qtest_writel(dev->pdev->bus->qts, vqpci->msix_addr, 0); return true; } else { return false; @@ -162,9 +162,9 @@ static bool qvirtio_pci_get_config_isr_status(QVirtioDevice *d) /* No ISR checking should be done if masked, but read anyway */ return qpci_msix_pending(dev->pdev, dev->config_msix_entry); } else { - data = readl(dev->config_msix_addr); + data = qtest_readl(dev->pdev->bus->qts, dev->config_msix_addr); if (data == dev->config_msix_data) { - writel(dev->config_msix_addr, 0); + qtest_writel(dev->pdev->bus->qts, dev->config_msix_addr, 0); return true; } else { return false; diff --git a/tests/libqos/virtio-scsi.c b/tests/libqos/virtio-scsi.c index 94842ec3fa..de739bec5f 100644 --- a/tests/libqos/virtio-scsi.c +++ b/tests/libqos/virtio-scsi.c @@ -95,7 +95,8 @@ static void virtio_scsi_register_nodes(void) }; QOSGraphEdgeOptions opts = { - .before_cmd_line = "-drive id=drv0,if=none,file=null-co://,format=raw", + .before_cmd_line = "-drive id=drv0,if=none,file=null-co://," + "file.read-zeroes=on,format=raw", .after_cmd_line = "-device scsi-hd,bus=vs0.0,drive=drv0", }; diff --git a/tests/libqos/virtio.c b/tests/libqos/virtio.c index b4c01dc0c1..91ce06954b 100644 --- a/tests/libqos/virtio.c +++ b/tests/libqos/virtio.c @@ -101,7 +101,7 @@ void qvirtio_wait_queue_isr(QVirtioDevice *d, * The virtqueue interrupt must not be raised, making this useful for testing * event_index functionality. */ -uint8_t qvirtio_wait_status_byte_no_isr(QVirtioDevice *d, +uint8_t qvirtio_wait_status_byte_no_isr(QTestState *qts, QVirtioDevice *d, QVirtQueue *vq, uint64_t addr, gint64 timeout_us) @@ -126,7 +126,7 @@ uint8_t qvirtio_wait_status_byte_no_isr(QVirtioDevice *d, * * This function waits for the next completed request on the used ring. */ -void qvirtio_wait_used_elem(QVirtioDevice *d, +void qvirtio_wait_used_elem(QTestState *qts, QVirtioDevice *d, QVirtQueue *vq, uint32_t desc_idx, uint32_t *len, @@ -140,7 +140,7 @@ void qvirtio_wait_used_elem(QVirtioDevice *d, clock_step(100); if (d->bus->get_queue_isr_status(d, vq) && - qvirtqueue_get_buf(vq, &got_desc_idx, len)) { + qvirtqueue_get_buf(qts, vq, &got_desc_idx, len)) { g_assert_cmpint(got_desc_idx, ==, desc_idx); return; } @@ -193,8 +193,9 @@ void qvring_init(QTestState *qts, const QGuestAllocator *alloc, QVirtQueue *vq, 0); } -QVRingIndirectDesc *qvring_indirect_desc_setup(QVirtioDevice *d, - QGuestAllocator *alloc, uint16_t elem) +QVRingIndirectDesc *qvring_indirect_desc_setup(QTestState *qs, QVirtioDevice *d, + QGuestAllocator *alloc, + uint16_t elem) { int i; QVRingIndirectDesc *indirect = g_malloc(sizeof(*indirect)); @@ -205,41 +206,41 @@ QVRingIndirectDesc *qvring_indirect_desc_setup(QVirtioDevice *d, for (i = 0; i < elem - 1; ++i) { /* indirect->desc[i].addr */ - writeq(indirect->desc + (16 * i), 0); + qtest_writeq(qs, indirect->desc + (16 * i), 0); /* indirect->desc[i].flags */ - writew(indirect->desc + (16 * i) + 12, VRING_DESC_F_NEXT); + qtest_writew(qs, indirect->desc + (16 * i) + 12, VRING_DESC_F_NEXT); /* indirect->desc[i].next */ - writew(indirect->desc + (16 * i) + 14, i + 1); + qtest_writew(qs, indirect->desc + (16 * i) + 14, i + 1); } return indirect; } -void qvring_indirect_desc_add(QVRingIndirectDesc *indirect, uint64_t data, - uint32_t len, bool write) +void qvring_indirect_desc_add(QTestState *qts, QVRingIndirectDesc *indirect, + uint64_t data, uint32_t len, bool write) { uint16_t flags; g_assert_cmpint(indirect->index, <, indirect->elem); - flags = readw(indirect->desc + (16 * indirect->index) + 12); + flags = qtest_readw(qts, indirect->desc + (16 * indirect->index) + 12); if (write) { flags |= VRING_DESC_F_WRITE; } /* indirect->desc[indirect->index].addr */ - writeq(indirect->desc + (16 * indirect->index), data); + qtest_writeq(qts, indirect->desc + (16 * indirect->index), data); /* indirect->desc[indirect->index].len */ - writel(indirect->desc + (16 * indirect->index) + 8, len); + qtest_writel(qts, indirect->desc + (16 * indirect->index) + 8, len); /* indirect->desc[indirect->index].flags */ - writew(indirect->desc + (16 * indirect->index) + 12, flags); + qtest_writew(qts, indirect->desc + (16 * indirect->index) + 12, flags); indirect->index++; } -uint32_t qvirtqueue_add(QVirtQueue *vq, uint64_t data, uint32_t len, bool write, - bool next) +uint32_t qvirtqueue_add(QTestState *qts, QVirtQueue *vq, uint64_t data, + uint32_t len, bool write, bool next) { uint16_t flags = 0; vq->num_free--; @@ -253,16 +254,17 @@ uint32_t qvirtqueue_add(QVirtQueue *vq, uint64_t data, uint32_t len, bool write, } /* vq->desc[vq->free_head].addr */ - writeq(vq->desc + (16 * vq->free_head), data); + qtest_writeq(qts, vq->desc + (16 * vq->free_head), data); /* vq->desc[vq->free_head].len */ - writel(vq->desc + (16 * vq->free_head) + 8, len); + qtest_writel(qts, vq->desc + (16 * vq->free_head) + 8, len); /* vq->desc[vq->free_head].flags */ - writew(vq->desc + (16 * vq->free_head) + 12, flags); + qtest_writew(qts, vq->desc + (16 * vq->free_head) + 12, flags); return vq->free_head++; /* Return and increase, in this order */ } -uint32_t qvirtqueue_add_indirect(QVirtQueue *vq, QVRingIndirectDesc *indirect) +uint32_t qvirtqueue_add_indirect(QTestState *qts, QVirtQueue *vq, + QVRingIndirectDesc *indirect) { g_assert(vq->indirect); g_assert_cmpint(vq->size, >=, indirect->elem); @@ -271,34 +273,36 @@ uint32_t qvirtqueue_add_indirect(QVirtQueue *vq, QVRingIndirectDesc *indirect) vq->num_free--; /* vq->desc[vq->free_head].addr */ - writeq(vq->desc + (16 * vq->free_head), indirect->desc); + qtest_writeq(qts, vq->desc + (16 * vq->free_head), indirect->desc); /* vq->desc[vq->free_head].len */ - writel(vq->desc + (16 * vq->free_head) + 8, + qtest_writel(qts, vq->desc + (16 * vq->free_head) + 8, sizeof(struct vring_desc) * indirect->elem); /* vq->desc[vq->free_head].flags */ - writew(vq->desc + (16 * vq->free_head) + 12, VRING_DESC_F_INDIRECT); + qtest_writew(qts, vq->desc + (16 * vq->free_head) + 12, + VRING_DESC_F_INDIRECT); return vq->free_head++; /* Return and increase, in this order */ } -void qvirtqueue_kick(QVirtioDevice *d, QVirtQueue *vq, uint32_t free_head) +void qvirtqueue_kick(QTestState *qts, QVirtioDevice *d, QVirtQueue *vq, + uint32_t free_head) { /* vq->avail->idx */ - uint16_t idx = readw(vq->avail + 2); + uint16_t idx = qtest_readw(qts, vq->avail + 2); /* vq->used->flags */ uint16_t flags; /* vq->used->avail_event */ uint16_t avail_event; /* vq->avail->ring[idx % vq->size] */ - writew(vq->avail + 4 + (2 * (idx % vq->size)), free_head); + qtest_writew(qts, vq->avail + 4 + (2 * (idx % vq->size)), free_head); /* vq->avail->idx */ - writew(vq->avail + 2, idx + 1); + qtest_writew(qts, vq->avail + 2, idx + 1); /* Must read after idx is updated */ - flags = readw(vq->avail); - avail_event = readw(vq->used + 4 + - sizeof(struct vring_used_elem) * vq->size); + flags = qtest_readw(qts, vq->avail); + avail_event = qtest_readw(qts, vq->used + 4 + + sizeof(struct vring_used_elem) * vq->size); /* < 1 because we add elements to avail queue one by one */ if ((flags & VRING_USED_F_NO_NOTIFY) == 0 && @@ -317,12 +321,13 @@ void qvirtqueue_kick(QVirtioDevice *d, QVirtQueue *vq, uint32_t free_head) * * Returns: true if an element was ready, false otherwise */ -bool qvirtqueue_get_buf(QVirtQueue *vq, uint32_t *desc_idx, uint32_t *len) +bool qvirtqueue_get_buf(QTestState *qts, QVirtQueue *vq, uint32_t *desc_idx, + uint32_t *len) { uint16_t idx; - uint64_t elem_addr; + uint64_t elem_addr, addr; - idx = readw(vq->used + offsetof(struct vring_used, idx)); + idx = qtest_readw(qts, vq->used + offsetof(struct vring_used, idx)); if (idx == vq->last_used_idx) { return false; } @@ -333,23 +338,25 @@ bool qvirtqueue_get_buf(QVirtQueue *vq, uint32_t *desc_idx, uint32_t *len) sizeof(struct vring_used_elem); if (desc_idx) { - *desc_idx = readl(elem_addr + offsetof(struct vring_used_elem, id)); + addr = elem_addr + offsetof(struct vring_used_elem, id); + *desc_idx = qtest_readl(qts, addr); } if (len) { - *len = readw(elem_addr + offsetof(struct vring_used_elem, len)); + addr = elem_addr + offsetof(struct vring_used_elem, len); + *len = qtest_readw(qts, addr); } vq->last_used_idx++; return true; } -void qvirtqueue_set_used_event(QVirtQueue *vq, uint16_t idx) +void qvirtqueue_set_used_event(QTestState *qts, QVirtQueue *vq, uint16_t idx) { g_assert(vq->event); /* vq->avail->used_event */ - writew(vq->avail + 4 + (2 * vq->size), idx); + qtest_writew(qts, vq->avail + 4 + (2 * vq->size), idx); } void qvirtio_start_device(QVirtioDevice *vdev) diff --git a/tests/libqos/virtio.h b/tests/libqos/virtio.h index 7b97f5e567..037176dbd8 100644 --- a/tests/libqos/virtio.h +++ b/tests/libqos/virtio.h @@ -114,11 +114,11 @@ void qvirtio_set_driver_ok(QVirtioDevice *d); void qvirtio_wait_queue_isr(QVirtioDevice *d, QVirtQueue *vq, gint64 timeout_us); -uint8_t qvirtio_wait_status_byte_no_isr(QVirtioDevice *d, +uint8_t qvirtio_wait_status_byte_no_isr(QTestState *qts, QVirtioDevice *d, QVirtQueue *vq, uint64_t addr, gint64 timeout_us); -void qvirtio_wait_used_elem(QVirtioDevice *d, +void qvirtio_wait_used_elem(QTestState *qts, QVirtioDevice *d, QVirtQueue *vq, uint32_t desc_idx, uint32_t *len, @@ -131,17 +131,21 @@ void qvirtqueue_cleanup(const QVirtioBus *bus, QVirtQueue *vq, void qvring_init(QTestState *qts, const QGuestAllocator *alloc, QVirtQueue *vq, uint64_t addr); -QVRingIndirectDesc *qvring_indirect_desc_setup(QVirtioDevice *d, - QGuestAllocator *alloc, uint16_t elem); -void qvring_indirect_desc_add(QVRingIndirectDesc *indirect, uint64_t data, - uint32_t len, bool write); -uint32_t qvirtqueue_add(QVirtQueue *vq, uint64_t data, uint32_t len, bool write, - bool next); -uint32_t qvirtqueue_add_indirect(QVirtQueue *vq, QVRingIndirectDesc *indirect); -void qvirtqueue_kick(QVirtioDevice *d, QVirtQueue *vq, uint32_t free_head); -bool qvirtqueue_get_buf(QVirtQueue *vq, uint32_t *desc_idx, uint32_t *len); - -void qvirtqueue_set_used_event(QVirtQueue *vq, uint16_t idx); +QVRingIndirectDesc *qvring_indirect_desc_setup(QTestState *qs, QVirtioDevice *d, + QGuestAllocator *alloc, + uint16_t elem); +void qvring_indirect_desc_add(QTestState *qts, QVRingIndirectDesc *indirect, + uint64_t data, uint32_t len, bool write); +uint32_t qvirtqueue_add(QTestState *qts, QVirtQueue *vq, uint64_t data, + uint32_t len, bool write, bool next); +uint32_t qvirtqueue_add_indirect(QTestState *qts, QVirtQueue *vq, + QVRingIndirectDesc *indirect); +void qvirtqueue_kick(QTestState *qts, QVirtioDevice *d, QVirtQueue *vq, + uint32_t free_head); +bool qvirtqueue_get_buf(QTestState *qts, QVirtQueue *vq, uint32_t *desc_idx, + uint32_t *len); + +void qvirtqueue_set_used_event(QTestState *qts, QVirtQueue *vq, uint16_t idx); void qvirtio_start_device(QVirtioDevice *vdev); diff --git a/tests/libqtest.c b/tests/libqtest.c index 3c5c3f49d8..eb971d0d11 100644 --- a/tests/libqtest.c +++ b/tests/libqtest.c @@ -1111,13 +1111,13 @@ QDict *qmp(const char *fmt, ...) return response; } -void qmp_assert_success(const char *fmt, ...) +void qtest_qmp_assert_success(QTestState *qts, const char *fmt, ...) { va_list ap; QDict *response; va_start(ap, fmt); - response = qtest_vqmp(global_qtest, fmt, ap); + response = qtest_vqmp(qts, fmt, ap); va_end(ap); g_assert(response); @@ -1130,17 +1130,6 @@ void qmp_assert_success(const char *fmt, ...) qobject_unref(response); } -char *hmp(const char *fmt, ...) -{ - va_list ap; - char *ret; - - va_start(ap, fmt); - ret = qtest_vhmp(global_qtest, fmt, ap); - va_end(ap); - return ret; -} - bool qtest_big_endian(QTestState *s) { return s->big_endian; @@ -1200,9 +1189,10 @@ void qtest_cb_for_every_machine(void (*cb)(const char *machine), QObject *qobj; QString *qstr; const char *mname; + QTestState *qts; - qtest_start("-machine none"); - response = qmp("{ 'execute': 'query-machines' }"); + qts = qtest_init("-machine none"); + response = qtest_qmp(qts, "{ 'execute': 'query-machines' }"); g_assert(response); list = qdict_get_qlist(response, "return"); g_assert(list); @@ -1220,7 +1210,7 @@ void qtest_cb_for_every_machine(void (*cb)(const char *machine), } } - qtest_end(); + qtest_quit(qts); qobject_unref(response); } @@ -1256,7 +1246,7 @@ QDict *qtest_qmp_receive_success(QTestState *s, /* * Generic hot-plugging test via the device_add QMP command. */ -void qtest_qmp_device_add(const char *driver, const char *id, +void qtest_qmp_device_add(QTestState *qts, const char *driver, const char *id, const char *fmt, ...) { QDict *args, *response; @@ -1270,7 +1260,8 @@ void qtest_qmp_device_add(const char *driver, const char *id, qdict_put_str(args, "driver", driver); qdict_put_str(args, "id", id); - response = qmp("{'execute': 'device_add', 'arguments': %p}", args); + response = qtest_qmp(qts, "{'execute': 'device_add', 'arguments': %p}", + args); g_assert(response); g_assert(!qdict_haskey(response, "event")); /* We don't expect any events */ g_assert(!qdict_haskey(response, "error")); @@ -1303,19 +1294,17 @@ static void device_deleted_cb(void *opaque, const char *name, QDict *data) * * But the order of arrival may vary - so we've got to detect both. */ -void qtest_qmp_device_del(const char *id) +void qtest_qmp_device_del(QTestState *qts, const char *id) { bool got_event = false; QDict *rsp; - qtest_qmp_send(global_qtest, - "{'execute': 'device_del', 'arguments': {'id': %s}}", + qtest_qmp_send(qts, "{'execute': 'device_del', 'arguments': {'id': %s}}", id); - rsp = qtest_qmp_receive_success(global_qtest, device_deleted_cb, - &got_event); + rsp = qtest_qmp_receive_success(qts, device_deleted_cb, &got_event); qobject_unref(rsp); if (!got_event) { - rsp = qtest_qmp_receive(global_qtest); + rsp = qtest_qmp_receive(qts); g_assert_cmpstr(qdict_get_try_str(rsp, "event"), ==, "DEVICE_DELETED"); qobject_unref(rsp); diff --git a/tests/libqtest.h b/tests/libqtest.h index cadf1d4a03..7833148358 100644 --- a/tests/libqtest.h +++ b/tests/libqtest.h @@ -666,7 +666,8 @@ static inline void qtest_end(void) QDict *qmp(const char *fmt, ...) GCC_FMT_ATTR(1, 2); /** - * qmp_assert_success: + * qtest_qmp_assert_success: + * @qts: QTestState instance to operate on * @fmt...: QMP message to send to qemu, formatted like * qobject_from_jsonf_nofail(). See parse_escape() for what's * supported after '%'. @@ -674,7 +675,8 @@ QDict *qmp(const char *fmt, ...) GCC_FMT_ATTR(1, 2); * Sends a QMP message to QEMU and asserts that a 'return' key is present in * the response. */ -void qmp_assert_success(const char *fmt, ...) GCC_FMT_ATTR(1, 2); +void qtest_qmp_assert_success(QTestState *qts, const char *fmt, ...) + GCC_FMT_ATTR(2, 3); /* * qmp_eventwait: @@ -688,16 +690,6 @@ static inline void qmp_eventwait(const char *event) } /** - * hmp: - * @fmt...: HMP command to send to QEMU, formats arguments like sprintf(). - * - * Send HMP command to QEMU via QMP's human-monitor-command. - * - * Returns: the command's output. The caller should g_free() it. - */ -char *hmp(const char *fmt, ...) GCC_FMT_ATTR(1, 2); - -/** * get_irq: * @num: Interrupt to observe. * @@ -956,6 +948,7 @@ void qtest_cb_for_every_machine(void (*cb)(const char *machine), /** * qtest_qmp_device_add: + * @qts: QTestState instance to operate on * @driver: Name of the device that should be added * @id: Identification string * @fmt...: QMP message to send to qemu, formatted like @@ -964,16 +957,17 @@ void qtest_cb_for_every_machine(void (*cb)(const char *machine), * * Generic hot-plugging test via the device_add QMP command. */ -void qtest_qmp_device_add(const char *driver, const char *id, const char *fmt, - ...) GCC_FMT_ATTR(3, 4); +void qtest_qmp_device_add(QTestState *qts, const char *driver, const char *id, + const char *fmt, ...) GCC_FMT_ATTR(4, 5); /** * qtest_qmp_device_del: + * @qts: QTestState instance to operate on * @id: Identification string * * Generic hot-unplugging test via the device_del QMP command. */ -void qtest_qmp_device_del(const char *id); +void qtest_qmp_device_del(QTestState *qts, const char *id); /** * qmp_rsp_is_err: diff --git a/tests/megasas-test.c b/tests/megasas-test.c index c3e4ab6595..d6796b9bd7 100644 --- a/tests/megasas-test.c +++ b/tests/megasas-test.c @@ -75,7 +75,8 @@ static void megasas_register_nodes(void) { QOSGraphEdgeOptions opts = { .extra_device_opts = "addr=04.0,id=scsi0", - .before_cmd_line = "-drive id=drv0,if=none,file=null-co://,format=raw", + .before_cmd_line = "-drive id=drv0,if=none,file=null-co://," + "file.read-zeroes=on,format=raw", .after_cmd_line = "-device scsi-hd,bus=scsi0.0,drive=drv0", }; diff --git a/tests/nvme-test.c b/tests/nvme-test.c index 505299324b..ff0442150c 100644 --- a/tests/nvme-test.c +++ b/tests/nvme-test.c @@ -70,7 +70,8 @@ static void nvme_register_nodes(void) { QOSGraphEdgeOptions opts = { .extra_device_opts = "addr=04.0,drive=drv0,serial=foo", - .before_cmd_line = "-drive id=drv0,if=none,file=null-co://,format=raw", + .before_cmd_line = "-drive id=drv0,if=none,file=null-co://," + "file.read-zeroes=on,format=raw", }; add_qpci_address(&opts, &(QPCIAddress) { .devfn = QPCI_DEVFN(4, 0) }); diff --git a/tests/qmp-test.c b/tests/qmp-test.c index 48a4fa791a..1b0eb69832 100644 --- a/tests/qmp-test.c +++ b/tests/qmp-test.c @@ -187,7 +187,7 @@ static void send_cmd_that_blocks(QTestState *s, const char *id) " 'arguments': {" " 'driver': 'blkdebug', 'node-name': %s," " 'config': %s," - " 'image': { 'driver': 'null-co' } } }", + " 'image': { 'driver': 'null-co', 'read-zeroes': true } } }", id, id, fifo_name); } diff --git a/tests/test-blockjob-txn.c b/tests/test-blockjob-txn.c index 86606f92b3..7da9216d5b 100644 --- a/tests/test-blockjob-txn.c +++ b/tests/test-blockjob-txn.c @@ -15,6 +15,7 @@ #include "qemu/main-loop.h" #include "block/blockjob_int.h" #include "sysemu/block-backend.h" +#include "qapi/qmp/qdict.h" typedef struct { BlockJob common; @@ -96,7 +97,9 @@ static BlockJob *test_block_job_start(unsigned int iterations, data = g_new0(TestBlockJobCBData, 1); - bs = bdrv_open("null-co://", NULL, NULL, 0, &error_abort); + QDict *opt = qdict_new(); + qdict_put_str(opt, "file.read-zeroes", "on"); + bs = bdrv_open("null-co://", NULL, opt, 0, &error_abort); g_assert_nonnull(bs); snprintf(job_id, sizeof(job_id), "job%u", counter++); diff --git a/tests/test-blockjob.c b/tests/test-blockjob.c index b33f899873..68a0819495 100644 --- a/tests/test-blockjob.c +++ b/tests/test-blockjob.c @@ -15,6 +15,7 @@ #include "qemu/main-loop.h" #include "block/blockjob_int.h" #include "sysemu/block-backend.h" +#include "qapi/qmp/qdict.h" static const BlockJobDriver test_block_job_driver = { .job_driver = { @@ -71,7 +72,9 @@ static BlockBackend *create_blk(const char *name) BlockBackend *blk = blk_new(qemu_get_aio_context(), 0, BLK_PERM_ALL); BlockDriverState *bs; - bs = bdrv_open("null-co://", NULL, NULL, 0, &error_abort); + QDict *opt = qdict_new(); + qdict_put_str(opt, "file.read-zeroes", "on"); + bs = bdrv_open("null-co://", NULL, opt, 0, &error_abort); g_assert_nonnull(bs); blk_insert_bs(blk, bs, &error_abort); diff --git a/tests/usb-hcd-ohci-test.c b/tests/usb-hcd-ohci-test.c index c12b892085..0cd73b7363 100644 --- a/tests/usb-hcd-ohci-test.c +++ b/tests/usb-hcd-ohci-test.c @@ -23,7 +23,7 @@ struct QOHCI_PCI { static void test_ohci_hotplug(void *obj, void *data, QGuestAllocator *alloc) { - usb_test_hotplug("ohci", "1", NULL); + usb_test_hotplug(global_qtest, "ohci", "1", NULL); } static void *ohci_pci_get_driver(void *obj, const char *interface) diff --git a/tests/usb-hcd-uhci-test.c b/tests/usb-hcd-uhci-test.c index a119d6d5c8..2eef8e3d1c 100644 --- a/tests/usb-hcd-uhci-test.c +++ b/tests/usb-hcd-uhci-test.c @@ -43,21 +43,24 @@ static void test_port_2(void) static void test_uhci_hotplug(void) { - usb_test_hotplug("uhci", "2", test_port_2); + usb_test_hotplug(global_qtest, "uhci", "2", test_port_2); } static void test_usb_storage_hotplug(void) { - qtest_qmp_device_add("usb-storage", "usbdev0", "{'drive': 'drive0'}"); + QTestState *qts = global_qtest; - qtest_qmp_device_del("usbdev0"); + qtest_qmp_device_add(qts, "usb-storage", "usbdev0", "{'drive': 'drive0'}"); + + qtest_qmp_device_del(qts, "usbdev0"); } int main(int argc, char **argv) { const char *arch = qtest_get_arch(); const char *cmd = "-device piix3-usb-uhci,id=uhci,addr=1d.0" - " -drive id=drive0,if=none,file=null-co://,format=raw" + " -drive id=drive0,if=none,file=null-co://," + "file.read-zeroes=on,format=raw" " -device usb-tablet,bus=uhci.0,port=1"; int ret; diff --git a/tests/usb-hcd-xhci-test.c b/tests/usb-hcd-xhci-test.c index 9eb24b00e4..01845371f9 100644 --- a/tests/usb-hcd-xhci-test.c +++ b/tests/usb-hcd-xhci-test.c @@ -18,30 +18,34 @@ static void test_xhci_init(void) static void test_xhci_hotplug(void) { - usb_test_hotplug("xhci", "1", NULL); + usb_test_hotplug(global_qtest, "xhci", "1", NULL); } static void test_usb_uas_hotplug(void) { - qtest_qmp_device_add("usb-uas", "uas", "{}"); - qtest_qmp_device_add("scsi-hd", "scsihd", "{'drive': 'drive0'}"); + QTestState *qts = global_qtest; + + qtest_qmp_device_add(qts, "usb-uas", "uas", "{}"); + qtest_qmp_device_add(qts, "scsi-hd", "scsihd", "{'drive': 'drive0'}"); /* TODO: UAS HBA driver in libqos, to check that added disk is visible after BUS rescan */ - qtest_qmp_device_del("scsihd"); - qtest_qmp_device_del("uas"); + qtest_qmp_device_del(qts, "scsihd"); + qtest_qmp_device_del(qts, "uas"); } static void test_usb_ccid_hotplug(void) { - qtest_qmp_device_add("usb-ccid", "ccid", "{}"); - qtest_qmp_device_del("ccid"); + QTestState *qts = global_qtest; + + qtest_qmp_device_add(qts, "usb-ccid", "ccid", "{}"); + qtest_qmp_device_del(qts, "ccid"); /* check the device can be added again */ - qtest_qmp_device_add("usb-ccid", "ccid", "{}"); - qtest_qmp_device_del("ccid"); + qtest_qmp_device_add(qts, "usb-ccid", "ccid", "{}"); + qtest_qmp_device_del(qts, "ccid"); } int main(int argc, char **argv) @@ -56,7 +60,8 @@ int main(int argc, char **argv) qtest_add_func("/xhci/pci/hotplug/usb-ccid", test_usb_ccid_hotplug); qtest_start("-device nec-usb-xhci,id=xhci" - " -drive id=drive0,if=none,file=null-co://,format=raw"); + " -drive id=drive0,if=none,file=null-co://," + "file.read-zeroes=on,format=raw"); ret = g_test_run(); qtest_end(); diff --git a/tests/virtio-9p-test.c b/tests/virtio-9p-test.c index ac49bca991..30e6cf3e63 100644 --- a/tests/virtio-9p-test.c +++ b/tests/virtio-9p-test.c @@ -39,6 +39,7 @@ static void pci_config(void *obj, void *data, QGuestAllocator *t_alloc) #define P9_MAX_SIZE 4096 /* Max size of a T-message or R-message */ typedef struct { + QTestState *qts; QVirtio9P *v9p; uint16_t tag; uint64_t t_msg; @@ -52,7 +53,7 @@ typedef struct { static void v9fs_memwrite(P9Req *req, const void *addr, size_t len) { - memwrite(req->t_msg + req->t_off, addr, len); + qtest_memwrite(req->qts, req->t_msg + req->t_off, addr, len); req->t_off += len; } @@ -63,7 +64,7 @@ static void v9fs_memskip(P9Req *req, size_t len) static void v9fs_memread(P9Req *req, void *addr, size_t len) { - memread(req->r_msg + req->r_off, addr, len); + qtest_memread(req->qts, req->r_msg + req->r_off, addr, len); req->r_off += len; } @@ -158,6 +159,7 @@ static P9Req *v9fs_req_init(QVirtio9P *v9p, uint32_t size, uint8_t id, g_assert_cmpint(total_size, <=, P9_MAX_SIZE); + req->qts = global_qtest; req->v9p = v9p; req->t_size = total_size; req->t_msg = guest_alloc(alloc, req->t_size); @@ -171,10 +173,10 @@ static void v9fs_req_send(P9Req *req) QVirtio9P *v9p = req->v9p; req->r_msg = guest_alloc(alloc, P9_MAX_SIZE); - req->free_head = qvirtqueue_add(v9p->vq, req->t_msg, req->t_size, false, - true); - qvirtqueue_add(v9p->vq, req->r_msg, P9_MAX_SIZE, true, false); - qvirtqueue_kick(v9p->vdev, v9p->vq, req->free_head); + req->free_head = qvirtqueue_add(req->qts, v9p->vq, req->t_msg, req->t_size, + false, true); + qvirtqueue_add(req->qts, v9p->vq, req->r_msg, P9_MAX_SIZE, true, false); + qvirtqueue_kick(req->qts, v9p->vdev, v9p->vq, req->free_head); req->t_off = 0; } @@ -195,7 +197,7 @@ static void v9fs_req_wait_for_reply(P9Req *req, uint32_t *len) { QVirtio9P *v9p = req->v9p; - qvirtio_wait_used_elem(v9p->vdev, v9p->vq, req->free_head, len, + qvirtio_wait_used_elem(req->qts, v9p->vdev, v9p->vq, req->free_head, len, QVIRTIO_9P_TIMEOUT_US); } diff --git a/tests/virtio-blk-test.c b/tests/virtio-blk-test.c index 1b02714bc7..982ff1538c 100644 --- a/tests/virtio-blk-test.c +++ b/tests/virtio-blk-test.c @@ -123,6 +123,7 @@ static void test_basic(QVirtioDevice *dev, QGuestAllocator *alloc, uint32_t free_head; uint8_t status; char *data; + QTestState *qts = global_qtest; capacity = qvirtio_config_readq(dev, 0); @@ -149,13 +150,14 @@ static void test_basic(QVirtioDevice *dev, QGuestAllocator *alloc, g_free(req.data); - free_head = qvirtqueue_add(vq, req_addr, 16, false, true); - qvirtqueue_add(vq, req_addr + 16, 512, false, true); - qvirtqueue_add(vq, req_addr + 528, 1, true, false); + free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true); + qvirtqueue_add(qts, vq, req_addr + 16, 512, false, true); + qvirtqueue_add(qts, vq, req_addr + 528, 1, true, false); - qvirtqueue_kick(dev, vq, free_head); + qvirtqueue_kick(qts, dev, vq, free_head); - qvirtio_wait_used_elem(dev, vq, free_head, NULL, QVIRTIO_BLK_TIMEOUT_US); + qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL, + QVIRTIO_BLK_TIMEOUT_US); status = readb(req_addr + 528); g_assert_cmpint(status, ==, 0); @@ -171,13 +173,14 @@ static void test_basic(QVirtioDevice *dev, QGuestAllocator *alloc, g_free(req.data); - free_head = qvirtqueue_add(vq, req_addr, 16, false, true); - qvirtqueue_add(vq, req_addr + 16, 512, true, true); - qvirtqueue_add(vq, req_addr + 528, 1, true, false); + free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true); + qvirtqueue_add(qts, vq, req_addr + 16, 512, true, true); + qvirtqueue_add(qts, vq, req_addr + 528, 1, true, false); - qvirtqueue_kick(dev, vq, free_head); + qvirtqueue_kick(qts, dev, vq, free_head); - qvirtio_wait_used_elem(dev, vq, free_head, NULL, QVIRTIO_BLK_TIMEOUT_US); + qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL, + QVIRTIO_BLK_TIMEOUT_US); status = readb(req_addr + 528); g_assert_cmpint(status, ==, 0); @@ -206,13 +209,14 @@ static void test_basic(QVirtioDevice *dev, QGuestAllocator *alloc, req_addr = virtio_blk_request(alloc, dev, &req, sizeof(dwz_hdr)); - free_head = qvirtqueue_add(vq, req_addr, 16, false, true); - qvirtqueue_add(vq, req_addr + 16, sizeof(dwz_hdr), false, true); - qvirtqueue_add(vq, req_addr + 16 + sizeof(dwz_hdr), 1, true, false); + free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true); + qvirtqueue_add(qts, vq, req_addr + 16, sizeof(dwz_hdr), false, true); + qvirtqueue_add(qts, vq, req_addr + 16 + sizeof(dwz_hdr), 1, true, + false); - qvirtqueue_kick(dev, vq, free_head); + qvirtqueue_kick(qts, dev, vq, free_head); - qvirtio_wait_used_elem(dev, vq, free_head, NULL, + qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL, QVIRTIO_BLK_TIMEOUT_US); status = readb(req_addr + 16 + sizeof(dwz_hdr)); g_assert_cmpint(status, ==, 0); @@ -229,13 +233,13 @@ static void test_basic(QVirtioDevice *dev, QGuestAllocator *alloc, g_free(req.data); - free_head = qvirtqueue_add(vq, req_addr, 16, false, true); - qvirtqueue_add(vq, req_addr + 16, 512, true, true); - qvirtqueue_add(vq, req_addr + 528, 1, true, false); + free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true); + qvirtqueue_add(qts, vq, req_addr + 16, 512, true, true); + qvirtqueue_add(qts, vq, req_addr + 528, 1, true, false); - qvirtqueue_kick(dev, vq, free_head); + qvirtqueue_kick(qts, dev, vq, free_head); - qvirtio_wait_used_elem(dev, vq, free_head, NULL, + qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL, QVIRTIO_BLK_TIMEOUT_US); status = readb(req_addr + 528); g_assert_cmpint(status, ==, 0); @@ -263,13 +267,13 @@ static void test_basic(QVirtioDevice *dev, QGuestAllocator *alloc, req_addr = virtio_blk_request(alloc, dev, &req, sizeof(dwz_hdr)); - free_head = qvirtqueue_add(vq, req_addr, 16, false, true); - qvirtqueue_add(vq, req_addr + 16, sizeof(dwz_hdr), false, true); - qvirtqueue_add(vq, req_addr + 16 + sizeof(dwz_hdr), 1, true, false); + free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true); + qvirtqueue_add(qts, vq, req_addr + 16, sizeof(dwz_hdr), false, true); + qvirtqueue_add(qts, vq, req_addr + 16 + sizeof(dwz_hdr), 1, true, false); - qvirtqueue_kick(dev, vq, free_head); + qvirtqueue_kick(qts, dev, vq, free_head); - qvirtio_wait_used_elem(dev, vq, free_head, NULL, + qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL, QVIRTIO_BLK_TIMEOUT_US); status = readb(req_addr + 16 + sizeof(dwz_hdr)); g_assert_cmpint(status, ==, 0); @@ -290,11 +294,11 @@ static void test_basic(QVirtioDevice *dev, QGuestAllocator *alloc, g_free(req.data); - free_head = qvirtqueue_add(vq, req_addr, 528, false, true); - qvirtqueue_add(vq, req_addr + 528, 1, true, false); - qvirtqueue_kick(dev, vq, free_head); + free_head = qvirtqueue_add(qts, vq, req_addr, 528, false, true); + qvirtqueue_add(qts, vq, req_addr + 528, 1, true, false); + qvirtqueue_kick(qts, dev, vq, free_head); - qvirtio_wait_used_elem(dev, vq, free_head, NULL, + qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL, QVIRTIO_BLK_TIMEOUT_US); status = readb(req_addr + 528); g_assert_cmpint(status, ==, 0); @@ -311,12 +315,12 @@ static void test_basic(QVirtioDevice *dev, QGuestAllocator *alloc, g_free(req.data); - free_head = qvirtqueue_add(vq, req_addr, 16, false, true); - qvirtqueue_add(vq, req_addr + 16, 513, true, false); + free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true); + qvirtqueue_add(qts, vq, req_addr + 16, 513, true, false); - qvirtqueue_kick(dev, vq, free_head); + qvirtqueue_kick(qts, dev, vq, free_head); - qvirtio_wait_used_elem(dev, vq, free_head, NULL, + qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL, QVIRTIO_BLK_TIMEOUT_US); status = readb(req_addr + 528); g_assert_cmpint(status, ==, 0); @@ -353,6 +357,7 @@ static void indirect(void *obj, void *u_data, QGuestAllocator *t_alloc) uint32_t free_head; uint8_t status; char *data; + QTestState *qts = global_qtest; capacity = qvirtio_config_readq(dev, 0); g_assert_cmpint(capacity, ==, TEST_IMAGE_SIZE / 512); @@ -378,13 +383,13 @@ static void indirect(void *obj, void *u_data, QGuestAllocator *t_alloc) g_free(req.data); - indirect = qvring_indirect_desc_setup(dev, t_alloc, 2); - qvring_indirect_desc_add(indirect, req_addr, 528, false); - qvring_indirect_desc_add(indirect, req_addr + 528, 1, true); - free_head = qvirtqueue_add_indirect(vq, indirect); - qvirtqueue_kick(dev, vq, free_head); + indirect = qvring_indirect_desc_setup(qts, dev, t_alloc, 2); + qvring_indirect_desc_add(qts, indirect, req_addr, 528, false); + qvring_indirect_desc_add(qts, indirect, req_addr + 528, 1, true); + free_head = qvirtqueue_add_indirect(qts, vq, indirect); + qvirtqueue_kick(qts, dev, vq, free_head); - qvirtio_wait_used_elem(dev, vq, free_head, NULL, + qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL, QVIRTIO_BLK_TIMEOUT_US); status = readb(req_addr + 528); g_assert_cmpint(status, ==, 0); @@ -403,13 +408,13 @@ static void indirect(void *obj, void *u_data, QGuestAllocator *t_alloc) g_free(req.data); - indirect = qvring_indirect_desc_setup(dev, t_alloc, 2); - qvring_indirect_desc_add(indirect, req_addr, 16, false); - qvring_indirect_desc_add(indirect, req_addr + 16, 513, true); - free_head = qvirtqueue_add_indirect(vq, indirect); - qvirtqueue_kick(dev, vq, free_head); + indirect = qvring_indirect_desc_setup(qts, dev, t_alloc, 2); + qvring_indirect_desc_add(qts, indirect, req_addr, 16, false); + qvring_indirect_desc_add(qts, indirect, req_addr + 16, 513, true); + free_head = qvirtqueue_add_indirect(qts, vq, indirect); + qvirtqueue_kick(qts, dev, vq, free_head); - qvirtio_wait_used_elem(dev, vq, free_head, NULL, + qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL, QVIRTIO_BLK_TIMEOUT_US); status = readb(req_addr + 528); g_assert_cmpint(status, ==, 0); @@ -461,6 +466,7 @@ static void msix(void *obj, void *u_data, QGuestAllocator *t_alloc) char *data; QOSGraphObject *blk_object = obj; QPCIDevice *pci_dev = blk_object->get_driver(blk_object, "pci-device"); + QTestState *qts = global_qtest; if (qpci_check_buggy_msi(pci_dev)) { return; @@ -504,12 +510,12 @@ static void msix(void *obj, void *u_data, QGuestAllocator *t_alloc) g_free(req.data); - free_head = qvirtqueue_add(vq, req_addr, 16, false, true); - qvirtqueue_add(vq, req_addr + 16, 512, false, true); - qvirtqueue_add(vq, req_addr + 528, 1, true, false); - qvirtqueue_kick(dev, vq, free_head); + free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true); + qvirtqueue_add(qts, vq, req_addr + 16, 512, false, true); + qvirtqueue_add(qts, vq, req_addr + 528, 1, true, false); + qvirtqueue_kick(qts, dev, vq, free_head); - qvirtio_wait_used_elem(dev, vq, free_head, NULL, + qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL, QVIRTIO_BLK_TIMEOUT_US); status = readb(req_addr + 528); @@ -527,14 +533,14 @@ static void msix(void *obj, void *u_data, QGuestAllocator *t_alloc) g_free(req.data); - free_head = qvirtqueue_add(vq, req_addr, 16, false, true); - qvirtqueue_add(vq, req_addr + 16, 512, true, true); - qvirtqueue_add(vq, req_addr + 528, 1, true, false); + free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true); + qvirtqueue_add(qts, vq, req_addr + 16, 512, true, true); + qvirtqueue_add(qts, vq, req_addr + 528, 1, true, false); - qvirtqueue_kick(dev, vq, free_head); + qvirtqueue_kick(qts, dev, vq, free_head); - qvirtio_wait_used_elem(dev, vq, free_head, NULL, + qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL, QVIRTIO_BLK_TIMEOUT_US); status = readb(req_addr + 528); @@ -569,6 +575,7 @@ static void idx(void *obj, void *u_data, QGuestAllocator *t_alloc) char *data; QOSGraphObject *blk_object = obj; QPCIDevice *pci_dev = blk_object->get_driver(blk_object, "pci-device"); + QTestState *qts = global_qtest; if (qpci_check_buggy_msi(pci_dev)) { return; @@ -603,12 +610,12 @@ static void idx(void *obj, void *u_data, QGuestAllocator *t_alloc) g_free(req.data); - free_head = qvirtqueue_add(vq, req_addr, 16, false, true); - qvirtqueue_add(vq, req_addr + 16, 512, false, true); - qvirtqueue_add(vq, req_addr + 528, 1, true, false); - qvirtqueue_kick(dev, vq, free_head); + free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true); + qvirtqueue_add(qts, vq, req_addr + 16, 512, false, true); + qvirtqueue_add(qts, vq, req_addr + 528, 1, true, false); + qvirtqueue_kick(qts, dev, vq, free_head); - qvirtio_wait_used_elem(dev, vq, free_head, NULL, + qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL, QVIRTIO_BLK_TIMEOUT_US); /* Write request */ @@ -623,15 +630,15 @@ static void idx(void *obj, void *u_data, QGuestAllocator *t_alloc) g_free(req.data); /* Notify after processing the third request */ - qvirtqueue_set_used_event(vq, 2); - free_head = qvirtqueue_add(vq, req_addr, 16, false, true); - qvirtqueue_add(vq, req_addr + 16, 512, false, true); - qvirtqueue_add(vq, req_addr + 528, 1, true, false); - qvirtqueue_kick(dev, vq, free_head); + qvirtqueue_set_used_event(qts, vq, 2); + free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true); + qvirtqueue_add(qts, vq, req_addr + 16, 512, false, true); + qvirtqueue_add(qts, vq, req_addr + 528, 1, true, false); + qvirtqueue_kick(qts, dev, vq, free_head); write_head = free_head; /* No notification expected */ - status = qvirtio_wait_status_byte_no_isr(dev, + status = qvirtio_wait_status_byte_no_isr(qts, dev, vq, req_addr + 528, QVIRTIO_BLK_TIMEOUT_US); g_assert_cmpint(status, ==, 0); @@ -648,16 +655,16 @@ static void idx(void *obj, void *u_data, QGuestAllocator *t_alloc) g_free(req.data); - free_head = qvirtqueue_add(vq, req_addr, 16, false, true); - qvirtqueue_add(vq, req_addr + 16, 512, true, true); - qvirtqueue_add(vq, req_addr + 528, 1, true, false); + free_head = qvirtqueue_add(qts, vq, req_addr, 16, false, true); + qvirtqueue_add(qts, vq, req_addr + 16, 512, true, true); + qvirtqueue_add(qts, vq, req_addr + 528, 1, true, false); - qvirtqueue_kick(dev, vq, free_head); + qvirtqueue_kick(qts, dev, vq, free_head); /* We get just one notification for both requests */ - qvirtio_wait_used_elem(dev, vq, write_head, NULL, + qvirtio_wait_used_elem(qts, dev, vq, write_head, NULL, QVIRTIO_BLK_TIMEOUT_US); - g_assert(qvirtqueue_get_buf(vq, &desc_idx, NULL)); + g_assert(qvirtqueue_get_buf(qts, vq, &desc_idx, NULL)); g_assert_cmpint(desc_idx, ==, free_head); status = readb(req_addr + 528); @@ -683,7 +690,7 @@ static void pci_hotplug(void *obj, void *data, QGuestAllocator *t_alloc) QTestState *qts = dev1->pdev->bus->qts; /* plug secondary disk */ - qtest_qmp_device_add("virtio-blk-pci", "drv1", + qtest_qmp_device_add(qts, "virtio-blk-pci", "drv1", "{'addr': %s, 'drive': 'drive1'}", stringify(PCI_SLOT_HP) ".0"); @@ -753,8 +760,10 @@ static void *virtio_blk_test_setup(GString *cmd_line, void *arg) char *tmp_path = drive_create(); g_string_append_printf(cmd_line, - " -drive if=none,id=drive0,file=%s,format=raw,auto-read-only=off " - "-drive if=none,id=drive1,file=null-co://,format=raw ", + " -drive if=none,id=drive0,file=%s," + "format=raw,auto-read-only=off " + "-drive if=none,id=drive1,file=null-co://," + "file.read-zeroes=on,format=raw ", tmp_path); return arg; diff --git a/tests/virtio-ccw-test.c b/tests/virtio-ccw-test.c index 48c714d84c..9f445ef4ad 100644 --- a/tests/virtio-ccw-test.c +++ b/tests/virtio-ccw-test.c @@ -45,15 +45,18 @@ static void virtio_serial_nop(void) static void virtio_serial_hotplug(void) { - global_qtest = qtest_initf("-device virtio-serial-ccw"); - qtest_qmp_device_add("virtserialport", "hp-port", "{}"); - qtest_qmp_device_del("hp-port"); - qtest_end(); + QTestState *qts = qtest_initf("-device virtio-serial-ccw"); + + qtest_qmp_device_add(qts, "virtserialport", "hp-port", "{}"); + qtest_qmp_device_del(qts, "hp-port"); + + qtest_quit(qts); } static void virtio_blk_nop(void) { - global_qtest = qtest_initf("-drive if=none,id=drv0,file=null-co://,format=raw " + global_qtest = qtest_initf("-drive if=none,id=drv0,file=null-co://," + "file.read-zeroes=on,format=raw " "-device virtio-blk-ccw,drive=drv0"); qtest_end(); } @@ -78,14 +81,16 @@ static void virtio_scsi_nop(void) static void virtio_scsi_hotplug(void) { - global_qtest = qtest_initf("-drive if=none,id=drv0,file=null-co://,format=raw " - "-drive if=none,id=drv1,file=null-co://,format=raw " + QTestState *s = qtest_initf("-drive if=none,id=drv0,file=null-co://," + "file.read-zeroes=on,format=raw " + "-drive if=none,id=drv1,file=null-co://," + "file.read-zeroes=on,format=raw " "-device virtio-scsi-ccw " "-device scsi-hd,drive=drv0"); - qtest_qmp_device_add("scsi-hd", "scsihd", "{'drive': 'drv1'}"); - qtest_qmp_device_del("scsihd"); + qtest_qmp_device_add(s, "scsi-hd", "scsihd", "{'drive': 'drv1'}"); + qtest_qmp_device_del(s, "scsihd"); - qtest_end(); + qtest_quit(s); } int main(int argc, char **argv) diff --git a/tests/virtio-net-test.c b/tests/virtio-net-test.c index 7aa9622f30..840875aaae 100644 --- a/tests/virtio-net-test.c +++ b/tests/virtio-net-test.c @@ -33,6 +33,7 @@ static void rx_test(QVirtioDevice *dev, QGuestAllocator *alloc, QVirtQueue *vq, int socket) { + QTestState *qts = global_qtest; uint64_t req_addr; uint32_t free_head; char test[] = "TEST"; @@ -51,13 +52,14 @@ static void rx_test(QVirtioDevice *dev, req_addr = guest_alloc(alloc, 64); - free_head = qvirtqueue_add(vq, req_addr, 64, true, false); - qvirtqueue_kick(dev, vq, free_head); + free_head = qvirtqueue_add(qts, vq, req_addr, 64, true, false); + qvirtqueue_kick(qts, dev, vq, free_head); ret = iov_send(socket, iov, 2, 0, sizeof(len) + sizeof(test)); g_assert_cmpint(ret, ==, sizeof(test) + sizeof(len)); - qvirtio_wait_used_elem(dev, vq, free_head, NULL, QVIRTIO_NET_TIMEOUT_US); + qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL, + QVIRTIO_NET_TIMEOUT_US); memread(req_addr + VNET_HDR_SIZE, buffer, sizeof(test)); g_assert_cmpstr(buffer, ==, "TEST"); @@ -68,6 +70,7 @@ static void tx_test(QVirtioDevice *dev, QGuestAllocator *alloc, QVirtQueue *vq, int socket) { + QTestState *qts = global_qtest; uint64_t req_addr; uint32_t free_head; uint32_t len; @@ -77,10 +80,11 @@ static void tx_test(QVirtioDevice *dev, req_addr = guest_alloc(alloc, 64); memwrite(req_addr + VNET_HDR_SIZE, "TEST", 4); - free_head = qvirtqueue_add(vq, req_addr, 64, false, false); - qvirtqueue_kick(dev, vq, free_head); + free_head = qvirtqueue_add(qts, vq, req_addr, 64, false, false); + qvirtqueue_kick(qts, dev, vq, free_head); - qvirtio_wait_used_elem(dev, vq, free_head, NULL, QVIRTIO_NET_TIMEOUT_US); + qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL, + QVIRTIO_NET_TIMEOUT_US); guest_free(alloc, req_addr); ret = qemu_recv(socket, &len, sizeof(len), 0); @@ -95,6 +99,7 @@ static void rx_stop_cont_test(QVirtioDevice *dev, QGuestAllocator *alloc, QVirtQueue *vq, int socket) { + QTestState *qts = global_qtest; uint64_t req_addr; uint32_t free_head; char test[] = "TEST"; @@ -114,8 +119,8 @@ static void rx_stop_cont_test(QVirtioDevice *dev, req_addr = guest_alloc(alloc, 64); - free_head = qvirtqueue_add(vq, req_addr, 64, true, false); - qvirtqueue_kick(dev, vq, free_head); + free_head = qvirtqueue_add(qts, vq, req_addr, 64, true, false); + qvirtqueue_kick(qts, dev, vq, free_head); rsp = qmp("{ 'execute' : 'stop'}"); qobject_unref(rsp); @@ -131,7 +136,8 @@ static void rx_stop_cont_test(QVirtioDevice *dev, rsp = qmp("{ 'execute' : 'cont'}"); qobject_unref(rsp); - qvirtio_wait_used_elem(dev, vq, free_head, NULL, QVIRTIO_NET_TIMEOUT_US); + qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL, + QVIRTIO_NET_TIMEOUT_US); memread(req_addr + VNET_HDR_SIZE, buffer, sizeof(test)); g_assert_cmpstr(buffer, ==, "TEST"); @@ -168,7 +174,7 @@ static void hotplug(void *obj, void *data, QGuestAllocator *t_alloc) QTestState *qts = dev->pdev->bus->qts; const char *arch = qtest_get_arch(); - qtest_qmp_device_add("virtio-net-pci", "net1", + qtest_qmp_device_add(qts, "virtio-net-pci", "net1", "{'addr': %s}", stringify(PCI_SLOT_HP)); if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) { @@ -283,19 +289,20 @@ static void large_tx(void *obj, void *data, QGuestAllocator *t_alloc) uint64_t req_addr; uint32_t free_head; size_t alloc_size = (size_t)data / 64; + QTestState *qts = global_qtest; int i; /* Bypass the limitation by pointing several descriptors to a single * smaller area */ req_addr = guest_alloc(t_alloc, alloc_size); - free_head = qvirtqueue_add(vq, req_addr, alloc_size, false, true); + free_head = qvirtqueue_add(qts, vq, req_addr, alloc_size, false, true); for (i = 0; i < 64; i++) { - qvirtqueue_add(vq, req_addr, alloc_size, false, i != 63); + qvirtqueue_add(qts, vq, req_addr, alloc_size, false, i != 63); } - qvirtqueue_kick(dev->vdev, vq, free_head); + qvirtqueue_kick(qts, dev->vdev, vq, free_head); - qvirtio_wait_used_elem(dev->vdev, vq, free_head, NULL, + qvirtio_wait_used_elem(qts, dev->vdev, vq, free_head, NULL, QVIRTIO_NET_TIMEOUT_US); guest_free(t_alloc, req_addr); } diff --git a/tests/virtio-rng-test.c b/tests/virtio-rng-test.c index a38a0d175b..092ba13068 100644 --- a/tests/virtio-rng-test.c +++ b/tests/virtio-rng-test.c @@ -22,7 +22,7 @@ static void rng_hotplug(void *obj, void *data, QGuestAllocator *alloc) const char *arch = qtest_get_arch(); - qtest_qmp_device_add("virtio-rng-pci", "rng1", + qtest_qmp_device_add(qts, "virtio-rng-pci", "rng1", "{'addr': %s}", stringify(PCI_SLOT_HP)); if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) { diff --git a/tests/virtio-scsi-test.c b/tests/virtio-scsi-test.c index 1ad9f75d74..09348765d7 100644 --- a/tests/virtio-scsi-test.c +++ b/tests/virtio-scsi-test.c @@ -72,6 +72,7 @@ static uint8_t virtio_scsi_do_command(QVirtioSCSIQueues *vs, uint64_t req_addr, resp_addr, data_in_addr = 0, data_out_addr = 0; uint8_t response; uint32_t free_head; + QTestState *qts = global_qtest; vq = vs->vq[2]; @@ -83,24 +84,24 @@ static uint8_t virtio_scsi_do_command(QVirtioSCSIQueues *vs, /* Add request header */ req_addr = qvirtio_scsi_alloc(vs, sizeof(req), &req); - free_head = qvirtqueue_add(vq, req_addr, sizeof(req), false, true); + free_head = qvirtqueue_add(qts, vq, req_addr, sizeof(req), false, true); if (data_out_len) { data_out_addr = qvirtio_scsi_alloc(vs, data_out_len, data_out); - qvirtqueue_add(vq, data_out_addr, data_out_len, false, true); + qvirtqueue_add(qts, vq, data_out_addr, data_out_len, false, true); } /* Add response header */ resp_addr = qvirtio_scsi_alloc(vs, sizeof(resp), &resp); - qvirtqueue_add(vq, resp_addr, sizeof(resp), true, !!data_in_len); + qvirtqueue_add(qts, vq, resp_addr, sizeof(resp), true, !!data_in_len); if (data_in_len) { data_in_addr = qvirtio_scsi_alloc(vs, data_in_len, data_in); - qvirtqueue_add(vq, data_in_addr, data_in_len, true, false); + qvirtqueue_add(qts, vq, data_in_addr, data_in_len, true, false); } - qvirtqueue_kick(vs->dev, vq, free_head); - qvirtio_wait_used_elem(vs->dev, vq, free_head, NULL, + qvirtqueue_kick(qts, vs->dev, vq, free_head); + qvirtio_wait_used_elem(qts, vs->dev, vq, free_head, NULL, QVIRTIO_SCSI_TIMEOUT_US); response = readb(resp_addr + @@ -149,8 +150,10 @@ static QVirtioSCSIQueues *qvirtio_scsi_init(QVirtioDevice *dev) static void hotplug(void *obj, void *data, QGuestAllocator *alloc) { - qtest_qmp_device_add("scsi-hd", "scsihd", "{'drive': 'drv1'}"); - qtest_qmp_device_del("scsihd"); + QTestState *qts = global_qtest; + + qtest_qmp_device_add(qts, "scsi-hd", "scsihd", "{'drive': 'drv1'}"); + qtest_qmp_device_del(qts, "scsihd"); } /* Test WRITE SAME with the lba not aligned */ @@ -222,10 +225,12 @@ static void test_iothread_attach_node(void *obj, void *data, mkqcow2(tmp_path, 64); /* Attach the overlay to the null0 node */ - qmp_assert_success("{'execute': 'blockdev-add', 'arguments': {" - " 'driver': 'qcow2', 'node-name': 'overlay'," - " 'backing': 'null0', 'file': {" - " 'driver': 'file', 'filename': %s}}}", tmp_path); + qtest_qmp_assert_success(scsi_pci->pci_vdev.pdev->bus->qts, + "{'execute': 'blockdev-add', 'arguments': {" + " 'driver': 'qcow2', 'node-name': 'overlay'," + " 'backing': 'null0', 'file': {" + " 'driver': 'file', 'filename': %s}}}", + tmp_path); /* Send a request to see if the AioContext is still right */ ret = virtio_scsi_do_command(vs, write_cdb, NULL, 0, buf, 512, NULL); @@ -239,7 +244,8 @@ fail: static void *virtio_scsi_hotplug_setup(GString *cmd_line, void *arg) { g_string_append(cmd_line, - " -drive id=drv1,if=none,file=null-co://,format=raw"); + " -drive id=drv1,if=none,file=null-co://," + "file.read-zeroes=on,format=raw"); return arg; } @@ -247,6 +253,7 @@ static void *virtio_scsi_setup(GString *cmd_line, void *arg) { g_string_append(cmd_line, " -drive file=blkdebug::null-co://," + "file.image.read-zeroes=on," "if=none,id=dr1,format=raw,file.align=4k " "-device scsi-hd,drive=dr1,lun=0,scsi-id=1"); return arg; @@ -256,7 +263,7 @@ static void *virtio_scsi_setup_iothread(GString *cmd_line, void *arg) { g_string_append(cmd_line, " -object iothread,id=thread0" - " -blockdev driver=null-co,node-name=null0" + " -blockdev driver=null-co,read-zeroes=on,node-name=null0" " -device scsi-hd,drive=null0"); return arg; } diff --git a/tests/virtio-serial-test.c b/tests/virtio-serial-test.c index 066ca61280..e584ad76e8 100644 --- a/tests/virtio-serial-test.c +++ b/tests/virtio-serial-test.c @@ -20,8 +20,8 @@ static void virtio_serial_nop(void *obj, void *data, QGuestAllocator *alloc) static void serial_hotplug(void *obj, void *data, QGuestAllocator *alloc) { - qtest_qmp_device_add("virtserialport", "hp-port", "{}"); - qtest_qmp_device_del("hp-port"); + qtest_qmp_device_add(global_qtest, "virtserialport", "hp-port", "{}"); + qtest_qmp_device_del(global_qtest, "hp-port"); } static void register_virtio_serial_test(void) @@ -4198,7 +4198,7 @@ int main(int argc, char **argv, char **envp) migration_object_init(); if (qtest_chrdev) { - qtest_init(qtest_chrdev, qtest_log, &error_fatal); + qtest_server_init(qtest_chrdev, qtest_log, &error_fatal); } machine_opts = qemu_get_machine_opts(); |