From: Baolu Lu <baolu.lu@linux.intel.com>
To: Xu Yilun <yilun.xu@linux.intel.com>,
jgg@nvidia.com, jgg@ziepe.ca, kevin.tian@intel.com,
will@kernel.org, aneesh.kumar@kernel.org
Cc: iommu@lists.linux.dev, linux-kernel@vger.kernel.org,
joro@8bytes.org, robin.murphy@arm.com, shuah@kernel.org,
nicolinc@nvidia.com, aik@amd.com, dan.j.williams@intel.com,
yilun.xu@intel.com
Subject: Re: [PATCH v3 2/5] iommufd: Destroy vdevice on idevice destroy
Date: Mon, 30 Jun 2025 13:08:32 +0800 [thread overview]
Message-ID: <b5b84208-e43c-483e-838b-c42375d3bada@linux.intel.com> (raw)
In-Reply-To: <20250627033809.1730752-3-yilun.xu@linux.intel.com>
On 6/27/25 11:38, Xu Yilun wrote:
> Destroy iommufd_vdevice (vdev) on iommufd_idevice (idev) destroy so
> that vdev can't outlive idev.
>
> iommufd_device (idev) represents the physical device bound to iommufd,
> while the iommufd_vdevice (vdev) represents the virtual instance of the
> physical device in the VM. The lifecycle of the vdev should not be
> longer than idev. This doesn't cause real problem on existing use cases
> cause vdev doesn't impact the physical device, only provides
> virtualization information. But to extend vdev for Confidential
> Computing (CC), there are needs to do secure configuration for the vdev,
> e.g. TSM Bind/Unbind. These configurations should be rolled back on idev
> destroy, or the external driver (VFIO) functionality may be impact.
>
> Building the association between idev & vdev requires the two objects
> pointing each other, but not referencing each other. This requires
> proper locking. This is done by reviving some of Nicolin's patch [1].
>
> There are 3 cases on idev destroy:
>
> 1. vdev is already destroyed by userspace. No extra handling needed.
> 2. vdev is still alive. Use iommufd_object_tombstone_user() to
> destroy vdev and tombstone the vdev ID.
> 3. vdev is being destroyed by userspace. The vdev ID is already freed,
> but vdev destroy handler is not completed. Destroy the vdev
> immediately. To solve the racing with userspace destruction, make
> iommufd_vdevice_abort() reentrant.
>
> [1]:https://lore.kernel.org/
> all/53025c827c44d68edb6469bfd940a8e8bc6147a5.1729897278.git.nicolinc@nvidia.com/
>
> Originally-by: Nicolin Chen<nicolinc@nvidia.com>
> Suggested-by: Jason Gunthorpe<jgg@nvidia.com>
> Co-developed-by: Aneesh Kumar K.V (Arm)<aneesh.kumar@kernel.org>
> Signed-off-by: Aneesh Kumar K.V (Arm)<aneesh.kumar@kernel.org>
> Signed-off-by: Xu Yilun<yilun.xu@linux.intel.com>
> ---
> drivers/iommu/iommufd/device.c | 42 +++++++++++++++++++++++
> drivers/iommu/iommufd/iommufd_private.h | 11 +++++++
> drivers/iommu/iommufd/main.c | 1 +
> drivers/iommu/iommufd/viommu.c | 44 +++++++++++++++++++++++--
> 4 files changed, 95 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/iommu/iommufd/device.c b/drivers/iommu/iommufd/device.c
> index 86244403b532..0937d4989185 100644
> --- a/drivers/iommu/iommufd/device.c
> +++ b/drivers/iommu/iommufd/device.c
> @@ -137,11 +137,53 @@ static struct iommufd_group *iommufd_get_group(struct iommufd_ctx *ictx,
> }
> }
>
> +static void iommufd_device_remove_vdev(struct iommufd_device *idev)
> +{
> + struct iommufd_vdevice *vdev;
> +
> + mutex_lock(&idev->igroup->lock);
> + /* vdev has been completely destroyed by userspace */
> + if (!idev->vdev)
> + goto out_unlock;
> +
> + vdev = iommufd_get_vdevice(idev->ictx, idev->vdev->obj.id);
> + if (IS_ERR(vdev)) {
> + /*
> + * vdev is removed from xarray by userspace, but is not
> + * destroyed/freed. Since iommufd_vdevice_abort() is reentrant,
> + * safe to destroy vdev here.
> + */
> + iommufd_vdevice_abort(&idev->vdev->obj);
> + goto out_unlock;
> + }
> +
> + /* Should never happen */
> + if (WARN_ON(vdev != idev->vdev)) {
> + iommufd_put_object(idev->ictx, &vdev->obj);
> + goto out_unlock;
> + }
> +
> + /*
> + * vdev is still alive. Hold a users refcount to prevent racing with
> + * userspace destruction, then use iommufd_object_tombstone_user() to
> + * destroy it and leave a tombstone.
> + */
> + refcount_inc(&vdev->obj.users);
> + iommufd_put_object(idev->ictx, &vdev->obj);
> + mutex_unlock(&idev->igroup->lock);
> + iommufd_object_tombstone_user(idev->ictx, &vdev->obj);
> + return;
> +
> +out_unlock:
> + mutex_unlock(&idev->igroup->lock);
> +}
> +
> void iommufd_device_destroy(struct iommufd_object *obj)
> {
> struct iommufd_device *idev =
> container_of(obj, struct iommufd_device, obj);
>
> + iommufd_device_remove_vdev(idev);
> iommu_device_release_dma_owner(idev->dev);
> iommufd_put_group(idev->igroup);
> if (!iommufd_selftest_is_mock_dev(idev->dev))
> diff --git a/drivers/iommu/iommufd/iommufd_private.h b/drivers/iommu/iommufd/iommufd_private.h
> index fbc9ef78d81f..f58aa4439c53 100644
> --- a/drivers/iommu/iommufd/iommufd_private.h
> +++ b/drivers/iommu/iommufd/iommufd_private.h
> @@ -446,6 +446,7 @@ struct iommufd_device {
> /* always the physical device */
> struct device *dev;
> bool enforce_cache_coherency;
> + struct iommufd_vdevice *vdev;
> };
>
> static inline struct iommufd_device *
> @@ -621,6 +622,7 @@ int iommufd_viommu_alloc_ioctl(struct iommufd_ucmd *ucmd);
> void iommufd_viommu_destroy(struct iommufd_object *obj);
> int iommufd_vdevice_alloc_ioctl(struct iommufd_ucmd *ucmd);
> void iommufd_vdevice_destroy(struct iommufd_object *obj);
> +void iommufd_vdevice_abort(struct iommufd_object *obj);
>
> struct iommufd_vdevice {
> struct iommufd_object obj;
> @@ -628,8 +630,17 @@ struct iommufd_vdevice {
> struct iommufd_viommu *viommu;
> struct device *dev;
> u64 id; /* per-vIOMMU virtual ID */
> + struct iommufd_device *idev;
> };
>
> +static inline struct iommufd_vdevice *
> +iommufd_get_vdevice(struct iommufd_ctx *ictx, u32 id)
> +{
> + return container_of(iommufd_get_object(ictx, id,
> + IOMMUFD_OBJ_VDEVICE),
> + struct iommufd_vdevice, obj);
> +}
> +
> #ifdef CONFIG_IOMMUFD_TEST
> int iommufd_test(struct iommufd_ucmd *ucmd);
> void iommufd_selftest_destroy(struct iommufd_object *obj);
> diff --git a/drivers/iommu/iommufd/main.c b/drivers/iommu/iommufd/main.c
> index 620923669b42..64731b4fdbdf 100644
> --- a/drivers/iommu/iommufd/main.c
> +++ b/drivers/iommu/iommufd/main.c
> @@ -529,6 +529,7 @@ static const struct iommufd_object_ops iommufd_object_ops[] = {
> },
> [IOMMUFD_OBJ_VDEVICE] = {
> .destroy = iommufd_vdevice_destroy,
> + .abort = iommufd_vdevice_abort,
> },
> [IOMMUFD_OBJ_VEVENTQ] = {
> .destroy = iommufd_veventq_destroy,
> diff --git a/drivers/iommu/iommufd/viommu.c b/drivers/iommu/iommufd/viommu.c
> index 01df2b985f02..632d1d7b8fd8 100644
> --- a/drivers/iommu/iommufd/viommu.c
> +++ b/drivers/iommu/iommufd/viommu.c
> @@ -84,16 +84,38 @@ int iommufd_viommu_alloc_ioctl(struct iommufd_ucmd *ucmd)
> return rc;
> }
>
> -void iommufd_vdevice_destroy(struct iommufd_object *obj)
> +void iommufd_vdevice_abort(struct iommufd_object *obj)
> {
> struct iommufd_vdevice *vdev =
> container_of(obj, struct iommufd_vdevice, obj);
> struct iommufd_viommu *viommu = vdev->viommu;
> + struct iommufd_device *idev = vdev->idev;
> +
> + lockdep_assert_held(&idev->igroup->lock);
> +
> + /*
> + * iommufd_vdevice_abort() could be reentrant, by
> + * iommufd_device_unbind() or by iommufd_destroy(). Cleanup only once.
> + */
> + if (!viommu)
> + return;
>
> /* xa_cmpxchg is okay to fail if alloc failed xa_cmpxchg previously */
> xa_cmpxchg(&viommu->vdevs, vdev->id, vdev, NULL, GFP_KERNEL);
> refcount_dec(&viommu->obj.users);
> put_device(vdev->dev);
> + vdev->viommu = NULL;
> + idev->vdev = NULL;
I feel it makes more sense to reorder the operations like this:
vdev->viommu = NULL;
vdev->idev = NULL;
idev->vdev = NULL;
put_device(vdev->dev);
put_device(vdev->dev) could potentially trigger other code paths that
might attempt to reference vdev or its associated pointers. Therefore,
it's safer to null all the relevant reference pointers before calling
put_device().
Others look good to me,
Reviewed-by: Lu Baolu <baolu.lu@linux.intel.com>
Thanks,
baolu
next prev parent reply other threads:[~2025-06-30 5:09 UTC|newest]
Thread overview: 32+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-06-27 3:38 [PATCH v3 0/5] iommufd: Destroy vdevice on device unbind Xu Yilun
2025-06-27 3:38 ` [PATCH v3 1/5] iommufd: Add iommufd_object_tombstone_user() helper Xu Yilun
2025-06-30 3:08 ` Baolu Lu
2025-06-30 7:24 ` Xu Yilun
2025-06-30 5:52 ` Tian, Kevin
2025-06-30 6:41 ` Xu Yilun
2025-06-30 19:50 ` Nicolin Chen
2025-07-08 8:45 ` Xu Yilun
2025-06-27 3:38 ` [PATCH v3 2/5] iommufd: Destroy vdevice on idevice destroy Xu Yilun
2025-06-30 5:08 ` Baolu Lu [this message]
2025-07-08 8:34 ` Xu Yilun
2025-06-30 6:27 ` Tian, Kevin
2025-06-30 10:18 ` Xu Yilun
2025-06-30 14:50 ` Jason Gunthorpe
2025-07-01 9:19 ` Xu Yilun
2025-07-01 12:13 ` Jason Gunthorpe
2025-07-02 2:23 ` Xu Yilun
2025-07-02 9:13 ` Tian, Kevin
2025-07-02 12:40 ` Jason Gunthorpe
2025-07-03 4:32 ` Tian, Kevin
2025-07-03 11:21 ` Jason Gunthorpe
2025-07-07 10:58 ` Xu Yilun
2025-07-07 12:25 ` Jason Gunthorpe
2025-07-07 19:41 ` Xu Yilun
2025-06-30 19:34 ` Nicolin Chen
2025-07-08 8:12 ` Xu Yilun
2025-06-27 3:38 ` [PATCH v3 3/5] iommufd/vdevice: Remove struct device reference from struct vdevice Xu Yilun
2025-06-30 5:11 ` Baolu Lu
2025-07-04 15:06 ` Jason Gunthorpe
2025-06-27 3:38 ` [PATCH v3 4/5] iommufd/selftest: Explicitly skip tests for inapplicable variant Xu Yilun
2025-07-04 15:07 ` Jason Gunthorpe
2025-06-27 3:38 ` [PATCH v3 5/5] iommufd/selftest: Add coverage for vdevice tombstone Xu Yilun
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=b5b84208-e43c-483e-838b-c42375d3bada@linux.intel.com \
--to=baolu.lu@linux.intel.com \
--cc=aik@amd.com \
--cc=aneesh.kumar@kernel.org \
--cc=dan.j.williams@intel.com \
--cc=iommu@lists.linux.dev \
--cc=jgg@nvidia.com \
--cc=jgg@ziepe.ca \
--cc=joro@8bytes.org \
--cc=kevin.tian@intel.com \
--cc=linux-kernel@vger.kernel.org \
--cc=nicolinc@nvidia.com \
--cc=robin.murphy@arm.com \
--cc=shuah@kernel.org \
--cc=will@kernel.org \
--cc=yilun.xu@intel.com \
--cc=yilun.xu@linux.intel.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox