summaryrefslogtreecommitdiffstats
path: root/drivers/iommu
diff options
context:
space:
mode:
authorDavid Woodhouse <David.Woodhouse@intel.com>2014-03-09 21:11:33 +0100
committerDavid Woodhouse <David.Woodhouse@intel.com>2014-03-24 15:06:39 +0100
commitb718cd3d8412edaf02665d29b0cf5ef828675a45 (patch)
treea4207bd503b4240f6334c4d3238d981131c97681 /drivers/iommu
parentiommu/vt-d: Pass iommu to domain_context_mapping_one() and iommu_support_dev_... (diff)
downloadlinux-b718cd3d8412edaf02665d29b0cf5ef828675a45.tar.xz
linux-b718cd3d8412edaf02665d29b0cf5ef828675a45.zip
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.c45
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;