thebeanogamer / rpms / qemu-kvm

Forked from rpms/qemu-kvm 5 months ago
Clone

Blame SOURCES/kvm-vhost-user-blk-Don-t-reconnect-during-initialisation.patch

a83cc2
From 5d39cb265db6ea2159662a2d071d340712940d33 Mon Sep 17 00:00:00 2001
a83cc2
From: Kevin Wolf <kwolf@redhat.com>
a83cc2
Date: Mon, 12 Jul 2021 10:22:27 -0400
a83cc2
Subject: [PATCH 07/43] vhost-user-blk: Don't reconnect during initialisation
a83cc2
a83cc2
RH-Author: Miroslav Rezanina <mrezanin@redhat.com>
a83cc2
RH-Bugzilla: 1957194
a83cc2
a83cc2
This is a partial revert of commits 77542d43149 and bc79c87bcde.
a83cc2
a83cc2
Usually, an error during initialisation means that the configuration was
a83cc2
wrong. Reconnecting won't make the error go away, but just turn the
a83cc2
error condition into an endless loop. Avoid this and return errors
a83cc2
again.
a83cc2
a83cc2
Additionally, calling vhost_user_blk_disconnect() from the chardev event
a83cc2
handler could result in use-after-free because none of the
a83cc2
initialisation code expects that the device could just go away in the
a83cc2
middle. So removing the call fixes crashes in several places.
a83cc2
a83cc2
For example, using a num-queues setting that is incompatible with the
a83cc2
backend would result in a crash like this (dereferencing dev->opaque,
a83cc2
which is already NULL):
a83cc2
a83cc2
 #0  0x0000555555d0a4bd in vhost_user_read_cb (source=0x5555568f4690, condition=(G_IO_IN | G_IO_HUP), opaque=0x7fffffffcbf0) at ../hw/virtio/vhost-user.c:313
a83cc2
 #1  0x0000555555d950d3 in qio_channel_fd_source_dispatch (source=0x555557c3f750, callback=0x555555d0a478 <vhost_user_read_cb>, user_data=0x7fffffffcbf0) at ../io/channel-watch.c:84
a83cc2
 #2  0x00007ffff7b32a9f in g_main_context_dispatch () at /lib64/libglib-2.0.so.0
a83cc2
 #3  0x00007ffff7b84a98 in g_main_context_iterate.constprop () at /lib64/libglib-2.0.so.0
a83cc2
 #4  0x00007ffff7b32163 in g_main_loop_run () at /lib64/libglib-2.0.so.0
a83cc2
 #5  0x0000555555d0a724 in vhost_user_read (dev=0x555557bc62f8, msg=0x7fffffffcc50) at ../hw/virtio/vhost-user.c:402
a83cc2
 #6  0x0000555555d0ee6b in vhost_user_get_config (dev=0x555557bc62f8, config=0x555557bc62ac "", config_len=60) at ../hw/virtio/vhost-user.c:2133
a83cc2
 #7  0x0000555555d56d46 in vhost_dev_get_config (hdev=0x555557bc62f8, config=0x555557bc62ac "", config_len=60) at ../hw/virtio/vhost.c:1566
a83cc2
 #8  0x0000555555cdd150 in vhost_user_blk_device_realize (dev=0x555557bc60b0, errp=0x7fffffffcf90) at ../hw/block/vhost-user-blk.c:510
a83cc2
 #9  0x0000555555d08f6d in virtio_device_realize (dev=0x555557bc60b0, errp=0x7fffffffcff0) at ../hw/virtio/virtio.c:3660
a83cc2
a83cc2
Note that this removes the ability to reconnect during initialisation
a83cc2
(but not during operation) when there is no permanent error, but the
a83cc2
backend restarts, as the implementation was buggy. This feature can be
a83cc2
added back in a follow-up series after changing error paths to
a83cc2
distinguish cases where retrying could help from cases with permanent
a83cc2
errors.
a83cc2
a83cc2
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
a83cc2
Message-Id: <20210429171316.162022-3-kwolf@redhat.com>
a83cc2
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
a83cc2
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
a83cc2
(cherry picked from commit dabefdd6abcbc7d858e9413e4734aab2e0b5c8d9)
a83cc2
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
a83cc2
Signed-off-by: Danilo C. L. de Paula <ddepaula@redhat.com>
a83cc2
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
a83cc2
---
a83cc2
 hw/block/vhost-user-blk.c | 59 +++++++++++----------------------------
a83cc2
 1 file changed, 17 insertions(+), 42 deletions(-)
a83cc2
a83cc2
diff --git a/hw/block/vhost-user-blk.c b/hw/block/vhost-user-blk.c
a83cc2
index 7c85248a7b..c0b9958da1 100644
a83cc2
--- a/hw/block/vhost-user-blk.c
a83cc2
+++ b/hw/block/vhost-user-blk.c
a83cc2
@@ -50,6 +50,8 @@ static const int user_feature_bits[] = {
a83cc2
     VHOST_INVALID_FEATURE_BIT
a83cc2
 };
a83cc2
 
a83cc2
+static void vhost_user_blk_event(void *opaque, QEMUChrEvent event);
a83cc2
+
a83cc2
 static void vhost_user_blk_update_config(VirtIODevice *vdev, uint8_t *config)
a83cc2
 {
a83cc2
     VHostUserBlk *s = VHOST_USER_BLK(vdev);
a83cc2
@@ -362,19 +364,6 @@ static void vhost_user_blk_disconnect(DeviceState *dev)
a83cc2
     vhost_dev_cleanup(&s->dev);
a83cc2
 }
a83cc2
 
a83cc2
-static void vhost_user_blk_event(void *opaque, QEMUChrEvent event,
a83cc2
-                                 bool realized);
a83cc2
-
a83cc2
-static void vhost_user_blk_event_realize(void *opaque, QEMUChrEvent event)
a83cc2
-{
a83cc2
-    vhost_user_blk_event(opaque, event, false);
a83cc2
-}
a83cc2
-
a83cc2
-static void vhost_user_blk_event_oper(void *opaque, QEMUChrEvent event)
a83cc2
-{
a83cc2
-    vhost_user_blk_event(opaque, event, true);
a83cc2
-}
a83cc2
-
a83cc2
 static void vhost_user_blk_chr_closed_bh(void *opaque)
a83cc2
 {
a83cc2
     DeviceState *dev = opaque;
a83cc2
@@ -382,12 +371,11 @@ static void vhost_user_blk_chr_closed_bh(void *opaque)
a83cc2
     VHostUserBlk *s = VHOST_USER_BLK(vdev);
a83cc2
 
a83cc2
     vhost_user_blk_disconnect(dev);
a83cc2
-    qemu_chr_fe_set_handlers(&s->chardev, NULL, NULL,
a83cc2
-            vhost_user_blk_event_oper, NULL, opaque, NULL, true);
a83cc2
+    qemu_chr_fe_set_handlers(&s->chardev, NULL, NULL, vhost_user_blk_event,
a83cc2
+                             NULL, opaque, NULL, true);
a83cc2
 }
a83cc2
 
a83cc2
-static void vhost_user_blk_event(void *opaque, QEMUChrEvent event,
a83cc2
-                                 bool realized)
a83cc2
+static void vhost_user_blk_event(void *opaque, QEMUChrEvent event)
a83cc2
 {
a83cc2
     DeviceState *dev = opaque;
a83cc2
     VirtIODevice *vdev = VIRTIO_DEVICE(dev);
a83cc2
@@ -401,17 +389,7 @@ static void vhost_user_blk_event(void *opaque, QEMUChrEvent event,
a83cc2
         }
a83cc2
         break;
a83cc2
     case CHR_EVENT_CLOSED:
a83cc2
-        /*
a83cc2
-         * Closing the connection should happen differently on device
a83cc2
-         * initialization and operation stages.
a83cc2
-         * On initalization, we want to re-start vhost_dev initialization
a83cc2
-         * from the very beginning right away when the connection is closed,
a83cc2
-         * so we clean up vhost_dev on each connection closing.
a83cc2
-         * On operation, we want to postpone vhost_dev cleanup to let the
a83cc2
-         * other code perform its own cleanup sequence using vhost_dev data
a83cc2
-         * (e.g. vhost_dev_set_log).
a83cc2
-         */
a83cc2
-        if (realized && !runstate_check(RUN_STATE_SHUTDOWN)) {
a83cc2
+        if (!runstate_check(RUN_STATE_SHUTDOWN)) {
a83cc2
             /*
a83cc2
              * A close event may happen during a read/write, but vhost
a83cc2
              * code assumes the vhost_dev remains setup, so delay the
a83cc2
@@ -431,8 +409,6 @@ static void vhost_user_blk_event(void *opaque, QEMUChrEvent event,
a83cc2
              * knowing its type (in this case vhost-user).
a83cc2
              */
a83cc2
             s->dev.started = false;
a83cc2
-        } else {
a83cc2
-            vhost_user_blk_disconnect(dev);
a83cc2
         }
a83cc2
         break;
a83cc2
     case CHR_EVENT_BREAK:
a83cc2
@@ -489,33 +465,32 @@ static void vhost_user_blk_device_realize(DeviceState *dev, Error **errp)
a83cc2
     s->vhost_vqs = g_new0(struct vhost_virtqueue, s->num_queues);
a83cc2
     s->connected = false;
a83cc2
 
a83cc2
-    qemu_chr_fe_set_handlers(&s->chardev,  NULL, NULL,
a83cc2
-                             vhost_user_blk_event_realize, NULL, (void *)dev,
a83cc2
-                             NULL, true);
a83cc2
-
a83cc2
-reconnect:
a83cc2
     if (qemu_chr_fe_wait_connected(&s->chardev, errp) < 0) {
a83cc2
         goto virtio_err;
a83cc2
     }
a83cc2
 
a83cc2
-    /* check whether vhost_user_blk_connect() failed or not */
a83cc2
-    if (!s->connected) {
a83cc2
-        goto reconnect;
a83cc2
+    if (vhost_user_blk_connect(dev) < 0) {
a83cc2
+        error_setg(errp, "vhost-user-blk: could not connect");
a83cc2
+        qemu_chr_fe_disconnect(&s->chardev);
a83cc2
+        goto virtio_err;
a83cc2
     }
a83cc2
+    assert(s->connected);
a83cc2
 
a83cc2
     ret = vhost_dev_get_config(&s->dev, (uint8_t *)&s->blkcfg,
a83cc2
                                sizeof(struct virtio_blk_config));
a83cc2
     if (ret < 0) {
a83cc2
-        error_report("vhost-user-blk: get block config failed");
a83cc2
-        goto reconnect;
a83cc2
+        error_setg(errp, "vhost-user-blk: get block config failed");
a83cc2
+        goto vhost_err;
a83cc2
     }
a83cc2
 
a83cc2
-    /* we're fully initialized, now we can operate, so change the handler */
a83cc2
+    /* we're fully initialized, now we can operate, so add the handler */
a83cc2
     qemu_chr_fe_set_handlers(&s->chardev,  NULL, NULL,
a83cc2
-                             vhost_user_blk_event_oper, NULL, (void *)dev,
a83cc2
+                             vhost_user_blk_event, NULL, (void *)dev,
a83cc2
                              NULL, true);
a83cc2
     return;
a83cc2
 
a83cc2
+vhost_err:
a83cc2
+    vhost_dev_cleanup(&s->dev);
a83cc2
 virtio_err:
a83cc2
     g_free(s->vhost_vqs);
a83cc2
     s->vhost_vqs = NULL;
a83cc2
-- 
a83cc2
2.27.0
a83cc2