Re: [PATCH v3 4/7] vhost-vsock: preserve vhost FD during CPR
Stefano Garzarella <[email protected]>
| Newsgroups | gmane.comp.emulators.qemu |
|---|---|
| Message-ID | <aoRyAqduT4FRj9NV@sgarzare-redhat> |
On Fri, Jun 26, 2026 at 07:46:40PM +0300, Andrey Drobyshev wrote: >During CPR (checkpoint-restore) migration the guest keeps running on the >same host, so instead of reopening /dev/vhost-vsock on the destination, >we should reuse the FD from the source. The FD is saved in the CPR >namespace (hash table) with cpr_save_fd() and then reclaimed on the >target via cpr_find_fd(). > >Since the key in CPR hash table is device ID, CPR needs a unique ID. >Rather than make it mandatory for every vhost-vsock device, we add CPR >migration blocker which only fires once we attempt CPR with ID-less >vhost-vsock. > >vhost_dev_init() (and thus VHOST_SET_OWNER) still runs in realize() here. >Deferring the ownership handoff to pre_save/post_load is done in a >following patch. So will this patch be bisectabale? Thanks, Stefano > >Signed-off-by: Andrey Drobyshev <[email protected]> >--- > hw/virtio/vhost-vsock.c | 50 ++++++++++++++++++++++++++++++--- > include/hw/virtio/vhost-vsock.h | 1 + > 2 files changed, 47 insertions(+), 4 deletions(-) > >diff --git a/hw/virtio/vhost-vsock.c b/hw/virtio/vhost-vsock.c >index fd7ffa88990..7eacb608d07 100644 >--- a/hw/virtio/vhost-vsock.c >+++ b/hw/virtio/vhost-vsock.c >@@ -21,6 +21,8 @@ > #include "hw/virtio/vhost-vsock.h" > #include "monitor/monitor.h" > #include "migration/cpr.h" >+#include "migration/blocker.h" >+#include "migration/misc.h" > > static void vhost_vsock_get_config(VirtIODevice *vdev, uint8_t *config) > { >@@ -141,6 +143,7 @@ static void vhost_vsock_device_realize(DeviceState *dev, Error **errp) > VHostVSockCommon *vvc = VHOST_VSOCK_COMMON(dev); > VirtIODevice *vdev = VIRTIO_DEVICE(dev); > VHostVSock *vsock = VHOST_VSOCK(dev); >+ DeviceState *proxy = qdev_get_parent_bus(DEVICE(vsock))->parent; > int vhostfd; > int ret; > >@@ -155,23 +158,49 @@ static void vhost_vsock_device_realize(DeviceState *dev, Error **errp) > return; > } > >- if (vsock->conf.vhostfd) { >+ /* >+ * Having a unique ID is mandatory for FD preservation during CPR >+ * migration, thus we add migration blockers for CPR modes. >+ */ >+ if (!proxy->id) { >+ error_setg(&vsock->migration_blocker, >+ "vhost-vsock: device ID is required for CPR migration"); >+ if (migrate_add_blocker_modes(&vsock->migration_blocker, >+ BIT(MIG_MODE_CPR_TRANSFER) | >+ BIT(MIG_MODE_CPR_EXEC), errp) < 0) { >+ return; >+ } >+ } >+ >+ if (cpr_is_incoming()) { >+ /* Reuse the fd handed over from the source QEMU. */ >+ if (!proxy->id) { >+ error_setg(errp, "vhost-vsock: device ID is required for " >+ "CPR migration"); >+ goto err_blocker; >+ } >+ vhostfd = cpr_find_fd(proxy->id, 0); >+ if (vhostfd < 0) { >+ error_setg(errp, "vhost-vsock: could not find restored vhost FD"); >+ goto err_blocker; >+ } >+ } else if (vsock->conf.vhostfd) { > vhostfd = monitor_fd_param(monitor_cur(), vsock->conf.vhostfd, errp); > if (vhostfd == -1) { > error_prepend(errp, "vhost-vsock: unable to parse vhostfd: "); >- return; >+ goto err_blocker; > } > } else { > vhostfd = open("/dev/vhost-vsock", O_RDWR); > if (vhostfd < 0) { > error_setg_file_open(errp, errno, "/dev/vhost-vsock"); >- return; >+ goto err_blocker; > } > } > > if (!qemu_set_blocking(vhostfd, false, errp)) { > close(vhostfd); >- return; >+ goto err_blocker; > } > > vhost_vsock_common_realize(vdev); >@@ -192,6 +221,11 @@ static void vhost_vsock_device_realize(DeviceState *dev, Error **errp) > goto err_vhost_dev; > } > >+ /* Register the fd for a future CPR after a fully successful realize */ >+ if (proxy->id) { >+ cpr_save_fd(proxy->id, 0, vhostfd); >+ } >+ > return; > > err_vhost_dev: >@@ -199,16 +233,24 @@ err_vhost_dev: > vhost_dev_cleanup(&vvc->vhost_dev); > err_virtio: > vhost_vsock_common_unrealize(vdev); >+err_blocker: >+ migrate_del_blocker(&vsock->migration_blocker); > } > > static void vhost_vsock_device_unrealize(DeviceState *dev) > { > VHostVSockCommon *vvc = VHOST_VSOCK_COMMON(dev); > VirtIODevice *vdev = VIRTIO_DEVICE(dev); >+ VHostVSock *vsock = VHOST_VSOCK(dev); >+ DeviceState *proxy = qdev_get_parent_bus(dev)->parent; > > /* This will stop vhost backend if appropriate. */ > vhost_vsock_set_status(vdev, 0); > >+ if (proxy->id) { >+ cpr_delete_fd(proxy->id, 0); >+ } >+ migrate_del_blocker(&vsock->migration_blocker); > vhost_dev_cleanup(&vvc->vhost_dev); > vhost_vsock_common_unrealize(vdev); > } >diff --git a/include/hw/virtio/vhost-vsock.h b/include/hw/virtio/vhost-vsock.h >index 84f4e727c70..5ebc63afc5a 100644 >--- a/include/hw/virtio/vhost-vsock.h >+++ b/include/hw/virtio/vhost-vsock.h >@@ -29,6 +29,7 @@ struct VHostVSock { > /*< private >*/ > VHostVSockCommon parent; > VHostVSockConf conf; >+ Error *migration_blocker; /* set when the device has no ID */ > > /*< public >*/ > }; >-- >2.47.1 >