[PATCH v5 10/20] vfio/pci: Retrieve preserved device files after Live Update
Vipin Sharma
vipinsh at google.com
Tue Jul 14 08:14:55 PDT 2026
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 <dmatlack at google.com>
Signed-off-by: David Matlack <dmatlack at google.com>
Signed-off-by: Vipin Sharma <vipinsh at google.com>
---
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
More information about the kexec
mailing list