diff --git a/drivers/vhost/vsock.c b/drivers/vhost/vsock.c index e6ac9b41c2a5..0cb87971d749 100644 --- a/drivers/vhost/vsock.c +++ b/drivers/vhost/vsock.c @@ -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);