@@ -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 and vfio_file_has_device_access()
+ */
+ 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 */
@@ -1118,6 +1118,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;
@@ -1145,6 +1149,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;
@@ -1158,6 +1166,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;
@@ -1169,6 +1181,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;