vhost/vsock: add VHOST_RESET_OWNER ioctl

This ioctl is needed for QEMU's CPR (checkpoint-restore) migration of
the guest with vhost-vsock device.  For this to work, we need to reset
the device ownership on the source side by calling RESET_OWNER, and then
claim it on the dest side by calling SET_OWNER.  We expect not to lose any
AF_VSOCK connection while this happens.

To that end, unlike the release path, RESET_OWNER keeps the guest CID
hashed: established connections survive, and host sends issued while
the device is between owners simply stay on send_pkt_queue until the
next device start drains them.

Since the device stays reachable through the CID hash, the lockless
send/cancel paths can race with the worker teardown in
vhost_workers_free().  The previous commit ("vhost: synchronize with
RCU readers when freeing workers") makes that safe.

Signed-off-by: Pavel Tikhomirov <ptikhomirov@virtuozzo.com>
Signed-off-by: Andrey Drobyshev <andrey.drobyshev@virtuozzo.com>
Reviewed-by: Stefano Garzarella <sgarzare@redhat.com>
Acked-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Message-ID: <20260724114542.734623-6-andrey.drobyshev@virtuozzo.com>
This commit is contained in:
Pavel Tikhomirov 2026-07-24 14:45:42 +03:00 committed by Michael S. Tsirkin
parent 5efd97e6f0
commit 8f2c2fb94a

View File

@ -905,6 +905,36 @@ static int vhost_vsock_set_features(struct vhost_vsock *vsock, u64 features)
return -EFAULT;
}
static long vhost_vsock_reset_owner(struct vhost_vsock *vsock)
{
struct vhost_iotlb *umem;
long err;
mutex_lock(&vsock->dev.mutex);
err = vhost_dev_check_owner(&vsock->dev);
if (err)
goto done;
umem = vhost_dev_reset_owner_prepare();
if (!umem) {
err = -ENOMEM;
goto done;
}
vhost_vsock_drop_backends(vsock);
vhost_vsock_flush(vsock);
vhost_dev_stop(&vsock->dev);
/*
* vsock keeps the CID hashed across RESET_OWNER, so a lockless sender
* can still reach the device while its workers are freed. Pass
* sync=true so vhost_workers_free() fences RCU readers and flushes
* before freeing them.
*/
vhost_dev_reset_owner(&vsock->dev, umem, true);
done:
mutex_unlock(&vsock->dev.mutex);
return err;
}
static long vhost_vsock_dev_ioctl(struct file *f, unsigned int ioctl,
unsigned long arg)
{
@ -948,6 +978,8 @@ static long vhost_vsock_dev_ioctl(struct file *f, unsigned int ioctl,
return -EOPNOTSUPP;
vhost_set_backend_features(&vsock->dev, features);
return 0;
case VHOST_RESET_OWNER:
return vhost_vsock_reset_owner(vsock);
default:
mutex_lock(&vsock->dev.mutex);
r = vhost_dev_ioctl(&vsock->dev, ioctl, argp);