diff mbox series

[05/14] vfio: refactor noiommu group creation

Message ID 20210811151500.2744-6-hch@lst.de (mailing list archive)
State New, archived
Headers show
Series [01/14] vfio: Move vfio_iommu_group_get() to vfio_register_group_dev() | expand

Commit Message

Christoph Hellwig Aug. 11, 2021, 3:14 p.m. UTC
Split the actual noiommu group creation from vfio_iommu_group_get into a
new helper, and open code the rest of vfio_iommu_group_get in its only
caller.  This creates an antirely separate and clear code path for the
noiommu group creation.

Signed-off-by: Christoph Hellwig <hch@lst.de>
---
 drivers/vfio/vfio.c | 100 +++++++++++++++++++++++---------------------
 1 file changed, 52 insertions(+), 48 deletions(-)

Comments

Alex Williamson Aug. 11, 2021, 10:03 p.m. UTC | #1
On Wed, 11 Aug 2021 17:14:51 +0200
Christoph Hellwig <hch@lst.de> wrote:
> @@ -833,14 +789,61 @@ void vfio_uninit_group_dev(struct vfio_device *device)
>  }
>  EXPORT_SYMBOL_GPL(vfio_uninit_group_dev);
>  
> -struct vfio_group *vfio_group_find_or_alloc(struct device *dev)
> +#ifdef CONFIG_VFIO_NOIOMMU
> +static struct vfio_group *vfio_noiommu_group_alloc(struct device *dev)
>  {
>  	struct iommu_group *iommu_group;
>  	struct vfio_group *group;
> +	int ret;
>  
> -	iommu_group = vfio_iommu_group_get(dev);
> -	if (!iommu_group)
> +	iommu_group = iommu_group_alloc();
> +	if (IS_ERR(iommu_group))
> +		return ERR_CAST(iommu_group);
> +
> +	iommu_group_set_name(iommu_group, "vfio-noiommu");
> +	iommu_group_set_iommudata(iommu_group, &noiommu, NULL);
> +	ret = iommu_group_add_device(iommu_group, dev);
> +	if (ret)
> +		goto out_put_group;
> +
> +	group = vfio_create_group(iommu_group);
> +	if (IS_ERR(group)) {
> +		ret = PTR_ERR(group);
> +		goto out_remove_device;
> +	}
> +
> +	return group;
> +
> +out_remove_device:
> +	iommu_group_remove_device(dev);
> +out_put_group:
> +	iommu_group_put(iommu_group);
> +	return ERR_PTR(ret);
> +}
> +#endif
> +
> +static struct vfio_group *vfio_group_find_or_alloc(struct device *dev)
> +{
> +	struct iommu_group *iommu_group;
> +	struct vfio_group *group;
> +
> +	iommu_group = iommu_group_get(dev);
> +	if (!iommu_group) {
> +#ifdef CONFIG_VFIO_NOIOMMU
> +		/*
> +		 * With noiommu enabled, create an IOMMU group for devices that
> +		 * don't already have one and don't have an iommu_ops on their
> +		 * bus.  Taint the kernel because we're about to give a DMA
> +		 * capable device to a user without IOMMU protection.
> +		 */
> +		if (noiommu && !iommu_present(dev->bus)) {
> +			add_taint(TAINT_USER, LOCKDEP_STILL_OK);
> +			dev_warn(dev, "Adding kernel taint for vfio-noiommu group on device\n");
> +			return vfio_noiommu_group_alloc(dev);

Nit, we taint regardless of the success of this function, should we
move the tainting back into the function (using the flags to skip for
mdev in subsequent patches) or swap the order to check the return value
before tainting?  Thanks,

Alex
Christoph Hellwig Aug. 12, 2021, 7:26 a.m. UTC | #2
On Wed, Aug 11, 2021 at 04:03:41PM -0600, Alex Williamson wrote:
> > +			dev_warn(dev, "Adding kernel taint for vfio-noiommu group on device\n");
> > +			return vfio_noiommu_group_alloc(dev);
> 
> Nit, we taint regardless of the success of this function, should we
> move the tainting back into the function (using the flags to skip for
> mdev in subsequent patches) or swap the order to check the return value
> before tainting?  Thanks,

Does it really matter to have the extra thread if a memory allocation
failed when going down this route?
Alex Williamson Aug. 12, 2021, 3:56 p.m. UTC | #3
On Thu, 12 Aug 2021 09:26:17 +0200
Christoph Hellwig <hch@lst.de> wrote:

> On Wed, Aug 11, 2021 at 04:03:41PM -0600, Alex Williamson wrote:
> > > +			dev_warn(dev, "Adding kernel taint for vfio-noiommu group on device\n");
> > > +			return vfio_noiommu_group_alloc(dev);  
> > 
> > Nit, we taint regardless of the success of this function, should we
> > move the tainting back into the function (using the flags to skip for
> > mdev in subsequent patches) or swap the order to check the return value
> > before tainting?  Thanks,  
> 
> Does it really matter to have the extra thread if a memory allocation
> failed when going down this route?

Extra thread?  In practice this is unlikely to ever fail, but if we've
chosen the point at which we have a no-iommu group as where we taint,
then let's at least be consistent and not move that back to the point
where we tried to make a no-iommu group, regardless of whether it was
successful.  Thanks,

Alex
Christoph Hellwig Aug. 12, 2021, 4:14 p.m. UTC | #4
On Thu, Aug 12, 2021 at 09:56:14AM -0600, Alex Williamson wrote:
> On Thu, 12 Aug 2021 09:26:17 +0200
> Christoph Hellwig <hch@lst.de> wrote:
> 
> > On Wed, Aug 11, 2021 at 04:03:41PM -0600, Alex Williamson wrote:
> > > > +			dev_warn(dev, "Adding kernel taint for vfio-noiommu group on device\n");
> > > > +			return vfio_noiommu_group_alloc(dev);  
> > > 
> > > Nit, we taint regardless of the success of this function, should we
> > > move the tainting back into the function (using the flags to skip for
> > > mdev in subsequent patches) or swap the order to check the return value
> > > before tainting?  Thanks,  
> > 
> > Does it really matter to have the extra thread if a memory allocation
> > failed when going down this route?
> 
> Extra thread?  In practice this is unlikely to ever fail, but if we've
> chosen the point at which we have a no-iommu group as where we taint,
> then let's at least be consistent and not move that back to the point
> where we tried to make a no-iommu group, regardless of whether it was
> successful.  Thanks,

Sorry, the mental spell checker kicked in.  Thread should have read
taint instead.

But if you don't want to tain in the failure case I'll need to refactor
this a bit.
Christoph Hellwig Aug. 15, 2021, 3:48 p.m. UTC | #5
Here is a version with the tain only on successful groip allocation:

http://git.infradead.org/users/hch/misc.git/commit/bdb5d2401ebd43ae6c069aeaa8a64e0c774dd104

I'm not going to spam the list with the whole series until a few more
reviews are in.
Jason Gunthorpe Aug. 18, 2021, 11:32 p.m. UTC | #6
On Sun, Aug 15, 2021 at 05:48:34PM +0200, Christoph Hellwig wrote:
> Here is a version with the tain only on successful groip allocation:
> 
> http://git.infradead.org/users/hch/misc.git/commit/bdb5d2401ebd43ae6c069aeaa8a64e0c774dd104
> 
> I'm not going to spam the list with the whole series until a few more
> reviews are in.

I hope to look at it next week after I unbury my mailboxes..

Thanks,
Jason
diff mbox series

Patch

diff --git a/drivers/vfio/vfio.c b/drivers/vfio/vfio.c
index 9e97ad36a1c052..d96acd7af50398 100644
--- a/drivers/vfio/vfio.c
+++ b/drivers/vfio/vfio.c
@@ -169,50 +169,6 @@  static void vfio_release_device_set(struct vfio_device *device)
 	xa_unlock(&vfio_device_set_xa);
 }
 
-static struct iommu_group *vfio_iommu_group_get(struct device *dev)
-{
-	struct iommu_group *group;
-	int __maybe_unused ret;
-
-	group = iommu_group_get(dev);
-
-#ifdef CONFIG_VFIO_NOIOMMU
-	/*
-	 * With noiommu enabled, an IOMMU group will be created for a device
-	 * that doesn't already have one and doesn't have an iommu_ops on their
-	 * bus.  We set iommudata simply to be able to identify these groups
-	 * as special use and for reclamation later.
-	 */
-	if (group || !noiommu || iommu_present(dev->bus))
-		return group;
-
-	group = iommu_group_alloc();
-	if (IS_ERR(group))
-		return NULL;
-
-	iommu_group_set_name(group, "vfio-noiommu");
-	iommu_group_set_iommudata(group, &noiommu, NULL);
-	ret = iommu_group_add_device(group, dev);
-	if (ret) {
-		iommu_group_put(group);
-		return NULL;
-	}
-
-	/*
-	 * Where to taint?  At this point we've added an IOMMU group for a
-	 * device that is not backed by iommu_ops, therefore any iommu_
-	 * callback using iommu_ops can legitimately Oops.  So, while we may
-	 * be about to give a DMA capable device to a user without IOMMU
-	 * protection, which is clearly taint-worthy, let's go ahead and do
-	 * it here.
-	 */
-	add_taint(TAINT_USER, LOCKDEP_STILL_OK);
-	dev_warn(dev, "Adding kernel taint for vfio-noiommu group on device\n");
-#endif
-
-	return group;
-}
-
 static void vfio_iommu_group_put(struct iommu_group *group, struct device *dev)
 {
 #ifdef CONFIG_VFIO_NOIOMMU
@@ -833,14 +789,61 @@  void vfio_uninit_group_dev(struct vfio_device *device)
 }
 EXPORT_SYMBOL_GPL(vfio_uninit_group_dev);
 
-struct vfio_group *vfio_group_find_or_alloc(struct device *dev)
+#ifdef CONFIG_VFIO_NOIOMMU
+static struct vfio_group *vfio_noiommu_group_alloc(struct device *dev)
 {
 	struct iommu_group *iommu_group;
 	struct vfio_group *group;
+	int ret;
 
-	iommu_group = vfio_iommu_group_get(dev);
-	if (!iommu_group)
+	iommu_group = iommu_group_alloc();
+	if (IS_ERR(iommu_group))
+		return ERR_CAST(iommu_group);
+
+	iommu_group_set_name(iommu_group, "vfio-noiommu");
+	iommu_group_set_iommudata(iommu_group, &noiommu, NULL);
+	ret = iommu_group_add_device(iommu_group, dev);
+	if (ret)
+		goto out_put_group;
+
+	group = vfio_create_group(iommu_group);
+	if (IS_ERR(group)) {
+		ret = PTR_ERR(group);
+		goto out_remove_device;
+	}
+
+	return group;
+
+out_remove_device:
+	iommu_group_remove_device(dev);
+out_put_group:
+	iommu_group_put(iommu_group);
+	return ERR_PTR(ret);
+}
+#endif
+
+static struct vfio_group *vfio_group_find_or_alloc(struct device *dev)
+{
+	struct iommu_group *iommu_group;
+	struct vfio_group *group;
+
+	iommu_group = iommu_group_get(dev);
+	if (!iommu_group) {
+#ifdef CONFIG_VFIO_NOIOMMU
+		/*
+		 * With noiommu enabled, create an IOMMU group for devices that
+		 * don't already have one and don't have an iommu_ops on their
+		 * bus.  Taint the kernel because we're about to give a DMA
+		 * capable device to a user without IOMMU protection.
+		 */
+		if (noiommu && !iommu_present(dev->bus)) {
+			add_taint(TAINT_USER, LOCKDEP_STILL_OK);
+			dev_warn(dev, "Adding kernel taint for vfio-noiommu group on device\n");
+			return vfio_noiommu_group_alloc(dev);
+		}
+#endif
 		return ERR_PTR(-EINVAL);
+	}
 
 	/*
 	 * A found vfio_group already holds a reference to the iommu_group.
@@ -852,7 +855,8 @@  struct vfio_group *vfio_group_find_or_alloc(struct device *dev)
 		if (!IS_ERR(group))
 			return group;
 	}
-	vfio_iommu_group_put(iommu_group, dev);
+
+	iommu_group_put(iommu_group);
 	return group;
 }