PCI: liveupdate: PCI core support for Live Update
Subsystems (5)
v6 cover PCI: liveupdate: PCI core support for Live Update
This series can be found on GitHub:
https://github.com/dmatlack/linux/tree/liveupdate/pci/base/v6
This series introduces initial support in the PCI core for Live Update, enabling drivers to preserve PCI devices across a kexec-based kernel update without interrupting the device. This functionality is critical for minimizing downtime in environments where PCI devices (e.g., those assigned to VMs via VFIO) must continue operating or maintain state across a host kernel upgrade.
Specifically, this series allows preserved PCI devices to perform uninterrupted memory transactions (DMA) to/from system memory across a Live Update. These devices can be behind a bridge but must not be VFs. Support for P2P and VF preservation will be addressed in future series.
Series Overview
---------------
This series implements the following to support PCI device preservation across Live Update:
1. Set up a File-Lifecycle-Bound (FLB) handler to track and preserve PCI-specific state (struct pci_ser) across Live Update using Kexec Handover (KHO).
2. Add APIs for drivers to register outgoing-preserved devices for preservation and for the PCI core to identify incoming-preserved devices during enumeration.
3. Automatically preserve all upstream bridges for any preserved endpoint. Use reference counting to ensure bridges remain preserved as long as any downstream device is preserved.
4. Guarantee that preserved devices retain the same RequesterID (bus, device, function) for the duration of their preservation by inheriting secondary bus numbers, subordinate bus numbers, and ARI Forwarding Enable on preserved bridges.
5. Guarantee that memory transactions to/from preserved devices are routed consistently by inheriting Access Control Services (ACS) flags across a Live Update, from the endpoint up to the root port.
6. Modify the PCI shutdown path to avoid disabling bus mastering on preserved devices, thereby allowing preserved devices to perform uninterrupted during kexec for Live Update.
7. Provide comprehensive documentation for the FLB API, device tracking mechanisms, and the division of responsibilities between the PCI core, drivers, and userspace.
Dependencies
------------
This series is built on top of the next branch of the liveupdate.git tree, which includes two commits to enable refcounting the incoming FLB:
https://git.kernel.org/pub/scm/linux/kernel/git/liveupdate/linux.git/log/?h=next
Testing
-------
This series was tested in conjunction with v4 of the VFIO PCI driver series:
https://lore.kernel.org/kvm/[email protected]/
The full set of patches used for testing can be found on GitHub:
https://github.com/dmatlack/linux/tree/liveupdate/pci/base/v6-with-vfio
Testing was performed using the new VFIO selftests:
- vfio_pci_liveupdate_uapi_test
- vfio_pci_liveupdate_kexec_test
Both tests were run in a QEMU-based VM environment (using a single virtio-net PCIe device connected to a root port to exercise bridge support) and on bare metal using an Intel EMR server with 8x Intel DSA PCIe devices and 1x NVMe device.
Future Work
-----------
Following this series, we expect to make further improvements to the PCI core support for Live Update:
- Allow P2P across Live Update by avoiding resizing or moving preserved device BARs and preserving all upstream bridge windows.
- Support preserving Virtual Functions by preserving SR-IOV configuration on PFs and enumerating VFs after Live Update.
Changelog
---------
v6:
- Fix truncated domain during bit shift in pci_ser_xa_key() (Sashiko)
- Replace complex and buggy per-device locks and outgoing mutex with a single rwsem (me)
- Use a loop instead of recursion to walk upstream bridges (Sashiko)
- Correctly account for all devices that need quirks to enable ACS instead of relying on PCI_DEV_FLAGS_ACS_ENABLED_QUIRK. This required adding a patch to refactor pci_dev_acs_ops in quirks.c (Sashiko)
- Fix circular locking dependency between pci_rescan_remove_lock and pci_liveupdate_flb.private->incoming.lock (me)
- Convert several functions to return 0/error instead of true/false.
- Bump PCI_LUO_FLB_COMPATIBLE in the patch that changes the semantics of pci_dev_ser.refcount (me)
- Convert was_prepared and frozen from bitfields to bools to avoid KCSAN warnings (Sashiko)
- Drop experimental verbiage from Kconfig and Documentation (me)
- Ensure that bridges inherit bus numbers during scanning if their parent bridge also inherits bus numbers. Otherwise, a race between a scan and pci_liveupdate_finish() could result in a bridge assigning a bus window larger than its parent while its parent is forced to inherit bus numbers (i.e., cannot expand) (me)
- Free struct pci_ser if an error occurs during pci_flb_retrieve() (Sashiko)
- Detect duplicate entries in incoming FLB when constructing xarray and return an error instead of silently ignoring (me)
- Add a wrapper function for fetching from the outgoing FLB (me)
- Grammatical and spelling fixes (Bjorn)
- Don't bother forcing bus inheritance when only outgoing devices are preserved. If a scan causes a bus number conflict, that is a general PCI core bug; it is not specific to Live Update (me)
- Convert bitfields in struct pci_liveupdate to bools to avoid data races (me)
v5: https://lore.kernel.org/linux-pci/[email protected]/
v4: https://lore.kernel.org/linux-pci/[email protected]/
v3: https://lore.kernel.org/kvm/[email protected]/
v2: https://lore.kernel.org/kvm/[email protected]/
v1: https://lore.kernel.org/kvm/[email protected]/
rfc: https://lore.kernel.org/kvm/[email protected]/
David Matlack (12):
PCI: liveupdate: Set up FLB handler for the PCI core
PCI: liveupdate: Track outgoing preserved PCI devices
PCI: liveupdate: Track incoming preserved PCI devices
PCI: liveupdate: Document driver binding responsibilities
PCI: liveupdate: Keep bus numbers constant during Live Update
PCI: liveupdate: Auto-preserve upstream bridges across Live Update
PCI: Refactor matching logic for pci_dev_acs_ops
PCI: liveupdate: Inherit ACS flags in incoming preserved devices
PCI: liveupdate: Inherit ARI Forwarding Enable on preserved bridges
PCI: liveupdate: Freeze preservation status during shutdown
PCI: liveupdate: Do not disable bus mastering on preserved devices
during kexec
Documentation: PCI: Add documentation for Live Update
Documentation/PCI/index.rst | 1 + Documentation/PCI/liveupdate.rst | 29 + .../admin-guide/kernel-parameters.txt | 6 +- Documentation/core-api/liveupdate.rst | 1 + MAINTAINERS | 12 + drivers/pci/Kconfig | 15 + drivers/pci/Makefile | 1 + drivers/pci/liveupdate.c | 850 ++++++++++++++++++ drivers/pci/liveupdate.h | 68 ++ drivers/pci/pci-driver.c | 9 +- drivers/pci/pci.c | 13 +- drivers/pci/pci.h | 5 + drivers/pci/probe.c | 22 +- drivers/pci/quirks.c | 57 +- include/linux/kho/abi/pci.h | 65 ++ include/linux/pci.h | 4 + include/linux/pci_liveupdate.h | 77 ++ 17 files changed, 1197 insertions(+), 38 deletions(-) create mode 100644 Documentation/PCI/liveupdate.rst create mode 100644 drivers/pci/liveupdate.c create mode 100644 drivers/pci/liveupdate.h create mode 100644 include/linux/kho/abi/pci.h create mode 100644 include/linux/pci_liveupdate.h
base-commit: 34e8f02817e31826e76bb2ded48bf28fe921f20b
Signature · 1 line
2.54.0.746.g67dd491aae-goog
PATCH v6 1/12 PCI: liveupdate: Set up FLB handler for the PCI core
Set up a File-Lifecycle-Bound (FLB) handler for the PCI core to enable it to participate in the preservation of PCI devices across Live Update. Essentially, this commit enables the PCI core to allocate a struct (struct pci_ser) and preserve it across a Live Update whenever at least one device is preserved.
Preserving PCI devices across Live Update is built on top of the Live Update Orchestrator's (LUO) support for file preservation. Drivers are expected to expose a file to userspace to represent a single PCI device and support preservation of that file. This is intended primarily to support preservation of PCI devices bound to VFIO drivers.
This commit enables drivers to register their liveupdate_file_handler with the PCI core so that the PCI core can do its own tracking and enforcement of which devices are preserved.
pci_liveupdate_register_flb(driver_file_handler); pci_liveupdate_unregister_flb(driver_file_handler);
When the first file (with a handler registered with the PCI core) is preserved, the PCI core will be notified to allocate its tracking struct (pci_ser). When the last file is unpreserved (i.e. preservation cancelled) the PCI core will be notified to free struct pci_ser.
This struct is preserved across a Live Update using KHO and can be fetched by the PCI core during early boot (e.g. during device enumeration) so that it knows which devices were preserved.
Note: This commit only allocates struct pci_ser and preserves it across Live Update. A subsequent commit will add an API for drivers to tell the PCI core exactly which devices are being preserved.
Note: There is no reason to check for kho_is_enabled() since it can be assumed to return true. If KHO was not enabled then Live Update would not be enabled and these routines would never run.
--- MAINTAINERS | 10 +++ drivers/pci/Kconfig | 15 ++++ drivers/pci/Makefile | 1 + drivers/pci/liveupdate.c | 145 +++++++++++++++++++++++++++++++++ include/linux/kho/abi/pci.h | 61 ++++++++++++++ include/linux/pci.h | 1 + include/linux/pci_liveupdate.h | 30 +++++++ 7 files changed, 263 insertions(+) create mode 100644 drivers/pci/liveupdate.c create mode 100644 include/linux/kho/abi/pci.h create mode 100644 include/linux/pci_liveupdate.h
MAINTAINERS +10 -0
@@ -20530,6 +20530,16 @@ L: [email protected] S: Supported F: Documentation/PCI/pci-error-recovery.rst +PCI LIVE UPDATE +M: David Matlack <[email protected]> +L: [email protected] +L: [email protected] +S: Maintained +T: git git://git.kernel.org/pub/scm/linux/kernel/git/liveupdate/linux.git +F: drivers/pci/liveupdate.c +F: include/linux/kho/abi/pci.h +F: include/linux/pci_liveupdate.h + PCI MSI DRIVER FOR ALTERA MSI IP L: [email protected] S: Orphan
drivers/pci/Kconfig +15 -0
@@ -328,6 +328,21 @@ config VGA_ARB_MAX_GPUS Reserves space in the kernel to maintain resource locking for multiple GPUS. The overhead for each GPU is very small. +config PCI_LIVEUPDATE + bool "PCI Live Update Support" + depends on PCI && LIVEUPDATE + help + Enable PCI core support for preserving PCI devices across Live + Update. This, in combination with support in a device's driver, + enables PCI devices to run and perform memory transactions + uninterrupted during a kexec for Live Update. + + This option should only be enabled by users who plan to use Live + Update for kernel upgrades and require preserving PCI devices during + those upgrades. + + If unsure, say N. + source "drivers/pci/hotplug/Kconfig" source "drivers/pci/controller/Kconfig" source "drivers/pci/endpoint/Kconfig"
drivers/pci/Makefile +1 -0
@@ -16,6 +16,7 @@ obj-$(CONFIG_PROC_FS) += proc.o obj-$(CONFIG_SYSFS) += pci-sysfs.o slot.o obj-$(CONFIG_ACPI) += pci-acpi.o obj-$(CONFIG_GENERIC_PCI_IOMAP) += iomap.o +obj-$(CONFIG_PCI_LIVEUPDATE) += liveupdate.o endif obj-$(CONFIG_OF) += of.o
drivers/pci/liveupdate.c new file +145 -0
145 lines not on this page · raw message
include/linux/kho/abi/pci.h new file +61 -0
61 lines not on this page · raw message
include/linux/pci.h +1 -0
@@ -42,6 +42,7 @@#include <uapi/linux/pci.h> #include <linux/pci_ids.h> +#include <linux/pci_liveupdate.h> #define PCI_STATUS_ERROR_BITS (PCI_STATUS_DETECTED_PARITY | \ PCI_STATUS_SIG_SYSTEM_ERROR | \
include/linux/pci_liveupdate.h new file +30 -0
@@ -0,0 +1,30 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* +* PCI Live Update support (Public/Driver API) +* +* Copyright (c) 2026, Google LLC. +* David Matlack <[email protected]> +*/ +#ifndef LINUX_PCI_LIVEUPDATE_H +#define LINUX_PCI_LIVEUPDATE_H + +#include <linux/liveupdate.h> +#include <linux/types.h> + +struct pci_dev ; + +#ifdef CONFIG_PCI_LIVEUPDATE +int pci_liveupdate_register_flb (struct liveupdate_file_handler *fh); +void pci_liveupdate_unregister_flb (struct liveupdate_file_handler *fh); +#else +static inline int pci_liveupdate_register_flb (struct liveupdate_file_handler *fh) +{ +return -EOPNOTSUPP ; +} + +static inline void pci_liveupdate_unregister_flb (struct liveupdate_file_handler *fh) +{ +} +#endif + +#endif /* LINUX_PCI_LIVEUPDATE_H */
Signature · 1 line
2.54.0.746.g67dd491aae-goog
[email protected]
AI reviewRe: [PATCH v6 01/12] PCI: liveupdate: Set up FLB handler for the PCI core
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider: - [Medium] Missing `kho_is_enabled()` check before calling KHO preservation APIs in PCI Live Update FLB…
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] Missing kho_is_enabled() check before calling KHO preservation APIs in PCI Live Update FLB operations. --
commit b0cb2fb154fba1aa85d63570fe0186e243353fb7
Author: David Matlack <[email protected]>
PCI: liveupdate: Set up FLB handler for the PCI core
This commit sets up a File-Lifecycle-Bound (FLB) handler for the PCI core to participate in the preservation of PCI devices across Live Update. It allocates and preserves a pci_ser structure using KHO when the first PCI device file is preserved.
Quoted 4 lines
drivers/pci/liveupdate.c new file +0
-0
[ ... ]
Quoted 10 lines
drivers/pci/liveupdate.c new file +10
-0+static int pci_flb_preserve (struct liveupdate_flb_op_args *args) +{ +struct pci_dev *dev =NULL ; +u32 max_nr_devices =0 ; +struct pci_ser *ser; +unsigned long size; + +/* +* Allocate enough space to preserve all devices that are currently +* present on the system. Extra padding can be added to this in the
drivers/pci/liveupdate.c line 70
Quoted 10 lines
drivers/pci/liveupdate.c new file +10
-0+* future to increase the chances that there is enough room to preserve +* devices that are not yet present on the system (e.g. VFs, hot-plugged +* devices). +*/ +for_each_pci_dev (dev) + max_nr_devices++; + + size = struct_size_t(struct pci_ser, devices, max_nr_devices); + + ser =kho_alloc_preserve (size);
[Severity: Medium]
Should this code verify kho_is_enabled() before calling kho_alloc_preserve()?
The commit message states:
"Note: There is no reason to check for kho_is_enabled() since it can be assumed to return true. If KHO was not enabled then Live Update would not be enabled and these routines would never run."
Does this assumption conflict with the Kexec Handover subsystem guidelines?
The guidelines mandate that all callers of serialization APIs must explicitly gate their usage with kho_is_enabled().
Calling preservation APIs like kho_alloc_preserve() without the check can silently add tracking state that will never be used if the subsystem is unexpectedly inactive.
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=1
Re: [PATCH v6 01/12] PCI: liveupdate: Set up FLB handler for the PCI core
Quoted 51 lines · On Fri, May 22, 2026 at 1:44 PM <[email protected]> wrote:
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] Missingkho_is_enabled()check before calling KHO preservation APIs in PCI Live Update FLB operations. --commit
b0cb2fb154fba1aa85d63570fe0186e243353fb7
Author: David Matlack <[email protected]>PCI: liveupdate: Set up FLB handler for the PCI core
This commit sets up a File-Lifecycle-Bound (FLB) handler for the PCI core to participate in the preservation of PCI devices across Live Update. It allocates and preserves a
pci_serstructure using KHO when the first PCI device file is preserved.Quoted 4 lines
drivers/pci/liveupdate.c new file +0
-0[ ... ]
Quoted 10 lines
drivers/pci/liveupdate.c new file +10
-0+static int pci_flb_preserve (struct liveupdate_flb_op_args *args) +{ +struct pci_dev *dev =NULL ; +u32 max_nr_devices =0 ; +struct pci_ser *ser; +unsigned long size; + +/* +* Allocate enough space to preserve all devices that are currently +* present on the system. Extra padding can be added to this in the drivers/pci/liveupdate.c line 70
Quoted 10 lines
drivers/pci/liveupdate.c new file +10
-0+* future to increase the chances that there is enough room to preserve +* devices that are not yet present on the system (e.g. VFs, hot-plugged +* devices). +*/ +for_each_pci_dev (dev) + max_nr_devices++; + + size = struct_size_t(struct pci_ser, devices, max_nr_devices); + + ser =kho_alloc_preserve (size);[Severity: Medium]
Should this code verifykho_is_enabled()before callingkho_alloc_preserve()?The commit message states:
"Note: There is no reason to check forkho_is_enabled()since it can be assumed to return true. If KHO was not enabled then Live Update would not be enabled and these routines would never run."
Quoted 8 lines
Does this assumption conflict with the Kexec Handover subsystem guidelines?
The guidelines mandate that all callers of serialization APIs must explicitly gate their usage with
kho_is_enabled().Calling preservation APIs like
kho_alloc_preserve()without the check can silently add tracking state that will never be used if the subsystem is unexpectedly inactive.
Sashiko keeps leaving this comment. It seems like a false positive to me. KHO maintainers, perhaps the KHO documentation needs adjustment?
Mike Rapoport
maintainerRe: [PATCH v6 01/12] PCI: liveupdate: Set up FLB handler for the PCI core
Quoted 57 lines · David Matlack
Quoted 56 lines · On Fri, May 22, 2026 at 1:44 PM <[email protected]> wrote:
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] Missingkho_is_enabled()check before calling KHO preservation APIs in PCI Live Update FLB operations. --commit
b0cb2fb154fba1aa85d63570fe0186e243353fb7
Author: David Matlack <[email protected]>PCI: liveupdate: Set up FLB handler for the PCI core
This commit sets up a File-Lifecycle-Bound (FLB) handler for the PCI core to participate in the preservation of PCI devices across Live Update. It allocates and preserves a
pci_serstructure using KHO when the first PCI device file is preserved.Quoted 4 lines
drivers/pci/liveupdate.c new file +0
-0[ ... ]
Quoted 10 lines
drivers/pci/liveupdate.c new file +10
-0+static int pci_flb_preserve (struct liveupdate_flb_op_args *args) +{ +struct pci_dev *dev =NULL ; +u32 max_nr_devices =0 ; +struct pci_ser *ser; +unsigned long size; + +/* +* Allocate enough space to preserve all devices that are currently +* present on the system. Extra padding can be added to this in the drivers/pci/liveupdate.c line 70
Quoted 10 lines
drivers/pci/liveupdate.c new file +10
-0+* future to increase the chances that there is enough room to preserve +* devices that are not yet present on the system (e.g. VFs, hot-plugged +* devices). +*/ +for_each_pci_dev (dev) + max_nr_devices++; + + size = struct_size_t(struct pci_ser, devices, max_nr_devices); + + ser =kho_alloc_preserve (size);[Severity: Medium]
Should this code verifykho_is_enabled()before callingkho_alloc_preserve()?The commit message states:
"Note: There is no reason to check forkho_is_enabled()since it can be assumed to return true. If KHO was not enabled then Live Update would not be enabled and these routines would never run."Does this assumption conflict with the Kexec Handover subsystem guidelines?
The guidelines mandate that all callers of serialization APIs must explicitly gate their usage with
kho_is_enabled().
Quoted 6 lines
Quoted 3 lines
Calling preservation APIs like
kho_alloc_preserve()without the check can silently add tracking state that will never be used if the subsystem is unexpectedly inactive.Sashiko keeps leaving this comment. It seems like a false positive to me. KHO maintainers, perhaps the KHO documentation needs adjustment?
TBH, I don't remember such guidelines, but patches are welcome ;-)
Signature · 2 lines
Sincerely yours, Mike.
Re: [PATCH v6 01/12] PCI: liveupdate: Set up FLB handler for the PCI core
Quoted 59 lines · Mike Rapoport
Quoted 57 lines · David Matlack
Quoted 56 lines · On Fri, May 22, 2026 at 1:44 PM <[email protected]> wrote:
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] Missingkho_is_enabled()check before calling KHO preservation APIs in PCI Live Update FLB operations. --commit
b0cb2fb154fba1aa85d63570fe0186e243353fb7
Author: David Matlack <[email protected]>PCI: liveupdate: Set up FLB handler for the PCI core
This commit sets up a File-Lifecycle-Bound (FLB) handler for the PCI core to participate in the preservation of PCI devices across Live Update. It allocates and preserves a
pci_serstructure using KHO when the first PCI device file is preserved.Quoted 4 lines
drivers/pci/liveupdate.c new file +0
-0[ ... ]
Quoted 10 lines
drivers/pci/liveupdate.c new file +10
-0+static int pci_flb_preserve (struct liveupdate_flb_op_args *args) +{ +struct pci_dev *dev =NULL ; +u32 max_nr_devices =0 ; +struct pci_ser *ser; +unsigned long size; + +/* +* Allocate enough space to preserve all devices that are currently +* present on the system. Extra padding can be added to this in the drivers/pci/liveupdate.c line 70
Quoted 10 lines
drivers/pci/liveupdate.c new file +10
-0+* future to increase the chances that there is enough room to preserve +* devices that are not yet present on the system (e.g. VFs, hot-plugged +* devices). +*/ +for_each_pci_dev (dev) + max_nr_devices++; + + size = struct_size_t(struct pci_ser, devices, max_nr_devices); + + ser =kho_alloc_preserve (size);[Severity: Medium]
Should this code verifykho_is_enabled()before callingkho_alloc_preserve()?The commit message states:
"Note: There is no reason to check forkho_is_enabled()since it can be assumed to return true. If KHO was not enabled then Live Update would not be enabled and these routines would never run."Does this assumption conflict with the Kexec Handover subsystem guidelines?
The guidelines mandate that all callers of serialization APIs must explicitly gate their usage with
kho_is_enabled().
Quoted 8 lines
Quoted 6 lines
Quoted 3 lines
Calling preservation APIs like
kho_alloc_preserve()without the check can silently add tracking state that will never be used if the subsystem is unexpectedly inactive.Sashiko keeps leaving this comment. It seems like a false positive to me. KHO maintainers, perhaps the KHO documentation needs adjustment?
TBH, I don't remember such guidelines, but patches are welcome ;-)
Yeah, on a quick scan of KHO documentation I see nothing of the sort. So possibly the bot is hallucinating?
But perhaps it would help if we update the subsystem prompts for Sashiko about this?
Re: [PATCH v6 01/12] PCI: liveupdate: Set up FLB handler for the PCI core
In reply to David MatlackQuoted 36 lines · David Matlack
Set up a File-Lifecycle-Bound (FLB) handler for the PCI core to enable it to participate in the preservation of PCI devices across Live Update. Essentially, this commit enables the PCI core to allocate a struct (struct
pci_ser) and preserve it across a Live Update whenever at least one device is preserved.Preserving PCI devices across Live Update is built on top of the Live Update Orchestrator's (LUO) support for file preservation. Drivers are expected to expose a file to userspace to represent a single PCI device and support preservation of that file. This is intended primarily to support preservation of PCI devices bound to VFIO drivers.
This commit enables drivers to register their
liveupdate_file_handlerwith the PCI core so that the PCI core can do its own tracking and enforcement of which devices are preserved.pci_liveupdate_register_flb(driver_file_handler); pci_liveupdate_unregister_flb(driver_file_handler);When the first file (with a handler registered with the PCI core) is preserved, the PCI core will be notified to allocate its tracking struct (
pci_ser). When the last file is unpreserved (i.e. preservation cancelled) the PCI core will be notified to free structpci_ser.This struct is preserved across a Live Update using KHO and can be fetched by the PCI core during early boot (e.g. during device enumeration) so that it knows which devices were preserved.
Note: This commit only allocates struct
pci_serand preserves it across Live Update. A subsequent commit will add an API for drivers to tell the PCI core exactly which devices are being preserved.Note: There is no reason to check for
kho_is_enabled()since it can be assumed to return true. If KHO was not enabled then Live Update would not be enabled and these routines would never run.
[...]
Quoted 22 lines
include/linux/kho/abi/pci.h new file +22
-0+/** +* struct pci_dev_ser - Serialized state about a single PCI device. +* +* @domain: The device's PCI domain number (segment). +* @bdf: The device's PCI bus, device, and function number. +* @padding: Padding to naturally align struct pci_dev_ser. +*/ +struct pci_dev_ser { +u32 domain; +u16 bdf; +u16 padding; +} __packed; + +/** +* struct pci_ser - PCI Subsystem Live Update State +* +* This struct tracks state about all devices that are being preserved across +* a Live Update for the next kernel. +* +* @max_nr_devices: The length of the devices[] flexible array. +* @nr_devices: The number of devices that were preserved. +* @devices: Flexible array of pci_dev_ser structs for each device.
include/linux/kho/abi/pci.h line 59
Quoted 10 lines
include/linux/kho/abi/pci.h new file +10
-0+*/ +struct pci_ser { +u32 max_nr_devices; +u32 nr_devices; +struct pci_dev_ser devices[]; +} __packed; + +/* Ensure all elements of devices[] are naturally aligned. */ +static_assert (offsetof(struct pci_ser , devices) %sizeof (unsigned long ) ==0 ); +static_assert (sizeof (struct pci_dev_ser ) %sizeof (unsigned long ) ==0 );
Minor Nit: Shall we consider using specific bitwidth types here? I'm wondering if down the line another u32 field is added to struct pci_dev_ser.. in that case on a 32-bit machine 12 % 4 == 0 but on a 64-bit machine 12 % 8 != 0..
[...]
With the nit:
Thanks,
Praan
Re: [PATCH v6 01/12] PCI: liveupdate: Set up FLB handler for the PCI core
Quoted 69 lines · Pranjal Shrivastava
Quoted 36 lines · David Matlack
Set up a File-Lifecycle-Bound (FLB) handler for the PCI core to enable it to participate in the preservation of PCI devices across Live Update. Essentially, this commit enables the PCI core to allocate a struct (struct
pci_ser) and preserve it across a Live Update whenever at least one device is preserved.Preserving PCI devices across Live Update is built on top of the Live Update Orchestrator's (LUO) support for file preservation. Drivers are expected to expose a file to userspace to represent a single PCI device and support preservation of that file. This is intended primarily to support preservation of PCI devices bound to VFIO drivers.
This commit enables drivers to register their
liveupdate_file_handlerwith the PCI core so that the PCI core can do its own tracking and enforcement of which devices are preserved.pci_liveupdate_register_flb(driver_file_handler); pci_liveupdate_unregister_flb(driver_file_handler);When the first file (with a handler registered with the PCI core) is preserved, the PCI core will be notified to allocate its tracking struct (
pci_ser). When the last file is unpreserved (i.e. preservation cancelled) the PCI core will be notified to free structpci_ser.This struct is preserved across a Live Update using KHO and can be fetched by the PCI core during early boot (e.g. during device enumeration) so that it knows which devices were preserved.
Note: This commit only allocates struct
pci_serand preserves it across Live Update. A subsequent commit will add an API for drivers to tell the PCI core exactly which devices are being preserved.Note: There is no reason to check for
kho_is_enabled()since it can be assumed to return true. If KHO was not enabled then Live Update would not be enabled and these routines would never run.[...]
Quoted 29 lines
include/linux/kho/abi/pci.h new file +29
-0+/** +* struct pci_dev_ser - Serialized state about a single PCI device. +* +* @domain: The device's PCI domain number (segment). +* @bdf: The device's PCI bus, device, and function number. +* @padding: Padding to naturally align struct pci_dev_ser. +*/ +struct pci_dev_ser { +u32 domain; +u16 bdf; +u16 padding; +} __packed; + +/** +* struct pci_ser - PCI Subsystem Live Update State +* +* This struct tracks state about all devices that are being preserved across +* a Live Update for the next kernel. +* +* @max_nr_devices: The length of the devices[] flexible array. +* @nr_devices: The number of devices that were preserved. +* @devices: Flexible array of pci_dev_ser structs for each device. +*/ +struct pci_ser { +u32 max_nr_devices; +u32 nr_devices; +struct pci_dev_ser devices[]; +} __packed; +
Quoted 8 lines
include/linux/kho/abi/pci.h line 59
Quoted 3 lines
include/linux/kho/abi/pci.h new file +3
-0+/* Ensure all elements of devices[] are naturally aligned. */ +static_assert (offsetof(struct pci_ser , devices) %sizeof (unsigned long ) ==0 ); +static_assert (sizeof (struct pci_dev_ser ) %sizeof (unsigned long ) ==0 );Minor Nit: Shall we consider using specific bitwidth types here? I'm wondering if down the line another u32 field is added to struct
pci_dev_ser.. in that case on a 32-bit machine 12 % 4 == 0 but on a 64-bit machine 12 % 8 != 0..
I think natural alignment is what matters for efficient access of the array elements. So failing the assert only on 64-bit architectures seems like the correct behavior.
Quoted 9 lines
[...]
With the nit:
Reviewed-by Pranjal Shrivastava <[email protected]>Thanks,
Praan
Re: [PATCH v6 01/12] PCI: liveupdate: Set up FLB handler for the PCI core
Quoted 14 lines · David Matlack
Quoted 13 lines · Pranjal Shrivastava
Quoted 12 lines · David Matlack
Set up a File-Lifecycle-Bound (FLB) handler for the PCI core to enable it to participate in the preservation of PCI devices across Live Update. Essentially, this commit enables the PCI core to allocate a struct (struct
pci_ser) and preserve it across a Live Update whenever at least one device is preserved.Preserving PCI devices across Live Update is built on top of the Live Update Orchestrator's (LUO) support for file preservation. Drivers are expected to expose a file to userspace to represent a single PCI device and support preservation of that file. This is intended primarily to support preservation of PCI devices bound to VFIO drivers.
[...]
Quoted 24 lines
Quoted 15 lines
Quoted 15 lines
+ * struct
pci_ser- PCI Subsystem Live Update State
+ *
+ * This struct tracks state about all devices that are being preserved across
+ * a Live Update for the next kernel.
+ *
+ * @max_nr_devices: The length of the devices[] flexible array.
+ * @nr_devices: The number of devices that were preserved.
+ * @devices: Flexible array ofpci_dev_serstructs for each device.
+ */include/linux/kho/abi/pci.h new file +6
-0+struct pci_ser { +u32 max_nr_devices; +u32 nr_devices; +struct pci_dev_ser devices[]; +} __packed; +Quoted 8 lines
include/linux/kho/abi/pci.h line 59
Quoted 3 lines
include/linux/kho/abi/pci.h new file +3
-0+/* Ensure all elements of devices[] are naturally aligned. */ +static_assert (offsetof(struct pci_ser , devices) %sizeof (unsigned long ) ==0 ); +static_assert (sizeof (struct pci_dev_ser ) %sizeof (unsigned long ) ==0 );Minor Nit: Shall we consider using specific bitwidth types here? I'm wondering if down the line another u32 field is added to struct
pci_dev_ser.. in that case on a 32-bit machine 12 % 4 == 0 but on a 64-bit machine 12 % 8 != 0..
Quoted 4 lines
I think natural alignment is what matters for efficient access of the array elements. So failing the assert only on 64-bit architectures seems like the correct behavior.
Ack. I guess what I was trying to say was we'd anyway need to keep both architectures in mind, i.e. adding members should be 64-bit aligned (which implicitly also handles 32-bit) as with the current assert any new addition would have to be both 32 & 64-bit aligned. I guess we can keep this as is.
Thanks,
Praan
Pasha Tatashin
maintainerRe: [PATCH v6 01/12] PCI: liveupdate: Set up FLB handler for the PCI core
In reply to David MatlackMAINTAINERS L: [email protected] · line 20534
Quoted 10 lines · David Matlack
MAINTAINERS +2
-0@@ -20530,6 +20530,16 @@ L: [email protected] S: Supported F: Documentation/PCI/pci-error-recovery.rst +PCI LIVE UPDATE +M: David Matlack <[email protected]>
Please add Pratyush, Mike, and myself so we are notified directly of incoming patches, the same as with other areas where the liveupdate/ tree is specified.
Quoted 22 lines
drivers/pci/liveupdate.c new file +15
-0@@ -0,0 +1,145 @@ +// SPDX-License-Identifier: GPL-2.0 + +/* +* Copyright (c) 2026, Google LLC. +* David Matlack <[email protected]> +*/ + +/** +* DOC: PCI Live Update +* +* The PCI subsystem participates in the Live Update process to enable drivers +* to preserve their PCI devices across kexec. +* +* File-Lifecycle-Bound (FLB) Data +* ===============================
...
Quoted 3 lines
+ *
+ * PCI device preservation across Live Update is built on top of the Live Update
+ * Orchestrator's (LUO) support for file preservation across kexec. Drivers
I prefer to just use acronyms FLB, and LUO, but have links to the actual documentations about them.
So, something like this:
* :ref:FLB <flb> Data
* =====================
*
* PCI device preservation across Live Update is built on top of the
* :ref:LUO <luo> support for file preservation across kexec. Drivers
And also add _luo and _flb to Documentation/core-api/liveupdate.rst
.. _luo:
========================
Live Update Orchestrator
========================
.. _flb:
LUO File Lifecycle Bound Global Data
====================================
drivers/pci/liveupdate.c
Quoted 7 lines
[ ... skip 17 lines ... ]
+ *
+ * * ``pci_liveupdate_register_flb(driver_file_handler)``
+ * * ``pci_liveupdate_unregister_flb(driver_file_handler)``
+ */drivers/pci/liveupdate.c new file +2
-0+ +#define pr_fmt (fmt) "PCI: liveupdate: " fmt
Nit, may be:
drivers/pci/liveupdate.c line 48
Quoted 7 lines
drivers/pci/liveupdate.c new file +7
-0+ +#include <linux/io.h> +#include <linux/kexec_handover.h> +#include <linux/kho/abi/pci.h> +#include <linux/liveupdate.h> +#include <linux/mutex.h> +#include <linux/mm.h>
Please sort alphabetically.
drivers/pci/liveupdate.c line 66
Quoted 7 lines
[ ... skip 12 lines ... ]
drivers/pci/liveupdate.c new file +6
-0+* future to increase the chances that there is enough room to preserve +* devices that are not yet present on the system (e.g. VFs, hot-plugged +* devices). +*/ +for_each_pci_dev (dev) + max_nr_devices++;
I think, we want to use kho_block [1] (it is in liveupdate/next branch) to allow number of supported devices to be dynamic.
To support this, we would redefine the ABI and tracking structures like so:
/* include/linux/kho/abi/pci.h */
struct pci_ser {
u64 devices; /* Phys address of the first block header of kho_block_set */
u64 nr_devices; /* Total count of active preserved devices */
} __packed;
/* drivers/pci/liveupdate.c */
struct pci_flb_outgoing {
struct pci_ser *ser; /* Points to the FDT/KHO-allocated ABI struct */
struct kho_block_set block_set; /* Controls the active blocks on the fly */
};
In __pci_liveupdate_preserve_device() , we would search for and reuse any inactive pci_dev_ser slot first, and only call kho_block_set_grow() to expand if no inactive slots are available.
In pci_liveupdate_unpreserve_device(), we would simply mark the pci_dev_ser as inactive.
Quoted 8 lines
include/linux/pci_liveupdate.h new file +0
-0@@ -0,0 +1,30 @@[ ... skip 24 lines ... ]
include/linux/pci_liveupdate.h line 30
Quoted 6 lines
include/linux/pci_liveupdate.h new file +6
-0+static inline void pci_liveupdate_unregister_flb (struct liveupdate_file_handler *fh) +{ +} +#endif + +#endif /* LINUX_PCI_LIVEUPDATE_H */
[1] https://lore.kernel.org/all/[email protected]/
Preserving: In __pci_liveupdate_preserve_device() , we would search for
Unpreserving: In pci_liveupdate_unpreserve_device(), we would simply
Preserving: In __pci_liveupdate_preserve_device() , we would search for
Unpreserving: In pci_liveupdate_unpreserve_device(), we would simply
Signature · 1 line
Pasha Tatashin <[email protected]>
Mike Rapoport
maintainerRe: [PATCH v6 01/12] PCI: liveupdate: Set up FLB handler for the PCI core
Quoted 9 lines · Pasha Tatashin
Quoted 8 lines · David Matlack
MAINTAINERS +0
-0@@ -20530,6 +20530,16 @@ L: [email protected] S: Supported F: Documentation/PCI/pci-error-recovery.rst
Quoted 6 lines
MAINTAINERS L: [email protected] · line 20534
Quoted 2 lines
MAINTAINERS +2
-0+PCI LIVE UPDATE +M: David Matlack <[email protected]>Please add Pratyush, Mike, and myself so we are notified directly of incoming patches, the same as with other areas where the liveupdate/ tree is specified.
Or we can add PCI liveupdate files to LIVEUPDATE entry.
Signature · 2 lines
Sincerely yours, Mike.
Pasha Tatashin
maintainerRe: [PATCH v6 01/12] PCI: liveupdate: Set up FLB handler for the PCI core
Quoted 9 lines · Mike Rapoport
Quoted 5 lines · Pasha Tatashin
On Fri, 22 May 2026 20:23:59 +0000, David Matlack <[email protected]> wrote:
Please add Pratyush, Mike, and myself so we are notified directly of incoming patches, the same as with other areas where the liveupdate/ tree is specified.
Or we can add PCI liveupdate files to LIVEUPDATE entry.
That will not work, as we cannot serve as maintainers for PCI/VFIO/IOMMU/KVM, etc. David Matlack will be the maintainer for the PCI components, and we will accept patches once they have been approved by him.
The simplification we could do is to create an email alias for the live-update tree maintainers. This would allow us to use a single entry instead of listing all three of us individually.
Re: [PATCH v6 01/12] PCI: liveupdate: Set up FLB handler for the PCI core
Quoted 11 lines · Pasha Tatashin
Quoted 9 lines · Mike Rapoport
Quoted 5 lines · Pasha Tatashin
On Fri, 22 May 2026 20:23:59 +0000, David Matlack <[email protected]> wrote:
Please add Pratyush, Mike, and myself so we are notified directly of incoming patches, the same as with other areas where the liveupdate/ tree is specified.
Or we can add PCI liveupdate files to LIVEUPDATE entry.
Quoted 8 lines
That will not work, as we cannot serve as maintainers for PCI/VFIO/IOMMU/KVM, etc. David Matlack will be the maintainer for the PCI components, and we will accept patches once they have been approved by him.
The simplification we could do is to create an email alias for the live-update tree maintainers. This would allow us to use a single entry instead of listing all three of us individually.
We could create a Live Update mailing list for all code that can be CCed on all patches that must be merged through the Live Update tree. I would also be interested in subscribing to that list.
But if you want to create a LUO maintainers-only list that would work fine too.
For now, I'll plan to add you as Reviewers under PCI LIVE UPDATE in v7.
Re: [PATCH v6 01/12] PCI: liveupdate: Set up FLB handler for the PCI core
Quoted 17 lines · David Matlack
Quoted 16 lines · Pasha Tatashin
Quoted 9 lines · Mike Rapoport
Quoted 5 lines · Pasha Tatashin
On Fri, 22 May 2026 20:23:59 +0000, David Matlack <[email protected]> wrote:
Please add Pratyush, Mike, and myself so we are notified directly of incoming patches, the same as with other areas where the liveupdate/ tree is specified.
Or we can add PCI liveupdate files to LIVEUPDATE entry.
That will not work, as we cannot serve as maintainers for PCI/VFIO/IOMMU/KVM, etc. David Matlack will be the maintainer for the PCI components, and we will accept patches once they have been approved by him.
Quoted 7 lines
Quoted 3 lines
The simplification we could do is to create an email alias for the live-update tree maintainers. This would allow us to use a single entry instead of listing all three of us individually.
We could create a Live Update mailing list for all code that can be CCed on all patches that must be merged through the Live Update tree. I would also be interested in subscribing to that list.
+1. I'd like if there's a specific Live Update mailing list for submissions & discussion about the Live Update tree.
Thanks,
Praan
Pratyush Yadav
maintainerRe: [PATCH v6 01/12] PCI: liveupdate: Set up FLB handler for the PCI core
Quoted 22 lines · Pranjal Shrivastava
Quoted 21 lines · David Matlack
Quoted 19 lines · Pasha Tatashin
Quoted 9 lines · Mike Rapoport
Quoted 5 lines · Pasha Tatashin
On Fri, 22 May 2026 20:23:59 +0000, David Matlack <[email protected]> wrote:
Please add Pratyush, Mike, and myself so we are notified directly of incoming patches, the same as with other areas where the liveupdate/ tree is specified.
Or we can add PCI liveupdate files to LIVEUPDATE entry.
That will not work, as we cannot serve as maintainers for PCI/VFIO/IOMMU/KVM, etc. David Matlack will be the maintainer for the PCI components, and we will accept patches once they have been approved by him.
The simplification we could do is to create an email alias for the live-update tree maintainers. This would allow us to use a single entry instead of listing all three of us individually.
Quoted 6 lines
Quoted 3 lines
We could create a Live Update mailing list for all code that can be CCed on all patches that must be merged through the Live Update tree. I would also be interested in subscribing to that list.
+1. I'd like if there's a specific Live Update mailing list for submissions & discussion about the Live Update tree.
We treat [email protected] as the "live update mailing list". We considered getting a separate one, but I reckon the traffic is low enough on kexec@ already that we can re-use it for live update.
So perhaps we just Cc kexec@? Is there anything to be gained by creating an alias?
Signature · 2 lines
Regards, Pratyush Yadav
Re: [PATCH v6 01/12] PCI: liveupdate: Set up FLB handler for the PCI core
In reply to Pasha TatashinQuoted 18 lines · Pasha Tatashin
Quoted 2 lines · David Matlack
+ * PCI device preservation across Live Update is built on top of the Live Update
+ * Orchestrator's (LUO) support for file preservation across kexec. DriversI prefer to just use acronyms FLB, and LUO, but have links to the actual documentations about them.
So, something like this:
* :ref:
FLB <flb>Data
* =====================
*
* PCI device preservation across Live Update is built on top of the
* :ref:LUO <luo>support for file preservation across kexec. DriversAnd also add
_luoand_flbtoDocumentation/core-api/liveupdate.rst
Quoted 7 lines
..
_luo:========================
Live Update Orchestrator
========================..
_flb:
Will do.
I guess I will need to add another patch to add the link references to liveupdate.rst?
Quoted 4 lines
LUO File Lifecycle Bound Global Data
====================================
Quoted 9 lines
Review
Quoted 7 lines
[ ... skip 17 lines ... ]
+ *
+ * * ``pci_liveupdate_register_flb(driver_file_handler)``
+ * * ``pci_liveupdate_unregister_flb(driver_file_handler)``
+ */(quoted diff) +2
-0+ +#define pr_fmt(fmt) "PCI: liveupdate: " fmtNit, may be:
Did you have a suggestion here that got lost?
Quoted 10 lines
drivers/pci/liveupdate.c line 48
Quoted 8 lines
drivers/pci/liveupdate.c new file +7
-0+ +#include <linux/io.h> +#include <linux/kexec_handover.h> +#include <linux/kho/abi/pci.h> +#include <linux/liveupdate.h> +#include <linux/mutex.h> +#include <linux/mm.h> Please sort alphabetically.
Will do.
Quoted 27 lines
drivers/pci/liveupdate.c line 66
Quoted 8 lines
[ ... skip 12 lines ... ]
drivers/pci/liveupdate.c new file +6
-0+* future to increase the chances that there is enough room to preserve +* devices that are not yet present on the system (e.g. VFs, hot-plugged +* devices). +*/ +for_each_pci_dev (dev) + max_nr_devices++;I think, we want to use
kho_block[1] (it is in liveupdate/next branch) to allow number of supported devices to be dynamic.To support this, we would redefine the ABI and tracking structures like so:
/*
include/linux/kho/abi/pci.h*/
structpci_ser{
u64 devices; /* Phys address of the first block header ofkho_block_set*/
u64nr_devices; /* Total count of active preserved devices */
}__packed;/*
drivers/pci/liveupdate.c*/
structpci_flb_outgoing{
structpci_ser*ser; /* Points to the FDT/KHO-allocated ABI struct */
structkho_block_setblock_set; /* Controls the active blocks on the fly */
};
Quoted 6 lines
In
__pci_liveupdate_preserve_device(), we would search for and reuse any inactivepci_dev_serslot first, and only callkho_block_set_grow()to expand if no inactive slots are available.In
pci_liveupdate_unpreserve_device(), we would simply mark thepci_dev_seras inactive.
Makes sense at a high level. I'll work on switching kho_block for v7 and get back to you if I hit any issues.
Quoted 26 lines
Quoted 9 lines
include/linux/pci_liveupdate.h new file +0
-0@@ -0,0 +1,30 @@[ ... skip 24 lines ... ]
include/linux/pci_liveupdate.h line 30
Quoted 6 lines
include/linux/pci_liveupdate.h new file +6
-0+static inline void pci_liveupdate_unregister_flb (struct liveupdate_file_handler *fh) +{ +} +#endif + +#endif /* LINUX_PCI_LIVEUPDATE_H */ [1] https://lore.kernel.org/all/[email protected]/
Preserving: In
__pci_liveupdate_preserve_device(), we would search for
Unpreserving: Inpci_liveupdate_unpreserve_device(), we would simplyPreserving: In
__pci_liveupdate_preserve_device(), we would search for
Unpreserving: Inpci_liveupdate_unpreserve_device(), we would simplySignature · 1 line
Pasha Tatashin <[email protected]>
Pasha Tatashin
maintainerRe: [PATCH v6 01/12] PCI: liveupdate: Set up FLB handler for the PCI core
Quoted 27 lines · David Matlack
Quoted 25 lines · Pasha Tatashin
Quoted 1 line · David Matlack
+ * PCI device preservation across Live Update is built on top of the Live Update
I prefer to just use acronyms FLB, and LUO, but have links to the actual documentations about them.
So, something like this:
* :ref:
FLB <flb>Data
* =====================
*
* PCI device preservation across Live Update is built on top of the
* :ref:LUO <luo>support for file preservation across kexec. DriversAnd also add
_luoand_flbtoDocumentation/core-api/liveupdate.rst..
_luo:========================
Live Update Orchestrator
========================
Quoted 6 lines
Quoted 1 line
..
_flb:Will do.
I guess I will need to add another patch to add the link references to
liveupdate.rst?
Yes, it can be a separate patch, but adding to this patch is also, OK.
Quoted 7 lines
Quoted 5 lines
LUO File Lifecycle Bound Global Data
====================================Nit, may be:
Did you have a suggestion here that got lost?
Yeah, I meant:
#define pr_fmt(fmt) "PCI: " KBUILD_BASENAME ": " fmt
Quoted 32 lines
Quoted 2 lines
Please sort alphabetically.
Will do.
Quoted 18 lines
I think, we want to use
kho_block[1] (it is in liveupdate/next branch) to allow number of supported devices to be dynamic.To support this, we would redefine the ABI and tracking structures like so:
/*
include/linux/kho/abi/pci.h*/
structpci_ser{
u64 devices; /* Phys address of the first block header ofkho_block_set*/
u64nr_devices; /* Total count of active preserved devices */
}__packed;/*
drivers/pci/liveupdate.c*/
structpci_flb_outgoing{
structpci_ser*ser; /* Points to the FDT/KHO-allocated ABI struct */
structkho_block_setblock_set; /* Controls the active blocks on the fly */
};Quoted 6 lines
In
__pci_liveupdate_preserve_device(), we would search for and reuse any inactivepci_dev_serslot first, and only callkho_block_set_grow()to expand if no inactive slots are available.In
pci_liveupdate_unpreserve_device(), we would simply mark thepci_dev_seras inactive.Makes sense at a high level. I'll work on switching
kho_blockfor v7 and get back to you if I hit any issues.
PATCH v6 2/12 PCI: liveupdate: Track outgoing preserved PCI devices
In reply to David MatlackAdd APIs to allow drivers to notify the PCI core of which devices are being preserved across a Live Update for the next kernel, i.e. "outgoing" devices.
Drivers must notify the PCI core when devices are preserved so that the PCI core can update its FLB data (struct pci_ser) and track the list of outgoing devices. pci_liveupdate_preserve() notifies the PCI core that a device must be preserved across Live Update. pci_liveupdate_unpreserve() reverses this (cancels the preservation of the device).
This tracking ensures the PCI core is fully aware of which devices may need special handling during shutdown and kexec, and so that it can be handed off to the next kernel.
--- drivers/pci/liveupdate.c | 167 +++++++++++++++++++++++++++++++++ drivers/pci/liveupdate.h | 21 +++++ drivers/pci/probe.c | 2 + include/linux/kho/abi/pci.h | 9 +- include/linux/pci.h | 3 + include/linux/pci_liveupdate.h | 21 +++++ 6 files changed, 220 insertions(+), 3 deletions(-) create mode 100644 drivers/pci/liveupdate.h
drivers/pci/liveupdate.c +167 -0
@@ -36,6 +36,26 @@* * * ``pci_liveupdate_register_flb(driver_file_handler)`` * * ``pci_liveupdate_unregister_flb(driver_file_handler)`` +* +* Device Tracking +* =============== +* +* Drivers must notify the PCI core when specific devices are preserved or +* unpreserved with the following APIs: +* +* * ``pci_liveupdate_preserve(pci_dev)`` +* * ``pci_liveupdate_unpreserve(pci_dev)`` +* +* This allows the PCI core to keep its FLB data (struct pci_ser) up to date +* with the list of **outgoing** preserved devices for the next kernel. +* +* Restrictions +* ============ +* +* The PCI core enforces the following restrictions on which devices can be +* preserved. These may be relaxed in the future: +* +* * The device cannot be a Virtual Function (VF). */ #define pr_fmt (fmt) "PCI: liveupdate: " fmt
@@ -48,6 +68,21 @@#include <linux/mm.h> #include <linux/pci.h> +#include "liveupdate.h" + +/** +* struct pci_liveupdate_global - Global state for PCI Live Update support +* @rwsem: Reader/writer semaphore used to protect the incoming and outgoing +* FLBs, and the references to them in struct pci_dev. +*/ +struct pci_liveupdate_global { +struct rw_semaphore rwsem; +}; + +static struct pci_liveupdate_global pci_liveupdate = { + .rwsem =__RWSEM_INITIALIZER (pci_liveupdate.rwsem), +}; +static int pci_flb_preserve (struct liveupdate_flb_op_args *args) {struct pci_dev *dev =NULL ;
@@ -115,6 +150,138 @@ static struct liveupdate_flb pci_liveupdate_flb = { .compatible = PCI_LUO_FLB_COMPATIBLE, }; +static struct pci_ser *pci_liveupdate_flb_get_outgoing (void ) +{ +struct pci_ser *ser =NULL ; +int ret; + + ret =liveupdate_flb_get_outgoing (&pci_liveupdate_flb, (void **)&ser); +if (ret) +return ERR_PTR (ret); + +if (!ser) +return ERR_PTR (-ENOENT ); + +return ser; +} + +static void pci_liveupdate_unpreserve_device (struct pci_ser *ser,struct pci_dev *dev) +{ +struct pci_dev_ser *dev_ser = dev->liveupdate.outgoing; + +if (!dev_ser) { +pci_warn (dev,"Cannot unpreserve device that is not preserved\n" ); +return ; + } + +pci_info (dev,"Device will no longer be preserved across next Live Update\n" ); + ser->nr_devices--; +memset (dev_ser,0 ,sizeof (*dev_ser)); + dev->liveupdate.outgoing =NULL ; +} + +static int pci_liveupdate_preserve_device (struct pci_ser *ser,struct pci_dev *dev) +{ +int i; + +if (dev->liveupdate.outgoing) +return -EBUSY ; + +if (ser->nr_devices == ser->max_nr_devices) +return -ENOSPC ; + +for (i =0 ; i < ser->max_nr_devices; i++) { +/* +* Start searching at index ser->nr_devices. This should result +* in a constant time search under expected conditions (devices +* are not getting unpreserved). +*/ +int index = (ser->nr_devices + i) % ser->max_nr_devices; +struct pci_dev_ser *dev_ser = &ser->devices[index]; + +if (dev_ser->refcount) +continue ; + +pci_info (dev,"Device will be preserved across next Live Update\n" ); + ser->nr_devices++; + + dev_ser->domain =pci_domain_nr (dev->bus); + dev_ser->bdf =pci_dev_id (dev); + dev_ser->refcount =1 ; + + dev->liveupdate.outgoing = dev_ser; +return 0 ; + } + +return -ENOSPC ; +} + +/** +* pci_liveupdate_preserve() - Preserve a PCI device across Live Update +* @dev: The PCI device to preserve. +* +* pci_liveupdate_preserve() notifies the PCI core that a PCI device should be +* preserved across the next Live Update. Drivers are expected to call +* pci_liveupdate_preserve() from their struct liveupdate_file_handler +* preserve() callback to ensure the outgoing struct pci_ser is already set up. +* +* Returns: 0 on success, <0 on failure. +*/ +int pci_liveupdate_preserve (struct pci_dev *dev) +{ +struct pci_ser *ser =NULL ; + +if (dev->is_virtfn) +return -EINVAL ; + +guard (rwsem_write)(&pci_liveupdate.rwsem); + + ser =pci_liveupdate_flb_get_outgoing (); +if (IS_ERR (ser)) +return PTR_ERR (ser); + +return pci_liveupdate_preserve_device (ser, dev); +} +EXPORT_SYMBOL_GPL (pci_liveupdate_preserve); + +/** +* pci_liveupdate_unpreserve() - Cancel preservation of a PCI device +* @dev: The PCI device to unpreserve. +* +* pci_liveupdate_unpreserve() notifies the PCI core that a PCI device should no +* longer be preserved across the next Live Update. Drivers are expected to call +* pci_liveupdate_unpreserve() from their struct liveupdate_file_handler +* unpreserve() callback to ensure the outgoing struct pci_ser is already set +* up. +*/ +void pci_liveupdate_unpreserve (struct pci_dev *dev) +{ +struct pci_ser *ser =NULL ; + +guard (rwsem_write)(&pci_liveupdate.rwsem); + + ser =pci_liveupdate_flb_get_outgoing (); +if (IS_ERR (ser)) { +pci_warn (dev,"Cannot unpreserve device without outgoing Live Update state\n" ); +return ; + } + +pci_liveupdate_unpreserve_device (ser, dev); +} +EXPORT_SYMBOL_GPL (pci_liveupdate_unpreserve); + +void pci_liveupdate_cleanup_device (struct pci_dev *dev) +{ +/* +* It should be safe to READ_ONCE() outside of the rwsem during cleanup +* since there should no longer be any references to @dev on the system. +*/ +if (READ_ONCE (dev->liveupdate.outgoing)) { +pci_WARN (dev,1 ,"Destroying outgoing-preserved device!\n" ); +pci_liveupdate_unpreserve (dev); + } +} +/** * pci_liveupdate_register_flb() - Register a file handler with the PCI core * @fh: The file handler to register.
drivers/pci/liveupdate.h new file +21 -0
@@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* +* PCI Live Update support (core API) +* +* Copyright (c) 2026, Google LLC. +* David Matlack <[email protected]> +*/ +#ifndef DRIVERS_PCI_LIVEUPDATE_H +#define DRIVERS_PCI_LIVEUPDATE_H + +#include <linux/pci.h> + +#ifdef CONFIG_PCI_LIVEUPDATE +void pci_liveupdate_cleanup_device (struct pci_dev *dev); +#else +static inline void pci_liveupdate_cleanup_device (struct pci_dev *dev) +{ +} +#endif + +#endif /* DRIVERS_PCI_LIVEUPDATE_H */
drivers/pci/probe.c +2 -0
@@ -24,6 +24,7 @@#include <linux/pm_runtime.h> #include <linux/bitfield.h> #include <trace/events/pci.h> +#include "liveupdate.h" #include "pci.h" static struct resource busn_resource = {
@@ -2490,6 +2491,7 @@ static void pci_release_dev(struct device *dev) pci_dev =to_pci_dev (dev);pci_release_capabilities (pci_dev); +pci_liveupdate_cleanup_device (pci_dev);pci_release_of_node (pci_dev);pcibios_release_device (pci_dev);pci_bus_put (pci_dev->bus);
include/linux/kho/abi/pci.h +6 -3
@@ -23,19 +23,22 @@* incrementing the version number in the PCI_LUO_FLB_COMPATIBLE string. */ -#define PCI_LUO_FLB_COMPATIBLE "pci-v1" +#define PCI_LUO_FLB_COMPATIBLE "pci-v2"/** * struct pci_dev_ser - Serialized state about a single PCI device. * * @domain: The device's PCI domain number (segment). * @bdf: The device's PCI bus, device, and function number. -* @padding: Padding to naturally align struct pci_dev_ser. +* @refcount: Reference count used by the PCI core to keep track of whether it +* is done using a device's struct pci_dev_ser. The value of the +* refcount is equal to 1 when the struct pci_dev_ser is in use, and +* 0 otherwise. */ struct pci_dev_ser {u32 domain;u16 bdf; -u16 padding; +u16 refcount; } __packed;/**
include/linux/pci.h +3 -0
@@ -594,6 +594,9 @@ struct pci_dev {u8 tph_mode;/* TPH mode */ u8 tph_req_type;/* TPH requester type */ #endif +#ifdef CONFIG_PCI_LIVEUPDATE +struct pci_liveupdate liveupdate; +#endif };static inline struct pci_dev *pci_physfn (struct pci_dev *dev)
include/linux/pci_liveupdate.h +21 -0
@@ -8,14 +8,26 @@ #ifndef LINUX_PCI_LIVEUPDATE_H #define LINUX_PCI_LIVEUPDATE_H +#include <linux/kho/abi/pci.h> #include <linux/liveupdate.h> #include <linux/types.h> +#include <linux/spinlock_types.h> + +/** + * struct pci_liveupdate - PCI Live Update state for a struct pci_dev + * @outgoing: State preserved for the next kernel. + */ +struct pci_liveupdate { + struct pci_dev_ser *outgoing; +}; struct pci_dev; #ifdef CONFIG_PCI_LIVEUPDATE int pci_liveupdate_register_flb(struct liveupdate_file_handler *fh); void pci_liveupdate_unregister_flb(struct liveupdate_file_handler *fh); +int pci_liveupdate_preserve(struct pci_dev *dev); +void pci_liveupdate_unpreserve(struct pci_dev *dev); #else static inline int pci_liveupdate_register_flb(struct liveupdate_file_handler *fh) {
@@ -25,6 +37,15 @@ static inline int pci_liveupdate_register_flb(struct liveupdate_file_handler *fhstatic inline void pci_liveupdate_unregister_flb (struct liveupdate_file_handler *fh) { } + +static inline int pci_liveupdate_preserve (struct pci_dev *dev) +{ +return -EOPNOTSUPP ; +} + +static inline void pci_liveupdate_unpreserve (struct pci_dev *dev) +{ +}#endif #endif /* LINUX_PCI_LIVEUPDATE_H */
Signature · 1 line
2.54.0.746.g67dd491aae-goog
[email protected]
AI reviewRe: [PATCH v6 02/12] PCI: liveupdate: Track outgoing preserved PCI devices
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider: - [High] Acquiring a sleepable rw_semaphore (rwsem_write) during PCI device release, which can occur in…
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] Acquiring a sleepable rw_semaphore (rwsem_write) during PCI device release, which can occur in atomic contexts. --
commit 306396f47fee049b9172957aca3ed638cf2241ab
Author: David Matlack <[email protected]>
PCI: liveupdate: Track outgoing preserved PCI devices
This commit adds APIs to allow drivers to notify the PCI core of which devices are being preserved across a Live Update for the next kernel.
Quoted 4 lines
drivers/pci/liveupdate.c +0
-0
[ ... ]
Quoted 1 line
drivers/pci/liveupdate.c +0
-0@@ -115,6 +150,138 @@ static struct liveupdate_flb pci_liveupdate_flb = {
[ ... ]
Quoted 15 lines
drivers/pci/liveupdate.c +15
-0+void pci_liveupdate_unpreserve (struct pci_dev *dev) +{ +struct pci_ser *ser =NULL ; + +guard (rwsem_write)(&pci_liveupdate.rwsem); + + ser =pci_liveupdate_flb_get_outgoing (); +if (IS_ERR (ser)) { +pci_warn (dev,"Cannot unpreserve device without outgoing Live Update state\n" ); +return ; + } + +pci_liveupdate_unpreserve_device (ser, dev); +} +EXPORT_SYMBOL_GPL (pci_liveupdate_unpreserve);
drivers/pci/liveupdate.c static struct liveupdate_flb pci_liveupdate_flb = { · line 281
Quoted 10 lines
drivers/pci/liveupdate.c +10
-0+ +void pci_liveupdate_cleanup_device (struct pci_dev *dev) +{ +/* +* It should be safe to READ_ONCE() outside of the rwsem during cleanup +* since there should no longer be any references to @dev on the system. +*/ +if (READ_ONCE (dev->liveupdate.outgoing)) { +pci_WARN (dev,1 ,"Destroying outgoing-preserved device!\n" ); +pci_liveupdate_unpreserve (dev);
[Severity: High]
Can calling pci_liveupdate_unpreserve() here cause a sleep-in-atomic bug?
pci_liveupdate_unpreserve() unconditionally acquires a sleepable rw_semaphore:
guard(rwsem_write)(&pci_liveupdate.rwsem).
Since pci_liveupdate_cleanup_device() is called from pci_release_dev(), this runs when the last reference to a struct pci_dev is dropped via pci_dev_put().
Because pci_dev_put() can be called from atomic contexts (such as hardware interrupt handlers or while holding spinlocks) to drop references acquired during lookups, acquiring a sleepable lock here could trigger a scheduling-while-atomic BUG or deadlock.
Quoted 2 lines
drivers/pci/liveupdate.c +2
-0+ } +}
[ ... ]
Quoted 4 lines
drivers/pci/probe.c +0
-0
[ ... ]
Quoted 8 lines
drivers/pci/probe.c +1
-0@@ -2490,6 +2491,7 @@ static void pci_release_dev(struct device *dev) pci_dev =to_pci_dev (dev);pci_release_capabilities (pci_dev); +pci_liveupdate_cleanup_device (pci_dev);pci_release_of_node (pci_dev);pcibios_release_device (pci_dev);pci_bus_put (pci_dev->bus);
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=2
Re: [PATCH v6 02/12] PCI: liveupdate: Track outgoing preserved PCI devices
Quoted 29 lines · On Fri, May 22, 2026 at 1:54 PM <[email protected]> wrote:
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] Acquiring a sleepablerw_semaphore(rwsem_write) during PCI device release, which can occur in atomic contexts. --drivers/pci/liveupdate.c static struct liveupdate_flb pci_liveupdate_flb = { · line 281
Quoted 9 lines
drivers/pci/liveupdate.c +9
-0+void pci_liveupdate_cleanup_device (struct pci_dev *dev) +{ +/* +* It should be safe to READ_ONCE() outside of the rwsem during cleanup +* since there should no longer be any references to @dev on the system. +*/ +if (READ_ONCE (dev->liveupdate.outgoing)) { +pci_WARN (dev,1 ,"Destroying outgoing-preserved device!\n" ); +pci_liveupdate_unpreserve (dev);[Severity: High]
Can callingpci_liveupdate_unpreserve()here cause a sleep-in-atomic bug?
pci_liveupdate_unpreserve()unconditionally acquires a sleepablerw_semaphore:
guard(rwsem_write)(&pci_liveupdate.rwsem).Since
pci_liveupdate_cleanup_device()is called frompci_release_dev(), this runs when the last reference to a structpci_devis dropped viapci_dev_put().Because
pci_dev_put()can be called from atomic contexts (such as hardware interrupt handlers or while holding spinlocks) to drop references acquired during lookups, acquiring a sleepable lock here could trigger a scheduling-while-atomic BUG or deadlock.
Quoted 8 lines
drivers/pci/probe.c static void pci_release_dev(struct device *dev) · line 2497
Quoted 8 lines
drivers/pci/probe.c +1
-0@@ -2490,6 +2491,7 @@ static void pci_release_dev(struct device *dev) pci_dev =to_pci_dev (dev);pci_release_capabilities (pci_dev); +pci_liveupdate_cleanup_device (pci_dev);pci_release_of_node (pci_dev);pcibios_release_device (pci_dev);pci_bus_put (pci_dev->bus);
Gemini found 3 files where pci_dev_put() is called under a spinlock:
- drivers/net/ethernet/microsoft/mana/gdma_main.c (mana_driver_exit())
- arch/x86/pci/i386.c (pcibios_fw_addr_list_del())
- arch/powerpc/platforms/pasemi/dma_lib.c (pasemi_dma_init())
OTOH, pci_release_dev() does not seem atomic-safe. On s390, it can take the zpci_add_remove_lock mutex via pcibios_release_device(). And on all architectures it can call kernfs_remove() via pci_bus_put(), which takes multiple semaphores.
Re: [PATCH v6 02/12] PCI: liveupdate: Track outgoing preserved PCI devices
Quoted 11 lines · David Matlack
Gemini found 3 files where
pci_dev_put()is called under a spinlock:-
drivers/net/ethernet/microsoft/mana/gdma_main.c(mana_driver_exit())
-arch/x86/pci/i386.c(pcibios_fw_addr_list_del())
-arch/powerpc/platforms/pasemi/dma_lib.c(pasemi_dma_init())OTOH,
pci_release_dev()does not seem atomic-safe. On s390, it can take thezpci_add_remove_lockmutex viapcibios_release_device(). And on all architectures it can callkernfs_remove()viapci_bus_put(), which takes multiple semaphores.
AFAICT, Sashiko seems to be wrong here.. pci_dev_put calls put_device() The put_device() doc clearly mentions might_sleep [1] to warns that dropping the final reference may trigger a sleepable cleanup.
Any existing code calling put_device in atomic context is in violation. put_device / release are *expected* to sleep.
This patch doesn't introduce any sleep-in-atomic issues.
Thanks,
Praan
[1] https://elixir.bootlin.com/linux/v7.1-rc6/source/drivers/base/core.c#L3812
Re: [PATCH v6 02/12] PCI: liveupdate: Track outgoing preserved PCI devices
In reply to David MatlackQuoted 15 lines · David Matlack
Add APIs to allow drivers to notify the PCI core of which devices are being preserved across a Live Update for the next kernel, i.e. "outgoing" devices.
Drivers must notify the PCI core when devices are preserved so that the PCI core can update its FLB data (struct
pci_ser) and track the list of outgoing devices.pci_liveupdate_preserve()notifies the PCI core that a device must be preserved across Live Update.pci_liveupdate_unpreserve()reverses this (cancels the preservation of the device).This tracking ensures the PCI core is fully aware of which devices may need special handling during shutdown and kexec, and so that it can be handed off to the next kernel.
Signed-off-by David Matlack <[email protected]>
[...]
Quoted 11 lines
/**
* structpci_dev_ser- Serialized state about a single PCI device. *
* @domain: The device's PCI domain number (segment).
* @bdf: The device's PCI bus, device, and function number.
- * @padding: Padding to naturally align structpci_dev_ser.
+ * @refcount: Reference count used by the PCI core to keep track of whether it+ * is done using a device's struct pci_dev_ser. The value of the + * refcount is equal to 1 when the struct pci_dev_ser is in use, and + * 0 otherwise.
Note to fellow reviewers: This may seem like a bool instead of refcount, but this is changed in Patch 6.
Thanks,
Praan
Pasha Tatashin
maintainerRe: [PATCH v6 02/12] PCI: liveupdate: Track outgoing preserved PCI devices
In reply to David Matlackdrivers/pci/liveupdate.c static struct liveupdate_flb pci_liveupdate_flb = { · line 214
Quoted 12 lines · David Matlack
drivers/pci/liveupdate.c +0
-0@@ -115,6 +150,138 @@ static struct liveupdate_flb pci_liveupdate_flb = {[ ... skip 59 lines ... ]
drivers/pci/liveupdate.c +6
-0+ dev_ser->bdf =pci_dev_id (dev); + dev_ser->refcount =1 ; + + dev->liveupdate.outgoing = dev_ser; +return 0 ; + }
This loop is compatible with KHO block iterators, as mentioned in the previous email. It should be straightforward to convert to them.
include/linux/kho/abi/pci.h line 41
Quoted 13 lines
include/linux/kho/abi/pci.h +0
-0@@ -23,19 +23,22 @@[ ... skip 16 lines ... ]
*/
structpci_dev_ser{include/linux/kho/abi/pci.h +1
-1u32 domain;u16 bdf; -u16 padding; +u16 refcount;
Just add refcount to the previous patch, to reduce changes to your own code.
Otherwise looks good
Signature · 1 line
Pasha Tatashin <[email protected]>
PATCH v6 3/12 PCI: liveupdate: Track incoming preserved PCI devices
In reply to David MatlackDuring PCI enumeration, the previous kernel might have passed state about devices that were preserved across kexec. The PCI core needs to fetch this state to identify which devices are "incoming" and require special handling.
Add pci_liveupdate_setup_device() which is called during device setup to fetch the serialized state (struct pci_ser) from the Live Update Orchestrator. The first time this happens, pci_flb_retrieve() will run and convert the array of pci_dev_ser structs into an xarray so that it can be looked up efficiently.
If a device is found in the xarray, the PCI core stores a pointer to its state in dev->liveupdate_incoming and holds a reference to the incoming FLB until pci_liveupdate_finish() is called by the driver.
This ensures proper lifecycle management for incoming preserved devices and allows the PCI core and drivers to apply specific Live Update logic to them in subsequent commits.
Drivers can check if a device is an incoming preserved device (e.g. during probe) by calling pci_liveupdate_is_incoming().
CONFIG_64BIT is now required to enable CONFIG_PCI_LIVEUPDATE so that the domain and bdf can be guaranteed to fit in an unsigned long and be used as the xarray key.
--- MAINTAINERS | 1 + drivers/pci/Kconfig | 2 +- drivers/pci/liveupdate.c | 230 ++++++++++++++++++++++++++++++++- drivers/pci/liveupdate.h | 5 + drivers/pci/probe.c | 3 + include/linux/pci_liveupdate.h | 13 ++ 6 files changed, 251 insertions(+), 3 deletions(-)
MAINTAINERS +1 -0
@@ -20537,6 +20537,7 @@ L: [email protected] S: Maintained T: git git://git.kernel.org/pub/scm/linux/kernel/git/liveupdate/linux.git F: drivers/pci/liveupdate.c +F: drivers/pci/liveupdate.h F: include/linux/kho/abi/pci.h F: include/linux/pci_liveupdate.h
drivers/pci/Kconfig +1 -1
@@ -330,7 +330,7 @@ config VGA_ARB_MAX_GPUS config PCI_LIVEUPDATE bool "PCI Live Update Support" - depends on PCI && LIVEUPDATE + depends on PCI && LIVEUPDATE && 64BIT help Enable PCI core support for preserving PCI devices across Live Update. This, in combination with support in a device's driver,
drivers/pci/liveupdate.c +228 -2
266 lines not on this page · raw message
drivers/pci/liveupdate.h +5 -0
@@ -11,8 +11,13 @@#include <linux/pci.h> #ifdef CONFIG_PCI_LIVEUPDATE +void pci_liveupdate_setup_device (struct pci_dev *dev);void pci_liveupdate_cleanup_device (struct pci_dev *dev);#else +static inline void pci_liveupdate_setup_device (struct pci_dev *dev) +{ +} +static inline void pci_liveupdate_cleanup_device (struct pci_dev *dev) { }
drivers/pci/probe.c +3 -0
@@ -2070,6 +2070,8 @@ int pci_setup_device(struct pci_dev *dev)if (pci_early_dump)early_dump_pci_device (dev); +pci_liveupdate_setup_device (dev); +/* Need to have dev->class ready */ dev->cfg_size =pci_cfg_space_size (dev);
@@ -2193,6 +2195,7 @@ int pci_setup_device(struct pci_dev *dev)default :/* unknown header */ pci_err (dev,"unknown header type %02x, ignoring device\n" , dev->hdr_type); +pci_liveupdate_cleanup_device (dev);pci_release_of_node (dev);return -EIO ;
include/linux/pci_liveupdate.h +13 -0
@@ -16,9 +16,11 @@/** * struct pci_liveupdate - PCI Live Update state for a struct pci_dev * @outgoing: State preserved for the next kernel. +* @incoming: State preserved by the previous kernel. */ struct pci_liveupdate {struct pci_dev_ser *outgoing; +struct pci_dev_ser *incoming; };struct pci_dev ;
@@ -28,6 +30,8 @@ int pci_liveupdate_register_flb(struct liveupdate_file_handler *fh);void pci_liveupdate_unregister_flb (struct liveupdate_file_handler *fh);int pci_liveupdate_preserve (struct pci_dev *dev);void pci_liveupdate_unpreserve (struct pci_dev *dev); +void pci_liveupdate_finish (struct pci_dev *dev); +bool pci_liveupdate_is_incoming (struct pci_dev *dev);#else static inline int pci_liveupdate_register_flb (struct liveupdate_file_handler *fh) {
@@ -46,6 +50,15 @@ static inline int pci_liveupdate_preserve(struct pci_dev *dev)static inline void pci_liveupdate_unpreserve (struct pci_dev *dev) { } + +static inline void pci_liveupdate_finish (struct pci_dev *dev) +{ +} + +static inline bool pci_liveupdate_is_incoming (struct pci_dev *dev) +{ +return false; +}#endif #endif /* LINUX_PCI_LIVEUPDATE_H */
Signature · 1 line
2.54.0.746.g67dd491aae-goog
[email protected]
AI reviewRe: [PATCH v6 03/12] PCI: liveupdate: Track incoming preserved PCI devices
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider: - [Critical] pci_flb_retrieve() frees the incoming preserved memory (ser) on failure, causing a…
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [Critical] pci_flb_retrieve() frees the incoming preserved memory (ser) on failure, causing a Use-After-Free when the core retries.
- [Medium] Leaked reference to the incoming FLB when a device's preserved refcount is corrupted.
--
commit 5af02c95c00f317cc5c4fa203b8b79373f2759a5
Author: David Matlack <[email protected]>
PCI: liveupdate: Track incoming preserved PCI devices
During PCI enumeration, the PCI core fetches serialized state from the Live Update Orchestrator to identify incoming preserved devices. This patch adds tracking and lifecycle management APIs for these devices.
Quoted 4 lines
drivers/pci/liveupdate.c +0
-0
[ ... ]
Quoted 28 lines
drivers/pci/liveupdate.c +23
-1@@ -128,13 +157,49 @@ static void pci_flb_unpreserve(struct liveupdate_flb_op_args *args)static int pci_flb_retrieve (struct liveupdate_flb_op_args *args) { - args->obj =phys_to_virt (args->data); +struct pci_ser *ser =phys_to_virt (args->data); +struct pci_flb_incoming *incoming; +int ret = -ENOMEM ; +u32 i; + + incoming =kmalloc_obj (*incoming); +if (!incoming) + goto err_restore_free; + + incoming->ser = ser; +xa_init (&incoming->xa); + +for (i =0 ; i < incoming->ser->max_nr_devices; i++) { +struct pci_dev_ser *dev_ser = &incoming->ser->devices[i]; +unsigned long key; + +if (!dev_ser->refcount) +continue ; + + key =pci_ser_xa_key (dev_ser->domain, dev_ser->bdf); + ret =xa_insert (&incoming->xa, key, dev_ser,GFP_KERNEL ); +if (ret) + goto err_xa_destroy;
drivers/pci/liveupdate.c static void pci_flb_unpreserve(struct liveupdate_flb_op_args *args) · line 192
Quoted 10 lines
drivers/pci/liveupdate.c +9
-0+ } + + args->obj = incoming;return 0 ; + +err_xa_destroy: +xa_destroy (&incoming->xa); +kfree (incoming); +err_restore_free: +kho_restore_free (ser);
[Severity: Critical]
Does this error path create a use-after-free if the retrieval is retried?
If pci_flb_retrieve() fails here (e.g. from -ENOMEM), kho_restore_free() frees the preserved physical memory for the incoming state. However, the Live Update Orchestrator propagates this error without marking the FLB as retrieved or finished.
When the next PCI device is enumerated, pci_liveupdate_setup_device() calls pci_liveupdate_flb_get_incoming() again, which invokes pci_flb_retrieve() a second time with the exact same data address. The function will then attempt to read incoming->ser->max_nr_devices from memory that was already freed.
Quoted 2 lines
drivers/pci/liveupdate.c +1
-0+return ret; }
[ ... ]
Quoted 11 lines
drivers/pci/liveupdate.c +7
-0@@ -280,7 +430,83 @@ void pci_liveupdate_cleanup_device(struct pci_dev *dev)pci_WARN (dev,1 ,"Destroying outgoing-preserved device!\n" );pci_liveupdate_unpreserve (dev); } + +if (READ_ONCE (dev->liveupdate.incoming)) { +pci_WARN (dev,1 ,"Destroying incoming-preserved device!\n" ); +pci_liveupdate_finish (dev); + } +} +
drivers/pci/liveupdate.c void pci_liveupdate_cleanup_device(struct pci_dev *dev) · line 449
Quoted 10 lines
drivers/pci/liveupdate.c +10
-0+static void pci_liveupdate_finish_device (struct pci_ser *ser,struct pci_dev *dev) +{ +if (!dev->liveupdate.incoming) { +pci_warn (dev,"Cannot finish preserving an unpreserved device\n" ); +return ; + } + +if (dev->liveupdate.incoming->refcount !=1 ) { +pci_WARN (dev,1 ,"Preserved device has a corrupted refcount!\n" ); +return ;
[Severity: Medium]
Can this early return leak a reference to the incoming FLB?
In pci_liveupdate_setup_device(), a reference is held to protect dev->liveupdate.incoming. This reference is expected to be released via pci_liveupdate_flb_put_incoming() at the end of this function.
By returning early here when the refcount is corrupted, we skip the put call, leaking the reference. Furthermore, dev->liveupdate.incoming is left non-NULL, which means pci_liveupdate_cleanup_device() might later try to finish it again and hit this same leak. Should this error path drop the reference and clear the incoming pointer?
Quoted 14 lines
drivers/pci/liveupdate.c +14
-0+ } + +/* +* Drop the refcount so this device does not get treated as an incoming +* device again, e.g. in case pci_liveupdate_setup_device() gets called +* again because the device is hot-plugged. +*/ + dev->liveupdate.incoming->refcount =0 ; + +pci_info (dev,"Device is finished participating in Live Update\n" ); + dev->liveupdate.incoming =NULL ; + ser->nr_devices--; +pci_liveupdate_flb_put_incoming (); +}
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=3
Re: [PATCH v6 03/12] PCI: liveupdate: Track incoming preserved PCI devices
Quoted 67 lines · On Fri, May 22, 2026 at 2:13 PM <[email protected]> wrote:
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [Critical]pci_flb_retrieve()frees the incoming preserved memory (ser) on failure, causing a Use-After-Free when the core retries.
- [Medium] Leaked reference to the incoming FLB when a device's preserved refcount is corrupted.
--commit
5af02c95c00f317cc5c4fa203b8b79373f2759a5
Author: David Matlack <[email protected]>PCI: liveupdate: Track incoming preserved PCI devices
During PCI enumeration, the PCI core fetches serialized state from the Live Update Orchestrator to identify incoming preserved devices. This patch adds tracking and lifecycle management APIs for these devices.
Quoted 4 lines
drivers/pci/liveupdate.c +0
-0[ ... ]
Quoted 28 lines
drivers/pci/liveupdate.c +23
-1@@ -128,13 +157,49 @@ static void pci_flb_unpreserve(struct liveupdate_flb_op_args *args)static int pci_flb_retrieve (struct liveupdate_flb_op_args *args) { - args->obj =phys_to_virt (args->data); +struct pci_ser *ser =phys_to_virt (args->data); +struct pci_flb_incoming *incoming; +int ret = -ENOMEM ; +u32 i; + + incoming =kmalloc_obj (*incoming); +if (!incoming) + goto err_restore_free; + + incoming->ser = ser; +xa_init (&incoming->xa); + +for (i =0 ; i < incoming->ser->max_nr_devices; i++) { +struct pci_dev_ser *dev_ser = &incoming->ser->devices[i]; +unsigned long key; + +if (!dev_ser->refcount) +continue ; + + key =pci_ser_xa_key (dev_ser->domain, dev_ser->bdf); + ret =xa_insert (&incoming->xa, key, dev_ser,GFP_KERNEL ); +if (ret) + goto err_xa_destroy;drivers/pci/liveupdate.c static void pci_flb_unpreserve(struct liveupdate_flb_op_args *args) · line 192
Quoted 10 lines
drivers/pci/liveupdate.c +9
-0+ } + + args->obj = incoming;return 0 ; + +err_xa_destroy: +xa_destroy (&incoming->xa); +kfree (incoming); +err_restore_free: +kho_restore_free (ser);[Severity: Critical]
Does this error path create a use-after-free if the retrieval is retried?If
pci_flb_retrieve()fails here (e.g. from-ENOMEM),kho_restore_free()frees the preserved physical memory for the incoming state. However, the Live Update Orchestrator propagates this error without marking the FLB as retrieved or finished.
Quoted 5 lines
When the next PCI device is enumerated,
pci_liveupdate_setup_device()callspci_liveupdate_flb_get_incoming()again, which invokespci_flb_retrieve()a second time with the exact same data address. The function will then attempt to readincoming->ser->max_nr_devicesfrom memory that was already freed.
Yes but that is a bug in LUO. It should not be attempting FLB retrieve() multiple times.
(Pasha and Pratyush FYI)
Quoted 33 lines
Quoted 3 lines
drivers/pci/liveupdate.c +1
-0+return ret; }[ ... ]
Quoted 11 lines
drivers/pci/liveupdate.c +7
-0@@ -280,7 +430,83 @@ void pci_liveupdate_cleanup_device(struct pci_dev *dev)pci_WARN (dev,1 ,"Destroying outgoing-preserved device!\n" );pci_liveupdate_unpreserve (dev); } + +if (READ_ONCE (dev->liveupdate.incoming)) { +pci_WARN (dev,1 ,"Destroying incoming-preserved device!\n" ); +pci_liveupdate_finish (dev); + } +} +drivers/pci/liveupdate.c void pci_liveupdate_cleanup_device(struct pci_dev *dev) · line 449
Quoted 10 lines
drivers/pci/liveupdate.c +10
-0+static void pci_liveupdate_finish_device (struct pci_ser *ser,struct pci_dev *dev) +{ +if (!dev->liveupdate.incoming) { +pci_warn (dev,"Cannot finish preserving an unpreserved device\n" ); +return ; + } + +if (dev->liveupdate.incoming->refcount !=1 ) { +pci_WARN (dev,1 ,"Preserved device has a corrupted refcount!\n" ); +return ;[Severity: Medium]
Can this early return leak a reference to the incoming FLB?In
pci_liveupdate_setup_device(), a reference is held to protectdev->liveupdate.incoming. This reference is expected to be released viapci_liveupdate_flb_put_incoming()at the end of this function.
Quoted 5 lines
By returning early here when the refcount is corrupted, we skip the put call, leaking the reference. Furthermore,
dev->liveupdate.incomingis left non-NULL, which meanspci_liveupdate_cleanup_device()might later try to finish it again and hit this same leak. Should this error path drop the reference and clear the incoming pointer?
Yes but dropping a reference to the incoming FLB when the refcount is corrupted could lead to use-after-free. Logging a warning and leaking FLB seems like the safer approach, aside from panicking.
Re: [PATCH v6 03/12] PCI: liveupdate: Track incoming preserved PCI devices
In reply to David MatlackQuoted 53 lines · David Matlack
During PCI enumeration, the previous kernel might have passed state about devices that were preserved across kexec. The PCI core needs to fetch this state to identify which devices are "incoming" and require special handling.
Add
pci_liveupdate_setup_device()which is called during device setup to fetch the serialized state (structpci_ser) from the Live Update Orchestrator. The first time this happens,pci_flb_retrieve()will run and convert the array ofpci_dev_serstructs into an xarray so that it can be looked up efficiently.If a device is found in the xarray, the PCI core stores a pointer to its state in
dev->liveupdate_incomingand holds a reference to the incoming FLB untilpci_liveupdate_finish()is called by the driver.This ensures proper lifecycle management for incoming preserved devices and allows the PCI core and drivers to apply specific Live Update logic to them in subsequent commits.
Drivers can check if a device is an incoming preserved device (e.g. during probe) by calling
pci_liveupdate_is_incoming().
CONFIG_64BITis now required to enableCONFIG_PCI_LIVEUPDATEso that the domain and bdf can be guaranteed to fit in an unsigned long and be used as the xarray key.Signed-off-by David Matlack <[email protected]>--- MAINTAINERS | 1 + drivers/pci/Kconfig | 2 +- drivers/pci/liveupdate.c | 230 ++++++++++++++++++++++++++++++++- drivers/pci/liveupdate.h | 5 + drivers/pci/probe.c | 3 + include/linux/pci_liveupdate.h | 13 ++ 6 files changed, 251 insertions(+), 3 deletions(-)MAINTAINERS +1
-0@@ -20537,6 +20537,7 @@ L: [email protected] S: Maintained T: git git://git.kernel.org/pub/scm/linux/kernel/git/liveupdate/linux.git F: drivers/pci/liveupdate.c +F: drivers/pci/liveupdate.h F: include/linux/kho/abi/pci.h F: include/linux/pci_liveupdate.hdrivers/pci/Kconfig +0
-0
drivers/pci/Kconfig config VGA_ARB_MAX_GPUS · line 333
Quoted 5 lines
drivers/pci/Kconfig +1
-1@@ -330,7 +330,7 @@ config VGA_ARB_MAX_GPUS config PCI_LIVEUPDATE bool "PCI Live Update Support" - depends on PCI && LIVEUPDATE + depends on PCI && LIVEUPDATE && 64BIT
I see that the static assertions in Patch 1 work because of the 64BIT enforcement here. In that case, should we have the assertions check u64?
Quoted 4 lines
drivers/pci/Kconfig +0
-0help Enable PCI core support for preserving PCI devices across Live Update. This, in combination with support in a device's driver,
[...]
Quoted 26 lines
static int
pci_flb_retrieve(struct liveupdate_flb_op_args *args){drivers/pci/Kconfig +23
-1- args->obj = phys_to_virt(args->data); + struct pci_ser *ser = phys_to_virt(args->data); + struct pci_flb_incoming *incoming; + int ret = -ENOMEM; + u32 i; + + incoming = kmalloc_obj(*incoming); + if (!incoming) + goto err_restore_free; + + incoming->ser = ser; + xa_init(&incoming->xa); + + for (i = 0; i < incoming->ser->max_nr_devices; i++) { + struct pci_dev_ser *dev_ser = &incoming->ser->devices[i]; + unsigned long key; + + if (!dev_ser->refcount) + continue; + + key = pci_ser_xa_key(dev_ser->domain, dev_ser->bdf); + ret = xa_insert(&incoming->xa, key, dev_ser, GFP_KERNEL); + if (ret) + goto err_xa_destroy;
drivers/pci/Kconfig
Quoted 10 lines
drivers/pci/Kconfig +9
-0+ } + + args->obj = incoming; return 0; + +err_xa_destroy: + xa_destroy(&incoming->xa); + kfree(incoming); +err_restore_free: + kho_restore_free(ser);
I tend to partly agree with Sashiko[1] here.. it raises a policy-hole. We may need a policy here, the options I have in mind are:
1. Retrieve shall ONLY be tried once, if it fails (like -ENOMEM in the xArray alloc), it's a liveupdate failure. We can't retry liveupdate.
2. Retrying retrieve is allowed.
The only downside with option 1 is, the user may want flexibility due to certain subsystems OR may choose NOT to use the proposed LUOd and instead have its own user-space component which might try funny things or have a different use-case.
In such a situation, the system may have transiently run out of memory during the kexec transition (for e.g. a subsystem uses GFP_ATOMIC to allocate memory and temporarily runs out of the atomic pool). [Note we removed it in IOMMU v1 [2] but subsystems may have a use-case for it]
If the kernel frees the KHO page on the first failure, it removes any chance of recovery. :/
Thus, it might make sense to let the user decide if it wants to fail the liveupdate or retry again based on the failure type / source?
[...]
The changes LGTM, except for policy-based, kho_restore_free discussion.
Thanks,
Praan
[1] https://lore.kernel.org/all/[email protected]/
[2] https://lore.kernel.org/all/[email protected]/
Re: [PATCH v6 03/12] PCI: liveupdate: Track incoming preserved PCI devices
Quoted 55 lines · Pranjal Shrivastava
Quoted 54 lines · David Matlack
During PCI enumeration, the previous kernel might have passed state about devices that were preserved across kexec. The PCI core needs to fetch this state to identify which devices are "incoming" and require special handling.
Add
pci_liveupdate_setup_device()which is called during device setup to fetch the serialized state (structpci_ser) from the Live Update Orchestrator. The first time this happens,pci_flb_retrieve()will run and convert the array ofpci_dev_serstructs into an xarray so that it can be looked up efficiently.If a device is found in the xarray, the PCI core stores a pointer to its state in
dev->liveupdate_incomingand holds a reference to the incoming FLB untilpci_liveupdate_finish()is called by the driver.This ensures proper lifecycle management for incoming preserved devices and allows the PCI core and drivers to apply specific Live Update logic to them in subsequent commits.
Drivers can check if a device is an incoming preserved device (e.g. during probe) by calling
pci_liveupdate_is_incoming().
CONFIG_64BITis now required to enableCONFIG_PCI_LIVEUPDATEso that the domain and bdf can be guaranteed to fit in an unsigned long and be used as the xarray key.Signed-off-by David Matlack <[email protected]>--- MAINTAINERS | 1 + drivers/pci/Kconfig | 2 +- drivers/pci/liveupdate.c | 230 ++++++++++++++++++++++++++++++++- drivers/pci/liveupdate.h | 5 + drivers/pci/probe.c | 3 + include/linux/pci_liveupdate.h | 13 ++ 6 files changed, 251 insertions(+), 3 deletions(-)MAINTAINERS +1
-0@@ -20537,6 +20537,7 @@ L: [email protected] S: Maintained T: git git://git.kernel.org/pub/scm/linux/kernel/git/liveupdate/linux.git F: drivers/pci/liveupdate.c +F: drivers/pci/liveupdate.h F: include/linux/kho/abi/pci.h F: include/linux/pci_liveupdate.hdrivers/pci/Kconfig +0
-0@@ -330,7 +330,7 @@ config VGA_ARB_MAX_GPUS
Quoted 7 lines
drivers/pci/Kconfig config VGA_ARB_MAX_GPUS · line 333
Quoted 4 lines
drivers/pci/Kconfig +1
-1config PCI_LIVEUPDATE bool "PCI Live Update Support" - depends on PCI && LIVEUPDATE + depends on PCI && LIVEUPDATE && 64BITI see that the static assertions in Patch 1 work because of the 64BIT enforcement here. In that case, should we have the assertions check u64?
The static asserts have nothing to do with the 64BIT enforcement here. The static asserts just verify that the array elements in struct pci_ser are naturally aligned (unsigned long) so they can be accessed efficiently. The requirement here for CONFIG_64BIT is for the xarray key.
Theoretically if we got the xarray to work with 32-bit architectures then we could drop the CONFIG_64BIT requirement here.
Quoted 63 lines
Quoted 5 lines
drivers/pci/Kconfig +0
-0help Enable PCI core support for preserving PCI devices across Live Update. This, in combination with support in a device's driver,[...]
Quoted 26 lines
static int
pci_flb_retrieve(struct liveupdate_flb_op_args *args){drivers/pci/Kconfig +23
-1- args->obj = phys_to_virt(args->data); + struct pci_ser *ser = phys_to_virt(args->data); + struct pci_flb_incoming *incoming; + int ret = -ENOMEM; + u32 i; + + incoming = kmalloc_obj(*incoming); + if (!incoming) + goto err_restore_free; + + incoming->ser = ser; + xa_init(&incoming->xa); + + for (i = 0; i < incoming->ser->max_nr_devices; i++) { + struct pci_dev_ser *dev_ser = &incoming->ser->devices[i]; + unsigned long key; + + if (!dev_ser->refcount) + continue; + + key = pci_ser_xa_key(dev_ser->domain, dev_ser->bdf); + ret = xa_insert(&incoming->xa, key, dev_ser, GFP_KERNEL); + if (ret) + goto err_xa_destroy;drivers/pci/Kconfig
Quoted 10 lines
drivers/pci/Kconfig +9
-0+ } + + args->obj = incoming; return 0; + +err_xa_destroy: + xa_destroy(&incoming->xa); + kfree(incoming); +err_restore_free: + kho_restore_free(ser);I tend to partly agree with Sashiko[1] here.. it raises a policy-hole. We may need a policy here, the options I have in mind are:
1. Retrieve shall ONLY be tried once, if it fails (like
-ENOMEMin the xArray alloc), it's a liveupdate failure. We can't retry liveupdate.2. Retrying retrieve is allowed.
The only downside with option 1 is, the user may want flexibility due to certain subsystems OR may choose NOT to use the proposed LUOd and instead have its own user-space component which might try funny things or have a different use-case.
In such a situation, the system may have transiently run out of memory during the kexec transition (for e.g. a subsystem uses
GFP_ATOMICto allocate memory and temporarily runs out of the atomic pool). [Note we removed it in IOMMU v1 [2] but subsystems may have a use-case for it]
Quoted 5 lines
If the kernel frees the KHO page on the first failure, it removes any chance of recovery. :/
Thus, it might make sense to let the user decide if it wants to fail the liveupdate or retry again based on the failure type / source?
The plan is to have LUO enforce that retrieve() is only called once:
https://lore.kernel.org/kexec/[email protected]/
Supporting retry gets complicated since there's many different places where retrieve() could have failed.
Quoted 12 lines
[...]
The changes LGTM, except for policy-based,
kho_restore_freediscussion.Reviewed-by Pranjal Shrivastava <[email protected]>Thanks,
Praan[1] https://lore.kernel.org/all/[email protected]/
[2] https://lore.kernel.org/all/[email protected]/
Re: [PATCH v6 03/12] PCI: liveupdate: Track incoming preserved PCI devices
Quoted 64 lines · David Matlack
Quoted 55 lines · Pranjal Shrivastava
Quoted 54 lines · David Matlack
During PCI enumeration, the previous kernel might have passed state about devices that were preserved across kexec. The PCI core needs to fetch this state to identify which devices are "incoming" and require special handling.
Add
pci_liveupdate_setup_device()which is called during device setup to fetch the serialized state (structpci_ser) from the Live Update Orchestrator. The first time this happens,pci_flb_retrieve()will run and convert the array ofpci_dev_serstructs into an xarray so that it can be looked up efficiently.If a device is found in the xarray, the PCI core stores a pointer to its state in
dev->liveupdate_incomingand holds a reference to the incoming FLB untilpci_liveupdate_finish()is called by the driver.This ensures proper lifecycle management for incoming preserved devices and allows the PCI core and drivers to apply specific Live Update logic to them in subsequent commits.
Drivers can check if a device is an incoming preserved device (e.g. during probe) by calling
pci_liveupdate_is_incoming().
CONFIG_64BITis now required to enableCONFIG_PCI_LIVEUPDATEso that the domain and bdf can be guaranteed to fit in an unsigned long and be used as the xarray key.Signed-off-by David Matlack <[email protected]>--- MAINTAINERS | 1 + drivers/pci/Kconfig | 2 +- drivers/pci/liveupdate.c | 230 ++++++++++++++++++++++++++++++++- drivers/pci/liveupdate.h | 5 + drivers/pci/probe.c | 3 + include/linux/pci_liveupdate.h | 13 ++ 6 files changed, 251 insertions(+), 3 deletions(-)MAINTAINERS +1
-0@@ -20537,6 +20537,7 @@ L: [email protected] S: Maintained T: git git://git.kernel.org/pub/scm/linux/kernel/git/liveupdate/linux.git F: drivers/pci/liveupdate.c +F: drivers/pci/liveupdate.h F: include/linux/kho/abi/pci.h F: include/linux/pci_liveupdate.hdrivers/pci/Kconfig +0
-0@@ -330,7 +330,7 @@ config VGA_ARB_MAX_GPUSQuoted 7 lines
drivers/pci/Kconfig config VGA_ARB_MAX_GPUS · line 333
Quoted 4 lines
drivers/pci/Kconfig +1
-1config PCI_LIVEUPDATE bool "PCI Live Update Support" - depends on PCI && LIVEUPDATE + depends on PCI && LIVEUPDATE && 64BITI see that the static assertions in Patch 1 work because of the 64BIT enforcement here. In that case, should we have the assertions check u64?
Quoted 9 lines
The static asserts have nothing to do with the 64BIT enforcement here. The static asserts just verify that the array elements in struct
pci_serare naturally aligned (unsigned long) so they can be accessed efficiently. The requirement here forCONFIG_64BITis for the xarray key.Theoretically if we got the xarray to work with 32-bit architectures then we could drop the
CONFIG_64BITrequirement here.
Ack. I see.
[...]
Quoted 26 lines
Quoted 20 lines
drivers/pci/Kconfig config VGA_ARB_MAX_GPUS · line 334
Quoted 1 line
drivers/pci/Kconfig +1
-0+ kho_restore_free(ser);I tend to partly agree with Sashiko[1] here.. it raises a policy-hole. We may need a policy here, the options I have in mind are:
1. Retrieve shall ONLY be tried once, if it fails (like
-ENOMEMin the xArray alloc), it's a liveupdate failure. We can't retry liveupdate.2. Retrying retrieve is allowed.
The only downside with option 1 is, the user may want flexibility due to certain subsystems OR may choose NOT to use the proposed LUOd and instead have its own user-space component which might try funny things or have a different use-case.
In such a situation, the system may have transiently run out of memory during the kexec transition (for e.g. a subsystem uses
GFP_ATOMICto allocate memory and temporarily runs out of the atomic pool). [Note we removed it in IOMMU v1 [2] but subsystems may have a use-case for it]Quoted 5 lines
If the kernel frees the KHO page on the first failure, it removes any chance of recovery. :/
Thus, it might make sense to let the user decide if it wants to fail the liveupdate or retry again based on the failure type / source?
Quoted 6 lines
The plan is to have LUO enforce that
retrieve()is only called once:https://lore.kernel.org/kexec/[email protected]/
Supporting retry gets complicated since there's many different places where
retrieve()could have failed.
Ack. Thanks for pointing me to the thread.
In that case, no problem.
Thanks,
Praan
Pasha Tatashin
maintainerRe: [PATCH v6 03/12] PCI: liveupdate: Track incoming preserved PCI devices
In reply to David Matlackdrivers/pci/Kconfig config VGA_ARB_MAX_GPUS · line 333
Quoted 10 lines · David Matlack
drivers/pci/Kconfig +1
-1@@ -330,7 +330,7 @@ config VGA_ARB_MAX_GPUS config PCI_LIVEUPDATE bool "PCI Live Update Support" - depends on PCI && LIVEUPDATE + depends on PCI && LIVEUPDATE && 64BIT
Please move this to the first patch, fewer changes between patches, and also KHO does not support anything but 64-bit mode.
drivers/pci/liveupdate.c static void pci_flb_unpreserve(struct liveupdate_flb_op_args *args) · line 192
Quoted 13 lines
drivers/pci/liveupdate.c +0
-0@@ -128,13 +157,49 @@ static void pci_flb_unpreserve(struct liveupdate_flb_op_args *args)[ ... skip 31 lines ... ]
drivers/pci/liveupdate.c +6
-0+ +err_xa_destroy: +xa_destroy (&incoming->xa); +kfree (incoming); +err_restore_free: +kho_restore_free (ser);
This is the pattern we have been enforcing in other places in LUO. If the first retrieval fails, return the same error thereafter.
drivers/pci/liveupdate.c void pci_liveupdate_unpreserve(struct pci_dev *dev) · line 341
Quoted 8 lines
drivers/pci/liveupdate.c +4
-0@@ -270,6 +335,91 @@ void pci_liveupdate_unpreserve(struct pci_dev *dev) }EXPORT_SYMBOL_GPL (pci_liveupdate_unpreserve); +static struct pci_flb_incoming *pci_liveupdate_flb_get_incoming (void ) +{ +struct pci_flb_incoming *incoming =NULL ; +int ret;
Maybe make the error return static, and avoid another search through compatible FLBs if it failed before?
1. Add "saved_err;"; if it is set, return it right away.
2. Change all errors to use goto save_err;, and at the end of the function, assign ret to saved_err;
drivers/pci/liveupdate.c void pci_liveupdate_unpreserve(struct pci_dev *dev) · line 362
Quoted 7 lines
[ ... skip 15 lines ... ]
drivers/pci/liveupdate.c +6
-0+* 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). +*/ +if (ret == -ENOENT ) { +pr_info_once ("No incoming FLB matched %s\n" , pci_liveupdate_flb.compatible);
I would assume this is very normal, e.g., no devices were preserved but memfd+hugetlb was preserved. Maybe use pr_debug_once().
drivers/pci/liveupdate.c void pci_liveupdate_unpreserve(struct pci_dev *dev) · line 371
Quoted 9 lines
drivers/pci/liveupdate.c +9
-0+return NULL ; + } + +/* +* There is incoming FLB data that matches pci_liveupdate_flb.compatible +* but it cannot be retrieved. +*/ +if (ret) { +WARN_ONCE (ret,"Failed to retrieve incoming FLB data\n" );
No need to print backtrace, please just print a warning:pr_warn_once("Failed to retrieve incoming FLB data: %pe\n", ERR_PTR(ret));
drivers/pci/liveupdate.c void pci_liveupdate_unpreserve(struct pci_dev *dev) · line 411
Quoted 7 lines
[ ... skip 34 lines ... ]
drivers/pci/liveupdate.c +6
-0+* through pci_liveupdate_finish(). This can happen if PCI core probes +* the same device multiple times, e.g. due to hotplug. +*/ +if (!dev_ser->refcount) { +pci_liveupdate_flb_put_incoming (); +return ;
Pleaes use 'goto put_incoming'
drivers/pci/liveupdate.c void pci_liveupdate_unpreserve(struct pci_dev *dev) · line 420
Quoted 9 lines
drivers/pci/liveupdate.c +9
-0+ } + +pci_info (dev,"Device was preserved by previous kernel across Live Update\n" ); + dev->liveupdate.incoming = dev_ser; + +/* +* Hold the ref on the incoming FLB until pci_liveupdate_finish() so +* that dev->liveupdate.incoming does not get freed while it is in use. +*/
How would that work? If finish is not called FLB stays around until the next reboot.
Signature · 1 line
Pasha Tatashin <[email protected]>
Re: [PATCH v6 03/12] PCI: liveupdate: Track incoming preserved PCI devices
Quoted 7 lines · Pasha Tatashin
Quoted 6 lines · David Matlack
drivers/pci/Kconfig +0
-0@@ -330,7 +330,7 @@ config VGA_ARB_MAX_GPUS
Quoted 7 lines
drivers/pci/Kconfig config VGA_ARB_MAX_GPUS · line 333
Quoted 4 lines
drivers/pci/Kconfig +1
-1config PCI_LIVEUPDATE bool "PCI Live Update Support" - depends on PCI && LIVEUPDATE + depends on PCI && LIVEUPDATE && 64BITPlease move this to the first patch, fewer changes between patches, and also KHO does not support anything but 64-bit mode.
I think it is preferred to introduce changes when they are needed. This is the exact patch that requires 64BIT so it makes sense to add the dependency within this patch no?
Quoted 22 lines
Quoted 8 lines
drivers/pci/liveupdate.c +0
-0@@ -128,13 +157,49 @@ static void pci_flb_unpreserve(struct liveupdate_flb_op_args *args)[ ... skip 31 lines ... ]
drivers/pci/liveupdate.c static void pci_flb_unpreserve(struct liveupdate_flb_op_args *args) · line 192
Quoted 6 lines
drivers/pci/liveupdate.c +6
-0+ +err_xa_destroy: +xa_destroy (&incoming->xa); +kfree (incoming); +err_restore_free: +kho_restore_free (ser);This is the pattern we have been enforcing in other places in LUO. If the first retrieval fails, return the same error thereafter.
Quoted 4 lines
drivers/pci/liveupdate.c +0
-0@@ -270,6 +335,91 @@ void pci_liveupdate_unpreserve(struct pci_dev *dev) }EXPORT_SYMBOL_GPL (pci_liveupdate_unpreserve);
Quoted 7 lines
drivers/pci/liveupdate.c void pci_liveupdate_unpreserve(struct pci_dev *dev) · line 341
Quoted 4 lines
drivers/pci/liveupdate.c +4
-0+static struct pci_flb_incoming *pci_liveupdate_flb_get_incoming (void ) +{ +struct pci_flb_incoming *incoming =NULL ; +int ret;Maybe make the error return static, and avoid another search through compatible FLBs if it failed before?
Good idea, will do.
Quoted 5 lines
1. Add "
saved_err;"; if it is set, return it right away.
2. Change all errors to use gotosave_err;, and at the end of the function, assign ret tosaved_err;
Quoted 10 lines
drivers/pci/liveupdate.c void pci_liveupdate_unpreserve(struct pci_dev *dev) · line 362
Quoted 7 lines
[ ... skip 15 lines ... ]
drivers/pci/liveupdate.c +6
-0+* 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). +*/ +if (ret == -ENOENT ) { +pr_info_once ("No incoming FLB matched %s\n" , pci_liveupdate_flb.compatible);I would assume this is very normal, e.g., no devices were preserved but memfd+hugetlb was preserved. Maybe use
pr_debug_once().
The problem is described in the comment above. The PCI core cannot distinguish between:
1. There was not PCI FLB preserved. and
2. There was PCI FLB preserved, but it was not compatible.
I agree we should not log anything for (1) but (2) definitely requires at least some kind of logging so that's why I went with info-level here and not debug.
Quoted 13 lines
drivers/pci/liveupdate.c void pci_liveupdate_unpreserve(struct pci_dev *dev) · line 371
Quoted 10 lines
drivers/pci/liveupdate.c +9
-0+return NULL ; + } + +/* +* There is incoming FLB data that matches pci_liveupdate_flb.compatible +* but it cannot be retrieved. +*/ +if (ret) { +WARN_ONCE (ret,"Failed to retrieve incoming FLB data\n" );No need to print backtrace, please just print a warning:
pr_warn_once("Failed to retrieve incoming FLB data: %pe\n", ERR_PTR(ret));
SGTM
Quoted 10 lines
drivers/pci/liveupdate.c void pci_liveupdate_unpreserve(struct pci_dev *dev) · line 411
Quoted 8 lines
[ ... skip 34 lines ... ]
drivers/pci/liveupdate.c +6
-0+* through pci_liveupdate_finish(). This can happen if PCI core probes +* the same device multiple times, e.g. due to hotplug. +*/ +if (!dev_ser->refcount) { +pci_liveupdate_flb_put_incoming (); +return ;Pleaes use 'goto
put_incoming'
SGTM.
Quoted 13 lines
drivers/pci/liveupdate.c void pci_liveupdate_unpreserve(struct pci_dev *dev) · line 420
Quoted 10 lines
drivers/pci/liveupdate.c +9
-0+ } + +pci_info (dev,"Device was preserved by previous kernel across Live Update\n" ); + dev->liveupdate.incoming = dev_ser; + +/* +* Hold the ref on the incoming FLB until pci_liveupdate_finish() so +* that dev->liveupdate.incoming does not get freed while it is in use. +*/ How would that work? If finish is not called FLB stays around until the next reboot.
True... I think if the PCI core trusts drivers to call pci_liveupdate_finish() then we don't need to hold onto the incoming reference here.
Quoted 3 lines
Signature · 2 lines
-- Pasha Tatashin <[email protected]>
Re: [PATCH v6 03/12] PCI: liveupdate: Track incoming preserved PCI devices
Quoted 11 lines · David Matlack
Quoted 9 lines · Pasha Tatashin
drivers/pci/liveupdate.c void pci_liveupdate_unpreserve(struct pci_dev *dev) · line 341
Quoted 4 lines · David Matlack
drivers/pci/liveupdate.c +4
-0+static struct pci_flb_incoming *pci_liveupdate_flb_get_incoming (void ) +{ +struct pci_flb_incoming *incoming =NULL ; +int ret;Maybe make the error return static, and avoid another search through compatible FLBs if it failed before?
Quoted 1 line
Good idea, will do.
Actually I'm not so sure this should be handled her. I would have to create a statically allocated variable to cache the result, like you said, and I would also have to invalidate it during FLB finish to avoid use-after-free. That defeats one of the main benefits of FLB which is that we don't have to manage global variables.
Can this be handled by LUO instead?
Pratyush Yadav
maintainerRe: [PATCH v6 03/12] PCI: liveupdate: Track incoming preserved PCI devices
In reply to David MatlackHi David,
Quoted 2 lines · David Matlack
Quoted 1 line · Pasha Tatashin
On Fri, 22 May 2026 20:24:01 +0000, David Matlack <[email protected]> wrote:
[...]
Quoted 13 lines
Quoted 4 lines
Quoted 4 lines
drivers/pci/liveupdate.c +4
-0+ } + +pci_info (dev,"Device was preserved by previous kernel across Live Update\n" ); + dev->liveupdate.incoming = dev_ser;Quoted 8 lines
drivers/pci/liveupdate.c void pci_liveupdate_unpreserve(struct pci_dev *dev) · line 420
Quoted 5 lines
drivers/pci/liveupdate.c +5
-0+ +/* +* Hold the ref on the incoming FLB until pci_liveupdate_finish() so +* that dev->liveupdate.incoming does not get freed while it is in use. +*/ How would that work? If finish is not called FLB stays around until the next reboot.
Quoted 3 lines
True... I think if the PCI core trusts drivers to call
pci_liveupdate_finish()then we don't need to hold onto the incoming reference here.
That was my point when I was arguing against refcounts on outgoing FLBs. This is very easy to abuse, especially when we are talking about device drivers. And this refcounting mechanism makes the FLB no longer file-lifecycle-bound, since now it is entirely up to drivers to decide the lifecycle of this data.
I have been thinking about this a bit more in the last couple days, and I wonder if we are doing this right. Here's an idea I have been thinking of.
We should make live update a first class citizen in PCI. Instead of patching in liveupdate via the liveupdate.incoming field, and letting drivers figure out when to use it, we should separate out probe and retrieve paths entirely.
Probe and retrieve are fundamentally different operations. While they may share some common initialization logic for the _software_ state, how they interface with the hardware is completely different. I think mixing the two will result in driver code being more spaghetti by having liveupdate checks sprayed out all over.
This series doesn't add support for any drivers, but looking at some of the code we have downstream, I see this problem. The liveupdate code is all over the place in the driver and it is very hard to wrap one's head around how the device is actually retrieved.
So I think PCI core should track preserved devices, and if the device is preserved, it should skip the probe and wait for retrieve. Retrieve does the full initialization of the device. This fits in with the LUO model as well. You can make retrieve a callback of struct pci_driver and do some wrappers to talk with LUO, so device drivers don't directly interface with LUO at all.
We should do similar things on the shutdown path. Shutdown is a fundamentally different operation from freeze, and so we should separate them out as well.
This solves the lifetime problem as well. When PCI core is initializing, it knows for sure that no retrievals are going to happen. That's because none of the drivers have registered yet. So it can safely access the FLB and initialize its state. After that, drivers can register themselves and start accepting retrieve() calls. Once the last driver goes away, the FLB is freed automatically.
I am sorry for suggesting a big refactor at v6, but the early versions looked good to me at the time, and I only thought more deeply about this when trying to figure out how we can make the lifetimes cleaner.
What do you think? Does this make sense?
Signature · 2 lines
Regards, Pratyush Yadav
Re: [PATCH v6 03/12] PCI: liveupdate: Track incoming preserved PCI devices
Quoted 25 lines · Pratyush Yadav
Hi David,
Quoted 2 lines · David Matlack
Quoted 1 line · Pasha Tatashin
On Fri, 22 May 2026 20:24:01 +0000, David Matlack <[email protected]> wrote:
[...]
Quoted 13 lines
Quoted 4 lines
Quoted 4 lines
drivers/pci/liveupdate.c +4
-0+ } + +pci_info (dev,"Device was preserved by previous kernel across Live Update\n" ); + dev->liveupdate.incoming = dev_ser;Quoted 8 lines
drivers/pci/liveupdate.c void pci_liveupdate_unpreserve(struct pci_dev *dev) · line 420
Quoted 5 lines
drivers/pci/liveupdate.c +5
-0+ +/* +* Hold the ref on the incoming FLB until pci_liveupdate_finish() so +* that dev->liveupdate.incoming does not get freed while it is in use. +*/ How would that work? If finish is not called FLB stays around until the next reboot.
Quoted 3 lines
True... I think if the PCI core trusts drivers to call
pci_liveupdate_finish()then we don't need to hold onto the incoming reference here.
Quoted 5 lines
That was my point when I was arguing against refcounts on outgoing FLBs. This is very easy to abuse, especially when we are talking about device drivers. And this refcounting mechanism makes the FLB no longer file-lifecycle-bound, since now it is entirely up to drivers to decide the lifecycle of this data.
The PCI core holds a reference to the incoming FLB for as long as it maintains a pointer to that FLB in struct pci_dev (dev->liveupdate.incoming). The lifetime of that pointer is aligned with the lifetime of the file as long as the driver calls pci_liveupdate_finish() in its file finish() callback.
If there is a bug in the driver that causes it to not call pci_liveupdate_finish() then the FLB will leak past the file yes. But the alternative would be to leak a pointer to freed memory in dev->liveupdate.incoming, which could lead to UAF.
Leaking the FLB seems safer than UAF, which is why I went for the refcounting approach.
Another approach entirely would be to drop the dev->liveupdate.incoming and do the xarray lookup everytime instead.
Quoted 10 lines
I have been thinking about this a bit more in the last couple days, and I wonder if we are doing this right. Here's an idea I have been thinking of.
We should make live update a first class citizen in PCI. Instead of patching in liveupdate via the liveupdate.incoming field, and letting drivers figure out when to use it, we should separate out probe and retrieve paths entirely.
Quoted 5 lines
Probe and retrieve are fundamentally different operations. While they may share some common initialization logic for the _software_ state, how they interface with the hardware is completely different. I think mixing the two will result in driver code being more spaghetti by having liveupdate checks sprayed out all over.
We are only planning on supporting Live Update for VFIO drivers for the forseeable future. The VFIO work during probe is almost entirely software state setup. The only hardware logic we need to "if" out in the vfio-pci driver's probe() is putting the device into a low-power mode via the runtime power manager. So I don't think we will get any benefit from this approach, and it would be a lot more intrusive to both the PCI core driver framework, and VFIO itself, to support this.
Quoted 4 lines
This series doesn't add support for any drivers, but looking at some of the code we have downstream, I see this problem. The liveupdate code is all over the place in the driver and it is very hard to wrap one's head around how the device is actually retrieved.
You can find the vfio-pci driver changes here:
https://lore.kernel.org/kvm/[email protected]/
Let's keep the discussion focused on upstream VFIO drivers since that is all we are planning to support right now due to LUO's requirement of file-based preservation. The downstream driver changes we are carrying is not reflective of what we want to support upstream.
Quoted 10 lines
So I think PCI core should track preserved devices, and if the device is preserved, it should skip the probe and wait for retrieve. Retrieve does the full initialization of the device. This fits in with the LUO model as well. You can make retrieve a callback of struct
pci_driverand do some wrappers to talk with LUO, so device drivers don't directly interface with LUO at all.We should do similar things on the shutdown path. Shutdown is a fundamentally different operation from freeze, and so we should separate them out as well.
This is speculative. In practice, we haven't needed to change VFIO's shutdown() or probe() functions so far. The only change I anticipate needing is skipping runtime power management "put" during probe() I mentioned above.
If we actually made retrieve() a first-class callback and used that instead of probe(), VFIO would internally just call its probe() function because that would be the cleanest way to set up all the software state it needs to manage the device.
Quoted 6 lines
This solves the lifetime problem as well. When PCI core is initializing, it knows for sure that no retrievals are going to happen. That's because none of the drivers have registered yet. So it can safely access the FLB and initialize its state. After that, drivers can register themselves and start accepting
retrieve()calls. Once the last driver goes away, the FLB is freed automatically.
It's not so simple. The PCI core does not really initialize itself. Scanning devices gets triggered externally, e.g. by ACPI, device trees, runtime hotplug events, etc., and that is when the PCI core gets notified about a device. None of this is synchronized with "when drivers have registered", which I assume you are referring to registering with LUO.
Quoted 10 lines
I am sorry for suggesting a big refactor at v6, but the early versions looked good to me at the time, and I only thought more deeply about this when trying to figure out how we can make the lifetimes cleaner.
What do you think? Does this make sense?
--
Regards,
Pratyush Yadav
Pratyush Yadav
maintainerRe: [PATCH v6 03/12] PCI: liveupdate: Track incoming preserved PCI devices
Quoted 38 lines · David Matlack
Quoted 25 lines · Pratyush Yadav
Hi David,
Quoted 2 lines · David Matlack
Quoted 1 line · Pasha Tatashin
On Fri, 22 May 2026 20:24:01 +0000, David Matlack <[email protected]> wrote:
[...]
Quoted 13 lines
Quoted 4 lines
Quoted 4 lines
drivers/pci/liveupdate.c +4
-0+ } + +pci_info (dev,"Device was preserved by previous kernel across Live Update\n" ); + dev->liveupdate.incoming = dev_ser;Quoted 8 lines
drivers/pci/liveupdate.c void pci_liveupdate_unpreserve(struct pci_dev *dev) · line 420
Quoted 5 lines
drivers/pci/liveupdate.c +5
-0+ +/* +* Hold the ref on the incoming FLB until pci_liveupdate_finish() so +* that dev->liveupdate.incoming does not get freed while it is in use. +*/ How would that work? If finish is not called FLB stays around until the next reboot.
Quoted 3 lines
True... I think if the PCI core trusts drivers to call
pci_liveupdate_finish()then we don't need to hold onto the incoming reference here.Quoted 5 lines
That was my point when I was arguing against refcounts on outgoing FLBs. This is very easy to abuse, especially when we are talking about device drivers. And this refcounting mechanism makes the FLB no longer file-lifecycle-bound, since now it is entirely up to drivers to decide the lifecycle of this data.
The PCI core holds a reference to the incoming FLB for as long as it maintains a pointer to that FLB in struct
pci_dev(dev->liveupdate.incoming). The lifetime of that pointer is aligned with the lifetime of the file as long as the driver callspci_liveupdate_finish()in its filefinish()callback.
Quoted 7 lines
If there is a bug in the driver that causes it to not call
pci_liveupdate_finish()then the FLB will leak past the file yes. But the alternative would be to leak a pointer to freed memory indev->liveupdate.incoming, which could lead to UAF.Leaking the FLB seems safer than UAF, which is why I went for the refcounting approach.
Hmm, that does make sense. I still feel a bit odd doing this, but since I don't have any better ideas, I think let's keep this as-is. If this does turn out to be a real problem, we can fix it later. This is kernel internal API anyway.
Also, I didn't know the plan was to do VFIO only. I thought at some point in the near future we will get support for PF drivers. With only VFIO, I think this is a lot simpler and problems will be a lot easier to fix since there is only one user. I was mainly worried about random drivers holding on to PCI/LUO core data structures.
Quoted 3 lines
Another approach entirely would be to drop the
dev->liveupdate.incomingand do the xarray lookup everytime instead.
But then you'd need to have a lifetime for the xarray, no?
Quoted 55 lines
Quoted 11 lines
I have been thinking about this a bit more in the last couple days, and I wonder if we are doing this right. Here's an idea I have been thinking of.
We should make live update a first class citizen in PCI. Instead of patching in liveupdate via the liveupdate.incoming field, and letting drivers figure out when to use it, we should separate out probe and retrieve paths entirely.
Quoted 5 lines
Probe and retrieve are fundamentally different operations. While they may share some common initialization logic for the _software_ state, how they interface with the hardware is completely different. I think mixing the two will result in driver code being more spaghetti by having liveupdate checks sprayed out all over.
We are only planning on supporting Live Update for VFIO drivers for the forseeable future. The VFIO work during probe is almost entirely software state setup. The only hardware logic we need to "if" out in the vfio-pci driver's
probe()is putting the device into a low-power mode via the runtime power manager. So I don't think we will get any benefit from this approach, and it would be a lot more intrusive to both the PCI core driver framework, and VFIO itself, to support this.Quoted 4 lines
This series doesn't add support for any drivers, but looking at some of the code we have downstream, I see this problem. The liveupdate code is all over the place in the driver and it is very hard to wrap one's head around how the device is actually retrieved.
You can find the vfio-pci driver changes here:
https://lore.kernel.org/kvm/[email protected]/
Let's keep the discussion focused on upstream VFIO drivers since that is all we are planning to support right now due to LUO's requirement of file-based preservation. The downstream driver changes we are carrying is not reflective of what we want to support upstream.
Quoted 10 lines
So I think PCI core should track preserved devices, and if the device is preserved, it should skip the probe and wait for retrieve. Retrieve does the full initialization of the device. This fits in with the LUO model as well. You can make retrieve a callback of struct
pci_driverand do some wrappers to talk with LUO, so device drivers don't directly interface with LUO at all.We should do similar things on the shutdown path. Shutdown is a fundamentally different operation from freeze, and so we should separate them out as well.
This is speculative. In practice, we haven't needed to change VFIO's
shutdown()orprobe()functions so far. The only change I anticipate needing is skipping runtime power management "put" duringprobe()I mentioned above.
Quoted 4 lines
If we actually made
retrieve()a first-class callback and used that instead ofprobe(), VFIO would internally just call itsprobe()function because that would be the cleanest way to set up all the software state it needs to manage the device.
Right, for only VFIO this doesn't make much sense. I wrote this thinking we will add PF preservation support at some point.
Quoted 19 lines
Quoted 7 lines
This solves the lifetime problem as well. When PCI core is initializing, it knows for sure that no retrievals are going to happen. That's because none of the drivers have registered yet. So it can safely access the FLB and initialize its state. After that, drivers can register themselves and start accepting
retrieve()calls. Once the last driver goes away, the FLB is freed automatically.It's not so simple. The PCI core does not really initialize itself. Scanning devices gets triggered externally, e.g. by ACPI, device trees, runtime hotplug events, etc., and that is when the PCI core gets notified about a device. None of this is synchronized with "when drivers have registered", which I assume you are referring to registering with LUO.
Quoted 4 lines
I am sorry for suggesting a big refactor at v6, but the early versions looked good to me at the time, and I only thought more deeply about this when trying to figure out how we can make the lifetimes cleaner.
Signature · 2 lines
Regards, Pratyush Yadav
Re: [PATCH v6 03/12] PCI: liveupdate: Track incoming preserved PCI devices
In reply to David MatlackQuoted 36 lines · David Matlack
During PCI enumeration, the previous kernel might have passed state about devices that were preserved across kexec. The PCI core needs to fetch this state to identify which devices are "incoming" and require special handling.
Add
pci_liveupdate_setup_device()which is called during device setup to fetch the serialized state (structpci_ser) from the Live Update Orchestrator. The first time this happens,pci_flb_retrieve()will run and convert the array ofpci_dev_serstructs into an xarray so that it can be looked up efficiently.If a device is found in the xarray, the PCI core stores a pointer to its state in
dev->liveupdate_incomingand holds a reference to the incoming FLB untilpci_liveupdate_finish()is called by the driver.This ensures proper lifecycle management for incoming preserved devices and allows the PCI core and drivers to apply specific Live Update logic to them in subsequent commits.
Drivers can check if a device is an incoming preserved device (e.g. during probe) by calling
pci_liveupdate_is_incoming().
CONFIG_64BITis now required to enableCONFIG_PCI_LIVEUPDATEso that the domain and bdf can be guaranteed to fit in an unsigned long and be used as the xarray key.Signed-off-by David Matlack <[email protected]>---
MAINTAINERS | 1 + drivers/pci/Kconfig | 2 +- drivers/pci/liveupdate.c | 230 ++++++++++++++++++++++++++++++++- drivers/pci/liveupdate.h | 5 + drivers/pci/probe.c | 3 + include/linux/pci_liveupdate.h | 13 ++ 6 files changed, 251 insertions(+), 3 deletions(-)
[snip]
Quoted 31 lines
static int
pci_flb_retrieve(struct liveupdate_flb_op_args *args){drivers/pci/liveupdate.c +26
-1- args->obj =phys_to_virt (args->data); +struct pci_ser *ser =phys_to_virt (args->data); +struct pci_flb_incoming *incoming; +int ret = -ENOMEM ; +u32 i; + + incoming =kmalloc_obj (*incoming); +if (!incoming) + goto err_restore_free; + + incoming->ser = ser; +xa_init (&incoming->xa); + +for (i =0 ; i < incoming->ser->max_nr_devices; i++) { +struct pci_dev_ser *dev_ser = &incoming->ser->devices[i]; +unsigned long key; + +if (!dev_ser->refcount) +continue ; + + key =pci_ser_xa_key (dev_ser->domain, dev_ser->bdf); + ret =xa_insert (&incoming->xa, key, dev_ser,GFP_KERNEL ); +if (ret) + goto err_xa_destroy; + } + + args->obj = incoming;return 0;
drivers/pci/liveupdate.c static void pci_flb_unpreserve(struct liveupdate_flb_op_args *args) · line 193
Quoted 7 lines
drivers/pci/liveupdate.c +7
-0+ +err_xa_destroy: +xa_destroy (&incoming->xa); +kfree (incoming); +err_restore_free: +kho_restore_free (ser); +return ret;
Hmm.. This is interesting, so the KHO state is freed and it cannot be reused. I see you already pointed out that we are putting an LUO policy to say that the retry is not allowed.
But what should be the behaviour of liveupdate in this regard? Let the system boot in a normal way? This might break other subsystems as they might depend on PCIe restoring state properly. Also I think some of the PCIe state, like device-id, BAR addresses, ACLs etc, might be used as source of truth by other components.
For example, lets say FLB retrieve() of PCIe fails, but succeeds for VFIO/IOMMU, now VFIO/IOMMU are restoring state of a device that is not restored/preserved?
Should this be considered fatal?
Quoted 41 lines
}
static void
pci_flb_finish(struct liveupdate_flb_op_args *args){drivers/pci/liveupdate.c +5
-1-kho_restore_free (args->obj); +struct pci_flb_incoming *incoming = args->obj; + +xa_destroy (&incoming->xa); +kho_restore_free (incoming->ser); +kfree (incoming);}
static struct
liveupdate_flb_opspci_liveupdate_flb_ops= {drivers/pci/liveupdate.c +24
-0@@ -270,6 +335,91 @@ void pci_liveupdate_unpreserve(struct pci_dev *dev) }EXPORT_SYMBOL_GPL (pci_liveupdate_unpreserve); +static struct pci_flb_incoming *pci_liveupdate_flb_get_incoming (void ) +{ +struct pci_flb_incoming *incoming =NULL ; +int ret; + + ret =liveupdate_flb_get_incoming (&pci_liveupdate_flb, (void **)&incoming); + +/* Live Update is not enabled. */ +if (ret == -EOPNOTSUPP ) +return NULL ; + +/* Live Update is enabled, but there is no incoming FLB data. */ +if (ret == -ENODATA ) +return NULL ; + +/* +* 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). +*/ +if (ret == -ENOENT ) {
drivers/pci/liveupdate.c void pci_liveupdate_unpreserve(struct pci_dev *dev) · line 371
Quoted 10 lines
drivers/pci/liveupdate.c +10
-0+pr_info_once ("No incoming FLB matched %s\n" , pci_liveupdate_flb.compatible); +return NULL ; + } + +/* +* There is incoming FLB data that matches pci_liveupdate_flb.compatible +* but it cannot be retrieved. +*/ +if (ret) { +WARN_ONCE (ret,"Failed to retrieve incoming FLB data\n" );
I think this should probably be considered fatal as mentioned above or the caller of this function should get an error so it can fail. I think retrievel of preserved state should generally not fail unless there is memory corruption or ABI is incompatible.
Quoted 6 lines
drivers/pci/liveupdate.c +6
-0+return NULL ; + } + +return incoming; +} +
[snip]
Quoted 11 lines
include/linux/pci_liveupdate.h +5
-0+ +static inline bool pci_liveupdate_is_incoming (struct pci_dev *dev) +{ +return false; +}#endif
#endif /*
LINUX_PCI_LIVEUPDATE_H*/Signature · 1 line
2.54.0.746.g67dd491aae-goog
Sami
Re: [PATCH v6 03/12] PCI: liveupdate: Track incoming preserved PCI devices
Quoted 89 lines · Samiullah Khawaja
Quoted 36 lines · David Matlack
During PCI enumeration, the previous kernel might have passed state about devices that were preserved across kexec. The PCI core needs to fetch this state to identify which devices are "incoming" and require special handling.
Add
pci_liveupdate_setup_device()which is called during device setup to fetch the serialized state (structpci_ser) from the Live Update Orchestrator. The first time this happens,pci_flb_retrieve()will run and convert the array ofpci_dev_serstructs into an xarray so that it can be looked up efficiently.If a device is found in the xarray, the PCI core stores a pointer to its state in
dev->liveupdate_incomingand holds a reference to the incoming FLB untilpci_liveupdate_finish()is called by the driver.This ensures proper lifecycle management for incoming preserved devices and allows the PCI core and drivers to apply specific Live Update logic to them in subsequent commits.
Drivers can check if a device is an incoming preserved device (e.g. during probe) by calling
pci_liveupdate_is_incoming().
CONFIG_64BITis now required to enableCONFIG_PCI_LIVEUPDATEso that the domain and bdf can be guaranteed to fit in an unsigned long and be used as the xarray key.Signed-off-by David Matlack <[email protected]>---
MAINTAINERS | 1 + drivers/pci/Kconfig | 2 +- drivers/pci/liveupdate.c | 230 ++++++++++++++++++++++++++++++++- drivers/pci/liveupdate.h | 5 + drivers/pci/probe.c | 3 + include/linux/pci_liveupdate.h | 13 ++ 6 files changed, 251 insertions(+), 3 deletions(-)[snip]
Quoted 28 lines
static int
pci_flb_retrieve(struct liveupdate_flb_op_args *args){drivers/pci/liveupdate.c +24
-1- args->obj =phys_to_virt (args->data); +struct pci_ser *ser =phys_to_virt (args->data); +struct pci_flb_incoming *incoming; +int ret = -ENOMEM ; +u32 i; + + incoming =kmalloc_obj (*incoming); +if (!incoming) + goto err_restore_free; + + incoming->ser = ser; +xa_init (&incoming->xa); + +for (i =0 ; i < incoming->ser->max_nr_devices; i++) { +struct pci_dev_ser *dev_ser = &incoming->ser->devices[i]; +unsigned long key; + +if (!dev_ser->refcount) +continue ; + + key =pci_ser_xa_key (dev_ser->domain, dev_ser->bdf); + ret =xa_insert (&incoming->xa, key, dev_ser,GFP_KERNEL ); +if (ret) + goto err_xa_destroy; + }drivers/pci/liveupdate.c static void pci_flb_unpreserve(struct liveupdate_flb_op_args *args) · line 193
Quoted 10 lines
drivers/pci/liveupdate.c +9
-0+ + args->obj = incoming;return 0 ; + +err_xa_destroy: +xa_destroy (&incoming->xa); +kfree (incoming); +err_restore_free: +kho_restore_free (ser); +return ret;Hmm.. This is interesting, so the KHO state is freed and it cannot be reused. I see you already pointed out that we are putting an LUO policy to say that the retry is not allowed.
But what should be the behaviour of liveupdate in this regard? Let the system boot in a normal way? This might break other subsystems as they might depend on PCIe restoring state properly. Also I think some of the PCIe state, like device-id, BAR addresses, ACLs etc, might be used as source of truth by other components.
Quoted 5 lines
For example, lets say FLB
retrieve()of PCIe fails, but succeeds for VFIO/IOMMU, now VFIO/IOMMU are restoring state of a device that is not restored/preserved?Should this be considered fatal?
If PCI FLB retrieve fails then there are certain things that cannot be guaranteed, such as BDF (B specifically) remaining constant. This could lead to memory corruption as the IOMMU may have live translations in place for those specific RequesterIDs. And, in the future, preserved devices may be doing P2P which depends on BARs not moving. If the PCI core cannot retrieve the FLB saved by the previous kernel, it cannot make these guarantees.
So yeah I think you're right that PCI core should treat FLB retrieve as fatal and just panic.
Quoted 48 lines
Quoted 48 lines
}
static void
pci_flb_finish(struct liveupdate_flb_op_args *args){drivers/pci/liveupdate.c +5
-1-kho_restore_free (args->obj); +struct pci_flb_incoming *incoming = args->obj; + +xa_destroy (&incoming->xa); +kho_restore_free (incoming->ser); +kfree (incoming);}
static struct
liveupdate_flb_opspci_liveupdate_flb_ops= {drivers/pci/liveupdate.c +31
-0@@ -270,6 +335,91 @@ void pci_liveupdate_unpreserve(struct pci_dev *dev) }EXPORT_SYMBOL_GPL (pci_liveupdate_unpreserve); +static struct pci_flb_incoming *pci_liveupdate_flb_get_incoming (void ) +{ +struct pci_flb_incoming *incoming =NULL ; +int ret; + + ret =liveupdate_flb_get_incoming (&pci_liveupdate_flb, (void **)&incoming); + +/* Live Update is not enabled. */ +if (ret == -EOPNOTSUPP ) +return NULL ; + +/* Live Update is enabled, but there is no incoming FLB data. */ +if (ret == -ENODATA ) +return NULL ; + +/* +* 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). +*/ +if (ret == -ENOENT ) { +pr_info_once ("No incoming FLB matched %s\n" , pci_liveupdate_flb.compatible); +return NULL ; + } + +/* +* There is incoming FLB data that matches pci_liveupdate_flb.compatible +* but it cannot be retrieved.
Quoted 8 lines
drivers/pci/liveupdate.c void pci_liveupdate_unpreserve(struct pci_dev *dev) · line 371
Quoted 3 lines
drivers/pci/liveupdate.c +3
-0+*/ +if (ret) { +WARN_ONCE (ret,"Failed to retrieve incoming FLB data\n" );I think this should probably be considered fatal as mentioned above or the caller of this function should get an error so it can fail. I think retrievel of preserved state should generally not fail unless there is memory corruption or ABI is incompatible.
Yeah. I think I will just call panic() here to cover all cases.
Quoted 21 lines
Quoted 6 lines
drivers/pci/liveupdate.c +6
-0+return NULL ; + } + +return incoming; +} +[snip]
Quoted 11 lines
include/linux/pci_liveupdate.h +5
-0+ +static inline bool pci_liveupdate_is_incoming (struct pci_dev *dev) +{ +return false; +}#endif
#endif /*
LINUX_PCI_LIVEUPDATE_H*/
--
2.54.0.746.g67dd491aae-googSami
Re: [PATCH v6 03/12] PCI: liveupdate: Track incoming preserved PCI devices
Quoted 2 lines · David Matlack
Quoted 1 line · Samiullah Khawaja
[snip]
Quoted 17 lines
Quoted 11 lines
Hmm.. This is interesting, so the KHO state is freed and it cannot be reused. I see you already pointed out that we are putting an LUO policy to say that the retry is not allowed.
But what should be the behaviour of liveupdate in this regard? Let the system boot in a normal way? This might break other subsystems as they might depend on PCIe restoring state properly. Also I think some of the PCIe state, like device-id, BAR addresses, ACLs etc, might be used as source of truth by other components.
Quoted 5 lines
For example, lets say FLB
retrieve()of PCIe fails, but succeeds for VFIO/IOMMU, now VFIO/IOMMU are restoring state of a device that is not restored/preserved?Should this be considered fatal?
Quoted 7 lines
If PCI FLB retrieve fails then there are certain things that cannot be guaranteed, such as BDF (B specifically) remaining constant. This could lead to memory corruption as the IOMMU may have live translations in place for those specific RequesterIDs. And, in the future, preserved devices may be doing P2P which depends on BARs not moving. If the PCI core cannot retrieve the FLB saved by the previous kernel, it cannot make these guarantees.
Yes, this is what I was worried about.
Quoted 3 lines
So yeah I think you're right that PCI core should treat FLB retrieve as fatal and just panic.
This sounds great.
Quoted 58 lines
Quoted 49 lines
Quoted 49 lines
}
static void
pci_flb_finish(struct liveupdate_flb_op_args *args){drivers/pci/liveupdate.c +5
-1-kho_restore_free (args->obj); +struct pci_flb_incoming *incoming = args->obj; + +xa_destroy (&incoming->xa); +kho_restore_free (incoming->ser); +kfree (incoming);}
static struct
liveupdate_flb_opspci_liveupdate_flb_ops= {drivers/pci/liveupdate.c +31
-0@@ -270,6 +335,91 @@ void pci_liveupdate_unpreserve(struct pci_dev *dev) }EXPORT_SYMBOL_GPL (pci_liveupdate_unpreserve); +static struct pci_flb_incoming *pci_liveupdate_flb_get_incoming (void ) +{ +struct pci_flb_incoming *incoming =NULL ; +int ret; + + ret =liveupdate_flb_get_incoming (&pci_liveupdate_flb, (void **)&incoming); + +/* Live Update is not enabled. */ +if (ret == -EOPNOTSUPP ) +return NULL ; + +/* Live Update is enabled, but there is no incoming FLB data. */ +if (ret == -ENODATA ) +return NULL ; + +/* +* 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). +*/ +if (ret == -ENOENT ) { +pr_info_once ("No incoming FLB matched %s\n" , pci_liveupdate_flb.compatible); +return NULL ; + } + +/* +* There is incoming FLB data that matches pci_liveupdate_flb.compatible +* but it cannot be retrieved. Quoted 8 lines
drivers/pci/liveupdate.c void pci_liveupdate_unpreserve(struct pci_dev *dev) · line 371
Quoted 3 lines
drivers/pci/liveupdate.c +3
-0+*/ +if (ret) { +WARN_ONCE (ret,"Failed to retrieve incoming FLB data\n" );I think this should probably be considered fatal as mentioned above or the caller of this function should get an error so it can fail. I think retrievel of preserved state should generally not fail unless there is memory corruption or ABI is incompatible.
Quoted 1 line
Yeah. I think I will just call
panic()here to cover all cases.
We have an luo specific panic macro/function that you can use.
luo_restore_fail()
Quoted 22 lines
Quoted 22 lines
Quoted 7 lines
drivers/pci/liveupdate.c +6
-0+return NULL ; + } + +return incoming; +} +[snip]
Quoted 11 lines
include/linux/pci_liveupdate.h +5
-0+ +static inline bool pci_liveupdate_is_incoming (struct pci_dev *dev) +{ +return false; +}#endif
#endif /*
LINUX_PCI_LIVEUPDATE_H*/
--
2.54.0.746.g67dd491aae-googSami
PATCH v6 4/12 PCI: liveupdate: Document driver binding responsibilities
In reply to David MatlackDocument how driver binding works during a Live Update and what the PCI core expects of drivers and users. Note that this is only a description of the current division of responsibilities. These can change in the future if we decide.
--- drivers/pci/liveupdate.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+)
drivers/pci/liveupdate.c +16 -0
@@ -70,6 +70,22 @@* preserved. These may be relaxed in the future: * * * The device cannot be a Virtual Function (VF). +* +* Driver Binding +* ============== +* +* In the outgoing kernel, it is the driver's responsibility to ensure that it +* does not release a device between pci_liveupdate_preserve() and +* pci_liveupdate_unpreserve(). +* +* In the incoming kernel, it is the driver's responsibility to ensure that it +* does not release a preserved device between probe() and +* pci_liveupdate_finish(). +* +* It is the user's responsibility to ensure that incoming preserved devices are +* bound to the correct driver. i.e. The PCI core does not protect against a +* device getting preserved by driver A in the outgoing kernel and then getting +* bound to driver B in the incoming kernel. */ #define pr_fmt (fmt) "PCI: liveupdate: " fmt
Signature · 1 line
2.54.0.746.g67dd491aae-goog
Pratyush Yadav
maintainerRe: [PATCH v6 04/12] PCI: liveupdate: Document driver binding responsibilities
Quoted 4 lines · David Matlack
Document how driver binding works during a Live Update and what the PCI core expects of drivers and users. Note that this is only a description of the current division of responsibilities. These can change in the future if we decide.
Nit: Should you also note this in the documentation that this can change in the future?
Quoted 33 lines
Signed-off-by David Matlack <[email protected]>--- drivers/pci/liveupdate.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+)drivers/pci/liveupdate.c +16
-0@@ -70,6 +70,22 @@* preserved. These may be relaxed in the future: * * * The device cannot be a Virtual Function (VF). +* +* Driver Binding +* ============== +* +* In the outgoing kernel, it is the driver's responsibility to ensure that it +* does not release a device between pci_liveupdate_preserve() and +* pci_liveupdate_unpreserve(). +* +* In the incoming kernel, it is the driver's responsibility to ensure that it +* does not release a preserved device between probe() and +* pci_liveupdate_finish(). +* +* It is the user's responsibility to ensure that incoming preserved devices are +* bound to the correct driver. i.e. The PCI core does not protect against a +* device getting preserved by driver A in the outgoing kernel and then getting +* bound to driver B in the incoming kernel. */ #define pr_fmt (fmt) "PCI: liveupdate: " fmt
Signature · 2 lines
Regards, Pratyush Yadav
Re: [PATCH v6 04/12] PCI: liveupdate: Document driver binding responsibilities
In reply to David MatlackQuoted 6 lines · David Matlack
Document how driver binding works during a Live Update and what the PCI core expects of drivers and users. Note that this is only a description of the current division of responsibilities. These can change in the future if we decide.
Signed-off-by David Matlack <[email protected]>
Thanks,
Praan
Re: [PATCH v6 04/12] PCI: liveupdate: Document driver binding responsibilities
In reply to David MatlackQuoted 4 lines · David Matlack
Document how driver binding works during a Live Update and what the PCI core expects of drivers and users. Note that this is only a description of the current division of responsibilities. These can change in the future if we decide.
Signature · 1 line
Pasha Tatashin <[email protected]>
Re: [PATCH v6 04/12] PCI: liveupdate: Document driver binding responsibilities
In reply to David MatlackQuoted 40 lines · David Matlack
Document how driver binding works during a Live Update and what the PCI core expects of drivers and users. Note that this is only a description of the current division of responsibilities. These can change in the future if we decide.
Signed-off-by David Matlack <[email protected]>---
drivers/pci/liveupdate.c| 16 ++++++++++++++++1 file changed, 16 insertions(+)drivers/pci/liveupdate.c +16
-0@@ -70,6 +70,22 @@* preserved. These may be relaxed in the future: * * * The device cannot be a Virtual Function (VF). +* +* Driver Binding +* ============== +* +* In the outgoing kernel, it is the driver's responsibility to ensure that it +* does not release a device between pci_liveupdate_preserve() and +* pci_liveupdate_unpreserve(). +* +* In the incoming kernel, it is the driver's responsibility to ensure that it +* does not release a preserved device between probe() and +* pci_liveupdate_finish(). +* +* It is the user's responsibility to ensure that incoming preserved devices are +* bound to the correct driver. i.e. The PCI core does not protect against a +* device getting preserved by driver A in the outgoing kernel and then getting +* bound to driver B in the incoming kernel. */ #define pr_fmt (fmt) "PCI: liveupdate: " fmtSignature · 1 line
2.54.0.746.g67dd491aae-goog
PATCH v6 5/12 PCI: liveupdate: Keep bus numbers constant during Live Update
In reply to David MatlackDuring a Live Update, preserved devices must be allowed to continue performing memory transactions so the kernel cannot change the fabric topology, including bus numbers, since that would require disabling and flushing any memory transactions first.
To keep bus numbers constant, always inherit the secondary and subordinate bus numbers assigned to bridges during scanning, instead of assigning new ones, if any PCI devices are being preserved. Note that the kernel inherits bus numbers even on bridges without any downstream endpoints that were preserved. This avoids accidentally assigning a bridge a new window that overlaps with a preserved device that is downstream of a different bridge.
If a bridge is scanned with a broken topology or has no bus numbers set during a Live Update, refuse to assign it new bus numbers and refuse to enumerate devices below it until the Live Update is finished. This is a safety measure to prevent topology conflicts.
Require that CONFIG_CARDBUS is not enabled to enable CONFIG_PCI_LIVEUPDATE since inheriting bus numbers on PCI-to-CardBus bridges requires additional work but is not a priority at the moment.
--- .../admin-guide/kernel-parameters.txt | 6 +- drivers/pci/Kconfig | 2 +- drivers/pci/liveupdate.c | 83 ++++++++++++++++++- drivers/pci/liveupdate.h | 14 ++++ drivers/pci/probe.c | 17 +++- include/linux/pci_liveupdate.h | 4 + 6 files changed, 119 insertions(+), 7 deletions(-)
Documentation/admin-guide/kernel-parameters.txt +5 -1
@@ -5138,7 +5138,11 @@ Kernel parameters explicitly which ones they are. assign-busses [X86] Always assign all PCI bus numbers ourselves, overriding - whatever the firmware may have done. + whatever the firmware may have done. Ignored + during a Live Update, where the kernel must + inherit the PCI topology (including bus numbers) + to avoid interrupting ongoing memory + transactions of preserved devices. usepirqmask [X86] Honor the possible IRQ mask stored in the BIOS $PIR table. This is needed on some systems with broken BIOSes, notably
drivers/pci/Kconfig +1 -1
@@ -330,7 +330,7 @@ config VGA_ARB_MAX_GPUS config PCI_LIVEUPDATE bool "PCI Live Update Support" - depends on PCI && LIVEUPDATE && 64BIT + depends on PCI && LIVEUPDATE && 64BIT && !CARDBUS help Enable PCI core support for preserving PCI devices across Live Update. This, in combination with support in a device's driver,
drivers/pci/liveupdate.c +82 -1
101 lines not on this page · raw message
drivers/pci/liveupdate.h +14 -0
@@ -13,6 +13,9 @@#ifdef CONFIG_PCI_LIVEUPDATE void pci_liveupdate_setup_device (struct pci_dev *dev);void pci_liveupdate_cleanup_device (struct pci_dev *dev); +bool pci_liveupdate_scan_bridge_begin (struct pci_bus *bus,struct pci_dev *dev, +int pass); +void pci_liveupdate_scan_bridge_end (struct pci_dev *dev,int pass);#else static inline void pci_liveupdate_setup_device (struct pci_dev *dev) {
@@ -21,6 +24,17 @@ static inline void pci_liveupdate_setup_device(struct pci_dev *dev)static inline void pci_liveupdate_cleanup_device (struct pci_dev *dev) { } + +static inline bool pci_liveupdate_scan_bridge_begin (struct pci_bus *bus, +struct pci_dev *dev, +int pass) +{ +return false; +} + +static inline void pci_liveupdate_scan_bridge_end (struct pci_dev *dev,int pass) +{ +}#endif #endif /* DRIVERS_PCI_LIVEUPDATE_H */
drivers/pci/probe.c +13 -4
@@ -1402,6 +1402,7 @@ static int pci_scan_bridge_extend(struct pci_bus *bus, struct pci_dev *dev, int max, unsigned int available_buses, int pass) { + bool liveupdate, assign_new_buses = pcibios_assign_all_busses();struct pci_bus *child;u32 buses;u16 bctl;
@@ -1411,6 +1412,10 @@ static int pci_scan_bridge_extend(struct pci_bus *bus, struct pci_dev *dev,u8 fixed_sec, fixed_sub;int next_busnr; + liveupdate =pci_liveupdate_scan_bridge_begin (bus, dev, pass); +if (liveupdate) + assign_new_buses = false; +/* * Make sure the bridge is powered on to be able to access config * space of devices below it.
@@ -1454,8 +1459,7 @@ static int pci_scan_bridge_extend(struct pci_bus *bus, struct pci_dev *dev, goto out; } -if ((secondary || subordinate) && - !pcibios_assign_all_busses () && !broken) { +if ((secondary || subordinate) && !assign_new_buses && !broken) {unsigned int cmax, buses;/*
@@ -1497,8 +1501,7 @@ static int pci_scan_bridge_extend(struct pci_bus *bus, struct pci_dev *dev,* do in the second pass. */ if (!pass) { -if (pcibios_assign_all_busses () || broken) - +if (assign_new_buses || broken)/* * Temporarily disable forwarding of the * configuration cycles on all bridges in
@@ -1512,6 +1515,11 @@ static int pci_scan_bridge_extend(struct pci_bus *bus, struct pci_dev *dev, goto out; } +if (liveupdate) { +pci_err (dev,"Cannot reconfigure bridge during Live Update, skipping\n" ); + goto out; + } +/* Clear errors */ pci_write_config_word (dev,PCI_STATUS ,0xffff );
@@ -1572,6 +1580,7 @@ static int pci_scan_bridge_extend(struct pci_bus *bus, struct pci_dev *dev,pci_write_config_word (dev,PCI_BRIDGE_CONTROL , bctl);pm_runtime_put (&dev->dev); +pci_liveupdate_scan_bridge_end (dev, pass);return max; }
include/linux/pci_liveupdate.h +4 -0
@@ -17,10 +17,14 @@* struct pci_liveupdate - PCI Live Update state for a struct pci_dev * @outgoing: State preserved for the next kernel. * @incoming: State preserved by the previous kernel. +* @inherit_buses: True if the PCI core should inherit the secondary and +* subordinate bus numbers assigned to this device due to +* an ongoing Live Update. */ struct pci_liveupdate {struct pci_dev_ser *outgoing;struct pci_dev_ser *incoming; +bool inherit_buses; };struct pci_dev ;
Signature · 1 line
2.54.0.746.g67dd491aae-goog
[email protected]
AI reviewRe: [PATCH v6 05/12] PCI: liveupdate: Keep bus numbers constant during Live Update
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider: - [Low] Mixing goto-based control flow with scope-based cleanup helpers (`scoped_guard`) in the function…
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Low] Mixing goto-based control flow with scope-based cleanup helpers (scoped_guard) in the function pci_liveupdate_scan_bridge_begin. --
commit 12ae1f010eb68b0654e38ce2800545f03bf1b835
Author: David Matlack <[email protected]>
PCI: liveupdate: Keep bus numbers constant during Live Update
During a Live Update, preserved devices must be allowed to continue performing memory transactions so the kernel cannot change the fabric topology. To keep bus numbers constant, this patch makes the PCI core inherit the secondary and subordinate bus numbers assigned to bridges during scanning if any PCI devices are being preserved.
Quoted 2 lines
drivers/pci/liveupdate.c +0
-0
[ ... ]
Quoted 30 lines
drivers/pci/liveupdate.c +30
-0+bool pci_liveupdate_scan_bridge_begin (struct pci_bus *bus,struct pci_dev *dev, +int pass) +{ +struct pci_dev *parent = bus->self; + +/* +* On the second pass, reuse the value that was set on the first pass +* so that the passes are consistent with one another. +*/ +if (pass) +return dev->liveupdate.inherit_buses; + +/* +* If the parent bridge is being forced to inherit its bus numbers +* during this scan then this bridge must as well, otherwise the PCI +* core could expand this bridge's reservation beyond its parent (which +* cannot expand). +*/ +if (parent && parent->liveupdate.inherit_buses) { + dev->liveupdate.inherit_buses = true; + goto out; + } + +/* +* Otherwise, if there are any incoming preserved devices, force the +* bus numbers to be inherited to avoid changing the bus numbers +* assigned to those devices during enumeration. +* +* To keep things simple, inherit bus numbers on all bridges if any PCI +* devices are incoming, to ensure that no bridge's reservation is
drivers/pci/liveupdate.c static void pci_liveupdate_flb_put_incoming(void) · line 453
Quoted 10 lines
drivers/pci/liveupdate.c +10
-0+* expanded to overlap with a preserved device downstream of a different +* bridge. +*/ + scoped_guard(rwsem_read, &pci_liveupdate.rwsem) { +struct pci_flb_incoming *incoming; + + incoming =pci_liveupdate_flb_get_incoming (); +if (!incoming) { + dev->liveupdate.inherit_buses = false; + goto out;
[Severity: Low]
Does this mix goto-based control flow with scope-based cleanup helpers?
According to the cleanup subsystem guidelines, functions should either use scope-based cleanups or goto-based cleanups, but never both in the same function.
Could these goto statements be replaced by directly returning the boolean value instead?
Quoted 15 lines
drivers/pci/liveupdate.c +15
-0+ } + +/* +* It is safe to sample incoming->ser->nr_devices and then +* drop the rwsem since nr_devices will only decrease. Thus the +* only "race" is that the current scan will be overly +* conservative and force bus inheritance. +*/ + dev->liveupdate.inherit_buses = incoming->ser->nr_devices; +pci_liveupdate_flb_put_incoming (); + } + +out: +return dev->liveupdate.inherit_buses; +}
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=5
Re: [PATCH v6 05/12] PCI: liveupdate: Keep bus numbers constant during Live Update
Quoted 63 lines · On Fri, May 22, 2026 at 2:08 PM <[email protected]> wrote:
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Low] Mixing goto-based control flow with scope-based cleanup helpers (scoped_guard) in the functionpci_liveupdate_scan_bridge_begin. --commit
12ae1f010eb68b0654e38ce2800545f03bf1b835
Author: David Matlack <[email protected]>PCI: liveupdate: Keep bus numbers constant during Live Update
During a Live Update, preserved devices must be allowed to continue performing memory transactions so the kernel cannot change the fabric topology. To keep bus numbers constant, this patch makes the PCI core inherit the secondary and subordinate bus numbers assigned to bridges during scanning if any PCI devices are being preserved.
Quoted 2 lines
drivers/pci/liveupdate.c +0
-0[ ... ]
Quoted 30 lines
drivers/pci/liveupdate.c +30
-0+bool pci_liveupdate_scan_bridge_begin (struct pci_bus *bus,struct pci_dev *dev, +int pass) +{ +struct pci_dev *parent = bus->self; + +/* +* On the second pass, reuse the value that was set on the first pass +* so that the passes are consistent with one another. +*/ +if (pass) +return dev->liveupdate.inherit_buses; + +/* +* If the parent bridge is being forced to inherit its bus numbers +* during this scan then this bridge must as well, otherwise the PCI +* core could expand this bridge's reservation beyond its parent (which +* cannot expand). +*/ +if (parent && parent->liveupdate.inherit_buses) { + dev->liveupdate.inherit_buses = true; + goto out; + } + +/* +* Otherwise, if there are any incoming preserved devices, force the +* bus numbers to be inherited to avoid changing the bus numbers +* assigned to those devices during enumeration. +* +* To keep things simple, inherit bus numbers on all bridges if any PCI +* devices are incoming, to ensure that no bridge's reservation is drivers/pci/liveupdate.c static void pci_liveupdate_flb_put_incoming(void) · line 453
Quoted 10 lines
drivers/pci/liveupdate.c +10
-0+* expanded to overlap with a preserved device downstream of a different +* bridge. +*/ + scoped_guard(rwsem_read, &pci_liveupdate.rwsem) { +struct pci_flb_incoming *incoming; + + incoming =pci_liveupdate_flb_get_incoming (); +if (!incoming) { + dev->liveupdate.inherit_buses = false; + goto out;[Severity: Low]
Does this mix goto-based control flow with scope-based cleanup helpers?
Quoted 6 lines
According to the cleanup subsystem guidelines, functions should either use scope-based cleanups or goto-based cleanups, but never both in the same function.
Could these goto statements be replaced by directly returning the boolean value instead?
That seems reasonable enough, will fix in v7..
Re: [PATCH v6 05/12] PCI: liveupdate: Keep bus numbers constant during Live Update
In reply to David MatlackQuoted 32 lines · David Matlack
During a Live Update, preserved devices must be allowed to continue performing memory transactions so the kernel cannot change the fabric topology, including bus numbers, since that would require disabling and flushing any memory transactions first.
To keep bus numbers constant, always inherit the secondary and subordinate bus numbers assigned to bridges during scanning, instead of assigning new ones, if any PCI devices are being preserved. Note that the kernel inherits bus numbers even on bridges without any downstream endpoints that were preserved. This avoids accidentally assigning a bridge a new window that overlaps with a preserved device that is downstream of a different bridge.
If a bridge is scanned with a broken topology or has no bus numbers set during a Live Update, refuse to assign it new bus numbers and refuse to enumerate devices below it until the Live Update is finished. This is a safety measure to prevent topology conflicts.
Require that
CONFIG_CARDBUSis not enabled to enableCONFIG_PCI_LIVEUPDATEsince inheriting bus numbers on PCI-to-CardBus bridges requires additional work but is not a priority at the moment.Signed-off-by David Matlack <[email protected]>--- .../admin-guide/kernel-parameters.txt | 6 +- drivers/pci/Kconfig | 2 +- drivers/pci/liveupdate.c | 83 ++++++++++++++++++- drivers/pci/liveupdate.h | 14 ++++ drivers/pci/probe.c | 17 +++- include/linux/pci_liveupdate.h | 4 + 6 files changed, 119 insertions(+), 7 deletions(-)
[...]
drivers/pci/liveupdate.c static void pci_liveupdate_flb_put_incoming(void) · line 462
Quoted 13 lines
drivers/pci/liveupdate.c +13
-0+ incoming =pci_liveupdate_flb_get_incoming (); +if (!incoming) { + dev->liveupdate.inherit_buses = false; + goto out; + } + +/* +* It is safe to sample incoming->ser->nr_devices and then +* drop the rwsem since nr_devices will only decrease. Thus the +* only "race" is that the current scan will be overly +* conservative and force bus inheritance. +*/ + dev->liveupdate.inherit_buses = incoming->ser->nr_devices;
Nit: inherit_buses is a bool, while compiler will handle it correctly, maybe we could:
dev->liveupdate.inherit_buses = !!incoming->ser->nr_devices
OR
dev->liveupdate.inherit_buses = (incoming->ser->nr_devices > 0)
for readability?
Quoted 7 lines
drivers/pci/liveupdate.c +7
-0+pci_liveupdate_flb_put_incoming (); + } + +out: +return dev->liveupdate.inherit_buses; +} +
[...]
Quoted 12 lines
drivers/pci/probe.c +1
-2/* @@ -1497,8 +1501,7 @@ static int pci_scan_bridge_extend(struct pci_bus *bus, struct pci_dev *dev,* do in the second pass. */ if (!pass) { -if (pcibios_assign_all_busses () || broken) - +if (assign_new_buses || broken)/* * Temporarily disable forwarding of the * configuration cycles on all bridges in
drivers/pci/probe.c static int pci_scan_bridge_extend(struct pci_bus *bus, struct pci_dev *dev, · line 1521
Quoted 7 lines
drivers/pci/probe.c +4
-0@@ -1512,6 +1515,11 @@ static int pci_scan_bridge_extend(struct pci_bus *bus, struct pci_dev *dev, goto out; } +if (liveupdate) { +pci_err (dev,"Cannot reconfigure bridge during Live Update, skipping\n" ); + goto out; + }
Quite helpful! Thanks :)
drivers/pci/probe.c static int pci_scan_bridge_extend(struct pci_bus *bus, struct pci_dev *dev, · line 1586
Quoted 12 lines
drivers/pci/probe.c +2
-0+/* Clear errors */ pci_write_config_word (dev,PCI_STATUS ,0xffff );@@ -1572,6 +1580,7 @@ static int pci_scan_bridge_extend(struct pci_bus *bus, struct pci_dev *dev,pci_write_config_word (dev,PCI_BRIDGE_CONTROL , bctl);pm_runtime_put (&dev->dev); +pci_liveupdate_scan_bridge_end (dev, pass);return max; }
With the minor nit above,
Thanks,
Praan
Pasha Tatashin
maintainerRe: [PATCH v6 05/12] PCI: liveupdate: Keep bus numbers constant during Live Update
Quoted 53 lines · Pranjal Shrivastava
Quoted 31 lines · David Matlack
During a Live Update, preserved devices must be allowed to continue performing memory transactions so the kernel cannot change the fabric topology, including bus numbers, since that would require disabling and flushing any memory transactions first.
To keep bus numbers constant, always inherit the secondary and subordinate bus numbers assigned to bridges during scanning, instead of assigning new ones, if any PCI devices are being preserved. Note that the kernel inherits bus numbers even on bridges without any downstream endpoints that were preserved. This avoids accidentally assigning a bridge a new window that overlaps with a preserved device that is downstream of a different bridge.
If a bridge is scanned with a broken topology or has no bus numbers set during a Live Update, refuse to assign it new bus numbers and refuse to enumerate devices below it until the Live Update is finished. This is a safety measure to prevent topology conflicts.
Require that
CONFIG_CARDBUSis not enabled to enableCONFIG_PCI_LIVEUPDATEsince inheriting bus numbers on PCI-to-CardBus bridges requires additional work but is not a priority at the moment.Signed-off-by David Matlack <[email protected]>--- .../admin-guide/kernel-parameters.txt | 6 +- drivers/pci/Kconfig | 2 +- drivers/pci/liveupdate.c | 83 ++++++++++++++++++- drivers/pci/liveupdate.h | 14 ++++ drivers/pci/probe.c | 17 +++- include/linux/pci_liveupdate.h | 4 + 6 files changed, 119 insertions(+), 7 deletions(-)[...]
drivers/pci/liveupdate.c static void pci_liveupdate_flb_put_incoming(void) · line 462
Quoted 13 lines
drivers/pci/liveupdate.c +13
-0+ incoming =pci_liveupdate_flb_get_incoming (); +if (!incoming) { + dev->liveupdate.inherit_buses = false; + goto out; + } + +/* +* It is safe to sample incoming->ser->nr_devices and then +* drop the rwsem since nr_devices will only decrease. Thus the +* only "race" is that the current scan will be overly +* conservative and force bus inheritance. +*/ + dev->liveupdate.inherit_buses = incoming->ser->nr_devices;Nit:
inherit_busesis a bool, while compiler will handle it correctly, maybe we could:
Quoted 1 line
dev->liveupdate.inherit_buses= !!incoming->ser->nr_devices
+1
Quoted 57 lines
OR
dev->liveupdate.inherit_buses= (incoming->ser->nr_devices> 0)for readability?
Quoted 7 lines
drivers/pci/liveupdate.c +7
-0+pci_liveupdate_flb_put_incoming (); + } + +out: +return dev->liveupdate.inherit_buses; +} +[...]
Quoted 12 lines
drivers/pci/probe.c +1
-2/* @@ -1497,8 +1501,7 @@ static int pci_scan_bridge_extend(struct pci_bus *bus, struct pci_dev *dev,* do in the second pass. */ if (!pass) { -if (pcibios_assign_all_busses () || broken) - +if (assign_new_buses || broken)/* * Temporarily disable forwarding of the * configuration cycles on all bridges in drivers/pci/probe.c static int pci_scan_bridge_extend(struct pci_bus *bus, struct pci_dev *dev, · line 1521
Quoted 7 lines
drivers/pci/probe.c +4
-0@@ -1512,6 +1515,11 @@ static int pci_scan_bridge_extend(struct pci_bus *bus, struct pci_dev *dev, goto out; } +if (liveupdate) { +pci_err (dev,"Cannot reconfigure bridge during Live Update, skipping\n" ); + goto out; + }Quite helpful! Thanks :)
drivers/pci/probe.c static int pci_scan_bridge_extend(struct pci_bus *bus, struct pci_dev *dev, · line 1586
Quoted 12 lines
drivers/pci/probe.c +2
-0+/* Clear errors */ pci_write_config_word (dev,PCI_STATUS ,0xffff );@@ -1572,6 +1580,7 @@ static int pci_scan_bridge_extend(struct pci_bus *bus, struct pci_dev *dev,pci_write_config_word (dev,PCI_BRIDGE_CONTROL , bctl);pm_runtime_put (&dev->dev); +pci_liveupdate_scan_bridge_end (dev, pass);return max; }With the minor nit above,
Reviewed-by Pranjal Shrivastava <[email protected]>Thanks,
Praan
Pasha Tatashin
maintainerRe: [PATCH v6 05/12] PCI: liveupdate: Keep bus numbers constant during Live Update
In reply to David Matlackdrivers/pci/liveupdate.c line 121
Quoted 10 lines · David Matlack
drivers/pci/liveupdate.c +1
-1@@ -103,7 +118,7 @@/** * struct pci_liveupdate_global - Global state for PCI Live Update support * @rwsem: Reader/writer semaphore used to protect the incoming and outgoing -* FLBs, and the references to them in struct pci_dev. +* FLBs and references to them in struct pci_dev.
This change does not belong to this patch.
drivers/pci/liveupdate.c static void pci_liveupdate_flb_put_incoming(void) · line 415
Quoted 6 lines
drivers/pci/liveupdate.c +2
-0@@ -396,6 +411,72 @@ static void pci_liveupdate_flb_put_incoming(void)liveupdate_flb_put_incoming (&pci_liveupdate_flb); } +bool pci_liveupdate_scan_bridge_begin (struct pci_bus *bus,struct pci_dev *dev, +int pass)
This function requires a header comment; it is public and not self-descriptive.
Signature · 1 line
Pasha Tatashin <[email protected]>
Re: [PATCH v6 05/12] PCI: liveupdate: Keep bus numbers constant during Live Update
Quoted 13 lines · Pasha Tatashin
drivers/pci/liveupdate.c line 121
Quoted 10 lines · David Matlack
drivers/pci/liveupdate.c +1
-1@@ -103,7 +118,7 @@/** * struct pci_liveupdate_global - Global state for PCI Live Update support * @rwsem: Reader/writer semaphore used to protect the incoming and outgoing -* FLBs, and the references to them in struct pci_dev. +* FLBs and references to them in struct pci_dev. This change does not belong to this patch.
Yes, will fix.
Quoted 9 lines
drivers/pci/liveupdate.c static void pci_liveupdate_flb_put_incoming(void) · line 415
Quoted 7 lines
drivers/pci/liveupdate.c +2
-0@@ -396,6 +411,72 @@ static void pci_liveupdate_flb_put_incoming(void)liveupdate_flb_put_incoming (&pci_liveupdate_flb); } +bool pci_liveupdate_scan_bridge_begin (struct pci_bus *bus,struct pci_dev *dev, +int pass)This function requires a header comment; it is public and not self-descriptive.
It is private to the PCI core, but I can still add a comment in v7.
Quoted 3 lines
Signature · 2 lines
-- Pasha Tatashin <[email protected]>
Re: [PATCH v6 05/12] PCI: liveupdate: Keep bus numbers constant during Live Update
In reply to David MatlackQuoted 23 lines · David Matlack
During a Live Update, preserved devices must be allowed to continue performing memory transactions so the kernel cannot change the fabric topology, including bus numbers, since that would require disabling and flushing any memory transactions first.
To keep bus numbers constant, always inherit the secondary and subordinate bus numbers assigned to bridges during scanning, instead of assigning new ones, if any PCI devices are being preserved. Note that the kernel inherits bus numbers even on bridges without any downstream endpoints that were preserved. This avoids accidentally assigning a bridge a new window that overlaps with a preserved device that is downstream of a different bridge.
If a bridge is scanned with a broken topology or has no bus numbers set during a Live Update, refuse to assign it new bus numbers and refuse to enumerate devices below it until the Live Update is finished. This is a safety measure to prevent topology conflicts.
Require that
CONFIG_CARDBUSis not enabled to enableCONFIG_PCI_LIVEUPDATEsince inheriting bus numbers on PCI-to-CardBus bridges requires additional work but is not a priority at the moment.Signed-off-by David Matlack <[email protected]>
Quoted 9 lines
---
.../admin-guide/kernel-parameters.txt | 6 +- drivers/pci/Kconfig | 2 +- drivers/pci/liveupdate.c | 83 ++++++++++++++++++- drivers/pci/liveupdate.h | 14 ++++ drivers/pci/probe.c | 17 +++- include/linux/pci_liveupdate.h | 4 + 6 files changed, 119 insertions(+), 7 deletions(-)
PATCH v6 6/12 PCI: liveupdate: Auto-preserve upstream bridges across Live Update
In reply to David MatlackWhen a PCI device is preserved across a Live Update, all of its upstream bridges up to the root port must also be preserved. This enables the PCI core and any drivers bound to the bridges to manage bridges correctly across a Live Update.
Notably, this will be used in subsequent commits to ensure that preserved devices can continue performing memory transactions without a disruption or change in routing.
To preserve bridges, the PCI core tracks the number of downstream devices preserved under each bridge using a reference count in struct pci_dev_ser. This allows a bridge to remain preserved until all its downstream preserved devices are unpreserved or finish their participation in the Live Update.
--- drivers/pci/liveupdate.c | 136 +++++++++++++++++++++++++++++++----- include/linux/kho/abi/pci.h | 5 +- 2 files changed, 122 insertions(+), 19 deletions(-)
drivers/pci/liveupdate.c +119 -17
@@ -101,6 +101,18 @@* If a misconfigured or unconfigured bridge is encountered during enumeration * while there are preserved devices, its secondary and subordinate bus numbers * will be cleared and devices below it will not be enumerated. +* +* PCI-to-PCI Bridges +* ================== +* +* Any PCI-to-PCI bridges upstream of a preserved device are automatically +* preserved when the device is preserved. The PCI core keeps track of the +* number of downstream devices that are preserved under a bridge so that the +* bridge is only unpreserved once all downstream devices are unpreserved. +* +* This enables the PCI core and any drivers bound to the bridge to participate +* in the Live Update so that preserved endpoints can continue issuing memory +* transactions during the Live Update. */ #define pr_fmt (fmt) "PCI: liveupdate: " fmt
@@ -261,28 +273,52 @@ static struct pci_ser *pci_liveupdate_flb_get_outgoing(void)return ser; } -static void pci_liveupdate_unpreserve_device (struct pci_ser *ser,struct pci_dev *dev) +static int pci_liveupdate_unpreserve_device (struct pci_ser *ser,struct pci_dev *dev) {struct pci_dev_ser *dev_ser = dev->liveupdate.outgoing;if (!dev_ser) {pci_warn (dev,"Cannot unpreserve device that is not preserved\n" ); -return ; +return -EINVAL ; + } + +if (!dev_ser->refcount) { +pci_WARN (dev,1 ,"Preserved device has a 0 refcount!\n" ); +return -EINVAL ; } +if (--dev_ser->refcount) +return 0 ; +pci_info (dev,"Device will no longer be preserved across next Live Update\n" ); ser->nr_devices--;memset (dev_ser,0 ,sizeof (*dev_ser)); dev->liveupdate.outgoing =NULL ; +return 0 ; } -static int pci_liveupdate_preserve_device (struct pci_ser *ser,struct pci_dev *dev) +static int pci_liveupdate_preserve_device_again (struct pci_dev *dev) { -int i; +if (!dev->liveupdate.outgoing->refcount) { +pci_WARN (dev,1 ,"Preserved device with 0 refcount!\n" ); +return -EINVAL ; + } -if (dev->liveupdate.outgoing) +/* +* Endpoint devices should not be preserved more than once. Bridges are +* preserved once for every downstream device that is preserved. +*/ +if (!dev->subordinate)return -EBUSY ; + dev->liveupdate.outgoing->refcount++; +return 0 ; +} + +static int __pci_liveupdate_preserve_device (struct pci_ser *ser,struct pci_dev *dev) +{ +int i; +if (ser->nr_devices == ser->max_nr_devices)return -ENOSPC ;
@@ -312,6 +348,52 @@ static int pci_liveupdate_preserve_device(struct pci_ser *ser, struct pci_dev *dreturn -ENOSPC ; } +static int pci_liveupdate_preserve_device (struct pci_ser *ser,struct pci_dev *dev) +{ +if (dev->liveupdate.outgoing) +return pci_liveupdate_preserve_device_again (dev); + +return __pci_liveupdate_preserve_device (ser, dev); +} + +#define for_each_pci_dev_in_path (_d, _start, _end) \ + for ((_d) = (_start); (_d) != (_end); (_d) = (_d)->bus->self) + +static void __pci_liveupdate_unpreserve_path (struct pci_ser *ser, +struct pci_dev *start, +struct pci_dev *end) +{ +struct pci_dev *dev; + +for_each_pci_dev_in_path (dev, start, end) { +if (pci_liveupdate_unpreserve_device (ser, dev)) +return ; + } +} + +static void pci_liveupdate_unpreserve_path (struct pci_ser *ser, +struct pci_dev *start) +{ +__pci_liveupdate_unpreserve_path (ser, start,/*end=*/ NULL ); +} + +static int pci_liveupdate_preserve_path (struct pci_ser *ser, +struct pci_dev *start) +{ +struct pci_dev *dev; +int ret; + +for_each_pci_dev_in_path (dev, start,NULL ) { + ret =pci_liveupdate_preserve_device (ser, dev); +if (ret) { +__pci_liveupdate_unpreserve_path (ser, start, dev); +return ret; + } + } + +return 0 ; +} +/** * pci_liveupdate_preserve() - Preserve a PCI device across Live Update * @dev: The PCI device to preserve.
@@ -321,6 +403,9 @@ static int pci_liveupdate_preserve_device(struct pci_ser *ser, struct pci_dev *d* pci_liveupdate_preserve() from their struct liveupdate_file_handler * preserve() callback to ensure the outgoing struct pci_ser is already set up. * +* pci_liveupdate_preserve() automatically preserves all bridges upstream of +* @dev. +* * Returns: 0 on success, <0 on failure. */ int pci_liveupdate_preserve (struct pci_dev *dev)
@@ -336,7 +421,7 @@ int pci_liveupdate_preserve(struct pci_dev *dev)if (IS_ERR (ser))return PTR_ERR (ser); -return pci_liveupdate_preserve_device (ser, dev); +return pci_liveupdate_preserve_path (ser, dev); }EXPORT_SYMBOL_GPL (pci_liveupdate_preserve);
@@ -349,6 +434,9 @@ EXPORT_SYMBOL_GPL(pci_liveupdate_preserve);* pci_liveupdate_unpreserve() from their struct liveupdate_file_handler * unpreserve() callback to ensure the outgoing struct pci_ser is already set * up. +* +* pci_liveupdate_unpreserve() automatically unpreserves all bridges upstream of +* @dev. */ void pci_liveupdate_unpreserve (struct pci_dev *dev) {
@@ -362,7 +450,7 @@ void pci_liveupdate_unpreserve(struct pci_dev *dev)return ; } -pci_liveupdate_unpreserve_device (ser, dev); +pci_liveupdate_unpreserve_path (ser, dev); }EXPORT_SYMBOL_GPL (pci_liveupdate_unpreserve);
@@ -534,29 +622,41 @@ void pci_liveupdate_cleanup_device(struct pci_dev *dev) } } -static void pci_liveupdate_finish_device (struct pci_ser *ser,struct pci_dev *dev) +static int pci_liveupdate_finish_device (struct pci_ser *ser,struct pci_dev *dev) {if (!dev->liveupdate.incoming) {pci_warn (dev,"Cannot finish preserving an unpreserved device\n" ); -return ; +return -EINVAL ; } -if (dev->liveupdate.incoming->refcount !=1 ) { -pci_WARN (dev,1 ,"Preserved device has a corrupted refcount!\n" ); -return ; +if (!dev->liveupdate.incoming->refcount) { +pci_WARN (dev,1 ,"Preserved device has a 0 refcount!\n" ); +return -EINVAL ; }/* -* Drop the refcount so this device does not get treated as an incoming -* device again, e.g. in case pci_liveupdate_setup_device() gets called -* again because the device is hot-plugged. +* Decrement the refcount so this device does not get treated as an +* incoming device again, e.g. in case pci_liveupdate_setup_device() +* gets called again because the device is hot-plugged. */ - dev->liveupdate.incoming->refcount =0 ; +if (--dev->liveupdate.incoming->refcount) +return 0 ;pci_info (dev,"Device is finished participating in Live Update\n" ); dev->liveupdate.incoming =NULL ; ser->nr_devices--;pci_liveupdate_flb_put_incoming (); +return 0 ; +} + +static void pci_liveupdate_finish_path (struct pci_ser *ser,struct pci_dev *start) +{ +struct pci_dev *dev; + +for_each_pci_dev_in_path (dev, start,NULL ) { +if (pci_liveupdate_finish_device (ser, dev)) +return ; + } }/**
@@ -568,6 +668,8 @@ static void pci_liveupdate_finish_device(struct pci_ser *ser, struct pci_dev *de* Update. Drivers must call pci_liveupdate_finish() from their struct * liveupdate_file_handler finish() callback to ensure the incoming struct * pci_ser is allocated. +* +* pci_liveupdate_finish() automatically finishes all bridges upstream of @dev. */ void pci_liveupdate_finish (struct pci_dev *dev) {
@@ -581,7 +683,7 @@ void pci_liveupdate_finish(struct pci_dev *dev)return ; } -pci_liveupdate_finish_device (incoming->ser, dev); +pci_liveupdate_finish_path (incoming->ser, dev);pci_liveupdate_flb_put_incoming (); }EXPORT_SYMBOL_GPL (pci_liveupdate_finish);
include/linux/kho/abi/pci.h +3 -2
@@ -23,7 +23,7 @@* incrementing the version number in the PCI_LUO_FLB_COMPATIBLE string. */ -#define PCI_LUO_FLB_COMPATIBLE "pci-v2" +#define PCI_LUO_FLB_COMPATIBLE "pci-v3"/** * struct pci_dev_ser - Serialized state about a single PCI device.
@@ -32,7 +32,8 @@* @bdf: The device's PCI bus, device, and function number. * @refcount: Reference count used by the PCI core to keep track of whether it * is done using a device's struct pci_dev_ser. The value of the -* refcount is equal to 1 when the struct pci_dev_ser is in use, and +* refcount is equal to the number of preserved devices at or below +* it in the PCI hierarchy when the struct pci_dev_ser is in use, and * 0 otherwise. */ struct pci_dev_ser {
Signature · 1 line
2.54.0.746.g67dd491aae-goog
Re: [PATCH v6 06/12] PCI: liveupdate: Auto-preserve upstream bridges across Live Update
Quoted 21 lines · David Matlack
When a PCI device is preserved across a Live Update, all of its upstream bridges up to the root port must also be preserved. This enables the PCI core and any drivers bound to the bridges to manage bridges correctly across a Live Update.
Notably, this will be used in subsequent commits to ensure that preserved devices can continue performing memory transactions without a disruption or change in routing.
To preserve bridges, the PCI core tracks the number of downstream devices preserved under each bridge using a reference count in struct
pci_dev_ser. This allows a bridge to remain preserved until all its downstream preserved devices are unpreserved or finish their participation in the Live Update.Signed-off-by David Matlack <[email protected]>--- drivers/pci/liveupdate.c | 136 +++++++++++++++++++++++++++++++----- include/linux/kho/abi/pci.h | 5 +- 2 files changed, 122 insertions(+), 19 deletions(-)
[...]
drivers/pci/liveupdate.c static int pci_liveupdate_preserve_device(struct pci_ser *ser, struct pci_dev *d · line 369
Quoted 12 lines
drivers/pci/liveupdate.c +12
-0+ +#define for_each_pci_dev_in_path (_d, _start, _end) \ + for ((_d) = (_start); (_d) != (_end); (_d) = (_d)->bus->self) + +static void __pci_liveupdate_unpreserve_path (struct pci_ser *ser, +struct pci_dev *start, +struct pci_dev *end) +{ +struct pci_dev *dev; + +for_each_pci_dev_in_path (dev, start, end) { +if (pci_liveupdate_unpreserve_device (ser, dev))
I might be reading this wrong but are we leaking some upstream devs if an intermediate node fails?
EP0 / Assume we have: RC -> B1 -> B2 \ EP1
and EP0 & EP1 were preserved successfully.
And then we try unpreserving EP1, we follow:
unpreserve EP1 -> unpreserve B2 failed due to a corruption.
This aborts the loop, skipping B1 and RC completely?
Their refcounts remain elevated, effectively leaking them as preserved state permanently? (i.e. if we unpreserve EP0 after this, B1 & RC will still get preserved).
Quoted 41 lines
drivers/pci/liveupdate.c +30
-0+return ; + } +} + +static void pci_liveupdate_unpreserve_path (struct pci_ser *ser, +struct pci_dev *start) +{ +__pci_liveupdate_unpreserve_path (ser, start,/*end=*/ NULL ); +} + +static int pci_liveupdate_preserve_path (struct pci_ser *ser, +struct pci_dev *start) +{ +struct pci_dev *dev; +int ret; + +for_each_pci_dev_in_path (dev, start,NULL ) { + ret =pci_liveupdate_preserve_device (ser, dev); +if (ret) { +__pci_liveupdate_unpreserve_path (ser, start, dev); +return ret; + } + } + +return 0 ; +} +/** * pci_liveupdate_preserve() - Preserve a PCI device across Live Update * @dev: The PCI device to preserve. @@ -321,6 +403,9 @@ static int pci_liveupdate_preserve_device(struct pci_ser *ser, struct pci_dev *d* pci_liveupdate_preserve() from their struct liveupdate_file_handler * preserve() callback to ensure the outgoing struct pci_ser is already set up. * +* pci_liveupdate_preserve() automatically preserves all bridges upstream of +* @dev. +* * Returns: 0 on success, <0 on failure. */ int pci_liveupdate_preserve (struct pci_dev *dev)
drivers/pci/liveupdate.c int pci_liveupdate_preserve(struct pci_dev *dev) · line 424
Quoted 5 lines
drivers/pci/liveupdate.c +1
-1@@ -336,7 +421,7 @@ int pci_liveupdate_preserve(struct pci_dev *dev)if (IS_ERR (ser))return PTR_ERR (ser); -return pci_liveupdate_preserve_device (ser, dev); +return pci_liveupdate_preserve_path (ser, dev);
Minor nit: I might be too nitpicky here (and it's NOT a strong opinion) but naming it pci_liveupdate_preserve_path_for_dev() reads better to me.
drivers/pci/liveupdate.c int pci_liveupdate_preserve(struct pci_dev *dev) · line 427
Quoted 3 lines
drivers/pci/liveupdate.c +0
-0}EXPORT_SYMBOL_GPL (pci_liveupdate_preserve);
[...]
Thanks,
Praan
Re: [PATCH v6 06/12] PCI: liveupdate: Auto-preserve upstream bridges across Live Update
Quoted 49 lines · Pranjal Shrivastava
Quoted 21 lines · David Matlack
When a PCI device is preserved across a Live Update, all of its upstream bridges up to the root port must also be preserved. This enables the PCI core and any drivers bound to the bridges to manage bridges correctly across a Live Update.
Notably, this will be used in subsequent commits to ensure that preserved devices can continue performing memory transactions without a disruption or change in routing.
To preserve bridges, the PCI core tracks the number of downstream devices preserved under each bridge using a reference count in struct
pci_dev_ser. This allows a bridge to remain preserved until all its downstream preserved devices are unpreserved or finish their participation in the Live Update.Signed-off-by David Matlack <[email protected]>--- drivers/pci/liveupdate.c | 136 +++++++++++++++++++++++++++++++----- include/linux/kho/abi/pci.h | 5 +- 2 files changed, 122 insertions(+), 19 deletions(-)[...]
drivers/pci/liveupdate.c static int pci_liveupdate_preserve_device(struct pci_ser *ser, struct pci_dev *d · line 369
Quoted 12 lines
drivers/pci/liveupdate.c +12
-0+ +#define for_each_pci_dev_in_path (_d, _start, _end) \ + for ((_d) = (_start); (_d) != (_end); (_d) = (_d)->bus->self) + +static void __pci_liveupdate_unpreserve_path (struct pci_ser *ser, +struct pci_dev *start, +struct pci_dev *end) +{ +struct pci_dev *dev; + +for_each_pci_dev_in_path (dev, start, end) { +if (pci_liveupdate_unpreserve_device (ser, dev))I might be reading this wrong but are we leaking some upstream devs if an intermediate node fails?
EP0 / Assume we have: RC -> B1 -> B2 \ EP1and EP0 & EP1 were preserved successfully.
Quoted 8 lines
And then we try unpreserving EP1, we follow:
unpreserve EP1 -> unpreserve B2 failed due to a corruption.
This aborts the loop, skipping B1 and RC completely?
Their refcounts remain elevated, effectively leaking them as preserved state permanently? (i.e. if we unpreserve EP0 after this, B1 & RC will still get preserved).
Yes, but that would only happen if there is some sort of kernel bug or silent data corruption. I guess we could proceed with trying to unpreserve the bridges upstream. But I opted to log a big warning and bail immediately.
pci_liveupdate_finish_path() has the same behavior BTW.
Quoted 45 lines
Quoted 45 lines
drivers/pci/liveupdate.c +30
-0+return ; + } +} + +static void pci_liveupdate_unpreserve_path (struct pci_ser *ser, +struct pci_dev *start) +{ +__pci_liveupdate_unpreserve_path (ser, start,/*end=*/ NULL ); +} + +static int pci_liveupdate_preserve_path (struct pci_ser *ser, +struct pci_dev *start) +{ +struct pci_dev *dev; +int ret; + +for_each_pci_dev_in_path (dev, start,NULL ) { + ret =pci_liveupdate_preserve_device (ser, dev); +if (ret) { +__pci_liveupdate_unpreserve_path (ser, start, dev); +return ret; + } + } + +return 0 ; +} +/** * pci_liveupdate_preserve() - Preserve a PCI device across Live Update * @dev: The PCI device to preserve. @@ -321,6 +403,9 @@ static int pci_liveupdate_preserve_device(struct pci_ser *ser, struct pci_dev *d* pci_liveupdate_preserve() from their struct liveupdate_file_handler * preserve() callback to ensure the outgoing struct pci_ser is already set up. * +* pci_liveupdate_preserve() automatically preserves all bridges upstream of +* @dev. +* * Returns: 0 on success, <0 on failure. */ int pci_liveupdate_preserve (struct pci_dev *dev)@@ -336,7 +421,7 @@ int pci_liveupdate_preserve(struct pci_dev *dev)if (IS_ERR (ser))return PTR_ERR (ser);
Quoted 5 lines
drivers/pci/liveupdate.c int pci_liveupdate_preserve(struct pci_dev *dev) · line 424
Quoted 2 lines
drivers/pci/liveupdate.c +1
-1-return pci_liveupdate_preserve_device (ser, dev); +return pci_liveupdate_preserve_path (ser, dev);Minor nit: I might be too nitpicky here (and it's NOT a strong opinion) but naming it
pci_liveupdate_preserve_path_for_dev()reads better to me.
Noted :). I'll keep the current name for now since that is pretty long, but if anyone else votes for it I'm happy to be overridden.
Quoted 8 lines
drivers/pci/liveupdate.c int pci_liveupdate_preserve(struct pci_dev *dev) · line 427
Quoted 3 lines
drivers/pci/liveupdate.c +0
-0}EXPORT_SYMBOL_GPL (pci_liveupdate_preserve);[...]
Thanks,
Praan
Re: [PATCH v6 06/12] PCI: liveupdate: Auto-preserve upstream bridges across Live Update
Quoted 59 lines · David Matlack
Quoted 49 lines · Pranjal Shrivastava
Quoted 21 lines · David Matlack
When a PCI device is preserved across a Live Update, all of its upstream bridges up to the root port must also be preserved. This enables the PCI core and any drivers bound to the bridges to manage bridges correctly across a Live Update.
Notably, this will be used in subsequent commits to ensure that preserved devices can continue performing memory transactions without a disruption or change in routing.
To preserve bridges, the PCI core tracks the number of downstream devices preserved under each bridge using a reference count in struct
pci_dev_ser. This allows a bridge to remain preserved until all its downstream preserved devices are unpreserved or finish their participation in the Live Update.Signed-off-by David Matlack <[email protected]>--- drivers/pci/liveupdate.c | 136 +++++++++++++++++++++++++++++++----- include/linux/kho/abi/pci.h | 5 +- 2 files changed, 122 insertions(+), 19 deletions(-)[...]
drivers/pci/liveupdate.c static int pci_liveupdate_preserve_device(struct pci_ser *ser, struct pci_dev *d · line 369
Quoted 12 lines
drivers/pci/liveupdate.c +12
-0+ +#define for_each_pci_dev_in_path (_d, _start, _end) \ + for ((_d) = (_start); (_d) != (_end); (_d) = (_d)->bus->self) + +static void __pci_liveupdate_unpreserve_path (struct pci_ser *ser, +struct pci_dev *start, +struct pci_dev *end) +{ +struct pci_dev *dev; + +for_each_pci_dev_in_path (dev, start, end) { +if (pci_liveupdate_unpreserve_device (ser, dev))I might be reading this wrong but are we leaking some upstream devs if an intermediate node fails?
EP0 / Assume we have: RC -> B1 -> B2 \ EP1and EP0 & EP1 were preserved successfully.
Quoted 8 lines
And then we try unpreserving EP1, we follow:
unpreserve EP1 -> unpreserve B2 failed due to a corruption.
This aborts the loop, skipping B1 and RC completely?
Their refcounts remain elevated, effectively leaking them as preserved state permanently? (i.e. if we unpreserve EP0 after this, B1 & RC will still get preserved).
Quoted 6 lines
Yes, but that would only happen if there is some sort of kernel bug or silent data corruption. I guess we could proceed with trying to unpreserve the bridges upstream. But I opted to log a big warning and bail immediately.
pci_liveupdate_finish_path()has the same behavior BTW.
Fair point. I agree we are in a broken state if we hit this.
I was originally thinking of a situation where we'd want to keep the failure localized. For example: unpreserve EP1 fails -> user sees the warning -> resets EP1 -> retries preserving it later.
But given the recent discussion/decision that retrieve operations will no longer be retried, I guess there isn't really a use-case for retrying anything. It makes sense to just bail here.
Quoted 46 lines
Quoted 46 lines
Quoted 46 lines
drivers/pci/liveupdate.c +30
-0+return ; + } +} + +static void pci_liveupdate_unpreserve_path (struct pci_ser *ser, +struct pci_dev *start) +{ +__pci_liveupdate_unpreserve_path (ser, start,/*end=*/ NULL ); +} + +static int pci_liveupdate_preserve_path (struct pci_ser *ser, +struct pci_dev *start) +{ +struct pci_dev *dev; +int ret; + +for_each_pci_dev_in_path (dev, start,NULL ) { + ret =pci_liveupdate_preserve_device (ser, dev); +if (ret) { +__pci_liveupdate_unpreserve_path (ser, start, dev); +return ret; + } + } + +return 0 ; +} +/** * pci_liveupdate_preserve() - Preserve a PCI device across Live Update * @dev: The PCI device to preserve. @@ -321,6 +403,9 @@ static int pci_liveupdate_preserve_device(struct pci_ser *ser, struct pci_dev *d* pci_liveupdate_preserve() from their struct liveupdate_file_handler * preserve() callback to ensure the outgoing struct pci_ser is already set up. * +* pci_liveupdate_preserve() automatically preserves all bridges upstream of +* @dev. +* * Returns: 0 on success, <0 on failure. */ int pci_liveupdate_preserve (struct pci_dev *dev)@@ -336,7 +421,7 @@ int pci_liveupdate_preserve(struct pci_dev *dev)if (IS_ERR (ser))return PTR_ERR (ser);
Quoted 8 lines
Quoted 5 lines
drivers/pci/liveupdate.c int pci_liveupdate_preserve(struct pci_dev *dev) · line 424
Quoted 2 lines
drivers/pci/liveupdate.c +1
-1-return pci_liveupdate_preserve_device (ser, dev); +return pci_liveupdate_preserve_path (ser, dev);Minor nit: I might be too nitpicky here (and it's NOT a strong opinion) but naming it
pci_liveupdate_preserve_path_for_dev()reads better to me.Noted :). I'll keep the current name for now since that is pretty long, but if anyone else votes for it I'm happy to be overridden.
Sounds good.
Thanks,
Praan
PATCH v6 7/12 PCI: Refactor matching logic for pci_dev_acs_ops
In reply to David MatlackRefactor the logic to match devices to pci_dev_acs_ops by factoring out the loop and device matching into its own routine. This eliminates some duplicate code between pci_dev_specific_enable_acs() and pci_dev_specific_disable_acs_redir(), and will also be used in a subsequent commit to check if a device requires device-specific enable_acs() during a Live Update.
No functional change intended.
--- drivers/pci/quirks.c | 50 ++++++++++++++++++-------------------------- 1 file changed, 20 insertions(+), 30 deletions(-)
drivers/pci/quirks.c +20 -30
@@ -5384,9 +5384,6 @@ static void pci_quirk_enable_intel_rp_mpc_acs(struct pci_dev *dev)*/ static int pci_quirk_enable_intel_pch_acs (struct pci_dev *dev) { -if (!pci_quirk_intel_pch_acs_match (dev)) -return -ENOTTY ; -if (pci_quirk_enable_intel_lpc_acs (dev)) {pci_warn (dev,"Failed to enable Intel PCH ACS quirk\n" );return 0 ;
@@ -5406,9 +5403,6 @@ static int pci_quirk_enable_intel_spt_pch_acs(struct pci_dev *dev)int pos;u32 cap, ctrl; -if (!pci_quirk_intel_spt_pch_acs_match (dev)) -return -ENOTTY ; - pos = dev->acs_cap;if (!pos)return -ENOTTY ;
@@ -5436,9 +5430,6 @@ static int pci_quirk_disable_intel_spt_pch_acs_redir(struct pci_dev *dev)int pos;u32 cap, ctrl; -if (!pci_quirk_intel_spt_pch_acs_match (dev)) -return -ENOTTY ; - pos = dev->acs_cap;if (!pos)return -ENOTTY ;
@@ -5458,22 +5449,25 @@ static int pci_quirk_disable_intel_spt_pch_acs_redir(struct pci_dev *dev)static const struct pci_dev_acs_ops {u16 vendor;u16 device; +bool (*match)(struct pci_dev *dev);int (*enable_acs)(struct pci_dev *dev);int (*disable_acs_redir)(struct pci_dev *dev); } pci_dev_acs_ops[] = { {PCI_VENDOR_ID_INTEL ,PCI_ANY_ID , + .match = pci_quirk_intel_pch_acs_match, .enable_acs = pci_quirk_enable_intel_pch_acs, }, {PCI_VENDOR_ID_INTEL ,PCI_ANY_ID , + .match = pci_quirk_intel_spt_pch_acs_match, .enable_acs = pci_quirk_enable_intel_spt_pch_acs, .disable_acs_redir = pci_quirk_disable_intel_spt_pch_acs_redir, }, }; -int pci_dev_specific_enable_acs (struct pci_dev *dev) +static const struct pci_dev_acs_ops *pci_dev_acs_ops_get (struct pci_dev *dev) {const struct pci_dev_acs_ops *p; -int i, ret; +int i;for (i =0 ; i <ARRAY_SIZE (pci_dev_acs_ops); i++) { p = &pci_dev_acs_ops[i];
@@ -5481,33 +5475,29 @@ int pci_dev_specific_enable_acs(struct pci_dev *dev) p->vendor == (u16)PCI_ANY_ID) && (p->device == dev->device || p->device == (u16 )PCI_ANY_ID ) && - p->enable_acs) { - ret = p->enable_acs (dev); -if (ret >=0 ) -return ret; - } + p->match(dev)) + return p; } +return NULL ; +} + +int pci_dev_specific_enable_acs (struct pci_dev *dev) +{ +const struct pci_dev_acs_ops *p =pci_dev_acs_ops_get (dev); + +if (p && p->enable_acs) +return p->enable_acs (dev); +return -ENOTTY ; }int pci_dev_specific_disable_acs_redir (struct pci_dev *dev) { -const struct pci_dev_acs_ops *p; -int i, ret; +const struct pci_dev_acs_ops *p =pci_dev_acs_ops_get (dev); -for (i =0 ; i <ARRAY_SIZE (pci_dev_acs_ops); i++) { - p = &pci_dev_acs_ops[i]; -if ((p->vendor == dev->vendor || - p->vendor == (u16 )PCI_ANY_ID ) && - (p->device == dev->device || - p->device == (u16 )PCI_ANY_ID ) && - p->disable_acs_redir) { - ret = p->disable_acs_redir (dev); -if (ret >=0 ) -return ret; - } - } +if (p && p->disable_acs_redir) +return p->disable_acs_redir (dev);return -ENOTTY ; }
Signature · 1 line
2.54.0.746.g67dd491aae-goog
Re: [PATCH v6 07/12] PCI: Refactor matching logic for pci_dev_acs_ops
Quoted 14 lines · David Matlack
Refactor the logic to match devices to
pci_dev_acs_opsby factoring out the loop and device matching into its own routine. This eliminates some duplicate code betweenpci_dev_specific_enable_acs()andpci_dev_specific_disable_acs_redir(), and will also be used in a subsequent commit to check if a device requires device-specificenable_acs()during a Live Update.No functional change intended.
Signed-off-by David Matlack <[email protected]>--- drivers/pci/quirks.c | 50 ++++++++++++++++++-------------------------- 1 file changed, 20 insertions(+), 30 deletions(-)
[...]
Quoted 22 lines
} pci_dev_acs_ops[] = {
drivers/pci/quirks.c +4
-2{PCI_VENDOR_ID_INTEL ,PCI_ANY_ID , + .match = pci_quirk_intel_pch_acs_match, .enable_acs = pci_quirk_enable_intel_pch_acs, }, { PCI_VENDOR_ID_INTEL, PCI_ANY_ID, + .match = pci_quirk_intel_spt_pch_acs_match, .enable_acs = pci_quirk_enable_intel_spt_pch_acs, .disable_acs_redir = pci_quirk_disable_intel_spt_pch_acs_redir, }, }; -int pci_dev_specific_enable_acs (struct pci_dev *dev) +static const struct pci_dev_acs_ops *pci_dev_acs_ops_get (struct pci_dev *dev) {const struct pci_dev_acs_ops *p; -int i, ret; +int i;for (i =0 ; i <ARRAY_SIZE (pci_dev_acs_ops); i++) { p = &pci_dev_acs_ops[i];
drivers/pci/quirks.c int pci_dev_specific_enable_acs(struct pci_dev *dev) · line 5479
Quoted 10 lines
drivers/pci/quirks.c +2
-5@@ -5481,33 +5475,29 @@ int pci_dev_specific_enable_acs(struct pci_dev *dev) p->vendor == (u16)PCI_ANY_ID) && (p->device == dev->device || p->device == (u16 )PCI_ANY_ID ) && - p->enable_acs) { - ret = p->enable_acs (dev); -if (ret >=0 ) -return ret; - } + p->match(dev)) + return p;
Nit:
Should we check if (p->match != NULL) like we check for p->enable_acs & p->disable_acs_redir().
Otherwise, it seems like we're mandating the existence of a match op in the pci_dev_acs_ops here? Today, we just have two Intel entries in that array, both of which need the match op. However, AFAICT, it shouldn't be mandatory for future SoCs that might only need a simple vid + devid match
[...]
with that nit:
Thanks,
Praan
Re: [PATCH v6 07/12] PCI: Refactor matching logic for pci_dev_acs_ops
Quoted 55 lines · Pranjal Shrivastava
Quoted 14 lines · David Matlack
Refactor the logic to match devices to
pci_dev_acs_opsby factoring out the loop and device matching into its own routine. This eliminates some duplicate code betweenpci_dev_specific_enable_acs()andpci_dev_specific_disable_acs_redir(), and will also be used in a subsequent commit to check if a device requires device-specificenable_acs()during a Live Update.No functional change intended.
Signed-off-by David Matlack <[email protected]>--- drivers/pci/quirks.c | 50 ++++++++++++++++++-------------------------- 1 file changed, 20 insertions(+), 30 deletions(-)[...]
Quoted 22 lines
} pci_dev_acs_ops[] = {
drivers/pci/quirks.c +4
-2{PCI_VENDOR_ID_INTEL ,PCI_ANY_ID , + .match = pci_quirk_intel_pch_acs_match, .enable_acs = pci_quirk_enable_intel_pch_acs, }, { PCI_VENDOR_ID_INTEL, PCI_ANY_ID, + .match = pci_quirk_intel_spt_pch_acs_match, .enable_acs = pci_quirk_enable_intel_spt_pch_acs, .disable_acs_redir = pci_quirk_disable_intel_spt_pch_acs_redir, }, }; -int pci_dev_specific_enable_acs (struct pci_dev *dev) +static const struct pci_dev_acs_ops *pci_dev_acs_ops_get (struct pci_dev *dev) {const struct pci_dev_acs_ops *p; -int i, ret; +int i;for (i =0 ; i <ARRAY_SIZE (pci_dev_acs_ops); i++) { p = &pci_dev_acs_ops[i];drivers/pci/quirks.c int pci_dev_specific_enable_acs(struct pci_dev *dev) · line 5479
Quoted 10 lines
drivers/pci/quirks.c +2
-5@@ -5481,33 +5475,29 @@ int pci_dev_specific_enable_acs(struct pci_dev *dev) p->vendor == (u16)PCI_ANY_ID) && (p->device == dev->device || p->device == (u16 )PCI_ANY_ID ) && - p->enable_acs) { - ret = p->enable_acs (dev); -if (ret >=0 ) -return ret; - } + p->match(dev)) + return p;Nit:
Should we check if (p->match!= NULL) like we check forp->enable_acs&p->disable_acs_redir().
Quoted 4 lines
Otherwise, it seems like we're mandating the existence of a match op in the
pci_dev_acs_opshere? Today, we just have two Intel entries in that array, both of which need the match op. However, AFAICT, it shouldn't be mandatory for future SoCs that might only need a simple vid + devid match
*shrug*
I would usually say those future SoCs should be the ones to make it optional if and when they need to.
But making p->matc optional now isn't so bad:
for (i = 0; i < ARRAY_SIZE(pci_dev_acs_ops); i++) {
p = &pci_dev_acs_ops[i];
if ((p->vendor == dev->vendor ||
p->vendor == (u16)PCI_ANY_ID) &&
(p->device == dev->device ||- p->device == (u16)PCI_ANY_ID) &&
- p->enable_acs) {
- ret = p->enable_acs(dev);
- if (ret >= 0)
- return ret;
+ p->device == (u16)PCI_ANY_ID)) {
+ if (!p->match || p->match(dev))
+ return p;
}
}I can include this in v7 if you would like.
Quoted 8 lines
[...]
with that nit:
Reviewed-by Pranjal Shrivastava <[email protected]>Thanks,
Praan
Re: [PATCH v6 07/12] PCI: Refactor matching logic for pci_dev_acs_ops
Quoted 61 lines · David Matlack
Quoted 55 lines · Pranjal Shrivastava
Quoted 14 lines · David Matlack
Refactor the logic to match devices to
pci_dev_acs_opsby factoring out the loop and device matching into its own routine. This eliminates some duplicate code betweenpci_dev_specific_enable_acs()andpci_dev_specific_disable_acs_redir(), and will also be used in a subsequent commit to check if a device requires device-specificenable_acs()during a Live Update.No functional change intended.
Signed-off-by David Matlack <[email protected]>--- drivers/pci/quirks.c | 50 ++++++++++++++++++-------------------------- 1 file changed, 20 insertions(+), 30 deletions(-)[...]
Quoted 22 lines
} pci_dev_acs_ops[] = {
drivers/pci/quirks.c +4
-2{PCI_VENDOR_ID_INTEL ,PCI_ANY_ID , + .match = pci_quirk_intel_pch_acs_match, .enable_acs = pci_quirk_enable_intel_pch_acs, }, { PCI_VENDOR_ID_INTEL, PCI_ANY_ID, + .match = pci_quirk_intel_spt_pch_acs_match, .enable_acs = pci_quirk_enable_intel_spt_pch_acs, .disable_acs_redir = pci_quirk_disable_intel_spt_pch_acs_redir, }, }; -int pci_dev_specific_enable_acs (struct pci_dev *dev) +static const struct pci_dev_acs_ops *pci_dev_acs_ops_get (struct pci_dev *dev) {const struct pci_dev_acs_ops *p; -int i, ret; +int i;for (i =0 ; i <ARRAY_SIZE (pci_dev_acs_ops); i++) { p = &pci_dev_acs_ops[i];drivers/pci/quirks.c int pci_dev_specific_enable_acs(struct pci_dev *dev) · line 5479
Quoted 10 lines
drivers/pci/quirks.c +2
-5@@ -5481,33 +5475,29 @@ int pci_dev_specific_enable_acs(struct pci_dev *dev) p->vendor == (u16)PCI_ANY_ID) && (p->device == dev->device || p->device == (u16 )PCI_ANY_ID ) && - p->enable_acs) { - ret = p->enable_acs (dev); -if (ret >=0 ) -return ret; - } + p->match(dev)) + return p;Nit:
Should we check if (p->match!= NULL) like we check forp->enable_acs&p->disable_acs_redir().Quoted 4 lines
Otherwise, it seems like we're mandating the existence of a match op in the
pci_dev_acs_opshere? Today, we just have two Intel entries in that array, both of which need the match op. However, AFAICT, it shouldn't be mandatory for future SoCs that might only need a simple vid + devid match
Quoted 4 lines
*shrug*
I would usually say those future SoCs should be the ones to make it optional if and when they need to.
Well.. that's fair I guess.
Quoted 19 lines
But making
p->matcoptional now isn't so bad:for (i = 0; i < ARRAY_SIZE(pci_dev_acs_ops); i++) { p = &pci_dev_acs_ops[i]; if ((p->vendor == dev->vendor || p->vendor == (u16)PCI_ANY_ID) && (p->device == dev->device ||drivers/pci/quirks.c +3
-5- p->device == (u16)PCI_ANY_ID) && - p->enable_acs) { - ret = p->enable_acs (dev); -if (ret >=0 ) -return ret; + p->device == (u16)PCI_ANY_ID)) { +if (!p->match || p->match (dev)) +return p; } }
Quoted 1 line
I can include this in v7 if you would like.
I don't have a strong opinion here, this should be fine. It's just that we have NULL checks for p->enable_acs and disable_acs_redir too. It'd be nice to keep the same pattern.
Thanks,
Praan
PATCH v6 8/12 PCI: liveupdate: Inherit ACS flags in incoming preserved devices
In reply to David MatlackInherit Access Control Services (ACS) flags on all incoming preserved devices (endpoints and upstream bridges) during a Live Update.
Inheriting ACS flags avoids changing routing rules while memory transactions are in flight from preserved devices. This is also strictly necessary to ensure that IOMMU group assignments do not change across a Live Update for preserved devices, as changing ACS configurations can split or merge IOMMU groups.
Cache the inherited ACS controls established by the previous kernel in struct pci_dev so that ACS controls do not change after a reset (pci_restore_state() calls pci_enable_acs()).
To simplify ACS inheritance, reject preserving any devices that require quirks to enable ACS as those quirks would also have to take Live Update into account.
--- drivers/pci/liveupdate.c | 68 ++++++++++++++++++++++++++++++++++ drivers/pci/liveupdate.h | 11 ++++++ drivers/pci/pci.c | 5 +++ drivers/pci/pci.h | 5 +++ drivers/pci/quirks.c | 7 ++++ include/linux/pci_liveupdate.h | 6 +++ 6 files changed, 102 insertions(+)
drivers/pci/liveupdate.c +68 -0
@@ -71,6 +71,9 @@* * * The device cannot be a Virtual Function (VF). * +* * The device cannot require device-specific quirks to enable Access +* Control Services (ACS). +* * Driver Binding * ============== *
@@ -113,6 +116,18 @@* This enables the PCI core and any drivers bound to the bridge to participate * in the Live Update so that preserved endpoints can continue issuing memory * transactions during the Live Update. +* +* Handling Preserved Devices +* ========================== +* +* The PCI core treats preserved devices differently than non-preserved devices. +* This section enumerates those differences. +* +* * The PCI core inherits all ACS flags enabled on incoming preserved devices +* rather than assigning new ones. This ensures that TLPs are routed the same +* way after Live Update and ensures that IOMMU groups do not change. Note +* that a device will use its inherited ACS flags for the lifetime of its +* struct pci_dev (i.e. even after pci_liveupdate_finish()). */ #define pr_fmt (fmt) "PCI: liveupdate: " fmt
@@ -126,6 +141,7 @@#include <linux/pci.h> #include "liveupdate.h" +#include "pci.h" /** * struct pci_liveupdate_global - Global state for PCI Live Update support
@@ -319,6 +335,16 @@ static int __pci_liveupdate_preserve_device(struct pci_ser *ser, struct pci_dev {int i; +/* +* Do not preserve devices that rely on device-specific ACS equivalents +* (for now) since that would complicate keeping ACS constant across +* Live Update. +*/ +if (pci_need_dev_specific_enable_acs (dev)) { +pci_warn (dev,"Refusing to preserve device that relies on ACS quirks\n" ); +return -EINVAL ; + } +if (ser->nr_devices == ser->max_nr_devices)return -ENOSPC ;
@@ -598,6 +624,7 @@ void pci_liveupdate_setup_device(struct pci_dev *dev)pci_info (dev,"Device was preserved by previous kernel across Live Update\n" ); dev->liveupdate.incoming = dev_ser; + dev->liveupdate.was_preserved = true;/* * Hold the ref on the incoming FLB until pci_liveupdate_finish() so
@@ -688,6 +715,47 @@ void pci_liveupdate_finish(struct pci_dev *dev) }EXPORT_SYMBOL_GPL (pci_liveupdate_finish); +void pci_liveupdate_init_acs (struct pci_dev *dev) +{ +guard (rwsem_read)(&pci_liveupdate.rwsem); + +if (!dev->acs_cap || !dev->liveupdate.incoming) +return ; + +pci_read_config_word (dev, dev->acs_cap +PCI_ACS_CTRL , &dev->liveupdate.acs_ctrl); +} + +int pci_liveupdate_enable_acs (struct pci_dev *dev) +{ +u16 acs_ctrl = dev->liveupdate.acs_ctrl; +u16 acs_cap = dev->acs_cap; + +/* +* Use liveupdate.was_preserved instead of liveupdate.incoming since the +* device's ACS controls should not change even after the device is +* finished participating in the Live Update. +*/ +if (!dev->liveupdate.was_preserved) +return -EINVAL ; + +/* +* The previous kernel should not have preserved any devices that +* require device-specific quirks to enable ACS, but if such a device is +* detected, log a big warning and fall back to the normal enable ACS +* path. +*/ +if (pci_need_dev_specific_enable_acs (dev)) { +pci_warn (dev,"Device-specific quirk required to enable ACS!\n" ); +WARN_ON_ONCE (true); +return -EINVAL ; + } + +if (acs_cap) +pci_write_config_word (dev, acs_cap +PCI_ACS_CTRL , acs_ctrl); + +return 0 ; +} +/** * pci_liveupdate_is_incoming() - Check if a device is incoming-preserved * @dev: The PCI device to check
drivers/pci/liveupdate.h +11 -0
@@ -16,6 +16,8 @@ void pci_liveupdate_cleanup_device(struct pci_dev *dev);bool pci_liveupdate_scan_bridge_begin (struct pci_bus *bus,struct pci_dev *dev,int pass);void pci_liveupdate_scan_bridge_end (struct pci_dev *dev,int pass); +void pci_liveupdate_init_acs (struct pci_dev *dev); +int pci_liveupdate_enable_acs (struct pci_dev *dev);#else static inline void pci_liveupdate_setup_device (struct pci_dev *dev) {
@@ -35,6 +37,15 @@ static inline bool pci_liveupdate_scan_bridge_begin(struct pci_bus *bus,static inline void pci_liveupdate_scan_bridge_end (struct pci_dev *dev,int pass) { } + +static inline void pci_liveupdate_init_acs (struct pci_dev *dev) +{ +} + +static inline int pci_liveupdate_enable_acs (struct pci_dev *dev) +{ +return -EINVAL ; +}#endif #endif /* DRIVERS_PCI_LIVEUPDATE_H */
drivers/pci/pci.c +5 -0
@@ -33,6 +33,7 @@#include <asm/dma.h> #include <linux/aer.h> #include <linux/bitfield.h> +#include "liveupdate.h" #include "pci.h" DEFINE_MUTEX (pci_slot_mutex);
@@ -1017,6 +1018,9 @@ void pci_enable_acs(struct pci_dev *dev)bool enable_acs = false;int pos; +if (!pci_liveupdate_enable_acs (dev)) +return ; +/* If an iommu is present we start with kernel default caps */ if (pci_acs_enable) {if (pci_dev_specific_enable_acs (dev))
@@ -3657,6 +3661,7 @@ void pci_acs_init(struct pci_dev *dev)pci_read_config_word (dev, pos +PCI_ACS_CAP , &dev->acs_capabilities);pci_disable_broken_acs_cap (dev); +pci_liveupdate_init_acs (dev); }/**
drivers/pci/pci.h +5 -0
@@ -1062,6 +1062,7 @@ void pci_acs_init(struct pci_dev *dev);void pci_enable_acs (struct pci_dev *dev);#ifdef CONFIG_PCI_QUIRKS int pci_dev_specific_acs_enabled (struct pci_dev *dev,u16 acs_flags); +bool pci_need_dev_specific_enable_acs (struct pci_dev *dev);int pci_dev_specific_enable_acs (struct pci_dev *dev);int pci_dev_specific_disable_acs_redir (struct pci_dev *dev);void pci_disable_broken_acs_cap (struct pci_dev *pdev);
@@ -1072,6 +1073,10 @@ static inline int pci_dev_specific_acs_enabled(struct pci_dev *dev, {return -ENOTTY ; } +static inline bool pci_need_dev_specific_enable_acs (struct pci_dev *dev) +{ +return false; +}static inline int pci_dev_specific_enable_acs (struct pci_dev *dev) {return -ENOTTY ;
drivers/pci/quirks.c +7 -0
@@ -5482,6 +5482,13 @@ static const struct pci_dev_acs_ops *pci_dev_acs_ops_get(struct pci_dev *dev)return NULL ; } +bool pci_need_dev_specific_enable_acs (struct pci_dev *dev) +{ +const struct pci_dev_acs_ops *p =pci_dev_acs_ops_get (dev); + +return p && p->enable_acs; +} +int pci_dev_specific_enable_acs (struct pci_dev *dev) {const struct pci_dev_acs_ops *p =pci_dev_acs_ops_get (dev);
include/linux/pci_liveupdate.h +6 -0
@@ -17,14 +17,20 @@* struct pci_liveupdate - PCI Live Update state for a struct pci_dev * @outgoing: State preserved for the next kernel. * @incoming: State preserved by the previous kernel. +* @acs_ctrl: ACS features established by the previous kernel. * @inherit_buses: True if the PCI core should inherit the secondary and * subordinate bus numbers assigned to this device due to * an ongoing Live Update. +* @was_preserved: True if this struct pci_dev was preserved by the previous +* kernel. Unlike @incoming, this field is not cleared after +* the device is finished participating in Live Update. */ struct pci_liveupdate {struct pci_dev_ser *outgoing;struct pci_dev_ser *incoming; +u16 acs_ctrl;bool inherit_buses; +bool was_preserved; };struct pci_dev ;
Signature · 1 line
2.54.0.746.g67dd491aae-goog
Re: [PATCH v6 08/12] PCI: liveupdate: Inherit ACS flags in incoming preserved devices
Quoted 27 lines · David Matlack
Inherit Access Control Services (ACS) flags on all incoming preserved devices (endpoints and upstream bridges) during a Live Update.
Inheriting ACS flags avoids changing routing rules while memory transactions are in flight from preserved devices. This is also strictly necessary to ensure that IOMMU group assignments do not change across a Live Update for preserved devices, as changing ACS configurations can split or merge IOMMU groups.
Cache the inherited ACS controls established by the previous kernel in struct
pci_devso that ACS controls do not change after a reset (pci_restore_state()callspci_enable_acs()).To simplify ACS inheritance, reject preserving any devices that require quirks to enable ACS as those quirks would also have to take Live Update into account.
Signed-off-by David Matlack <[email protected]>--- drivers/pci/liveupdate.c | 68 ++++++++++++++++++++++++++++++++++ drivers/pci/liveupdate.h | 11 ++++++ drivers/pci/pci.c | 5 +++ drivers/pci/pci.h | 5 +++ drivers/pci/quirks.c | 7 ++++ include/linux/pci_liveupdate.h | 6 +++ 6 files changed, 102 insertions(+)
[...]
drivers/pci/liveupdate.c void pci_liveupdate_finish(struct pci_dev *dev) · line 725
Quoted 9 lines
drivers/pci/liveupdate.c +8
-0+void pci_liveupdate_init_acs (struct pci_dev *dev) +{ +guard (rwsem_read)(&pci_liveupdate.rwsem); + +if (!dev->acs_cap || !dev->liveupdate.incoming) +return ; + +pci_read_config_word (dev, dev->acs_cap +PCI_ACS_CTRL , &dev->liveupdate.acs_ctrl);
I might be thinking out loud here, but as an attacker, this motivates me to somehow hack the EP FW to mis-report the PCI_ACS_CTRL register across a liveupdate to fool the incoming kernel. If the FW feeds a 0, it silently strips ACS protections.
Should we also serialize ACS state in ser somehow to ensure we aren't fooled by something like this?
Quoted 11 lines
drivers/pci/liveupdate.c +11
-0+} + +int pci_liveupdate_enable_acs (struct pci_dev *dev) +{ +u16 acs_ctrl = dev->liveupdate.acs_ctrl; +u16 acs_cap = dev->acs_cap; + +/* +* Use liveupdate.was_preserved instead of liveupdate.incoming since the +* device's ACS controls should not change even after the device is +* finished participating in the Live Update.
drivers/pci/liveupdate.c void pci_liveupdate_finish(struct pci_dev *dev) · line 746
Quoted 10 lines
drivers/pci/liveupdate.c +10
-0+*/ +if (!dev->liveupdate.was_preserved) +return -EINVAL ; + +/* +* The previous kernel should not have preserved any devices that +* require device-specific quirks to enable ACS, but if such a device is +* detected, log a big warning and fall back to the normal enable ACS +* path. +*/
Nit: It might be worth adding a note here that this can also happen if a new device-specific ACS quirk is introduced in the incoming kernel for a device that was preserved by the old kernel (which didn't have the quirk). In such cases, the two kernels are essentially non-LUO-compatible..
Quoted 5 lines
drivers/pci/liveupdate.c +5
-0+if (pci_need_dev_specific_enable_acs (dev)) { +pci_warn (dev,"Device-specific quirk required to enable ACS!\n" ); +WARN_ON_ONCE (true); +return -EINVAL ; + }
drivers/pci/liveupdate.c void pci_liveupdate_finish(struct pci_dev *dev) · line 761
Quoted 10 lines
drivers/pci/liveupdate.c +7
-0+ +if (acs_cap) +pci_write_config_word (dev, acs_cap +PCI_ACS_CTRL , acs_ctrl); + +return 0 ; +} +/** * pci_liveupdate_is_incoming() - Check if a device is incoming-preserved * @dev: The PCI device to check
[...]
Thanks,
Praan
Re: [PATCH v6 08/12] PCI: liveupdate: Inherit ACS flags in incoming preserved devices
Quoted 32 lines · Pranjal Shrivastava
Quoted 27 lines · David Matlack
Inherit Access Control Services (ACS) flags on all incoming preserved devices (endpoints and upstream bridges) during a Live Update.
Inheriting ACS flags avoids changing routing rules while memory transactions are in flight from preserved devices. This is also strictly necessary to ensure that IOMMU group assignments do not change across a Live Update for preserved devices, as changing ACS configurations can split or merge IOMMU groups.
Cache the inherited ACS controls established by the previous kernel in struct
pci_devso that ACS controls do not change after a reset (pci_restore_state()callspci_enable_acs()).To simplify ACS inheritance, reject preserving any devices that require quirks to enable ACS as those quirks would also have to take Live Update into account.
Signed-off-by David Matlack <[email protected]>--- drivers/pci/liveupdate.c | 68 ++++++++++++++++++++++++++++++++++ drivers/pci/liveupdate.h | 11 ++++++ drivers/pci/pci.c | 5 +++ drivers/pci/pci.h | 5 +++ drivers/pci/quirks.c | 7 ++++ include/linux/pci_liveupdate.h | 6 +++ 6 files changed, 102 insertions(+)[...]
Quoted 1 line
Quoted 13 lines
drivers/pci/liveupdate.c void pci_liveupdate_finish(struct pci_dev *dev) · line 725
Quoted 8 lines
drivers/pci/liveupdate.c +8
-0+void pci_liveupdate_init_acs (struct pci_dev *dev) +{ +guard (rwsem_read)(&pci_liveupdate.rwsem); + +if (!dev->acs_cap || !dev->liveupdate.incoming) +return ; + +pci_read_config_word (dev, dev->acs_cap +PCI_ACS_CTRL , &dev->liveupdate.acs_ctrl);I might be thinking out loud here, but as an attacker, this motivates me to somehow hack the EP FW to mis-report the
PCI_ACS_CTRLregister across a liveupdate to fool the incoming kernel. If the FW feeds a 0, it silently strips ACS protections.
Minor note here: I used "0" as an example value, I'm aware that'll effectively disable ACS and kernel will enforce more security.
My point was that a FW exploit can meddle with the bitfields of the ACS_CTRL to spoof and mis-report the ACS flags.
Additionally, we might give rise to use-cases that start depending on this, for e.g. if someone wants to change ACS policies in the new kernel, the FW may silently update these flags across a kexec.
Quoted 4 lines
Should we also serialize ACS state in ser somehow to ensure we aren't fooled by something like this?
Thanks,
Praan
Re: [PATCH v6 08/12] PCI: liveupdate: Inherit ACS flags in incoming preserved devices
Quoted 2 lines · Pranjal Shrivastava
My point was that a FW exploit can meddle with the bitfields of the
ACS_CTRLto spoof and mis-report the ACS flags.
Devices can also ignore the ACS flags. I don't think this is an area where we should be worrying about devices being actively hostile.
Jason
Re: [PATCH v6 08/12] PCI: liveupdate: Inherit ACS flags in incoming preserved devices
Quoted 7 lines · Jason Gunthorpe
Quoted 2 lines · Pranjal Shrivastava
My point was that a FW exploit can meddle with the bitfields of the
ACS_CTRLto spoof and mis-report the ACS flags.Devices can also ignore the ACS flags. I don't think this is an area where we should be worrying about devices being actively hostile.
I'm wondering what happens if we preserve IOMMU groups across a kexec, but a switch's ACS capability is dropped or the ACS_RR bit gets cleared? The incoming kernel assumes that it's the same ACS cap from the old one
Now, the incoming kernel restores the groups assuming they're still isolated, but the hardware no longer enforces it, silently allowing DMAs & breaking isolation?
Thanks,
Praan
Re: [PATCH v6 08/12] PCI: liveupdate: Inherit ACS flags in incoming preserved devices
Quoted 9 lines · Pranjal Shrivastava
Quoted 7 lines · Jason Gunthorpe
Quoted 2 lines · Pranjal Shrivastava
My point was that a FW exploit can meddle with the bitfields of the
ACS_CTRLto spoof and mis-report the ACS flags.Devices can also ignore the ACS flags. I don't think this is an area where we should be worrying about devices being actively hostile.
Quoted 7 lines
I'm wondering what happens if we preserve IOMMU groups across a kexec, but a switch's ACS capability is dropped or the
ACS_RRbit gets cleared? The incoming kernel assumes that it's the same ACS cap from the old oneNow, the incoming kernel restores the groups assuming they're still isolated, but the hardware no longer enforces it, silently allowing DMAs & breaking isolation?
Again, to clarify, I'm aware that we aren't preserving IOMMU groups, the incoming kernel has to rebuild the groups. My concern is that if the ACS_RR bit is cleared during the kexec window, the produced grouping would be different than the old kernel. What happens if two devices on the same bridge were assigned to 2 different VMs?
Thanks,
Praan
Re: [PATCH v6 08/12] PCI: liveupdate: Inherit ACS flags in incoming preserved devices
Quoted 19 lines · Pranjal Shrivastava
Quoted 9 lines · Pranjal Shrivastava
Quoted 7 lines · Jason Gunthorpe
Quoted 2 lines · Pranjal Shrivastava
My point was that a FW exploit can meddle with the bitfields of the
ACS_CTRLto spoof and mis-report the ACS flags.Devices can also ignore the ACS flags. I don't think this is an area where we should be worrying about devices being actively hostile.
Quoted 7 lines
I'm wondering what happens if we preserve IOMMU groups across a kexec, but a switch's ACS capability is dropped or the
ACS_RRbit gets cleared? The incoming kernel assumes that it's the same ACS cap from the old oneNow, the incoming kernel restores the groups assuming they're still isolated, but the hardware no longer enforces it, silently allowing DMAs & breaking isolation?
Quoted 5 lines
Again, to clarify, I'm aware that we aren't preserving IOMMU groups, the incoming kernel has to rebuild the groups. My concern is that if the
ACS_RRbit is cleared during the kexec window, the produced grouping would be different than the old kernel. What happens if two devices on the same bridge were assigned to 2 different VMs?
In this patch the kernel reads PCI_ACS_CTRL after kexec to determine the bridge's state and uses that information going forward. We don't assume that if ACS_RR was set on the previous kernel then it is still set now.
So if ACS_RR were cleared during kexec somehow, the new kernel would see that and place those devices into the same group. Someitme after that (I'm a little fuzzy on the iommufd restore path during Live Update) the kernel would try and fail to restore the 2 devices into separate domains because they are in the same group and thus the 2 different VMs would fail to come up.
Of course maybe ACS_RR can somehow get cleared after the kernel reads it, but at that point the issue has nothing to do with Live Update.
So that's what would happen if ACS_RR ever got cleared during kexec and seems reasonable to me?
Re: [PATCH v6 08/12] PCI: liveupdate: Inherit ACS flags in incoming preserved devices
In reply to Pranjal ShrivastavaQuoted 46 lines · Pranjal Shrivastava
Quoted 27 lines · David Matlack
Inherit Access Control Services (ACS) flags on all incoming preserved devices (endpoints and upstream bridges) during a Live Update.
Inheriting ACS flags avoids changing routing rules while memory transactions are in flight from preserved devices. This is also strictly necessary to ensure that IOMMU group assignments do not change across a Live Update for preserved devices, as changing ACS configurations can split or merge IOMMU groups.
Cache the inherited ACS controls established by the previous kernel in struct
pci_devso that ACS controls do not change after a reset (pci_restore_state()callspci_enable_acs()).To simplify ACS inheritance, reject preserving any devices that require quirks to enable ACS as those quirks would also have to take Live Update into account.
Signed-off-by David Matlack <[email protected]>--- drivers/pci/liveupdate.c | 68 ++++++++++++++++++++++++++++++++++ drivers/pci/liveupdate.h | 11 ++++++ drivers/pci/pci.c | 5 +++ drivers/pci/pci.h | 5 +++ drivers/pci/quirks.c | 7 ++++ include/linux/pci_liveupdate.h | 6 +++ 6 files changed, 102 insertions(+)[...]
drivers/pci/liveupdate.c void pci_liveupdate_finish(struct pci_dev *dev) · line 725
Quoted 9 lines
drivers/pci/liveupdate.c +8
-0+void pci_liveupdate_init_acs (struct pci_dev *dev) +{ +guard (rwsem_read)(&pci_liveupdate.rwsem); + +if (!dev->acs_cap || !dev->liveupdate.incoming) +return ; + +pci_read_config_word (dev, dev->acs_cap +PCI_ACS_CTRL , &dev->liveupdate.acs_ctrl);I might be thinking out loud here, but as an attacker, this motivates me to somehow hack the EP FW to mis-report the
PCI_ACS_CTRLregister across a liveupdate to fool the incoming kernel. If the FW feeds a 0, it silently strips ACS protections.
Quoted 2 lines
Should we also serialize ACS state in ser somehow to ensure we aren't fooled by something like this?
What does "EP FW" mean?
Does such an attacker even need Live Update to attack the system? It seems like such an attacker could route TLPs in whatever malicious way they want regardless of Live Update.
Quoted 19 lines
Quoted 19 lines
drivers/pci/liveupdate.c +18
-0+} + +int pci_liveupdate_enable_acs (struct pci_dev *dev) +{ +u16 acs_ctrl = dev->liveupdate.acs_ctrl; +u16 acs_cap = dev->acs_cap; + +/* +* Use liveupdate.was_preserved instead of liveupdate.incoming since the +* device's ACS controls should not change even after the device is +* finished participating in the Live Update. +*/ +if (!dev->liveupdate.was_preserved) +return -EINVAL ; + +/* +* The previous kernel should not have preserved any devices that +* require device-specific quirks to enable ACS, but if such a device is
Quoted 8 lines
drivers/pci/liveupdate.c void pci_liveupdate_finish(struct pci_dev *dev) · line 746
Quoted 3 lines
drivers/pci/liveupdate.c +3
-0+* detected, log a big warning and fall back to the normal enable ACS +* path. +*/ Nit: It might be worth adding a note here that this can also happen if a new device-specific ACS quirk is introduced in the incoming kernel for a device that was preserved by the old kernel (which didn't have the quirk). In such cases, the two kernels are essentially non-LUO-compatible..
Yes will do.
Quoted 21 lines
Quoted 6 lines
drivers/pci/liveupdate.c +5
-0+if (pci_need_dev_specific_enable_acs (dev)) { +pci_warn (dev,"Device-specific quirk required to enable ACS!\n" ); +WARN_ON_ONCE (true); +return -EINVAL ; + }drivers/pci/liveupdate.c void pci_liveupdate_finish(struct pci_dev *dev) · line 761
Quoted 10 lines
drivers/pci/liveupdate.c +7
-0+ +if (acs_cap) +pci_write_config_word (dev, acs_cap +PCI_ACS_CTRL , acs_ctrl); + +return 0 ; +} +/** * pci_liveupdate_is_incoming() - Check if a device is incoming-preserved * @dev: The PCI device to check [...]
Thanks,
Praan
Re: [PATCH v6 08/12] PCI: liveupdate: Inherit ACS flags in incoming preserved devices
Quoted 47 lines · David Matlack
Quoted 46 lines · Pranjal Shrivastava
Quoted 27 lines · David Matlack
Inherit Access Control Services (ACS) flags on all incoming preserved devices (endpoints and upstream bridges) during a Live Update.
Inheriting ACS flags avoids changing routing rules while memory transactions are in flight from preserved devices. This is also strictly necessary to ensure that IOMMU group assignments do not change across a Live Update for preserved devices, as changing ACS configurations can split or merge IOMMU groups.
Cache the inherited ACS controls established by the previous kernel in struct
pci_devso that ACS controls do not change after a reset (pci_restore_state()callspci_enable_acs()).To simplify ACS inheritance, reject preserving any devices that require quirks to enable ACS as those quirks would also have to take Live Update into account.
Signed-off-by David Matlack <[email protected]>--- drivers/pci/liveupdate.c | 68 ++++++++++++++++++++++++++++++++++ drivers/pci/liveupdate.h | 11 ++++++ drivers/pci/pci.c | 5 +++ drivers/pci/pci.h | 5 +++ drivers/pci/quirks.c | 7 ++++ include/linux/pci_liveupdate.h | 6 +++ 6 files changed, 102 insertions(+)[...]
drivers/pci/liveupdate.c void pci_liveupdate_finish(struct pci_dev *dev) · line 725
Quoted 9 lines
drivers/pci/liveupdate.c +8
-0+void pci_liveupdate_init_acs (struct pci_dev *dev) +{ +guard (rwsem_read)(&pci_liveupdate.rwsem); + +if (!dev->acs_cap || !dev->liveupdate.incoming) +return ; + +pci_read_config_word (dev, dev->acs_cap +PCI_ACS_CTRL , &dev->liveupdate.acs_ctrl);I might be thinking out loud here, but as an attacker, this motivates me to somehow hack the EP FW to mis-report the
PCI_ACS_CTRLregister across a liveupdate to fool the incoming kernel. If the FW feeds a 0, it silently strips ACS protections.
Quoted 4 lines
Quoted 2 lines
Should we also serialize ACS state in ser somehow to ensure we aren't fooled by something like this?
What does "EP FW" mean?
I was referring to the Endpoint Firmware (basically any SW running on a downstream device)
Quoted 5 lines
Does such an attacker even need Live Update to attack the system? It seems like such an attacker could route TLPs in whatever malicious way they want regardless of Live Update.
I agree that compromised PCIe devices are a menace anyway. But I was talking about the potential window opened up by Live Update here, suppose we have Device A & B assigned to 2 different VMs (implying they are in separate IOMMU groups because the switch set ACS_RR = 1).
Now, the attacker has an opportunity with Liveupdate, since the devices are already assigned, if *somehow* it flips a bit like ACS_RR, the incoming kernel might see both the devices in the same IOMMU group. Who detects this case and what happens if this happens if the devices are kept assigned to these VMs?
Thanks,
Praan
Re: [PATCH v6 08/12] PCI: liveupdate: Inherit ACS flags in incoming preserved devices
Quoted 68 lines · Pranjal Shrivastava
Quoted 47 lines · David Matlack
Quoted 46 lines · Pranjal Shrivastava
Quoted 27 lines · David Matlack
Inherit Access Control Services (ACS) flags on all incoming preserved devices (endpoints and upstream bridges) during a Live Update.
Inheriting ACS flags avoids changing routing rules while memory transactions are in flight from preserved devices. This is also strictly necessary to ensure that IOMMU group assignments do not change across a Live Update for preserved devices, as changing ACS configurations can split or merge IOMMU groups.
Cache the inherited ACS controls established by the previous kernel in struct
pci_devso that ACS controls do not change after a reset (pci_restore_state()callspci_enable_acs()).To simplify ACS inheritance, reject preserving any devices that require quirks to enable ACS as those quirks would also have to take Live Update into account.
Signed-off-by David Matlack <[email protected]>--- drivers/pci/liveupdate.c | 68 ++++++++++++++++++++++++++++++++++ drivers/pci/liveupdate.h | 11 ++++++ drivers/pci/pci.c | 5 +++ drivers/pci/pci.h | 5 +++ drivers/pci/quirks.c | 7 ++++ include/linux/pci_liveupdate.h | 6 +++ 6 files changed, 102 insertions(+)[...]
drivers/pci/liveupdate.c void pci_liveupdate_finish(struct pci_dev *dev) · line 725
Quoted 9 lines
drivers/pci/liveupdate.c +8
-0+void pci_liveupdate_init_acs (struct pci_dev *dev) +{ +guard (rwsem_read)(&pci_liveupdate.rwsem); + +if (!dev->acs_cap || !dev->liveupdate.incoming) +return ; + +pci_read_config_word (dev, dev->acs_cap +PCI_ACS_CTRL , &dev->liveupdate.acs_ctrl);I might be thinking out loud here, but as an attacker, this motivates me to somehow hack the EP FW to mis-report the
PCI_ACS_CTRLregister across a liveupdate to fool the incoming kernel. If the FW feeds a 0, it silently strips ACS protections.Quoted 4 lines
Quoted 2 lines
Should we also serialize ACS state in ser somehow to ensure we aren't fooled by something like this?
What does "EP FW" mean?
I was referring to the Endpoint Firmware (basically any SW running on a downstream device)
Quoted 5 lines
Does such an attacker even need Live Update to attack the system? It seems like such an attacker could route TLPs in whatever malicious way they want regardless of Live Update.
I agree that compromised PCIe devices are a menace anyway. But I was talking about the potential window opened up by Live Update here, suppose we have Device A & B assigned to 2 different VMs (implying they are in separate IOMMU groups because the switch set
ACS_RR= 1).
Quoted 5 lines
Now, the attacker has an opportunity with Liveupdate, since the devices are already assigned, if *somehow* it flips a bit like
ACS_RR, the incoming kernel might see both the devices in the same IOMMU group. Who detects this case and what happens if this happens if the devices are kept assigned to these VMs?
I suspect that would be caught during the restore of the iommufds to which those devices are attached.
The kernel would attempt to restore each device into a separate domain (since that's how they were preserved before the Live Update) but that will fail because they are in the same group now. Even if one of the devices was not preserved, that will still cause a failure when a user tries to start using that device (e.g. to try to attach it to a different VM).
Re: [PATCH v6 08/12] PCI: liveupdate: Inherit ACS flags in incoming preserved devices
Quoted 78 lines · David Matlack
Quoted 68 lines · Pranjal Shrivastava
Quoted 47 lines · David Matlack
Quoted 46 lines · Pranjal Shrivastava
Quoted 27 lines · David Matlack
Inherit Access Control Services (ACS) flags on all incoming preserved devices (endpoints and upstream bridges) during a Live Update.
Inheriting ACS flags avoids changing routing rules while memory transactions are in flight from preserved devices. This is also strictly necessary to ensure that IOMMU group assignments do not change across a Live Update for preserved devices, as changing ACS configurations can split or merge IOMMU groups.
Cache the inherited ACS controls established by the previous kernel in struct
pci_devso that ACS controls do not change after a reset (pci_restore_state()callspci_enable_acs()).To simplify ACS inheritance, reject preserving any devices that require quirks to enable ACS as those quirks would also have to take Live Update into account.
Signed-off-by David Matlack <[email protected]>--- drivers/pci/liveupdate.c | 68 ++++++++++++++++++++++++++++++++++ drivers/pci/liveupdate.h | 11 ++++++ drivers/pci/pci.c | 5 +++ drivers/pci/pci.h | 5 +++ drivers/pci/quirks.c | 7 ++++ include/linux/pci_liveupdate.h | 6 +++ 6 files changed, 102 insertions(+)[...]
drivers/pci/liveupdate.c void pci_liveupdate_finish(struct pci_dev *dev) · line 725
Quoted 9 lines
drivers/pci/liveupdate.c +8
-0+void pci_liveupdate_init_acs (struct pci_dev *dev) +{ +guard (rwsem_read)(&pci_liveupdate.rwsem); + +if (!dev->acs_cap || !dev->liveupdate.incoming) +return ; + +pci_read_config_word (dev, dev->acs_cap +PCI_ACS_CTRL , &dev->liveupdate.acs_ctrl);I might be thinking out loud here, but as an attacker, this motivates me to somehow hack the EP FW to mis-report the
PCI_ACS_CTRLregister across a liveupdate to fool the incoming kernel. If the FW feeds a 0, it silently strips ACS protections.Quoted 4 lines
Quoted 2 lines
Should we also serialize ACS state in ser somehow to ensure we aren't fooled by something like this?
What does "EP FW" mean?
I was referring to the Endpoint Firmware (basically any SW running on a downstream device)
Quoted 5 lines
Does such an attacker even need Live Update to attack the system? It seems like such an attacker could route TLPs in whatever malicious way they want regardless of Live Update.
I agree that compromised PCIe devices are a menace anyway. But I was talking about the potential window opened up by Live Update here, suppose we have Device A & B assigned to 2 different VMs (implying they are in separate IOMMU groups because the switch set
ACS_RR= 1).Quoted 5 lines
Now, the attacker has an opportunity with Liveupdate, since the devices are already assigned, if *somehow* it flips a bit like
ACS_RR, the incoming kernel might see both the devices in the same IOMMU group. Who detects this case and what happens if this happens if the devices are kept assigned to these VMs?I suspect that would be caught during the restore of the iommufds to which those devices are attached.
Quoted 6 lines
The kernel would attempt to restore each device into a separate domain (since that's how they were preserved before the Live Update) but that will fail because they are in the same group now. Even if one of the devices was not preserved, that will still cause a failure when a user tries to start using that device (e.g. to try to attach it to a different VM).
Yes, IOMMU would eventually catch-up but what about the DMAs that were done already? Say to an NVMe disk? We'll have to wipe the entire disk in such a case? Also, we wouldn't know the offending device..
If such situations aren't a problem, then I guess it's fine.
Thanks,
Praan
Re: [PATCH v6 08/12] PCI: liveupdate: Inherit ACS flags in incoming preserved devices
In reply to Pranjal ShrivastavaQuoted 2 lines · Pranjal Shrivastava
Now, the attacker has an opportunity with Liveupdate, since the devices are already assigned, if *somehow* it flips a bit like
ACS_RR, the
If this is possible then your environment is already security broken, no need to involve live update.
Jason
Re: [PATCH v6 08/12] PCI: liveupdate: Inherit ACS flags in incoming preserved devices
Quoted 7 lines · Jason Gunthorpe
Quoted 2 lines · Pranjal Shrivastava
Now, the attacker has an opportunity with Liveupdate, since the devices are already assigned, if *somehow* it flips a bit like
ACS_RR, theIf this is possible then your environment is already security broken, no need to involve live update.
Ack. Alright.
Thanks,
Praan
PATCH v6 9/12 PCI: liveupdate: Inherit ARI Forwarding Enable on preserved bridges
In reply to David MatlackInherit the ARI Forwarding Enable on preserved bridges and update pci_dev->ari_enabled accordingly during a Live Update. This ensures that the preserved devices on the bridge's secondary bus can be identified with the same expanded 8-bit function number after a Live Update.
--- drivers/pci/liveupdate.c | 18 ++++++++++++++++++ drivers/pci/liveupdate.h | 6 ++++++ drivers/pci/pci.c | 8 +++++++- 3 files changed, 31 insertions(+), 1 deletion(-)
drivers/pci/liveupdate.c +18 -0
@@ -128,6 +128,10 @@* way after Live Update and ensures that IOMMU groups do not change. Note * that a device will use its inherited ACS flags for the lifetime of its * struct pci_dev (i.e. even after pci_liveupdate_finish()). +* +* * The PCI core inherits ARI Forwarding Enable on all bridges with downstream +* preserved devices to ensure that all preserved devices on the bridge's +* secondary bus are addressable after the Live Update. */ #define pr_fmt (fmt) "PCI: liveupdate: " fmt
@@ -756,6 +760,20 @@ int pci_liveupdate_enable_acs(struct pci_dev *dev)return 0 ; } +int pci_liveupdate_configure_ari (struct pci_dev *dev) +{ +u16 val; + +guard (rwsem_read)(&pci_liveupdate.rwsem); + +if (!dev->liveupdate.incoming) +return -EINVAL ; + +pcie_capability_read_word (dev,PCI_EXP_DEVCTL2 , &val); + dev->ari_enabled = !!(val &PCI_EXP_DEVCTL2_ARI ); +return 0 ; +} +/** * pci_liveupdate_is_incoming() - Check if a device is incoming-preserved * @dev: The PCI device to check
drivers/pci/liveupdate.h +6 -0
@@ -18,6 +18,7 @@ bool pci_liveupdate_scan_bridge_begin(struct pci_bus *bus, struct pci_dev *dev,void pci_liveupdate_scan_bridge_end (struct pci_dev *dev,int pass);void pci_liveupdate_init_acs (struct pci_dev *dev);int pci_liveupdate_enable_acs (struct pci_dev *dev); +int pci_liveupdate_configure_ari (struct pci_dev *dev);#else static inline void pci_liveupdate_setup_device (struct pci_dev *dev) {
@@ -46,6 +47,11 @@ static inline int pci_liveupdate_enable_acs(struct pci_dev *dev) {return -EINVAL ; } + +static inline int pci_liveupdate_configure_ari (struct pci_dev *dev) +{ +return -EINVAL ; +}#endif #endif /* DRIVERS_PCI_LIVEUPDATE_H */
drivers/pci/pci.c +7 -1
@@ -3495,7 +3495,7 @@ void pci_configure_ari(struct pci_dev *dev)u32 cap;struct pci_dev *bridge; -if (pcie_ari_disabled || !pci_is_pcie (dev) || dev->devfn) +if (!pci_is_pcie (dev) || dev->devfn)return ; bridge = dev->bus->self;
@@ -3506,6 +3506,12 @@ void pci_configure_ari(struct pci_dev *dev)if (!(cap &PCI_EXP_DEVCAP2_ARI ))return ; +if (!pci_liveupdate_configure_ari (bridge)) +return ; + +if (pcie_ari_disabled) +return ; +if (pci_find_ext_capability (dev,PCI_EXT_CAP_ID_ARI )) {pcie_capability_set_word (bridge,PCI_EXP_DEVCTL2 ,PCI_EXP_DEVCTL2_ARI );
Signature · 1 line
2.54.0.746.g67dd491aae-goog
[email protected]
AI reviewRe: [PATCH v6 09/12] PCI: liveupdate: Inherit ARI Forwarding Enable on preserved bridges
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
Pre-existing issues:
- [High] Bitfield data race when updating ari_enabled on a shared bridge device. --
commit 9819403e762e1d3e8a471294f5aa07554019d8b4
Author: David Matlack <[email protected]>
PCI: liveupdate: Inherit ARI Forwarding Enable on preserved bridges
Inherit the ARI Forwarding Enable on preserved bridges and update pci_dev->ari_enabled accordingly during a Live Update. This ensures that the preserved devices on the bridge's secondary bus can be identified with the same expanded 8-bit function number after a Live Update.
Quoted 4 lines
drivers/pci/liveupdate.c +0
-0
[ ... ]
Quoted 5 lines
drivers/pci/liveupdate.c +1
-0@@ -756,6 +760,20 @@ int pci_liveupdate_enable_acs(struct pci_dev *dev)return 0 ; } +int pci_liveupdate_configure_ari (struct pci_dev *dev)
drivers/pci/liveupdate.c int pci_liveupdate_enable_acs(struct pci_dev *dev) · line 773
Quoted 10 lines
drivers/pci/liveupdate.c +10
-0+{ +u16 val; + +guard (rwsem_read)(&pci_liveupdate.rwsem); + +if (!dev->liveupdate.incoming) +return -EINVAL ; + +pcie_capability_read_word (dev,PCI_EXP_DEVCTL2 , &val); + dev->ari_enabled = !!(val &PCI_EXP_DEVCTL2_ARI );
[Severity: High]
This isn't a bug introduced by this patch, but could this bitfield update cause a data race on the shared bridge device?
Since C bitfield updates are not atomic, modifying dev->ari_enabled compiles down to a read-modify-write of the entire surrounding machine word.
If another thread concurrently modifies adjacent bitfields on the same bridge device (for example, if the pcieport driver is unbound from the bridge via sysfs, invoking pci_disable_msi() and pci_clear_master() to update msi_enabled and is_busmaster), couldn't one of the updates be lost?
Since pci_setup_device(), which calls pci_configure_ari(), does not hold device_lock(bridge), these paths can execute concurrently. This might corrupt the bridge's state by silently dropping updates like MSI enablement, potentially leading to interrupt routing failures or crashes.
The new code appears to duplicate this unprotected modification pattern from the preexisting fallback path in pci_configure_ari().
Quoted 2 lines
drivers/pci/liveupdate.c +2
-0+return 0 ; +}
Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=9
Re: [PATCH v6 09/12] PCI: liveupdate: Inherit ARI Forwarding Enable on preserved bridges
In reply to David MatlackQuoted 31 lines · David Matlack
Inherit the ARI Forwarding Enable on preserved bridges and update
pci_dev->ari_enabledaccordingly during a Live Update. This ensures that the preserved devices on the bridge's secondary bus can be identified with the same expanded 8-bit function number after a Live Update.Signed-off-by David Matlack <[email protected]>--- drivers/pci/liveupdate.c | 18 ++++++++++++++++++ drivers/pci/liveupdate.h | 6 ++++++ drivers/pci/pci.c | 8 +++++++- 3 files changed, 31 insertions(+), 1 deletion(-)drivers/pci/liveupdate.c +4
-0@@ -128,6 +128,10 @@* way after Live Update and ensures that IOMMU groups do not change. Note * that a device will use its inherited ACS flags for the lifetime of its * struct pci_dev (i.e. even after pci_liveupdate_finish()). +* +* * The PCI core inherits ARI Forwarding Enable on all bridges with downstream +* preserved devices to ensure that all preserved devices on the bridge's +* secondary bus are addressable after the Live Update. */ #define pr_fmt (fmt) "PCI: liveupdate: " fmt@@ -756,6 +760,20 @@ int pci_liveupdate_enable_acs(struct pci_dev *dev)return 0 ; }
drivers/pci/liveupdate.c int pci_liveupdate_enable_acs(struct pci_dev *dev) · line 772
Quoted 10 lines
drivers/pci/liveupdate.c +10
-0+int pci_liveupdate_configure_ari (struct pci_dev *dev) +{ +u16 val; + +guard (rwsem_read)(&pci_liveupdate.rwsem); + +if (!dev->liveupdate.incoming) +return -EINVAL ; + +pcie_capability_read_word (dev,PCI_EXP_DEVCTL2 , &val);
Again, I might be thinking out loud here, but since these are hot-pluggable devices, with some FW / SW running on them, I'm a little worried while assuming the HW registers can be trusted across a kexec.
Say, if the bridge experiences a reset (e.g. link drop etc) during the kexec blackout, the PCI_EXP_DEVCTL2 register could revert to its default state, meaning the ARI bit will be 0.
In that scenario, pci_liveupdate_configure_ari() will read 0, set bridge->ari_enabled = false, and bypass the pci_configure_ari() logic as well, permanently leaving ARI disabled on the bridge. Any preserved downstream devices with function numbers > 7 will instantly become unaddressable, breaking the Live Update. Even if that's desired it gets hard to identify why the Liveupdate broke.
Should ari_enabled be serialized with bridge's pci_ser to ensure we correctly restore / match it in case HW changed it during the kexec?
drivers/pci/liveupdate.c int pci_liveupdate_enable_acs(struct pci_dev *dev) · line 776
Quoted 4 lines
drivers/pci/liveupdate.c +4
-0+ dev->ari_enabled = !!(val &PCI_EXP_DEVCTL2_ARI ); +return 0 ; +} +
[...]
Thanks,
Praan
Re: [PATCH v6 09/12] PCI: liveupdate: Inherit ARI Forwarding Enable on preserved bridges
Quoted 47 lines · Pranjal Shrivastava
Quoted 31 lines · David Matlack
Inherit the ARI Forwarding Enable on preserved bridges and update
pci_dev->ari_enabledaccordingly during a Live Update. This ensures that the preserved devices on the bridge's secondary bus can be identified with the same expanded 8-bit function number after a Live Update.Signed-off-by David Matlack <[email protected]>--- drivers/pci/liveupdate.c | 18 ++++++++++++++++++ drivers/pci/liveupdate.h | 6 ++++++ drivers/pci/pci.c | 8 +++++++- 3 files changed, 31 insertions(+), 1 deletion(-)drivers/pci/liveupdate.c +4
-0@@ -128,6 +128,10 @@* way after Live Update and ensures that IOMMU groups do not change. Note * that a device will use its inherited ACS flags for the lifetime of its * struct pci_dev (i.e. even after pci_liveupdate_finish()). +* +* * The PCI core inherits ARI Forwarding Enable on all bridges with downstream +* preserved devices to ensure that all preserved devices on the bridge's +* secondary bus are addressable after the Live Update. */ #define pr_fmt (fmt) "PCI: liveupdate: " fmt@@ -756,6 +760,20 @@ int pci_liveupdate_enable_acs(struct pci_dev *dev)return 0 ; }drivers/pci/liveupdate.c int pci_liveupdate_enable_acs(struct pci_dev *dev) · line 772
Quoted 10 lines
drivers/pci/liveupdate.c +10
-0+int pci_liveupdate_configure_ari (struct pci_dev *dev) +{ +u16 val; + +guard (rwsem_read)(&pci_liveupdate.rwsem); + +if (!dev->liveupdate.incoming) +return -EINVAL ; + +pcie_capability_read_word (dev,PCI_EXP_DEVCTL2 , &val);Again, I might be thinking out loud here, but since these are hot-pluggable devices, with some FW / SW running on them, I'm a little worried while assuming the HW registers can be trusted across a kexec.
Quoted 3 lines
Say, if the bridge experiences a reset (e.g. link drop etc) during the kexec blackout, the
PCI_EXP_DEVCTL2register could revert to its default state, meaning the ARI bit will be 0.
This does seem like something to be concerned about, but realistically I think if you get a PCIe error I'm not sure the incoming kernel is equipped to handle it at all :\
Just resuming the driver is going to fail too, I don't know how VFIO can learn and forward the event, and so on..
But maybe it is worth being a little more defensive here
Jason
Re: [PATCH v6 09/12] PCI: liveupdate: Inherit ARI Forwarding Enable on preserved bridges
Quoted 34 lines · Jason Gunthorpe
Quoted 32 lines · Pranjal Shrivastava
Quoted 31 lines · David Matlack
Inherit the ARI Forwarding Enable on preserved bridges and update
pci_dev->ari_enabledaccordingly during a Live Update. This ensures that the preserved devices on the bridge's secondary bus can be identified with the same expanded 8-bit function number after a Live Update.Signed-off-by David Matlack <[email protected]>--- drivers/pci/liveupdate.c | 18 ++++++++++++++++++ drivers/pci/liveupdate.h | 6 ++++++ drivers/pci/pci.c | 8 +++++++- 3 files changed, 31 insertions(+), 1 deletion(-)drivers/pci/liveupdate.c +4
-0@@ -128,6 +128,10 @@* way after Live Update and ensures that IOMMU groups do not change. Note * that a device will use its inherited ACS flags for the lifetime of its * struct pci_dev (i.e. even after pci_liveupdate_finish()). +* +* * The PCI core inherits ARI Forwarding Enable on all bridges with downstream +* preserved devices to ensure that all preserved devices on the bridge's +* secondary bus are addressable after the Live Update. */ #define pr_fmt (fmt) "PCI: liveupdate: " fmt@@ -756,6 +760,20 @@ int pci_liveupdate_enable_acs(struct pci_dev *dev)return 0 ; }
Quoted 14 lines
Quoted 6 lines
Quoted 6 lines
drivers/pci/liveupdate.c +6
-0+int pci_liveupdate_configure_ari (struct pci_dev *dev) +{ +u16 val; + +guard (rwsem_read)(&pci_liveupdate.rwsem); +Quoted 8 lines
drivers/pci/liveupdate.c int pci_liveupdate_enable_acs(struct pci_dev *dev) · line 772
Quoted 4 lines
drivers/pci/liveupdate.c +4
-0+if (!dev->liveupdate.incoming) +return -EINVAL ; + +pcie_capability_read_word (dev,PCI_EXP_DEVCTL2 , &val);Again, I might be thinking out loud here, but since these are hot-pluggable devices, with some FW / SW running on them, I'm a little worried while assuming the HW registers can be trusted across a kexec.
This is, in-part [*], why I explicitly read the capability rather than caching what the previous kernel thinks it was in struct pci_dev_ser.
In other words, the kerenl does not assume that hardware registers remain unchanged across kexec. It reads them after kexec to determine what state the device is in and inherits that.
[*] The other reason is just to keep the ABI as minimal as possible.
Quoted 4 lines
Quoted 3 lines
Say, if the bridge experiences a reset (e.g. link drop etc) during the kexec blackout, the
PCI_EXP_DEVCTL2register could revert to its default state, meaning the ARI bit will be 0.
Quoted 8 lines
This does seem like something to be concerned about, but realistically I think if you get a PCIe error I'm not sure the incoming kernel is equipped to handle it at all :\
Just resuming the driver is going to fail too, I don't know how VFIO can learn and forward the event, and so on..
But maybe it is worth being a little more defensive here
If this were to happen, the kernel would see that ARI is disabled on the bridge after kexec and proceed with that state (ARI disabled). Devices (devfn) 8+ on the bus would not be available to use or restore (the kernel would not discover them during scanning). It should be fairly obvious to the user that something went wrong (devices they are trying to restore do not even exist) and they can reboot at that point to recover.
This should be extremely rare though as it requires a PCIe error that affects the bridge to race with kexec.
This seems like a reasonable way to handle this scenario, at least in the initial version. We can always look at more gracefully handling PCIe errors during kexec for Live Update if-and-when there is value.
PATCH v6 10/12 PCI: liveupdate: Freeze preservation status during shutdown
In reply to David MatlackFreeze a device's outgoing preservation status (preserved or not preserved) during shutdown. This enables the PCI core and drivers to safely make decisions based on the device's preservation status during shutdown.
Note that pci_liveupdate_freeze() is triggered by the PCI core rather than from drivers participating in Live Update so that all devices can have their status frozen (i.e. prevent non-preserved devices from getting preserved late).
--- drivers/pci/liveupdate.c | 16 ++++++++++++++++ drivers/pci/liveupdate.h | 5 +++++ drivers/pci/pci-driver.c | 2 ++ include/linux/pci_liveupdate.h | 3 +++ 4 files changed, 26 insertions(+)
drivers/pci/liveupdate.c +16 -0
@@ -297,6 +297,11 @@ static int pci_liveupdate_unpreserve_device(struct pci_ser *ser, struct pci_dev {struct pci_dev_ser *dev_ser = dev->liveupdate.outgoing; +if (dev->liveupdate.frozen) { +pci_warn (dev,"Cannot unpreserve device after it is frozen!\n" ); +return -EINVAL ; + } +if (!dev_ser) {pci_warn (dev,"Cannot unpreserve device that is not preserved\n" );return -EINVAL ;
@@ -380,6 +385,11 @@ static int __pci_liveupdate_preserve_device(struct pci_ser *ser, struct pci_devstatic int pci_liveupdate_preserve_device (struct pci_ser *ser,struct pci_dev *dev) { +if (dev->liveupdate.frozen) { +pci_warn (dev,"Cannot preserve device after it is frozen!\n" ); +return -EINVAL ; + } +if (dev->liveupdate.outgoing)return pci_liveupdate_preserve_device_again (dev);
@@ -653,6 +663,12 @@ void pci_liveupdate_cleanup_device(struct pci_dev *dev) } } +void pci_liveupdate_freeze (struct pci_dev *dev) +{ +guard (rwsem_write)(&pci_liveupdate.rwsem); + dev->liveupdate.frozen =1 ; +} +static int pci_liveupdate_finish_device (struct pci_ser *ser,struct pci_dev *dev) {if (!dev->liveupdate.incoming) {
drivers/pci/liveupdate.h +5 -0
@@ -13,6 +13,7 @@#ifdef CONFIG_PCI_LIVEUPDATE void pci_liveupdate_setup_device (struct pci_dev *dev);void pci_liveupdate_cleanup_device (struct pci_dev *dev); +void pci_liveupdate_freeze (struct pci_dev *dev);bool pci_liveupdate_scan_bridge_begin (struct pci_bus *bus,struct pci_dev *dev,int pass);void pci_liveupdate_scan_bridge_end (struct pci_dev *dev,int pass);
@@ -28,6 +29,10 @@ static inline void pci_liveupdate_cleanup_device(struct pci_dev *dev) { } +static inline void pci_liveupdate_freeze (struct pci_dev *dev) +{ +} +static inline bool pci_liveupdate_scan_bridge_begin (struct pci_bus *bus,struct pci_dev *dev,int pass)
drivers/pci/pci-driver.c +2 -0
@@ -21,6 +21,7 @@#include <linux/acpi.h> #include <linux/dma-map-ops.h> #include <linux/iommu.h> +#include "liveupdate.h" #include "pci.h" #include "pcie/portdrv.h"
@@ -536,6 +537,7 @@ static void pci_device_shutdown(struct device *dev)struct pci_dev *pci_dev =to_pci_dev (dev);struct pci_driver *drv = pci_dev->driver; +pci_liveupdate_freeze (pci_dev);pm_runtime_resume (dev);if (drv && drv->shutdown)
include/linux/pci_liveupdate.h +3 -0
@@ -24,6 +24,8 @@* @was_preserved: True if this struct pci_dev was preserved by the previous * kernel. Unlike @incoming, this field is not cleared after * the device is finished participating in Live Update. +* @frozen: True if the outgoing preservation status of this device is frozen +* and thus cannot be changed. */ struct pci_liveupdate {struct pci_dev_ser *outgoing;
@@ -31,6 +33,7 @@ struct pci_liveupdate {u16 acs_ctrl;bool inherit_buses;bool was_preserved; +bool frozen; };struct pci_dev ;
Signature · 1 line
2.54.0.746.g67dd491aae-goog
Re: [PATCH v6 10/12] PCI: liveupdate: Freeze preservation status during shutdown
Quoted 11 lines · David Matlack
Freeze a device's outgoing preservation status (preserved or not preserved) during shutdown. This enables the PCI core and drivers to safely make decisions based on the device's preservation status during shutdown.
Note that
pci_liveupdate_freeze()is triggered by the PCI core rather than from drivers participating in Live Update so that all devices can have their status frozen (i.e. prevent non-preserved devices from getting preserved late).Signed-off-by David Matlack <[email protected]>
Thanks,
Praan
PATCH v6 11/12 PCI: liveupdate: Do not disable bus mastering on preserved devices during kexec
In reply to David MatlackDo not disable bus mastering on outgoing preserved devices during pci_device_shutdown() for kexec.
Preserved devices must be allowed to perform memory transactions during a Live Update to ensure continuous operation. Clearing the bus mastering bit would prevent these devices from issuing any memory requests while the new kernel boots.
Because bridges upstream of preserved endpoint devices are also automatically preserved, this change also avoids clearing bus mastering on them. This is critical because clearing bus mastering on an upstream bridge prevents the bridge from forwarding memory requests upstream (i.e. it would prevent the endpoint device from accessing system RAM and doing peer-to-peer transactions with devices not downstream of the bridge).
--- drivers/pci/liveupdate.c | 11 +++++++++++ drivers/pci/liveupdate.h | 6 ++++++ drivers/pci/pci-driver.c | 7 +++++-- 3 files changed, 22 insertions(+), 2 deletions(-)
drivers/pci/liveupdate.c +11 -0
@@ -132,6 +132,10 @@* * The PCI core inherits ARI Forwarding Enable on all bridges with downstream * preserved devices to ensure that all preserved devices on the bridge's * secondary bus are addressable after the Live Update. +* +* * The PCI core does not disable bus mastering on outgoing preserved devices +* during kexec. This allows preserved devices to issue memory transactions +* throughout the Live Update. */ #define pr_fmt (fmt) "PCI: liveupdate: " fmt
@@ -790,6 +794,13 @@ int pci_liveupdate_configure_ari(struct pci_dev *dev)return 0 ; } +bool pci_liveupdate_is_outgoing (struct pci_dev *dev) +{ +guard (rwsem_read)(&pci_liveupdate.rwsem); +pci_WARN_ONCE (dev, !dev->liveupdate.frozen,"Preservation status is unstable!\n" ); +return dev->liveupdate.outgoing; +} +/** * pci_liveupdate_is_incoming() - Check if a device is incoming-preserved * @dev: The PCI device to check
drivers/pci/liveupdate.h +6 -0
@@ -20,6 +20,7 @@ void pci_liveupdate_scan_bridge_end(struct pci_dev *dev, int pass);void pci_liveupdate_init_acs (struct pci_dev *dev);int pci_liveupdate_enable_acs (struct pci_dev *dev);int pci_liveupdate_configure_ari (struct pci_dev *dev); +bool pci_liveupdate_is_outgoing (struct pci_dev *dev);#else static inline void pci_liveupdate_setup_device (struct pci_dev *dev) {
@@ -57,6 +58,11 @@ static inline int pci_liveupdate_configure_ari(struct pci_dev *dev) {return -EINVAL ; } + +static inline bool pci_liveupdate_is_outgoing (struct pci_dev *dev) +{ +return false; +}#endif #endif /* DRIVERS_PCI_LIVEUPDATE_H */
drivers/pci/pci-driver.c +5 -2
@@ -546,11 +546,14 @@ static void pci_device_shutdown(struct device *dev)/* * If this is a kexec reboot, turn off Bus Master bit on the * device to tell it to not continue to do DMA. Don't touch -* devices in D3cold or unknown states. +* devices being preserved for Live Update or in D3cold or +* unknown states. +* * If it is not a kexec reboot, firmware will hit the PCI * devices with big hammer and stop their DMA any way. */ -if (kexec_in_progress && (pci_dev->current_state <= PCI_D3hot)) +if (kexec_in_progress && !pci_liveupdate_is_outgoing (pci_dev) && + pci_dev->current_state <= PCI_D3hot)pci_clear_master (pci_dev); }
Signature · 1 line
2.54.0.746.g67dd491aae-goog
Re: [PATCH v6 11/12] PCI: liveupdate: Do not disable bus mastering on preserved devices during kexec
Quoted 48 lines · David Matlack
Do not disable bus mastering on outgoing preserved devices during
pci_device_shutdown()for kexec.Preserved devices must be allowed to perform memory transactions during a Live Update to ensure continuous operation. Clearing the bus mastering bit would prevent these devices from issuing any memory requests while the new kernel boots.
Because bridges upstream of preserved endpoint devices are also automatically preserved, this change also avoids clearing bus mastering on them. This is critical because clearing bus mastering on an upstream bridge prevents the bridge from forwarding memory requests upstream (i.e. it would prevent the endpoint device from accessing system RAM and doing peer-to-peer transactions with devices not downstream of the bridge).
Signed-off-by David Matlack <[email protected]>--- drivers/pci/liveupdate.c | 11 +++++++++++ drivers/pci/liveupdate.h | 6 ++++++ drivers/pci/pci-driver.c | 7 +++++-- 3 files changed, 22 insertions(+), 2 deletions(-)drivers/pci/liveupdate.c +11
-0@@ -132,6 +132,10 @@* * The PCI core inherits ARI Forwarding Enable on all bridges with downstream * preserved devices to ensure that all preserved devices on the bridge's * secondary bus are addressable after the Live Update. +* +* * The PCI core does not disable bus mastering on outgoing preserved devices +* during kexec. This allows preserved devices to issue memory transactions +* throughout the Live Update. */ #define pr_fmt (fmt) "PCI: liveupdate: " fmt@@ -790,6 +794,13 @@ int pci_liveupdate_configure_ari(struct pci_dev *dev)return 0 ; } +bool pci_liveupdate_is_outgoing (struct pci_dev *dev) +{ +guard (rwsem_read)(&pci_liveupdate.rwsem); +pci_WARN_ONCE (dev, !dev->liveupdate.frozen,"Preservation status is unstable!\n" ); +return dev->liveupdate.outgoing; +} +
[...]
Quoted 10 lines
drivers/pci/pci-driver.c +1
-1@@ -546,11 +546,14 @@ static void pci_device_shutdown(struct device *dev)/* * If this is a kexec reboot, turn off Bus Master bit on the * device to tell it to not continue to do DMA. Don't touch -* devices in D3cold or unknown states. +* devices being preserved for Live Update or in D3cold or
drivers/pci/pci-driver.c static void pci_device_shutdown(struct device *dev) · line 558
Quoted 10 lines
drivers/pci/pci-driver.c +4
-1+* unknown states. +* * If it is not a kexec reboot, firmware will hit the PCI * devices with big hammer and stop their DMA any way. */ -if (kexec_in_progress && (pci_dev->current_state <= PCI_D3hot)) +if (kexec_in_progress && !pci_liveupdate_is_outgoing (pci_dev) && + pci_dev->current_state <= PCI_D3hot)pci_clear_master (pci_dev); }
Looks good.
Thanks,
Praan
PATCH v6 12/12 Documentation: PCI: Add documentation for Live Update
In reply to David MatlackAdd documentation files for the PCI subsystem's participation in Live Update.
These documentation files are generated from the kernel-doc comments in the PCI Live Update source code. They describe the File-Lifecycle Bound (FLB) API, the device tracking API, and the specific policies applied to preserved devices (such as bus number inheritance and bus mastering preservation).
--- Documentation/PCI/index.rst | 1 + Documentation/PCI/liveupdate.rst | 29 +++++++++++++++++++++++++++ Documentation/core-api/liveupdate.rst | 1 + MAINTAINERS | 1 + 4 files changed, 32 insertions(+) create mode 100644 Documentation/PCI/liveupdate.rst
Documentation/PCI/index.rst +1 -0
@@ -20,3 +20,4 @@ PCI Bus Subsystem controller/index boot-interrupts tph + liveupdate
Documentation/PCI/liveupdate.rst new file +29 -0
@@ -0,0 +1,29 @@ +.. SPDX-License-Identifier: GPL-2.0-or-later + +=========================== +PCI Support for Live Update +=========================== + +.. kernel-doc:: drivers/pci/liveupdate.c + :doc: PCI Live Update + +Driver API +========== + +.. kernel-doc:: drivers/pci/liveupdate.c + :export: + +Live Update ABI +=============== + +.. kernel-doc:: include/linux/kho/abi/pci.h + :doc: PCI File-Lifecycle Bound (FLB) Live Update ABI + +.. kernel-doc:: include/linux/kho/abi/pci.h + :internal: + +See Also +======== + + * :doc:`/core-api/liveupdate` + * :doc:`/core-api/kho/index`
Documentation/core-api/liveupdate.rst +1 -0
@@ -70,3 +70,4 @@ See Also - :doc:`Live Update uAPI </userspace-api/liveupdate>` - :doc:`/core-api/kho/index` +- :doc:`PCI </PCI/liveupdate>`
MAINTAINERS +1 -0
@@ -20536,6 +20536,7 @@ L: [email protected] L: [email protected] S: Maintained T: git git://git.kernel.org/pub/scm/linux/kernel/git/liveupdate/linux.git +F: Documentation/PCI/liveupdate.rst F: drivers/pci/liveupdate.c F: drivers/pci/liveupdate.h F: include/linux/kho/abi/pci.h
Signature · 1 line
2.54.0.746.g67dd491aae-goog
Re: [PATCH v6 12/12] Documentation: PCI: Add documentation for Live Update
Quoted 9 lines · David Matlack
Add documentation files for the PCI subsystem's participation in Live Update.
These documentation files are generated from the kernel-doc comments in the PCI Live Update source code. They describe the File-Lifecycle Bound (FLB) API, the device tracking API, and the specific policies applied to preserved devices (such as bus number inheritance and bus mastering preservation).
Quoted 7 lines
Signed-off-by David Matlack <[email protected]>--- Documentation/PCI/index.rst | 1 + Documentation/PCI/liveupdate.rst | 29 +++++++++++++++++++++++++++ Documentation/core-api/liveupdate.rst | 1 + MAINTAINERS | 1 + 4 files changed, 32 insertions(+)
The kernel-doc directives seem to be wired up properly, along with formatting/indentation while keeping MAINTAINERS in sync in the same go.
Thanks,
Praan