diff options
author | David Woodhouse <David.Woodhouse@intel.com> | 2014-03-10 00:11:33 +0400 |
---|---|---|
committer | David Woodhouse <David.Woodhouse@intel.com> | 2014-03-24 18:06:39 +0400 |
commit | b718cd3d8412edaf02665d29b0cf5ef828675a45 (patch) | |
tree | a4207bd503b4240f6334c4d3238d981131c97681 /drivers/iommu | |
parent | 64ae892bfee37c0f982710363c39474218028e33 (diff) | |
download | linux-b718cd3d8412edaf02665d29b0cf5ef828675a45.tar.xz |
iommu/vt-d: Stop dmar_insert_dev_info() freeing domains on losing race
By moving this into get_domain_for_dev() we can make dmar_insert_dev_info()
suitable for use with "special" domains such as the si_domain, which
currently use domain_add_dev_info().
Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
Diffstat (limited to 'drivers/iommu')
-rw-r--r-- | drivers/iommu/intel-iommu.c | 45 |
1 files changed, 21 insertions, 24 deletions
diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c index 1c43a7b3008a..c1c564233768 100644 --- a/drivers/iommu/intel-iommu.c +++ b/drivers/iommu/intel-iommu.c @@ -2147,16 +2147,17 @@ dmar_search_domain_by_dev_info(int segment, int bus, int devfn) return NULL; } -static int dmar_insert_dev_info(int segment, int bus, int devfn, - struct device *dev, struct dmar_domain **domp) +static struct dmar_domain *dmar_insert_dev_info(int segment, int bus, int devfn, + struct device *dev, + struct dmar_domain *domain) { - struct dmar_domain *found, *domain = *domp; + struct dmar_domain *found; struct device_domain_info *info; unsigned long flags; info = alloc_devinfo_mem(); if (!info) - return -ENOMEM; + return NULL; info->segment = segment; info->bus = bus; @@ -2174,19 +2175,17 @@ static int dmar_insert_dev_info(int segment, int bus, int devfn, if (found) { spin_unlock_irqrestore(&device_domain_lock, flags); free_devinfo_mem(info); - if (found != domain) { - domain_exit(domain); - *domp = found; - } - } else { - list_add(&info->link, &domain->devices); - list_add(&info->global, &device_domain_list); - if (dev) - dev->archdata.iommu = info; - spin_unlock_irqrestore(&device_domain_lock, flags); + /* Caller must free the original domain */ + return found; } - return 0; + list_add(&info->link, &domain->devices); + list_add(&info->global, &device_domain_list); + if (dev) + dev->archdata.iommu = info; + spin_unlock_irqrestore(&device_domain_lock, flags); + + return domain; } /* domain is initialized */ @@ -2245,21 +2244,19 @@ static struct dmar_domain *get_domain_for_dev(struct pci_dev *pdev, int gaw) /* register pcie-to-pci device */ if (dev_tmp) { - if (dmar_insert_dev_info(segment, bus, devfn, NULL, &domain)) + domain = dmar_insert_dev_info(segment, bus, devfn, NULL, domain); + if (!domain) goto error; - else - free = NULL; } found_domain: - if (dmar_insert_dev_info(segment, pdev->bus->number, pdev->devfn, - &pdev->dev, &domain) == 0) - return domain; + domain = dmar_insert_dev_info(segment, pdev->bus->number, pdev->devfn, + &pdev->dev, domain); error: - if (free) + if (free != domain) domain_exit(free); - /* recheck it here, maybe others set it */ - return find_domain(&pdev->dev); + + return domain; } static int iommu_identity_mapping; |