]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
vfio: Create vfio_fs_type with inode per device
authorAlex Williamson <alex.williamson@redhat.com>
Thu, 30 May 2024 04:52:30 +0000 (22:52 -0600)
committerAlex Williamson <alex.williamson@redhat.com>
Fri, 31 May 2024 21:15:51 +0000 (15:15 -0600)
By linking all the device fds we provide to userspace to an
address space through a new pseudo fs, we can use tools like
unmap_mapping_range() to zap all vmas associated with a device.

Suggested-by: Jason Gunthorpe <jgg@nvidia.com>
Reviewed-by: Jason Gunthorpe <jgg@nvidia.com>
Reviewed-by: Kevin Tian <kevin.tian@intel.com>
Link: https://lore.kernel.org/r/20240530045236.1005864-2-alex.williamson@redhat.com
Signed-off-by: Alex Williamson <alex.williamson@redhat.com>
drivers/vfio/device_cdev.c
drivers/vfio/group.c
drivers/vfio/vfio_main.c
include/linux/vfio.h

index e75da0a70d1f838a1d611e89fa6102876f2c5fba..bb1817bd4ff319d72bed19e846ddcc598fc6d280 100644 (file)
@@ -39,6 +39,13 @@ int vfio_device_fops_cdev_open(struct inode *inode, struct file *filep)
 
        filep->private_data = df;
 
+       /*
+        * Use the pseudo fs inode on the device to link all mmaps
+        * to the same address space, allowing us to unmap all vmas
+        * associated to this device using unmap_mapping_range().
+        */
+       filep->f_mapping = device->inode->i_mapping;
+
        return 0;
 
 err_put_registration:
index 610a429c61912568e35dba0431923f393afe718f..ded364588d29737ba0f1b1adc32581661cdb21c4 100644 (file)
@@ -286,6 +286,13 @@ static struct file *vfio_device_open_file(struct vfio_device *device)
         */
        filep->f_mode |= (FMODE_PREAD | FMODE_PWRITE);
 
+       /*
+        * Use the pseudo fs inode on the device to link all mmaps
+        * to the same address space, allowing us to unmap all vmas
+        * associated to this device using unmap_mapping_range().
+        */
+       filep->f_mapping = device->inode->i_mapping;
+
        if (device->group->type == VFIO_NO_IOMMU)
                dev_warn(device->dev, "vfio-noiommu device opened by user "
                         "(%s:%d)\n", current->comm, task_pid_nr(current));
index e97d796a54fbaf8da0fc3860b8bbb5ca5039acce..a5a62d9d963f72ec704730717f305edae29297d1 100644 (file)
 #include <linux/list.h>
 #include <linux/miscdevice.h>
 #include <linux/module.h>
+#include <linux/mount.h>
 #include <linux/mutex.h>
 #include <linux/pci.h>
+#include <linux/pseudo_fs.h>
 #include <linux/rwsem.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
 #define DRIVER_AUTHOR  "Alex Williamson <alex.williamson@redhat.com>"
 #define DRIVER_DESC    "VFIO - User Level meta-driver"
 
+#define VFIO_MAGIC 0x5646494f /* "VFIO" */
+
 static struct vfio {
        struct class                    *device_class;
        struct ida                      device_ida;
+       struct vfsmount                 *vfs_mount;
+       int                             fs_count;
 } vfio;
 
 #ifdef CONFIG_VFIO_NOIOMMU
@@ -186,6 +192,8 @@ static void vfio_device_release(struct device *dev)
        if (device->ops->release)
                device->ops->release(device);
 
+       iput(device->inode);
+       simple_release_fs(&vfio.vfs_mount, &vfio.fs_count);
        kvfree(device);
 }
 
@@ -228,6 +236,34 @@ out_free:
 }
 EXPORT_SYMBOL_GPL(_vfio_alloc_device);
 
+static int vfio_fs_init_fs_context(struct fs_context *fc)
+{
+       return init_pseudo(fc, VFIO_MAGIC) ? 0 : -ENOMEM;
+}
+
+static struct file_system_type vfio_fs_type = {
+       .name = "vfio",
+       .owner = THIS_MODULE,
+       .init_fs_context = vfio_fs_init_fs_context,
+       .kill_sb = kill_anon_super,
+};
+
+static struct inode *vfio_fs_inode_new(void)
+{
+       struct inode *inode;
+       int ret;
+
+       ret = simple_pin_fs(&vfio_fs_type, &vfio.vfs_mount, &vfio.fs_count);
+       if (ret)
+               return ERR_PTR(ret);
+
+       inode = alloc_anon_inode(vfio.vfs_mount->mnt_sb);
+       if (IS_ERR(inode))
+               simple_release_fs(&vfio.vfs_mount, &vfio.fs_count);
+
+       return inode;
+}
+
 /*
  * Initialize a vfio_device so it can be registered to vfio core.
  */
@@ -246,6 +282,11 @@ static int vfio_init_device(struct vfio_device *device, struct device *dev,
        init_completion(&device->comp);
        device->dev = dev;
        device->ops = ops;
+       device->inode = vfio_fs_inode_new();
+       if (IS_ERR(device->inode)) {
+               ret = PTR_ERR(device->inode);
+               goto out_inode;
+       }
 
        if (ops->init) {
                ret = ops->init(device);
@@ -260,6 +301,9 @@ static int vfio_init_device(struct vfio_device *device, struct device *dev,
        return 0;
 
 out_uninit:
+       iput(device->inode);
+       simple_release_fs(&vfio.vfs_mount, &vfio.fs_count);
+out_inode:
        vfio_release_device_set(device);
        ida_free(&vfio.device_ida, device->index);
        return ret;
index 8b1a2982040914052b423c73d7871ed71b563a09..000a6cab2d318a93cf495a18ae5cc39df38beac5 100644 (file)
@@ -64,6 +64,7 @@ struct vfio_device {
        struct completion comp;
        struct iommufd_access *iommufd_access;
        void (*put_kvm)(struct kvm *kvm);
+       struct inode *inode;
 #if IS_ENABLED(CONFIG_IOMMUFD)
        struct iommufd_device *iommufd_device;
        u8 iommufd_attached:1;