On Sun, Sep 19, 2021 at 02:38:35PM +0800, Liu Yi L wrote:

> +/*
> + * A iommufd_device object represents the binding relationship
> + * between iommufd and device. It is created per a successful
> + * binding request from device driver. The bound device must be
> + * a physical device so far. Subdevice will be supported later
> + * (with additional PASID information). An user-assigned cookie
> + * is also recorded to mark the device in the /dev/iommu uAPI.
> + */
> +struct iommufd_device {
> +     unsigned int id;
> +     struct iommufd_ctx *ictx;
> +     struct device *dev; /* always be the physical device */
> +     u64 dev_cookie;
>  };
>  
>  static int iommufd_fops_open(struct inode *inode, struct file *filep)
> @@ -32,15 +52,58 @@ static int iommufd_fops_open(struct inode *inode, struct 
> file *filep)
>               return -ENOMEM;
>  
>       refcount_set(&ictx->refs, 1);
> +     mutex_init(&ictx->lock);
> +     xa_init_flags(&ictx->device_xa, XA_FLAGS_ALLOC);
>       filep->private_data = ictx;
>  
>       return ret;
>  }
>  
> +static void iommufd_ctx_get(struct iommufd_ctx *ictx)
> +{
> +     refcount_inc(&ictx->refs);
> +}

See my earlier remarks about how to structure the lifetime logic, this
ref isn't necessary.

> +static const struct file_operations iommufd_fops;
> +
> +/**
> + * iommufd_ctx_fdget - Acquires a reference to the internal iommufd context.
> + * @fd: [in] iommufd file descriptor.
> + *
> + * Returns a pointer to the iommufd context, otherwise NULL;
> + *
> + */
> +static struct iommufd_ctx *iommufd_ctx_fdget(int fd)
> +{
> +     struct fd f = fdget(fd);
> +     struct file *file = f.file;
> +     struct iommufd_ctx *ictx;
> +
> +     if (!file)
> +             return NULL;
> +
> +     if (file->f_op != &iommufd_fops)
> +             return NULL;

Leaks the fdget

> +
> +     ictx = file->private_data;
> +     if (ictx)
> +             iommufd_ctx_get(ictx);

Use success oriented flow

> +     fdput(f);
> +     return ictx;
> +}

> + */
> +struct iommufd_device *iommufd_bind_device(int fd, struct device *dev,
> +                                        u64 dev_cookie)
> +{
> +     struct iommufd_ctx *ictx;
> +     struct iommufd_device *idev;
> +     unsigned long index;
> +     unsigned int id;
> +     int ret;
> +
> +     ictx = iommufd_ctx_fdget(fd);
> +     if (!ictx)
> +             return ERR_PTR(-EINVAL);
> +
> +     mutex_lock(&ictx->lock);
> +
> +     /* check duplicate registration */
> +     xa_for_each(&ictx->device_xa, index, idev) {
> +             if (idev->dev == dev || idev->dev_cookie == dev_cookie) {
> +                     idev = ERR_PTR(-EBUSY);
> +                     goto out_unlock;
> +             }

I can't think of a reason why this expensive check is needed.

> +     }
> +
> +     idev = kzalloc(sizeof(*idev), GFP_KERNEL);
> +     if (!idev) {
> +             ret = -ENOMEM;
> +             goto out_unlock;
> +     }
> +
> +     /* Establish the security context */
> +     ret = iommu_device_init_user_dma(dev, (unsigned long)ictx);
> +     if (ret)
> +             goto out_free;
> +
> +     ret = xa_alloc(&ictx->device_xa, &id, idev,
> +                    XA_LIMIT(IOMMUFD_DEVID_MIN, IOMMUFD_DEVID_MAX),
> +                    GFP_KERNEL);

idev should be fully initialized before being placed in the xarray, so
this should be the last thing done.

Why not just use the standard xa_limit_32b instead of special single
use constants?

Jason
_______________________________________________
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu

Reply via email to