diff options
author | David Woodhouse <David.Woodhouse@intel.com> | 2014-03-09 16:11:33 -0400 |
---|---|---|
committer | David Woodhouse <David.Woodhouse@intel.com> | 2014-03-24 10:06:39 -0400 |
commit | b718cd3d8412edaf02665d29b0cf5ef828675a45 (patch) | |
tree | a4207bd503b4240f6334c4d3238d981131c97681 | |
parent | 64ae892bfee37c0f982710363c39474218028e33 (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.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) | |||
2147 | return NULL; | 2147 | return NULL; |
2148 | } | 2148 | } |
2149 | 2149 | ||
2150 | static int dmar_insert_dev_info(int segment, int bus, int devfn, | 2150 | static 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 | ||
2254 | found_domain: | 2252 | found_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; | ||
2258 | error: | 2255 | error: |
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 | ||
2265 | static int iommu_identity_mapping; | 2262 | static int iommu_identity_mapping; |