The device IOTLB is shared by vhost backends, but clearing it requires dropping each virtqueue's IOTLB pointer and metadata cache before the old table is freed. Add a common helper for this teardown sequence so backend-specific feature code only needs to decide when the table must be cleared.
The caller must hold the device mutex. The helper does not update acked_features; backends continue to update that state in their own virtqueue loops. Signed-off-by: Jia Jia <[email protected]> --- drivers/vhost/vhost.c | 24 ++++++++++++++++++++++++ drivers/vhost/vhost.h | 1 + 2 files changed, 25 insertions(+) diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c index 269efad90369..7eaa61d9ceeb 100644 --- a/drivers/vhost/vhost.c +++ b/drivers/vhost/vhost.c @@ -2283,6 +2283,30 @@ long vhost_vring_ioctl(struct vhost_dev *d, unsigned int ioctl, void __user *argp) } EXPORT_SYMBOL_GPL(vhost_vring_ioctl); +/* Caller must hold the device mutex. */ +void vhost_clear_device_iotlb(struct vhost_dev *d) +{ + struct vhost_iotlb *iotlb; + int i; + + iotlb = d->iotlb; + d->iotlb = NULL; + + for (i = 0; i < d->nvqs; ++i) { + struct vhost_virtqueue *vq = d->vqs[i]; + + mutex_lock(&vq->mutex); + vq->iotlb = NULL; + __vhost_vq_meta_reset(vq); + mutex_unlock(&vq->mutex); + } + + vhost_clear_msg(d); + vhost_iotlb_free(iotlb); + wake_up_interruptible_poll(&d->wait, EPOLLIN | EPOLLRDNORM); +} +EXPORT_SYMBOL_GPL(vhost_clear_device_iotlb); + int vhost_init_device_iotlb(struct vhost_dev *d) { struct vhost_iotlb *niotlb, *oiotlb; diff --git a/drivers/vhost/vhost.h b/drivers/vhost/vhost.h index 0192ade6e749..3c75e8089373 100644 --- a/drivers/vhost/vhost.h +++ b/drivers/vhost/vhost.h @@ -277,6 +277,7 @@ ssize_t vhost_chr_read_iter(struct vhost_dev *dev, struct iov_iter *to, int noblock); ssize_t vhost_chr_write_iter(struct vhost_dev *dev, struct iov_iter *from); +void vhost_clear_device_iotlb(struct vhost_dev *d); int vhost_init_device_iotlb(struct vhost_dev *d); void vhost_iotlb_map_free(struct vhost_iotlb *iotlb, -- 2.34.1

