mirror of
https://github.com/torvalds/linux.git
synced 2026-06-01 11:03:43 +02:00
vfio: Wait for dma-buf invalidation to complete
dma-buf invalidation is handled asynchronously by the hardware, so VFIO
must wait until all affected objects have been fully invalidated.
In addition, the dma-buf exporter is expecting that all importers unmap any
buffers they previously mapped.
Fixes: 5d74781ebc ("vfio/pci: Add dma-buf export support for MMIO regions")
Reviewed-by: Kevin Tian <kevin.tian@intel.com>
Reviewed-by: Alex Williamson <alex@shazbot.org>
Signed-off-by: Leon Romanovsky <leonro@nvidia.com>
Signed-off-by: Christian König <christian.koenig@amd.com>
Link: https://lore.kernel.org/r/20260131-dmabuf-revoke-v7-4-463d956bd527@nvidia.com
This commit is contained in:
parent
a408c0ca0c
commit
1a8a5227f2
|
|
@ -17,6 +17,8 @@ struct vfio_pci_dma_buf {
|
||||||
struct phys_vec *phys_vec;
|
struct phys_vec *phys_vec;
|
||||||
struct p2pdma_provider *provider;
|
struct p2pdma_provider *provider;
|
||||||
u32 nr_ranges;
|
u32 nr_ranges;
|
||||||
|
struct kref kref;
|
||||||
|
struct completion comp;
|
||||||
u8 revoked : 1;
|
u8 revoked : 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -44,27 +46,46 @@ static int vfio_pci_dma_buf_attach(struct dma_buf *dmabuf,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void vfio_pci_dma_buf_done(struct kref *kref)
|
||||||
|
{
|
||||||
|
struct vfio_pci_dma_buf *priv =
|
||||||
|
container_of(kref, struct vfio_pci_dma_buf, kref);
|
||||||
|
|
||||||
|
complete(&priv->comp);
|
||||||
|
}
|
||||||
|
|
||||||
static struct sg_table *
|
static struct sg_table *
|
||||||
vfio_pci_dma_buf_map(struct dma_buf_attachment *attachment,
|
vfio_pci_dma_buf_map(struct dma_buf_attachment *attachment,
|
||||||
enum dma_data_direction dir)
|
enum dma_data_direction dir)
|
||||||
{
|
{
|
||||||
struct vfio_pci_dma_buf *priv = attachment->dmabuf->priv;
|
struct vfio_pci_dma_buf *priv = attachment->dmabuf->priv;
|
||||||
|
struct sg_table *ret;
|
||||||
|
|
||||||
dma_resv_assert_held(priv->dmabuf->resv);
|
dma_resv_assert_held(priv->dmabuf->resv);
|
||||||
|
|
||||||
if (priv->revoked)
|
if (priv->revoked)
|
||||||
return ERR_PTR(-ENODEV);
|
return ERR_PTR(-ENODEV);
|
||||||
|
|
||||||
return dma_buf_phys_vec_to_sgt(attachment, priv->provider,
|
ret = dma_buf_phys_vec_to_sgt(attachment, priv->provider,
|
||||||
priv->phys_vec, priv->nr_ranges,
|
priv->phys_vec, priv->nr_ranges,
|
||||||
priv->size, dir);
|
priv->size, dir);
|
||||||
|
if (IS_ERR(ret))
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
kref_get(&priv->kref);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void vfio_pci_dma_buf_unmap(struct dma_buf_attachment *attachment,
|
static void vfio_pci_dma_buf_unmap(struct dma_buf_attachment *attachment,
|
||||||
struct sg_table *sgt,
|
struct sg_table *sgt,
|
||||||
enum dma_data_direction dir)
|
enum dma_data_direction dir)
|
||||||
{
|
{
|
||||||
|
struct vfio_pci_dma_buf *priv = attachment->dmabuf->priv;
|
||||||
|
|
||||||
|
dma_resv_assert_held(priv->dmabuf->resv);
|
||||||
|
|
||||||
dma_buf_free_sgt(attachment, sgt, dir);
|
dma_buf_free_sgt(attachment, sgt, dir);
|
||||||
|
kref_put(&priv->kref, vfio_pci_dma_buf_done);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void vfio_pci_dma_buf_release(struct dma_buf *dmabuf)
|
static void vfio_pci_dma_buf_release(struct dma_buf *dmabuf)
|
||||||
|
|
@ -286,6 +307,9 @@ int vfio_pci_core_feature_dma_buf(struct vfio_pci_core_device *vdev, u32 flags,
|
||||||
goto err_dev_put;
|
goto err_dev_put;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
kref_init(&priv->kref);
|
||||||
|
init_completion(&priv->comp);
|
||||||
|
|
||||||
/* dma_buf_put() now frees priv */
|
/* dma_buf_put() now frees priv */
|
||||||
INIT_LIST_HEAD(&priv->dmabufs_elm);
|
INIT_LIST_HEAD(&priv->dmabufs_elm);
|
||||||
down_write(&vdev->memory_lock);
|
down_write(&vdev->memory_lock);
|
||||||
|
|
@ -330,9 +354,33 @@ void vfio_pci_dma_buf_move(struct vfio_pci_core_device *vdev, bool revoked)
|
||||||
|
|
||||||
if (priv->revoked != revoked) {
|
if (priv->revoked != revoked) {
|
||||||
dma_resv_lock(priv->dmabuf->resv, NULL);
|
dma_resv_lock(priv->dmabuf->resv, NULL);
|
||||||
priv->revoked = revoked;
|
if (revoked)
|
||||||
|
priv->revoked = true;
|
||||||
dma_buf_invalidate_mappings(priv->dmabuf);
|
dma_buf_invalidate_mappings(priv->dmabuf);
|
||||||
|
dma_resv_wait_timeout(priv->dmabuf->resv,
|
||||||
|
DMA_RESV_USAGE_BOOKKEEP, false,
|
||||||
|
MAX_SCHEDULE_TIMEOUT);
|
||||||
dma_resv_unlock(priv->dmabuf->resv);
|
dma_resv_unlock(priv->dmabuf->resv);
|
||||||
|
if (revoked) {
|
||||||
|
kref_put(&priv->kref, vfio_pci_dma_buf_done);
|
||||||
|
wait_for_completion(&priv->comp);
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* Kref is initialize again, because when revoke
|
||||||
|
* was performed the reference counter was decreased
|
||||||
|
* to zero to trigger completion.
|
||||||
|
*/
|
||||||
|
kref_init(&priv->kref);
|
||||||
|
/*
|
||||||
|
* There is no need to wait as no mapping was
|
||||||
|
* performed when the previous status was
|
||||||
|
* priv->revoked == true.
|
||||||
|
*/
|
||||||
|
reinit_completion(&priv->comp);
|
||||||
|
dma_resv_lock(priv->dmabuf->resv, NULL);
|
||||||
|
priv->revoked = false;
|
||||||
|
dma_resv_unlock(priv->dmabuf->resv);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
fput(priv->dmabuf->file);
|
fput(priv->dmabuf->file);
|
||||||
}
|
}
|
||||||
|
|
@ -353,7 +401,12 @@ void vfio_pci_dma_buf_cleanup(struct vfio_pci_core_device *vdev)
|
||||||
priv->vdev = NULL;
|
priv->vdev = NULL;
|
||||||
priv->revoked = true;
|
priv->revoked = true;
|
||||||
dma_buf_invalidate_mappings(priv->dmabuf);
|
dma_buf_invalidate_mappings(priv->dmabuf);
|
||||||
|
dma_resv_wait_timeout(priv->dmabuf->resv,
|
||||||
|
DMA_RESV_USAGE_BOOKKEEP, false,
|
||||||
|
MAX_SCHEDULE_TIMEOUT);
|
||||||
dma_resv_unlock(priv->dmabuf->resv);
|
dma_resv_unlock(priv->dmabuf->resv);
|
||||||
|
kref_put(&priv->kref, vfio_pci_dma_buf_done);
|
||||||
|
wait_for_completion(&priv->comp);
|
||||||
vfio_device_put_registration(&vdev->vdev);
|
vfio_device_put_registration(&vdev->vdev);
|
||||||
fput(priv->dmabuf->file);
|
fput(priv->dmabuf->file);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user