aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Woodhouse <David.Woodhouse@intel.com>2014-03-09 16:11:33 -0400
committerDavid Woodhouse <David.Woodhouse@intel.com>2014-03-24 10:06:39 -0400
commitb718cd3d8412edaf02665d29b0cf5ef828675a45 (patch)
treea4207bd503b4240f6334c4d3238d981131c97681
parent64ae892bfee37c0f982710363c39474218028e33 (diff)
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>
-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)
2147 return NULL; 2147 return NULL;
2148} 2148}
2149 2149
2150static int dmar_insert_dev_info(int segment, int bus, int devfn, 2150static struct dmar_domain *dmar_insert_dev_info(int segment, int bus, int devfn,
2151 struct device *dev, struct dmar_domain **domp) 2151 struct device *dev,
2152 struct dmar_domain *domain)
2152{ 2153{
2153 struct dmar_domain *found, *domain = *domp; 2154 struct dmar_domain *found;
2154 struct device_domain_info *info; 2155 struct device_domain_info *info;
2155 unsigned long flags; 2156 unsigned long flags;
2156 2157
2157 info = alloc_devinfo_mem(); 2158 info = alloc_devinfo_mem();
2158 if (!info) 2159 if (!info)
2159 return -ENOMEM; 2160 return NULL;
2160 2161
2161 info->segment = segment; 2162 info->segment = segment;
2162 info->bus = bus; 2163 info->bus = bus;
@@ -2174,19 +2175,17 @@ static int dmar_insert_dev_info(int segment, int bus, int devfn,
2174 if (found) { 2175 if (found) {
2175 spin_unlock_irqrestore(&device_domain_lock, flags); 2176 spin_unlock_irqrestore(&device_domain_lock, flags);
2176 free_devinfo_mem(info); 2177 free_devinfo_mem(info);
2177 if (found != domain) { 2178 /* Caller must free the original domain */
2178 domain_exit(domain); 2179 return found;
2179 *domp = found;
2180 }
2181 } else {
2182 list_add(&info->link, &domain->devices);
2183 list_add(&info->global, &device_domain_list);
2184 if (dev)
2185 dev->archdata.iommu = info;
2186 spin_unlock_irqrestore(&device_domain_lock, flags);
2187 } 2180 }
2188 2181
2189 return 0; 2182 list_add(&info->link, &domain->devices);
2183 list_add(&info->global, &device_domain_list);
2184 if (dev)
2185 dev->archdata.iommu = info;
2186 spin_unlock_irqrestore(&device_domain_lock, flags);
2187
2188 return domain;
2190} 2189}
2191 2190
2192/* domain is initialized */ 2191/* domain is initialized */
@@ -2245,21 +2244,19 @@ static struct dmar_domain *get_domain_for_dev(struct pci_dev *pdev, int gaw)
2245 2244
2246 /* register pcie-to-pci device */ 2245 /* register pcie-to-pci device */
2247 if (dev_tmp) { 2246 if (dev_tmp) {
2248 if (dmar_insert_dev_info(segment, bus, devfn, NULL, &domain)) 2247 domain = dmar_insert_dev_info(segment, bus, devfn, NULL, domain);
2248 if (!domain)
2249 goto error; 2249 goto error;
2250 else
2251 free = NULL;
2252 } 2250 }
2253 2251
2254found_domain: 2252found_domain:
2255 if (dmar_insert_dev_info(segment, pdev->bus->number, pdev->devfn, 2253 domain = dmar_insert_dev_info(segment, pdev->bus->number, pdev->devfn,
2256 &pdev->dev, &domain) == 0) 2254 &pdev->dev, domain);
2257 return domain;
2258error: 2255error:
2259 if (free) 2256 if (free != domain)
2260 domain_exit(free); 2257 domain_exit(free);
2261 /* recheck it here, maybe others set it */ 2258
2262 return find_domain(&pdev->dev); 2259 return domain;
2263} 2260}
2264 2261
2265static int iommu_identity_mapping; 2262static int iommu_identity_mapping;