diff options
Diffstat (limited to 'hw/block')
-rw-r--r-- | hw/block/vhost-user-blk.c | 79 |
1 files changed, 48 insertions, 31 deletions
diff --git a/hw/block/vhost-user-blk.c b/hw/block/vhost-user-blk.c index b870a50e6b..0b5b9d44cd 100644 --- a/hw/block/vhost-user-blk.c +++ b/hw/block/vhost-user-blk.c @@ -362,7 +362,18 @@ static void vhost_user_blk_disconnect(DeviceState *dev) vhost_dev_cleanup(&s->dev); } -static void vhost_user_blk_event(void *opaque, QEMUChrEvent event); +static void vhost_user_blk_event(void *opaque, QEMUChrEvent event, + bool realized); + +static void vhost_user_blk_event_realize(void *opaque, QEMUChrEvent event) +{ + vhost_user_blk_event(opaque, event, false); +} + +static void vhost_user_blk_event_oper(void *opaque, QEMUChrEvent event) +{ + vhost_user_blk_event(opaque, event, true); +} static void vhost_user_blk_chr_closed_bh(void *opaque) { @@ -371,11 +382,12 @@ static void vhost_user_blk_chr_closed_bh(void *opaque) VHostUserBlk *s = VHOST_USER_BLK(vdev); vhost_user_blk_disconnect(dev); - qemu_chr_fe_set_handlers(&s->chardev, NULL, NULL, vhost_user_blk_event, - NULL, opaque, NULL, true); + qemu_chr_fe_set_handlers(&s->chardev, NULL, NULL, + vhost_user_blk_event_oper, NULL, opaque, NULL, true); } -static void vhost_user_blk_event(void *opaque, QEMUChrEvent event) +static void vhost_user_blk_event(void *opaque, QEMUChrEvent event, + bool realized) { DeviceState *dev = opaque; VirtIODevice *vdev = VIRTIO_DEVICE(dev); @@ -390,38 +402,38 @@ static void vhost_user_blk_event(void *opaque, QEMUChrEvent event) break; case CHR_EVENT_CLOSED: /* - * A close event may happen during a read/write, but vhost - * code assumes the vhost_dev remains setup, so delay the - * stop & clear. There are two possible paths to hit this - * disconnect event: - * 1. When VM is in the RUN_STATE_PRELAUNCH state. The - * vhost_user_blk_device_realize() is a caller. - * 2. In tha main loop phase after VM start. - * - * For p2 the disconnect event will be delayed. We can't - * do the same for p1, because we are not running the loop - * at this moment. So just skip this step and perform - * disconnect in the caller function. - * - * TODO: maybe it is a good idea to make the same fix - * for other vhost-user devices. + * Closing the connection should happen differently on device + * initialization and operation stages. + * On initalization, we want to re-start vhost_dev initialization + * from the very beginning right away when the connection is closed, + * so we clean up vhost_dev on each connection closing. + * On operation, we want to postpone vhost_dev cleanup to let the + * other code perform its own cleanup sequence using vhost_dev data + * (e.g. vhost_dev_set_log). */ - if (runstate_is_running()) { + if (realized && !runstate_check(RUN_STATE_SHUTDOWN)) { + /* + * A close event may happen during a read/write, but vhost + * code assumes the vhost_dev remains setup, so delay the + * stop & clear. + */ AioContext *ctx = qemu_get_current_aio_context(); qemu_chr_fe_set_handlers(&s->chardev, NULL, NULL, NULL, NULL, NULL, NULL, false); aio_bh_schedule_oneshot(ctx, vhost_user_blk_chr_closed_bh, opaque); - } - /* - * Move vhost device to the stopped state. The vhost-user device - * will be clean up and disconnected in BH. This can be useful in - * the vhost migration code. If disconnect was caught there is an - * option for the general vhost code to get the dev state without - * knowing its type (in this case vhost-user). - */ - s->dev.started = false; + /* + * Move vhost device to the stopped state. The vhost-user device + * will be clean up and disconnected in BH. This can be useful in + * the vhost migration code. If disconnect was caught there is an + * option for the general vhost code to get the dev state without + * knowing its type (in this case vhost-user). + */ + s->dev.started = false; + } else { + vhost_user_blk_disconnect(dev); + } break; case CHR_EVENT_BREAK: case CHR_EVENT_MUX_IN: @@ -473,8 +485,9 @@ static void vhost_user_blk_device_realize(DeviceState *dev, Error **errp) s->vhost_vqs = g_new0(struct vhost_virtqueue, s->num_queues); s->connected = false; - qemu_chr_fe_set_handlers(&s->chardev, NULL, NULL, vhost_user_blk_event, - NULL, (void *)dev, NULL, true); + qemu_chr_fe_set_handlers(&s->chardev, NULL, NULL, + vhost_user_blk_event_realize, NULL, (void *)dev, + NULL, true); reconnect: if (qemu_chr_fe_wait_connected(&s->chardev, &err) < 0) { @@ -494,6 +507,10 @@ reconnect: goto reconnect; } + /* we're fully initialized, now we can operate, so change the handler */ + qemu_chr_fe_set_handlers(&s->chardev, NULL, NULL, + vhost_user_blk_event_oper, NULL, (void *)dev, + NULL, true); return; virtio_err: |