Virtuozzo QEMU development (svt-core@virtuozzo.com)
 help / color / mirror / Atom feed
From: Andrey Zhadchenko <andrey.zhadchenko@virtuozzo.com>
To: svt-core@virtuozzo.com
Cc: den@openvz.org, andrey.drobyshev@virtuozzo.com
Subject: [QEMU HCI-8.0 PATCH v4 5/5] vhost-blk: preserve the uevent socket across cpr-exec
Date: Tue,  8 Sep 2026 15:52:08 +0300	[thread overview]
Message-ID: <20260908125208.278402-6-andrey.zhadchenko@virtuozzo.com> (raw)
In-Reply-To: <20260908125208.278402-1-andrey.zhadchenko@virtuozzo.com>

qemu-update uses cpr-exec migration: QEMU re-execs itself in place.
A plain monitor fdset descriptor like our uevent socket does not
survive that (unlike the cpr_save_fd()'d tap/vhost fds), so without
help the resized-device notifications would silently stop until the
next full VM start.

Preserve it the same way the other devices do: on cold boot
cpr_save_fd() the socket under the "<proxy id>_ueventfd" key, and
on the re-exec'd (incoming) side adopt it with cpr_find_fd()
instead of reopening a command line fd that no longer resolves.
The management layer passes a placeholder for the "ueventfd"
property in that case.  The restored socket is validated just like
a cold-boot one.

Block CPR migration modes when the proxy has no ID or we disabled
the socket after the error.

Drop the saved descriptor on teardown so it does not outlive the
device.

https://virtuozzo.atlassian.net/browse/VSTOR-143437
Signed-off-by: Andrey Zhadchenko <andrey.zhadchenko@virtuozzo.com>
---
v2:
 - old one dropped, setup moved to libvirt
 - added new patch to support uevent socket cpr

v3:
 - use the proxy ID for the CPR fd name and block CPR without an ID
 - validate restored sockets and improve failure cleanup

v4:
 - split cold-boot and restore socket setup paths
 - reject restored socket/property mismatches
 - block CPR after a permanent uevent receive error

 hw/block/vhost-blk.c          | 107 +++++++++++++++++++++++++++++++++-
 include/hw/virtio/vhost-blk.h |   1 +
 2 files changed, 105 insertions(+), 3 deletions(-)

diff --git a/hw/block/vhost-blk.c b/hw/block/vhost-blk.c
index ef46c55665..abddff02c6 100644
--- a/hw/block/vhost-blk.c
+++ b/hw/block/vhost-blk.c
@@ -29,6 +29,8 @@
 #include <sys/ioctl.h>
 #include <linux/fs.h>
 #include <linux/netlink.h>
+#include "migration/blocker.h"
+#include "migration/cpr.h"
 #include "system/runstate.h"
 
 static int vhost_blk_start(VirtIODevice *vdev)
@@ -250,12 +252,27 @@ static void vhost_blk_resize_bh(void *opaque)
     }
 }
 
+static char *vhost_blk_cpr_name(VHostBlk *s)
+{
+    DeviceState *proxy = qdev_get_parent_bus(DEVICE(s))->parent;
+
+    return proxy->id ? g_strdup_printf("%s_ueventfd", proxy->id) : NULL;
+}
+
 static void vhost_blk_uevent_detach(VHostBlk *s)
 {
+    g_autofree char *cpr_name = NULL;
+
+    migrate_del_blocker(&s->cpr_blocker);
+
     if (s->uevent_fd < 0) {
         return;
     }
 
+    cpr_name = vhost_blk_cpr_name(s);
+    if (cpr_name) {
+        cpr_delete_fd(cpr_name, 0);
+    }
     qemu_set_fd_handler(s->uevent_fd, NULL, NULL, NULL);
     qemu_bh_delete(s->resize_bh);
     s->resize_bh = NULL;
@@ -263,6 +280,19 @@ static void vhost_blk_uevent_detach(VHostBlk *s)
     s->uevent_fd = -1;
 }
 
+static void vhost_blk_block_cpr(VHostBlk *s)
+{
+    Error *local_err = NULL;
+
+    error_setg(&s->cpr_blocker,
+               "vhost-blk: the uevent socket was detached after an error");
+    if (migrate_add_blocker_modes(&s->cpr_blocker, &local_err,
+                                  MIG_MODE_CPR_TRANSFER,
+                                  MIG_MODE_CPR_EXEC, -1) < 0) {
+        error_report_err(local_err);
+    }
+}
+
 /*
  * The uevent socket is created, bound and filtered by the management
  * layer and passed to us via the "ueventfd" property.
@@ -300,6 +330,7 @@ static void vhost_blk_uevent_read(void *opaque)
                 error_report("vhost-blk: detaching uevent after the error: %s",
                              strerror(errno));
                 vhost_blk_uevent_detach(s);
+                vhost_blk_block_cpr(s);
             }
             return;
         }
@@ -395,7 +426,41 @@ static bool vhost_blk_uevent_check(int fd, const char *src, Error **errp)
     return true;
 }
 
-static bool vhost_blk_uevent_attach(VHostBlk *s, Error **errp)
+static bool vhost_blk_uevent_restore(VHostBlk *s, const char *cpr_name,
+                                     Error **errp)
+{
+    int fd = -1;
+
+    if (cpr_name) {
+        fd = cpr_find_fd(cpr_name, 0);
+    }
+
+    if (!s->conf.ueventfd) {
+        if (fd >= 0) {
+            error_setg(errp, "vhost-blk: a preserved uevent socket exists "
+                       "but the 'ueventfd' property is not configured");
+            return false;
+        }
+        return true;
+    }
+
+    if (fd < 0) {
+        error_setg(errp, "vhost-blk: no preserved uevent socket to restore");
+        return false;
+    }
+
+    if (!vhost_blk_uevent_check(fd, cpr_name, errp)) {
+        cpr_delete_fd(cpr_name, 0);
+        qemu_close(fd);
+        return false;
+    }
+
+    s->uevent_fd = fd;
+    return true;
+}
+
+static bool vhost_blk_uevent_open(VHostBlk *s, const char *cpr_name,
+                                  Error **errp)
 {
     int fd;
 
@@ -403,18 +468,54 @@ static bool vhost_blk_uevent_attach(VHostBlk *s, Error **errp)
         return true;
     }
 
+    if (!cpr_name) {
+        error_setg(&s->cpr_blocker,
+                   "vhost-blk: device ID is required for CPR migration");
+        if (migrate_add_blocker_modes(&s->cpr_blocker, errp,
+                                      MIG_MODE_CPR_TRANSFER,
+                                      MIG_MODE_CPR_EXEC, -1) < 0) {
+            return false;
+        }
+    }
+
     fd = monitor_fd_param(monitor_cur(), s->conf.ueventfd, errp);
     if (fd < 0) {
         error_prepend(errp, "vhost-blk: unable to obtain uevent socket: ");
-        return false;
+        goto fail;
     }
 
     if (!vhost_blk_uevent_check(fd, s->conf.ueventfd, errp)) {
         qemu_close(fd);
-        return false;
+        goto fail;
+    }
+
+    if (cpr_name) {
+        cpr_save_fd(cpr_name, 0, fd);
     }
 
     s->uevent_fd = fd;
+    return true;
+
+fail:
+    migrate_del_blocker(&s->cpr_blocker);
+    return false;
+}
+
+static bool vhost_blk_uevent_attach(VHostBlk *s, Error **errp)
+{
+    g_autofree char *cpr_name = vhost_blk_cpr_name(s);
+    bool ok;
+
+    ok = cpr_is_incoming() ? vhost_blk_uevent_restore(s, cpr_name, errp)
+                           : vhost_blk_uevent_open(s, cpr_name, errp);
+    if (!ok) {
+        return false;
+    }
+
+    if (s->uevent_fd < 0) {
+        return true;
+    }
+
     s->resize_bh = qemu_bh_new(vhost_blk_resize_bh, s);
     qemu_set_fd_handler(s->uevent_fd, vhost_blk_uevent_read, NULL, s);
     return true;
diff --git a/include/hw/virtio/vhost-blk.h b/include/hw/virtio/vhost-blk.h
index e3ad92bc6e..059f1ebc70 100644
--- a/include/hw/virtio/vhost-blk.h
+++ b/include/hw/virtio/vhost-blk.h
@@ -47,6 +47,7 @@ typedef struct VHostBlk {
     uint64_t length;
     uint64_t backend_rdev;
     QEMUBH *resize_bh;
+    Error *cpr_blocker;
 } VHostBlk;
 
 #endif
-- 
2.43.5


  parent reply	other threads:[~2026-09-08 12:55 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-08 12:52 [QEMU HCI-8.0 PATCH v4 0/5] vhost-blk change backend setup Andrey Zhadchenko
2026-09-08 12:52 ` [QEMU HCI-8.0 PATCH v4 1/5] vhost-blk: improve vhost_blk_device_realize cleanup Andrey Zhadchenko
2026-09-08 12:52 ` [QEMU HCI-8.0 PATCH v4 2/5] vhost-blk: change backend setup Andrey Zhadchenko
2026-09-08 13:34   ` Andrey Drobyshev
2026-09-08 12:52 ` [QEMU HCI-8.0 PATCH v4 3/5] vhost-blk: add read-only flag Andrey Zhadchenko
2026-09-08 12:52 ` [QEMU HCI-8.0 PATCH v4 4/5] vhost-blk: watch the device for resize events Andrey Zhadchenko
2026-09-08 12:52 ` Andrey Zhadchenko [this message]
2026-09-08 13:34   ` [QEMU HCI-8.0 PATCH v4 5/5] vhost-blk: preserve the uevent socket across cpr-exec Andrey Drobyshev
2026-09-08 13:34 ` [QEMU HCI-8.0 PATCH v4 0/5] vhost-blk change backend setup Andrey Drobyshev

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260908125208.278402-6-andrey.zhadchenko@virtuozzo.com \
    --to=andrey.zhadchenko@virtuozzo.com \
    --cc=andrey.drobyshev@virtuozzo.com \
    --cc=den@openvz.org \
    --cc=svt-core@virtuozzo.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox