|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] RE: [PATCH 3/9] VT-d: undo device mappings upon error
> From: Jan Beulich <jbeulich@xxxxxxxx>
> Sent: Wednesday, June 9, 2021 5:28 PM
>
> When
> - flushes (supposedly not possible anymore after XSA-373),
> - secondary mappings for legacy PCI devices behind bridges,
> - secondary mappings for chipset quirks, or
> - find_upstream_bridge() invocations
> fail, the successfully established device mappings should not be left
> around.
>
> Further, when (parts of) unmapping fail, simply returning an error is
> typically not enough. Crash the domain instead in such cases, arranging
> for domain cleanup to continue in a best effort manner despite such
> failures.
>
> Finally make domain_context_unmap()'s error behavior consistent in the
> legacy PCI device case: Don't bail from the function in one special
> case, but always just exit the switch statement.
>
> Signed-off-by: Jan Beulich <jbeulich@xxxxxxxx>
> Reviewed-by: Paul Durrant <paul@xxxxxxx>
Reviewed-by: Kevin Tian <kevin.tian@xxxxxxxxx>
>
> --- a/xen/drivers/passthrough/vtd/iommu.c
> +++ b/xen/drivers/passthrough/vtd/iommu.c
> @@ -1442,9 +1442,15 @@ int domain_context_mapping_one(
> if ( !seg && !rc )
> rc = me_wifi_quirk(domain, bus, devfn, MAP_ME_PHANTOM_FUNC);
>
> + if ( rc )
> + domain_context_unmap_one(domain, iommu, bus, devfn);
> +
> return rc;
> }
>
> +static int domain_context_unmap(struct domain *d, uint8_t devfn,
> + struct pci_dev *pdev);
> +
> static int domain_context_mapping(struct domain *domain, u8 devfn,
> struct pci_dev *pdev)
> {
> @@ -1505,16 +1511,21 @@ static int domain_context_mapping(struct
> if ( ret )
> break;
>
> - if ( find_upstream_bridge(seg, &bus, &devfn, &secbus) < 1 )
> - break;
> + if ( (ret = find_upstream_bridge(seg, &bus, &devfn, &secbus)) < 1 )
> + {
> + if ( !ret )
> + break;
> + ret = -ENXIO;
> + }
>
> /*
> * Mapping a bridge should, if anything, pass the struct pci_dev of
> * that bridge. Since bridges don't normally get assigned to guests,
> * their owner would be the wrong one. Pass NULL instead.
> */
> - ret = domain_context_mapping_one(domain, drhd->iommu, bus, devfn,
> - NULL);
> + if ( ret >= 0 )
> + ret = domain_context_mapping_one(domain, drhd->iommu, bus,
> devfn,
> + NULL);
>
> /*
> * Devices behind PCIe-to-PCI/PCIx bridge may generate different
> @@ -1531,6 +1542,9 @@ static int domain_context_mapping(struct
> ret = domain_context_mapping_one(domain, drhd->iommu, secbus,
> 0,
> NULL);
>
> + if ( ret )
> + domain_context_unmap(domain, devfn, pdev);
> +
> break;
>
> default:
> @@ -1609,6 +1623,19 @@ int domain_context_unmap_one(
> if ( !iommu->drhd->segment && !rc )
> rc = me_wifi_quirk(domain, bus, devfn, UNMAP_ME_PHANTOM_FUNC);
>
> + if ( rc && !is_hardware_domain(domain) && domain != dom_io )
> + {
> + if ( domain->is_dying )
> + {
> + printk(XENLOG_ERR "%pd: error %d
> unmapping %04x:%02x:%02x.%u\n",
> + domain, rc, iommu->drhd->segment, bus,
> + PCI_SLOT(devfn), PCI_FUNC(devfn));
> + rc = 0; /* Make upper layers continue in a best effort manner. */
> + }
> + else
> + domain_crash(domain);
> + }
> +
> return rc;
> }
>
> @@ -1661,17 +1688,29 @@ static int domain_context_unmap(struct d
>
> tmp_bus = bus;
> tmp_devfn = devfn;
> - if ( find_upstream_bridge(seg, &tmp_bus, &tmp_devfn, &secbus) < 1 )
> + if ( (ret = find_upstream_bridge(seg, &tmp_bus, &tmp_devfn,
> + &secbus)) < 1 )
> + {
> + if ( ret )
> + {
> + ret = -ENXIO;
> + if ( !domain->is_dying &&
> + !is_hardware_domain(domain) && domain != dom_io )
> + {
> + domain_crash(domain);
> + /* Make upper layers continue in a best effort manner. */
> + ret = 0;
> + }
> + }
> break;
> + }
>
> /* PCIe to PCI/PCIx bridge */
> if ( pdev_type(seg, tmp_bus, tmp_devfn) ==
> DEV_TYPE_PCIe2PCI_BRIDGE )
> {
> ret = domain_context_unmap_one(domain, iommu, tmp_bus,
> tmp_devfn);
> - if ( ret )
> - return ret;
> -
> - ret = domain_context_unmap_one(domain, iommu, secbus, 0);
> + if ( !ret )
> + ret = domain_context_unmap_one(domain, iommu, secbus, 0);
> }
> else /* Legacy PCI bridge */
> ret = domain_context_unmap_one(domain, iommu, tmp_bus,
> tmp_devfn);
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |