[PATCH v4 08/11] PCI: liveupdate: Require preserved devices are in immutable singleton IOMMU groups

Jacob Pan jacob.pan at linux.microsoft.com
Mon Apr 27 13:56:25 PDT 2026


Hi David,

On Thu, 23 Apr 2026 21:23:12 +0000
David Matlack <dmatlack at google.com> wrote:

> Restrict support for preserving PCI devices across Live Update to
> devices in immutable singleton IOMMU groups. A device's group is
> considered immutable if all bridges upstream from the device up to the
> root port have the required ACS features enabled.
> 
> Since ACS flags are inherited across a Live Update for preserved
> devices and all the way up to the root port, the preserved device
> should be in a singleton IOMMU group after kexec in the new kernel.
> 
> This change should still permit all the current use-cases for PCI
> device preservation across Live Update, since it is intended to be
> used in Cloud enviroments which should have the required ACS features
> enabled for virtualization purposes.
> 
> If a device is part of a multi-device IOMMU group, preserving it will
> now fail with an error. This restriction may be lifted in the future
> if support for preserving multi-device groups is desired.
> 
> Signed-off-by: David Matlack <dmatlack at google.com>
> ---
>  drivers/iommu/iommu.c    | 35 +++++++++++++++++++++++++++++++++++
>  drivers/pci/liveupdate.c |  6 ++++++
>  include/linux/iommu.h    |  7 +++++++
>  3 files changed, 48 insertions(+)
> 
> diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
> index 61c12ba78206..782e73a9d45f 100644
> --- a/drivers/iommu/iommu.c
> +++ b/drivers/iommu/iommu.c
> @@ -1664,6 +1664,41 @@ struct iommu_group *pci_device_group(struct
> device *dev) }
>  EXPORT_SYMBOL_GPL(pci_device_group);
>  
> +bool pci_device_group_immutable_singleton(struct pci_dev *dev)
> +{
> +	struct iommu_group *group;
> +	struct group_device *d;
> +	struct pci_bus *bus;
> +	int nr_devices = 0;
> +
> +	group = iommu_group_get(&dev->dev);
> +	if (!group)
> +		return false;
This may not work for noiommu mode where we could have a null group.
Maybe I can add special case later?

> +	mutex_lock(&group->mutex);
> +
> +	for_each_group_device(group, d)
> +		nr_devices++;
> +
> +	mutex_unlock(&group->mutex);
> +	iommu_group_put(group);
nit:
	scoped_guard(mutex, &group->mutex) {
        	for_each_group_device(group, d)
                	nr_devices++;
 	}
> +
> +	if (nr_devices != 1)
> +		return false;
> +
> +	for (bus = dev->bus; !pci_is_root_bus(bus); bus =
> bus->parent) {
> +		if (!bus->self)
> +			continue;
> +
> +		if (!pci_acs_path_enabled(bus->self, NULL,
> REQ_ACS_FLAGS))
> +			return false;
> +
> +		break;
> +	}
> +
> +	return true;
> +}
> +
>  /* Get the IOMMU group for device on fsl-mc bus */
>  struct iommu_group *fsl_mc_device_group(struct device *dev)
>  {
> diff --git a/drivers/pci/liveupdate.c b/drivers/pci/liveupdate.c
> index a9a89f7bd3e5..54a90ff02bdd 100644
> --- a/drivers/pci/liveupdate.c
> +++ b/drivers/pci/liveupdate.c
> @@ -133,6 +133,7 @@
>  #define pr_fmt(fmt) "PCI: liveupdate: " fmt
>  
>  #include <linux/io.h>
> +#include <linux/iommu.h>
>  #include <linux/kexec_handover.h>
>  #include <linux/kho/abi/pci.h>
>  #include <linux/liveupdate.h>
> @@ -359,6 +360,11 @@ int pci_liveupdate_preserve(struct pci_dev *dev)
>  	if (dev->is_virtfn)
>  		return -EINVAL;
>  
> +	if (!pci_device_group_immutable_singleton(dev)) {
> +		pci_warn(dev, "Device preservation limited to
> immutable singleton iommu groups\n");
> +		return -EINVAL;
> +	}
> +
>  	if (dev->liveupdate_outgoing)
>  		return -EBUSY;
>  
> diff --git a/include/linux/iommu.h b/include/linux/iommu.h
> index e587d4ac4d33..6f5d1dec3f89 100644
> --- a/include/linux/iommu.h
> +++ b/include/linux/iommu.h
> @@ -1096,6 +1096,8 @@ extern struct iommu_group
> *generic_device_group(struct device *dev); struct iommu_group
> *fsl_mc_device_group(struct device *dev); extern struct iommu_group
> *generic_single_device_group(struct device *dev); 
> +bool pci_device_group_immutable_singleton(struct pci_dev *dev);
> +
>  /**
>   * struct iommu_fwspec - per-device IOMMU instance data
>   * @iommu_fwnode: firmware handle for this device's IOMMU
> @@ -1528,6 +1530,11 @@ static inline int
> pci_dev_reset_iommu_prepare(struct pci_dev *pdev) static inline void
> pci_dev_reset_iommu_done(struct pci_dev *pdev) {
>  }
> +
> +static inline bool pci_device_group_immutable_singleton(struct
> pci_dev *dev) +{
> +	return false;
> +}
>  #endif /* CONFIG_IOMMU_API */
>  
>  #ifdef CONFIG_IRQ_MSI_IOMMU




More information about the kexec mailing list