During Live Update restore, VFIO PCI driver needs to recreate the device
file context that was preserved before kexec and return it to the user.

Provide an API for VFIO Live Update to get VFIO device file. Use an
anonymous inode when creating the file, since the retrieved device file
is not opened through any particular cdev inode, and the cdev inode does
not matter in practice.

Co-developed-by: David Matlack <[email protected]>
Signed-off-by: David Matlack <[email protected]>
Signed-off-by: Vipin Sharma <[email protected]>
---
 drivers/vfio/device_cdev.c | 39 ++++++++++++++++++++++++++++++++++++--
 include/linux/vfio.h       |  9 +++++++++
 2 files changed, 46 insertions(+), 2 deletions(-)

diff --git a/drivers/vfio/device_cdev.c b/drivers/vfio/device_cdev.c
index 2231423fe56d..970932f22ecb 100644
--- a/drivers/vfio/device_cdev.c
+++ b/drivers/vfio/device_cdev.c
@@ -2,6 +2,7 @@
 /*
  * Copyright (c) 2023 Intel Corporation.
  */
+#include <linux/anon_inodes.h>
 #include <linux/vfio.h>
 #include <linux/iommufd.h>
 
@@ -16,9 +17,10 @@ void vfio_init_device_cdev(struct vfio_device *device)
        device->cdev.owner = THIS_MODULE;
 }
 
-static int vfio_device_cdev_open(struct vfio_device *device, struct file *file)
+static int vfio_device_cdev_open(struct vfio_device *device, struct file 
**filep)
 {
        struct vfio_device_file *df;
+       struct file *file = *filep;
        int ret;
 
        /* Paired with the put in vfio_device_fops_release() */
@@ -31,6 +33,24 @@ static int vfio_device_cdev_open(struct vfio_device *device, 
struct file *file)
                goto err_put_registration;
        }
 
+       /*
+        * Simulate opening the character device using an anonymous inode. The
+        * returned file has the same properties as a cdev file (e.g. operations
+        * are blocked until BIND_IOMMUFD is called).
+        */
+       if (!file) {
+               file = anon_inode_getfile_fmode("[vfio-device-liveupdate]",
+                                               &vfio_device_fops, NULL,
+                                               O_RDWR, FMODE_PREAD | 
FMODE_PWRITE);
+
+               if (IS_ERR(file)) {
+                       ret = PTR_ERR(file);
+                       goto err_free_device_file;
+               }
+
+               *filep = file;
+       }
+
        file->private_data = df;
 
        /*
@@ -42,11 +62,26 @@ static int vfio_device_cdev_open(struct vfio_device 
*device, struct file *file)
 
        return 0;
 
+err_free_device_file:
+       kfree(df);
 err_put_registration:
        vfio_device_put_registration(device);
        return ret;
 }
 
+struct file *vfio_device_liveupdate_cdev_open(struct vfio_device *device)
+{
+       struct file *file = NULL;
+       int ret;
+
+       ret = vfio_device_cdev_open(device, &file);
+       if (ret)
+               return ERR_PTR(ret);
+
+       return file;
+}
+EXPORT_SYMBOL_GPL(vfio_device_liveupdate_cdev_open);
+
 /*
  * device access via the fd opened by this function is blocked until
  * .open_device() is called successfully during BIND_IOMMUFD.
@@ -56,7 +91,7 @@ int vfio_device_fops_cdev_open(struct inode *inode, struct 
file *file)
        struct vfio_device *device = container_of(inode->i_cdev,
                                                  struct vfio_device, cdev);
 
-       return vfio_device_cdev_open(device, file);
+       return vfio_device_cdev_open(device, &file);
 }
 
 static void vfio_df_get_kvm_safe(struct vfio_device_file *df)
diff --git a/include/linux/vfio.h b/include/linux/vfio.h
index 42c3a9ae3a85..b896c64b11da 100644
--- a/include/linux/vfio.h
+++ b/include/linux/vfio.h
@@ -430,6 +430,15 @@ int vfio_virqfd_enable(void *opaque, int (*handler)(void 
*, void *),
 void vfio_virqfd_disable(struct virqfd **pvirqfd);
 void vfio_virqfd_flush_thread(struct virqfd **pvirqfd);
 
+#if IS_ENABLED(CONFIG_VFIO_DEVICE_CDEV)
+struct file *vfio_device_liveupdate_cdev_open(struct vfio_device *device);
+#else
+static inline struct file *vfio_device_liveupdate_cdev_open(struct vfio_device 
*device)
+{
+       return ERR_PTR(-EOPNOTSUPP);
+}
+#endif /* IS_ENABLED(CONFIG_VFIO_DEVICE_CDEV) */
+
 struct vfio_device *vfio_find_device(const void *data, device_match_t match);
 
 #endif /* VFIO_H */
-- 
2.55.0.795.g602f6c329a-goog


Reply via email to