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

Reply via email to