Re: [PATCH v2 07/22] vfio/pci: Notify PCI subsystem about devices preserved across Live Update
From: Alex Williamson
Date: Thu Feb 26 2026 - 18:05:00 EST
On Thu, 29 Jan 2026 21:24:54 +0000
David Matlack <dmatlack@xxxxxxxxxx> wrote:
> Notify the PCI subsystem about devices vfio-pci is preserving across
> Live Update by registering the vfio-pci liveupdate file handler with the
> PCI subsystem's FLB handler.
>
> Notably this will ensure that devices preserved through vfio-pci will
> have their PCI bus numbers preserved across Live Update, allowing VFIO
> to use BDF as a key to identify the device across the Live Update and
> (in the future) allow the device to continue DMA operations across
> the Live Update.
>
> This also enables VFIO to detect that a device was preserved before
> userspace first retrieves the file from it, which will be used in
> subsequent commits.
>
> Signed-off-by: David Matlack <dmatlack@xxxxxxxxxx>
> ---
> drivers/vfio/pci/vfio_pci_liveupdate.c | 25 ++++++++++++++++++++++++-
> 1 file changed, 24 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/vfio/pci/vfio_pci_liveupdate.c b/drivers/vfio/pci/vfio_pci_liveupdate.c
> index 7f4117181fd0..ad915352303f 100644
> --- a/drivers/vfio/pci/vfio_pci_liveupdate.c
> +++ b/drivers/vfio/pci/vfio_pci_liveupdate.c
> @@ -53,6 +53,8 @@ static int vfio_pci_liveupdate_preserve(struct liveupdate_file_op_args *args)
> if (IS_ERR(ser))
> return PTR_ERR(ser);
>
> + pci_liveupdate_outgoing_preserve(pdev);
Why do we get to ignore the return value here?
> +
> ser->bdf = pci_dev_id(pdev);
> ser->domain = pci_domain_nr(pdev->bus);
>
> @@ -62,6 +64,9 @@ static int vfio_pci_liveupdate_preserve(struct liveupdate_file_op_args *args)
>
> static void vfio_pci_liveupdate_unpreserve(struct liveupdate_file_op_args *args)
> {
> + struct vfio_device *device = vfio_device_from_file(args->file);
> +
> + pci_liveupdate_outgoing_unpreserve(to_pci_dev(device->dev));
> kho_unpreserve_free(phys_to_virt(args->serialized_data));
> }
>
> @@ -171,6 +176,9 @@ static bool vfio_pci_liveupdate_can_finish(struct liveupdate_file_op_args *args)
>
> static void vfio_pci_liveupdate_finish(struct liveupdate_file_op_args *args)
> {
> + struct vfio_device *device = vfio_device_from_file(args->file);
> +
> + pci_liveupdate_incoming_finish(to_pci_dev(device->dev));
> kho_restore_free(phys_to_virt(args->serialized_data));
> }
>
> @@ -192,10 +200,24 @@ static struct liveupdate_file_handler vfio_pci_liveupdate_fh = {
>
> int __init vfio_pci_liveupdate_init(void)
> {
> + int ret;
> +
> if (!liveupdate_enabled())
> return 0;
>
> - return liveupdate_register_file_handler(&vfio_pci_liveupdate_fh);
> + ret = liveupdate_register_file_handler(&vfio_pci_liveupdate_fh);
> + if (ret)
> + return ret;
> +
> + ret = pci_liveupdate_register_fh(&vfio_pci_liveupdate_fh);
> + if (ret)
> + goto error;
> +
> + return 0;
> +
> +error:
> + liveupdate_unregister_file_handler(&vfio_pci_liveupdate_fh);
> + return ret;
> }
>
> void vfio_pci_liveupdate_cleanup(void)
> @@ -203,5 +225,6 @@ void vfio_pci_liveupdate_cleanup(void)
> if (!liveupdate_enabled())
> return;
>
> + WARN_ON_ONCE(pci_liveupdate_unregister_fh(&vfio_pci_liveupdate_fh));
This is propagation of a poor API choice in liveupdate, the unregister
should return void, it shouldn't be allowed to fail, IMO. Thanks,
Alex
> liveupdate_unregister_file_handler(&vfio_pci_liveupdate_fh);
> }