Opt-out backend initialization code, and instead get the state from migration channel (including inflight region).
Signed-off-by: Vladimir Sementsov-Ogievskiy <[email protected]> --- hw/block/vhost-user-blk.c | 129 ++++++++++++++++++++++++----- include/hw/virtio/vhost-user-blk.h | 2 + include/hw/virtio/vhost.h | 3 +- 3 files changed, 111 insertions(+), 23 deletions(-) diff --git a/hw/block/vhost-user-blk.c b/hw/block/vhost-user-blk.c index ffdd600526..a8fd90480a 100644 --- a/hw/block/vhost-user-blk.c +++ b/hw/block/vhost-user-blk.c @@ -17,6 +17,7 @@ */ #include "qemu/osdep.h" +#include "qapi-types-run-state.h" #include "qapi/error.h" #include "qemu/error-report.h" #include "qemu/cutils.h" @@ -31,7 +32,13 @@ #include "hw/virtio/virtio-access.h" #include "system/system.h" #include "system/runstate.h" +#include "chardev/char-backend-transfer.h" #include "trace.h" +#include "migration/qemu-file.h" +#include "migration/migration.h" +#include "migration/options.h" +#include "qemu/event_notifier.h" +#include <sys/mman.h> static const int user_feature_bits[] = { VIRTIO_BLK_F_SIZE_MAX, @@ -160,32 +167,35 @@ static int vhost_user_blk_start(VirtIODevice *vdev, Error **errp) s->dev.acked_features = vdev->guest_features; - ret = vhost_dev_prepare_inflight(&s->dev, vdev); - if (ret < 0) { - error_setg_errno(errp, -ret, "Error setting inflight format"); - goto err_guest_notifiers; - } - - if (!s->inflight->addr) { - ret = vhost_dev_get_inflight(&s->dev, s->queue_size, s->inflight); + if (!s->dev.backend_transfer) { + ret = vhost_dev_prepare_inflight(&s->dev, vdev); if (ret < 0) { - error_setg_errno(errp, -ret, "Error getting inflight"); + error_setg_errno(errp, -ret, "Error setting inflight format"); goto err_guest_notifiers; } - } - ret = vhost_dev_set_inflight(&s->dev, s->inflight); - if (ret < 0) { - error_setg_errno(errp, -ret, "Error setting inflight"); - goto err_guest_notifiers; - } + if (!s->inflight->addr) { + ret = vhost_dev_get_inflight(&s->dev, s->queue_size, s->inflight); + if (ret < 0) { + error_setg_errno(errp, -ret, "Error getting inflight"); + goto err_guest_notifiers; + } + } - /* guest_notifier_mask/pending not used yet, so just unmask - * everything here. virtio-pci will do the right thing by - * enabling/disabling irqfd. - */ - for (i = 0; i < s->dev.nvqs; i++) { - vhost_virtqueue_mask(&s->dev, vdev, i, false); + ret = vhost_dev_set_inflight(&s->dev, s->inflight); + if (ret < 0) { + error_setg_errno(errp, -ret, "Error setting inflight"); + goto err_guest_notifiers; + } + + /* + * guest_notifier_mask/pending not used yet, so just unmask + * everything here. virtio-pci will do the right thing by + * enabling/disabling irqfd. + */ + for (i = 0; i < s->dev.nvqs; i++) { + vhost_virtqueue_mask(&s->dev, vdev, i, false); + } } s->dev.vq_index_end = s->dev.nvqs; @@ -232,6 +242,10 @@ static int vhost_user_blk_stop(VirtIODevice *vdev) force_stop = s->skip_get_vring_base_on_force_shutdown && qemu_force_shutdown_requested(); + s->dev.backend_transfer = s->dev.backend_transfer || + (runstate_check(RUN_STATE_FINISH_MIGRATE) && + migrate_local_vhost_user_blk()); + ret = force_stop ? vhost_dev_force_stop(&s->dev, vdev, true) : vhost_dev_stop(&s->dev, vdev, true); @@ -391,6 +405,7 @@ static int vhost_user_blk_connect(DeviceState *dev, trace_vhost_user_blk_connect_in(vdev); assert(!s->connected); + assert(!s->dev.backend_transfer); ret = vhost_dev_connect(&s->dev, errp); if (ret < 0) { @@ -464,6 +479,9 @@ static int vhost_user_blk_realize_connect(VHostUserBlk *s, Error **errp) DeviceState *dev = DEVICE(s); int ret; + assert(!s->connected); + assert(!s->dev.backend_transfer); + ret = qemu_chr_fe_wait_connected(&s->chardev, errp); if (ret < 0) { return ret; @@ -642,7 +660,13 @@ static bool vhost_user_blk_pre_incoming(void *opaque, Error **errp) { VHostUserBlk *s = VHOST_USER_BLK(opaque); - return vhost_user_blk_realize_connect(s, errp) == 0; + s->dev.backend_transfer = migrate_local_vhost_user_blk(); + + if (!s->dev.backend_transfer) { + return vhost_user_blk_realize_connect_loop(s, errp) >= 0; + } + + return true; } static const VMStateDescription vmstate_vhost_user_blk = { @@ -656,6 +680,64 @@ static const VMStateDescription vmstate_vhost_user_blk = { }, }; +static bool vhost_user_needed(void *opaque) +{ + return migrate_local_vhost_user_blk(); +} + +static const VMStateDescription vmstate_vhost_user_blk_device = { + .name = "vhost-user-blk-device", + .version_id = 1, + .needed = vhost_user_needed, + .fields = (const VMStateField[]) { + VMSTATE_BACKEND_TRANSFER_CHARDEV(chardev, VHostUserBlk), + VMSTATE_BACKEND_TRANSFER_VHOST_INFLIGHT(inflight, VHostUserBlk), + VMSTATE_BACKEND_TRANSFER_VHOST_USER(dev, VHostUserBlk), + VMSTATE_BACKEND_TRANSFER_VHOST(dev, VHostUserBlk), + VMSTATE_END_OF_LIST() + }, +}; + +static int vhost_user_blk_post_load(VirtIODevice *vdev) +{ + VHostUserBlk *s = VHOST_USER_BLK(vdev); + struct vhost_dev *hdev = vhost_user_blk_get_vhost(vdev); + DeviceState *dev = &s->parent_obj.parent_obj; + + if (!hdev->backend_transfer) { + return 0; + } + + s->connected = true; + + memcpy(&s->blkcfg, vdev->config, vdev->config_len); + + if (virtio_device_started(vdev, vdev->status)) { + int ret; + ret = vhost_user_blk_start(vdev, NULL); + if (ret < 0) { + return ret; + } + } + + /* we're fully initialized, now we can operate, so add the handler */ + qemu_chr_fe_set_handlers(&s->chardev, NULL, NULL, + vhost_user_blk_event, NULL, (void *)dev, + NULL, true); + + return 0; +} + +static bool vhost_user_blk_skip_migration_log(VirtIODevice *vdev) +{ + /* + * Note that hdev->migrating_backend is false at this moment, + * as logging is being setup during outging migration setup stage, + * which is far before vm stop. + */ + return migrate_local_vhost_user_blk(); +} + static const Property vhost_user_blk_properties[] = { DEFINE_PROP_CHR_NO_CONNECT("chardev", VHostUserBlk, chardev), DEFINE_PROP_UINT16("num-queues", VHostUserBlk, num_queues, @@ -688,6 +770,9 @@ static void vhost_user_blk_class_init(ObjectClass *klass, const void *data) vdc->set_status = vhost_user_blk_set_status; vdc->reset = vhost_user_blk_reset; vdc->get_vhost = vhost_user_blk_get_vhost; + vdc->vmsd = &vmstate_vhost_user_blk_device; + vdc->post_load = vhost_user_blk_post_load, + vdc->skip_vhost_migration_log = vhost_user_blk_skip_migration_log; } static const TypeInfo vhost_user_blk_info = { diff --git a/include/hw/virtio/vhost-user-blk.h b/include/hw/virtio/vhost-user-blk.h index a10f785672..b06f55fd6f 100644 --- a/include/hw/virtio/vhost-user-blk.h +++ b/include/hw/virtio/vhost-user-blk.h @@ -52,6 +52,8 @@ struct VHostUserBlk { bool started_vu; bool skip_get_vring_base_on_force_shutdown; + + bool incoming_backend; }; #endif diff --git a/include/hw/virtio/vhost.h b/include/hw/virtio/vhost.h index 55ad822848..13ca2c319f 100644 --- a/include/hw/virtio/vhost.h +++ b/include/hw/virtio/vhost.h @@ -592,7 +592,8 @@ static inline int vhost_load_backend_state(struct vhost_dev *dev, QEMUFile *f, extern const VMStateDescription vmstate_backend_transfer_vhost_inflight; #define VMSTATE_BACKEND_TRANSFER_VHOST_INFLIGHT(_field, _state) \ - VMSTATE_STRUCT_POINTER(_field, _state, vmstate_inflight, \ + VMSTATE_STRUCT_POINTER(_field, _state, \ + vmstate_backend_transfer_vhost_inflight, \ struct vhost_inflight) extern const VMStateDescription vmstate_vhost_dev; -- 2.48.1
