Enable userspace to retrieve preserved VFIO device files from VFIO after
a Live Update by implementing the retrieve(), can_finish() and finish()
file handler callbacks.

During retrieve, find the VFIO device using the BDF and domain
information from the serialized state, and open it using the new
vfio_device_liveupdate_cdev_open() API.

Disallow Live Update to finish if userspace hasn't opened the file
successfully or any error occurred during retrieve.

Co-developed-by: David Matlack <[email protected]>
Signed-off-by: David Matlack <[email protected]>
Signed-off-by: Vipin Sharma <[email protected]>
---
 drivers/vfio/pci/vfio_pci_liveupdate.c | 64 +++++++++++++++++++++++++-
 1 file changed, 62 insertions(+), 2 deletions(-)

diff --git a/drivers/vfio/pci/vfio_pci_liveupdate.c 
b/drivers/vfio/pci/vfio_pci_liveupdate.c
index e6eb7f6b53d7..4baac80d03f0 100644
--- a/drivers/vfio/pci/vfio_pci_liveupdate.c
+++ b/drivers/vfio/pci/vfio_pci_liveupdate.c
@@ -39,7 +39,13 @@
  *    preserved, so there is no way for the file to be destroyed or the device
  *    to be unbound from the vfio-pci driver while it is preserved.
  *
- * Retrieving the file after kexec is not yet supported.
+ * After kexec, the preserved VFIO device file can be retrieved from the 
session
+ * just like any other preserved file::
+ *
+ *   ioctl(session_fd, LIVEUPDATE_SESSION_RETRIEVE_FD, &arg);
+ *   device_fd = arg.fd;
+ *   ...
+ *   ioctl(session_fd, LIVEUPDATE_SESSION_FINISH, ...);
  *
  * Restrictions
  * ============
@@ -93,6 +99,7 @@
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
 #include <linux/errno.h>
+#include <linux/file.h>
 #include <linux/kexec_handover.h>
 #include <linux/kho/abi/vfio_pci.h>
 #include <linux/liveupdate.h>
@@ -223,13 +230,65 @@ static int vfio_pci_liveupdate_freeze(struct 
liveupdate_file_op_args *args)
        return 0;
 }
 
+static int match_device(struct device *dev, const void *arg)
+{
+       struct vfio_device *device = container_of(dev, struct vfio_device, 
device);
+       const struct vfio_pci_core_device_ser *ser = arg;
+       struct pci_dev *pdev;
+
+       pdev = dev_is_pci(device->dev) ? to_pci_dev(device->dev) : NULL;
+       if (!pdev)
+               return false;
+
+       return ser->bdf == pci_dev_id(pdev) && ser->domain == 
pci_domain_nr(pdev->bus);
+}
+
 static int vfio_pci_liveupdate_retrieve(struct liveupdate_file_op_args *args)
 {
-       return -EOPNOTSUPP;
+       struct vfio_pci_core_device_ser *ser;
+       struct vfio_device *device;
+       struct file *file;
+       int ret = 0;
+
+       ser = phys_to_virt(args->serialized_data);
+
+       device = vfio_find_device(ser, match_device);
+       if (!device)
+               return -ENODEV;
+
+       file = vfio_device_liveupdate_cdev_open(device);
+       if (IS_ERR(file)) {
+               ret = PTR_ERR(file);
+               goto out;
+       }
+
+       args->file = file;
+out:
+       /* Drop the reference from vfio_find_device() */
+       vfio_device_put_registration(device);
+       return ret;
+
+}
+
+
+static bool vfio_pci_liveupdate_can_finish(struct liveupdate_file_op_args 
*args)
+{
+       struct vfio_device *device;
+
+       if (args->retrieve_status <= 0)
+               return false;
+
+       device = vfio_device_from_file(args->file);
+       guard(mutex)(&device->dev_set->lock);
+       return vfio_device_cdev_opened(device);
 }
 
 static void vfio_pci_liveupdate_finish(struct liveupdate_file_op_args *args)
 {
+       struct vfio_device *device = vfio_device_from_file(args->file);
+
+       pci_liveupdate_finish(to_pci_dev(device->dev));
+       kho_restore_free(phys_to_virt(args->serialized_data));
 }
 
 static const struct liveupdate_file_ops vfio_pci_liveupdate_file_ops = {
@@ -238,6 +297,7 @@ static const struct liveupdate_file_ops 
vfio_pci_liveupdate_file_ops = {
        .unpreserve = vfio_pci_liveupdate_unpreserve,
        .freeze = vfio_pci_liveupdate_freeze,
        .retrieve = vfio_pci_liveupdate_retrieve,
+       .can_finish = vfio_pci_liveupdate_can_finish,
        .finish = vfio_pci_liveupdate_finish,
        .owner = THIS_MODULE,
 };
-- 
2.55.0.795.g602f6c329a-goog


Reply via email to