Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

vhost-vdpa: clean iotlb map during reset for older userspace

Using .compat_reset op from the previous patch, the buggy .reset
behaviour can be kept as-is on older userspace apps, which don't ack the
IOTLB_PERSIST backend feature. As this compatibility quirk is limited to
those drivers that used to be buggy in the past, it won't affect change
the behaviour or affect ABI on the setups with API compliant driver.

The separation of .compat_reset from the regular .reset allows
vhost-vdpa able to know which driver had broken behaviour before, so it
can apply the corresponding compatibility quirk to the individual driver
whenever needed. Compared to overloading the existing .reset with
flags, .compat_reset won't cause any extra burden to the implementation
of every compliant driver.

[mst: squashed in two fixup commits]

Message-Id: <1697880319-4937-6-git-send-email-si-wei.liu@oracle.com>
Message-Id: <1698102863-21122-1-git-send-email-si-wei.liu@oracle.com>
Reported-by: Dragos Tatulea <dtatulea@nvidia.com>
Tested-by: Dragos Tatulea <dtatulea@nvidia.com>
Message-Id: <1698275594-19204-1-git-send-email-si-wei.liu@oracle.com>
Reported-by: Lei Yang <leiyang@redhat.com>
Signed-off-by: Si-Wei Liu <si-wei.liu@oracle.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Tested-by: Lei Yang <leiyang@redhat.com>

authored by

Si-Wei Liu and committed by
Michael S. Tsirkin
bc91df5c a26f2e4e

+22 -7
+16 -4
drivers/vhost/vdpa.c
··· 227 227 irq_bypass_unregister_producer(&vq->call_ctx.producer); 228 228 } 229 229 230 - static int vhost_vdpa_reset(struct vhost_vdpa *v) 230 + static int _compat_vdpa_reset(struct vhost_vdpa *v) 231 231 { 232 232 struct vdpa_device *vdpa = v->vdpa; 233 + u32 flags = 0; 233 234 235 + if (v->vdev.vqs) { 236 + flags |= !vhost_backend_has_feature(v->vdev.vqs[0], 237 + VHOST_BACKEND_F_IOTLB_PERSIST) ? 238 + VDPA_RESET_F_CLEAN_MAP : 0; 239 + } 240 + 241 + return vdpa_reset(vdpa, flags); 242 + } 243 + 244 + static int vhost_vdpa_reset(struct vhost_vdpa *v) 245 + { 234 246 v->in_batch = 0; 235 - 236 - return vdpa_reset(vdpa); 247 + return _compat_vdpa_reset(v); 237 248 } 238 249 239 250 static long vhost_vdpa_bind_mm(struct vhost_vdpa *v) ··· 323 312 vhost_vdpa_unsetup_vq_irq(v, i); 324 313 325 314 if (status == 0) { 326 - ret = vdpa_reset(vdpa); 315 + ret = _compat_vdpa_reset(v); 327 316 if (ret) 328 317 return ret; 329 318 } else ··· 1355 1344 vhost_vdpa_free_domain(v); 1356 1345 vhost_dev_cleanup(&v->vdev); 1357 1346 kfree(v->vdev.vqs); 1347 + v->vdev.vqs = NULL; 1358 1348 } 1359 1349 1360 1350 static int vhost_vdpa_open(struct inode *inode, struct file *filep)
+1 -1
drivers/virtio/virtio_vdpa.c
··· 100 100 { 101 101 struct vdpa_device *vdpa = vd_get_vdpa(vdev); 102 102 103 - vdpa_reset(vdpa); 103 + vdpa_reset(vdpa, 0); 104 104 } 105 105 106 106 static bool virtio_vdpa_notify(struct virtqueue *vq)
+5 -2
include/linux/vdpa.h
··· 519 519 return vdev->dma_dev; 520 520 } 521 521 522 - static inline int vdpa_reset(struct vdpa_device *vdev) 522 + static inline int vdpa_reset(struct vdpa_device *vdev, u32 flags) 523 523 { 524 524 const struct vdpa_config_ops *ops = vdev->config; 525 525 int ret; 526 526 527 527 down_write(&vdev->cf_lock); 528 528 vdev->features_valid = false; 529 - ret = ops->reset(vdev); 529 + if (ops->compat_reset && flags) 530 + ret = ops->compat_reset(vdev, flags); 531 + else 532 + ret = ops->reset(vdev); 530 533 up_write(&vdev->cf_lock); 531 534 return ret; 532 535 }