@@ -194,9 +194,18 @@ static int vfio_device_group_open(struct vfio_device_file *df)
df->iommufd = device->group->iommufd;
ret = vfio_device_open(df);
- if (ret)
+ if (ret) {
df->iommufd = NULL;
+ goto out_put_kvm;
+ }
+
+ /*
+ * Paired with smp_load_acquire() in vfio_device_fops::ioctl/
+ * read/write/mmap
+ */
+ smp_store_release(&df->access_granted, true);
+out_put_kvm:
if (device->open_count == 0)
vfio_device_put_kvm(device);
@@ -18,6 +18,7 @@ struct vfio_container;
struct vfio_device_file {
struct vfio_device *device;
+ bool access_granted;
spinlock_t kvm_ref_lock; /* protect kvm field */
struct kvm *kvm;
struct iommufd_ctx *iommufd; /* protected by struct vfio_device_set::lock */
@@ -1114,6 +1114,10 @@ static long vfio_device_fops_unl_ioctl(struct file *filep,
struct vfio_device *device = df->device;
int ret;
+ /* Paired with smp_store_release() following vfio_device_open() */
+ if (!smp_load_acquire(&df->access_granted))
+ return -EINVAL;
+
ret = vfio_device_pm_runtime_get(device);
if (ret)
return ret;
@@ -1141,6 +1145,10 @@ static ssize_t vfio_device_fops_read(struct file *filep, char __user *buf,
struct vfio_device_file *df = filep->private_data;
struct vfio_device *device = df->device;
+ /* Paired with smp_store_release() following vfio_device_open() */
+ if (!smp_load_acquire(&df->access_granted))
+ return -EINVAL;
+
if (unlikely(!device->ops->read))
return -EINVAL;
@@ -1154,6 +1162,10 @@ static ssize_t vfio_device_fops_write(struct file *filep,
struct vfio_device_file *df = filep->private_data;
struct vfio_device *device = df->device;
+ /* Paired with smp_store_release() following vfio_device_open() */
+ if (!smp_load_acquire(&df->access_granted))
+ return -EINVAL;
+
if (unlikely(!device->ops->write))
return -EINVAL;
@@ -1165,6 +1177,10 @@ static int vfio_device_fops_mmap(struct file *filep, struct vm_area_struct *vma)
struct vfio_device_file *df = filep->private_data;
struct vfio_device *device = df->device;
+ /* Paired with smp_store_release() following vfio_device_open() */
+ if (!smp_load_acquire(&df->access_granted))
+ return -EINVAL;
+
if (unlikely(!device->ops->mmap))
return -EINVAL;
@@ -1201,6 +1217,24 @@ bool vfio_file_is_valid(struct file *file)
}
EXPORT_SYMBOL_GPL(vfio_file_is_valid);
+/*
+ * Return true if the input file is a vfio device file and has opened
+ * the input device. Otherwise, return false.
+ */
+static bool vfio_file_has_device_access(struct file *file,
+ struct vfio_device *device)
+{
+ struct vfio_device *vdev = vfio_device_from_file(file);
+ struct vfio_device_file *df;
+
+ if (!vdev || vdev != device)
+ return false;
+
+ df = file->private_data;
+
+ return READ_ONCE(df->access_granted);
+}
+
/**
* vfio_file_has_dev - True if the VFIO file is a handle for device
* @file: VFIO file to check
@@ -1211,17 +1245,12 @@ EXPORT_SYMBOL_GPL(vfio_file_is_valid);
bool vfio_file_has_dev(struct file *file, struct vfio_device *device)
{
struct vfio_group *group;
- struct vfio_device *vdev;
group = vfio_group_from_file(file);
if (group)
return vfio_group_has_dev(group, device);
- vdev = vfio_device_from_file(file);
- if (vdev)
- return vdev == device;
-
- return false;
+ return vfio_file_has_device_access(file, device);
}
EXPORT_SYMBOL_GPL(vfio_file_has_dev);