RE: [PATCH v3 14/15] vfio: Add ioctls for device cdev using iommufd

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



> From: Zhao, Yan Y <yan.y.zhao@xxxxxxxxx>
> Sent: Thursday, February 16, 2023 5:23 PM
> 
> On Thu, Feb 16, 2023 at 05:10:06PM +0800, Liu, Yi L wrote:
> > > From: Zhao, Yan Y <yan.y.zhao@xxxxxxxxx>
> > > Sent: Thursday, February 16, 2023 4:24 PM
> > >
> > > On Mon, Feb 13, 2023 at 07:13:47AM -0800, Yi Liu wrote:
> > > ...
> > >
> > > > +long vfio_device_ioctl_bind_iommufd(struct vfio_device_file *df,
> > > > +				    unsigned long arg)
> > > > +{
> > > > +	struct vfio_device *device = df->device;
> > > > +	struct vfio_device_bind_iommufd bind;
> > > > +	struct iommufd_ctx *iommufd = NULL;
> > > > +	struct fd f;
> > > > +	unsigned long minsz;
> > > > +	int ret;
> > > > +
> > > > +	minsz = offsetofend(struct vfio_device_bind_iommufd, out_devid);
> > > > +
> > > > +	if (copy_from_user(&bind, (void __user *)arg, minsz))
> > > > +		return -EFAULT;
> > > > +
> > > > +	if (bind.argsz < minsz || bind.flags)
> > > > +		return -EINVAL;
> > > > +
> > > > +	if (!device->ops->bind_iommufd)
> > > > +		return -ENODEV;
> > > > +
> > > > +	ret = vfio_device_claim_group(device);
> > > > +	if (ret)
> > > > +		return ret;
> > > > +
> > > > +	mutex_lock(&device->dev_set->lock);
> > > > +	/*
> > > > +	 * If already been bound to an iommufd, or already set noiommu
> > > > +	 * then fail it.
> > > > +	 */
> > > > +	if (df->iommufd || df->noiommu) {
> > > > +		ret = -EINVAL;
> > > > +		goto out_unlock;
> > > > +	}
> > > > +
> > > > +	/* iommufd < 0 means noiommu mode */
> > > > +	if (bind.iommufd < 0) {
> > > > +		if (!capable(CAP_SYS_RAWIO)) {
> > > > +			ret = -EPERM;
> > > > +			goto out_unlock;
> > > > +		}
> > > > +		df->noiommu = true;
> > > > +	} else {
> > > > +		f = fdget(bind.iommufd);
> > > Here, the iommufd file count + 1,
> > >
> > > > +		if (!f.file) {
> > > > +			ret = -EBADF;
> > > > +			goto out_unlock;
> > > > +		}
> > > > +		iommufd = iommufd_ctx_from_file(f.file);
> > > iommufd file count + 1, again
> > >
> > > > +		if (IS_ERR(iommufd)) {
> > > > +			ret = PTR_ERR(iommufd);
> > > > +			goto out_put_file;
> > > > +		}
> > > > +	}
> > > > +
> > > > +	/*
> > > > +	 * Before the device open, get the KVM pointer currently
> > > > +	 * associated with the device file (if there is) and obtain a
> > > > +	 * reference. This reference is held until device closed. Save
> > > > +	 * the pointer in the device for use by drivers.
> > > > +	 */
> > > > +	vfio_device_get_kvm_safe(df);
> > > > +
> > > > +	df->iommufd = iommufd;
> > > > +	ret = vfio_device_open(df, &bind.out_devid, NULL);
> > > iommufd file count + 1 in iommufd_device_bind for first open.
> > >
> > > > +	if (ret)
> > > > +		goto out_put_kvm;
> > > > +
> > > > +	ret = copy_to_user((void __user *)arg +
> > > > +			   offsetofend(struct vfio_device_bind_iommufd,
> > > iommufd),
> > > > +			   &bind.out_devid,
> > > > +			   sizeof(bind.out_devid)) ? -EFAULT : 0;
> > > > +	if (ret)
> > > > +		goto out_close_device;
> > > > +
> > > > +	if (iommufd)
> > > > +		fdput(f);
> > > But, only one file count is put.
> >
> > Good catch! Yes it is missed. And needs to call iommufd_ctx_put()
> > in vfio_device_cdev_close() as well.
> If I read correctly, iommufd_device_bind() in the first open will
> get the reference through iommufd_ctx_get(ictx) and
> iommufd_device_destroy() in the last close will do the iommufd_ctx_put().

Aha, functionally no problem. Even storing iommufd_ctx in df without
an explicit get for iommufd_ctx is fine since iommufd_device_bind()
has an implicitly get for iommufd_ctx. But it appears to be better to
have an explicit get.

However, I need to admit, your fix can reduce the reference of iommufd file.
This may avoid file reference counting overflow if there are multiple devices
assigned to an application. I'm not sure how possible it is though. 😊 I'll see
if Alex or Jason have any preference.

Regards,
Yi Liu

> As vfio_device_ioctl_bind_iommufd() isn't paring with
> vfio_device_cdev_close(), I think the fix below is simpler :)
> 
> > > Need a paring iommufd_ctx_put() after a successful
> > > iommufd_ctx_from_file()
> > > above to avoid iommufd_fops_release() never being called.
> > >
> > > e.g.
> > >
> > > @@ -1222,11 +1226,13 @@ static long
> > > vfio_device_ioctl_bind_iommufd(struct vfio_device_file *df,
> > >                         ret = -EBADF;
> > >                         goto out_unlock;
> > >                 }
> > >                 iommufd = iommufd_ctx_from_file(f.file);
> > >                 if (IS_ERR(iommufd)) {
> > >                         ret = PTR_ERR(iommufd);
> > >                         goto out_put_file;
> > >                 }
> > > +               iommufd_ctx_put(iommufd);
> >
> > Since iommufd is recorded in df, so needs to hold refcount till
> > df->iommufd=NULL;
> >
> >
> > >         }
> > >
> > >         /* df->kvm is supposed to be set in vfio_device_file_set_kvm() */
> > >
> > > > +	else if (df->noiommu)
> > > > +		dev_warn(device->dev, "vfio-noiommu device used by user
> > > "
> > > > +			 "(%s:%d)\n", current->comm,
> > > task_pid_nr(current));
> > > > +	mutex_unlock(&device->dev_set->lock);
> > > > +	return 0;
> > > > +
> > > > +out_close_device:
> > > > +	vfio_device_close(df);
> > > > +out_put_kvm:
> > > > +	df->iommufd = NULL;
> > > > +	df->noiommu = false;
> > > > +	vfio_device_put_kvm(device);
> > > > +out_put_file:
> > > > +	if (iommufd)
> > > > +		fdput(f);
> > > > +out_unlock:
> > > > +	mutex_unlock(&device->dev_set->lock);
> > > > +	vfio_device_release_group(device);
> > > > +	return ret;
> > > > +}
> > > > +




[Index of Archives]     [KVM ARM]     [KVM ia64]     [KVM ppc]     [Virtualization Tools]     [Spice Development]     [Libvirt]     [Libvirt Users]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite Questions]     [Linux Kernel]     [Linux SCSI]     [XFree86]

  Powered by Linux