On 2026-03-23 11:57 PM, David Matlack wrote:
> +static void pci_flb_finish(struct liveupdate_flb_op_args *args)
> +{
> + kho_restore_free(args->obj);
> +}
> +
> +static struct liveupdate_flb_ops pci_liveupdate_flb_ops = {
> + .preserve = pci_flb_preserve,
> + .unpreserve = pci_flb_unpreserve,
> + .retrieve = pci_flb_retrieve,
> + .finish = pci_flb_finish,
> + .owner = THIS_MODULE,
> +};
...
> +static int pci_liveupdate_flb_get_incoming(struct pci_ser **serp)
> +{
> + int ret;
> +
> + ret = liveupdate_flb_get_incoming(&pci_liveupdate_flb, (void **)serp);
> +
> + /* Live Update is not enabled. */
> + if (ret == -EOPNOTSUPP)
> + return ret;
> +
> + /* Live Update is enabled, but there is no incoming FLB data. */
> + if (ret == -ENODATA)
> + return ret;
> +
> + /*
> + * Live Update is enabled and there is incoming FLB data, but none of it
> + * matches pci_liveupdate_flb.compatible.
> + *
> + * This could mean that no PCI FLB data was passed by the previous
> + * kernel, but it could also mean the previous kernel used a different
> + * compatibility string (i.e.a different ABI). The latter deserves at
> + * least a WARN_ON_ONCE() but it cannot be distinguished from the
> + * former.
> + */
> + if (ret == -ENOENT) {
> + pr_info_once("PCI: No incoming FLB data detected during Live
> Update");
> + return ret;
> + }
> +
> + /*
> + * There is incoming FLB data that matches pci_liveupdate_flb.compatible
> + * but it cannot be retrieved. Proceed with standard initialization as
> + * if there was not incoming PCI FLB data.
> + */
> + WARN_ONCE(ret, "PCI: Failed to retrieve incoming FLB data during Live
> Update");
> + return ret;
> +}
> +
> +u32 pci_liveupdate_incoming_nr_devices(void)
> +{
> + struct pci_ser *ser;
> +
> + if (pci_liveupdate_flb_get_incoming(&ser))
> + return 0;
> +
> + return ser->nr_devices;
> +}
> +
> +void pci_liveupdate_setup_device(struct pci_dev *dev)
> +{
> + struct pci_ser *ser;
> +
> + if (pci_liveupdate_flb_get_incoming(&ser))
> + return;
> +
> + if (!pci_ser_find(ser, dev))
> + return;
> +
> + dev->liveupdate_incoming = true;
> +}
There is an inerent race between callers of
liveupdate_flb_get_incoming() and liveupdate_flb_ops.finish(). There is
no way for callers to protect themselves against the finish() callback
running and freeing the incoming FLB after liveupdate_flb_get_incoming()
returns. Sashiko flagged this as well [1].
After some off list discussion with Pasha and Sami, the proposal to fix
this is to have liveupdate_flb_get_incoming() increment the reference
count on the incoming FLB. We will add a liveupdate_flb_put_incoming()
to drop the reference when the caller is done using the incoming FLB.
I plan to include a patch for this in v4.
[1]
https://sashiko.dev/#/patchset/20260323235817.1960573-1-dmatlack%40google.com?patch=7974