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().
Use the (suffixed) device path as the key in CPR hash table. Device path is obtained with qdev_get_dev_path() and is essentially the device's address on the underlying bus. As any vhost-vsock device is attached to a virtio bus, whose .get_dev_path() forwards to the proxy device, and every proxy bus (PCI, MMIO, CCW) implements it, we should always be getting a unique non-empty path with qdev_get_dev_path(). 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. Until then CPR remains blocked, so the restore path added here is not reachable yet. Signed-off-by: Andrey Drobyshev <[email protected]> --- hw/virtio/vhost-vsock.c | 37 ++++++++++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/hw/virtio/vhost-vsock.c b/hw/virtio/vhost-vsock.c index 3ec20d87606..6e89007b2ce 100644 --- a/hw/virtio/vhost-vsock.c +++ b/hw/virtio/vhost-vsock.c @@ -69,6 +69,18 @@ static int vhost_vsock_set_running(VirtIODevice *vdev, int start) return 0; } +/* + * Any vhost-vsock device is attached to a virtio bus, whose .get_dev_path() + * forwards to the proxy device, and every proxy bus (PCI, MMIO, CCW) + * implements it. Thus qdev_get_dev_path() always returns a non-empty string, + * which guarantees us a unique CPR name. + */ +static char *vhost_vsock_cpr_name(DeviceState *dev) +{ + g_autofree char *path = qdev_get_dev_path(dev); + g_assert(path && path[0]); + return g_strdup_printf("%s/vhost-vsock", path); +} static int vhost_vsock_set_status(VirtIODevice *vdev, uint8_t status) { @@ -143,6 +155,8 @@ 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); + g_autofree char *cpr_name = vhost_vsock_cpr_name(dev); + bool cpr_incoming = cpr_is_incoming(); int vhostfd; int ret; @@ -170,7 +184,14 @@ static void vhost_vsock_device_realize(DeviceState *dev, Error **errp) return; } - if (vsock->conf.vhostfd) { + if (cpr_incoming) { + /* Reuse the fd handed over from the source QEMU */ + vhostfd = cpr_find_fd(cpr_name, 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: "); @@ -186,6 +207,9 @@ static void vhost_vsock_device_realize(DeviceState *dev, Error **errp) if (!qemu_set_blocking(vhostfd, false, errp)) { close(vhostfd); + if (cpr_incoming) { + cpr_delete_fd(cpr_name, 0); + } goto err_blocker; } @@ -207,11 +231,20 @@ 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 (!cpr_incoming && !cpr_save_fd(cpr_name, 0, vhostfd, errp)) { + goto err_vhost_dev; + } + return; err_vhost_dev: /* vhost_dev_cleanup() closes the vhostfd passed to vhost_dev_init() */ vhost_dev_cleanup(&vvc->vhost_dev); + if (cpr_incoming) { + /* The fd came from cpr_find_fd() and is closed now, drop the entry */ + cpr_delete_fd(cpr_name, 0); + } err_virtio: vhost_vsock_common_unrealize(vdev); err_blocker: @@ -223,10 +256,12 @@ static void vhost_vsock_device_unrealize(DeviceState *dev) VHostVSockCommon *vvc = VHOST_VSOCK_COMMON(dev); VirtIODevice *vdev = VIRTIO_DEVICE(dev); VHostVSock *vsock = VHOST_VSOCK(dev); + g_autofree char *cpr_name = vhost_vsock_cpr_name(dev); /* This will stop vhost backend if appropriate. */ vhost_vsock_set_status(vdev, 0); + cpr_delete_fd(cpr_name, 0); migrate_del_blocker(&vsock->migration_blocker); vhost_dev_cleanup(&vvc->vhost_dev); vhost_vsock_common_unrealize(vdev); -- 2.47.1
