diff options
author | Alex Williamson <alex.williamson@redhat.com> | 2012-04-17 23:46:44 -0400 |
---|---|---|
committer | Marcelo Tosatti <mtosatti@redhat.com> | 2012-04-18 23:04:18 -0400 |
commit | 21a1416a1c945c5aeaeaf791b63c64926018eb77 (patch) | |
tree | 4a6ac6aae66648bba9de57902ec98dfa5ae9b98d /virt/kvm/iommu.c | |
parent | 2225fd56049643c1a7d645c0ce9d499d43c7974e (diff) |
KVM: lock slots_lock around device assignment
As pointed out by Jason Baron, when assigning a device to a guest
we first set the iommu domain pointer, which enables mapping
and unmapping of memory slots to the iommu. This leaves a window
where this path is enabled, but we haven't synchronized the iommu
mappings to the existing memory slots. Thus a slot being removed
at that point could send us down unexpected code paths removing
non-existent pinnings and iommu mappings. Take the slots_lock
around creating the iommu domain and initial mappings as well as
around iommu teardown to avoid this race.
Signed-off-by: Alex Williamson <alex.williamson@redhat.com>
Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
Diffstat (limited to 'virt/kvm/iommu.c')
-rw-r--r-- | virt/kvm/iommu.c | 23 |
1 files changed, 15 insertions, 8 deletions
diff --git a/virt/kvm/iommu.c b/virt/kvm/iommu.c index fec1723de9b4..e9fff9830bf0 100644 --- a/virt/kvm/iommu.c +++ b/virt/kvm/iommu.c | |||
@@ -240,9 +240,13 @@ int kvm_iommu_map_guest(struct kvm *kvm) | |||
240 | return -ENODEV; | 240 | return -ENODEV; |
241 | } | 241 | } |
242 | 242 | ||
243 | mutex_lock(&kvm->slots_lock); | ||
244 | |||
243 | kvm->arch.iommu_domain = iommu_domain_alloc(&pci_bus_type); | 245 | kvm->arch.iommu_domain = iommu_domain_alloc(&pci_bus_type); |
244 | if (!kvm->arch.iommu_domain) | 246 | if (!kvm->arch.iommu_domain) { |
245 | return -ENOMEM; | 247 | r = -ENOMEM; |
248 | goto out_unlock; | ||
249 | } | ||
246 | 250 | ||
247 | if (!allow_unsafe_assigned_interrupts && | 251 | if (!allow_unsafe_assigned_interrupts && |
248 | !iommu_domain_has_cap(kvm->arch.iommu_domain, | 252 | !iommu_domain_has_cap(kvm->arch.iommu_domain, |
@@ -253,17 +257,16 @@ int kvm_iommu_map_guest(struct kvm *kvm) | |||
253 | " module option.\n", __func__); | 257 | " module option.\n", __func__); |
254 | iommu_domain_free(kvm->arch.iommu_domain); | 258 | iommu_domain_free(kvm->arch.iommu_domain); |
255 | kvm->arch.iommu_domain = NULL; | 259 | kvm->arch.iommu_domain = NULL; |
256 | return -EPERM; | 260 | r = -EPERM; |
261 | goto out_unlock; | ||
257 | } | 262 | } |
258 | 263 | ||
259 | r = kvm_iommu_map_memslots(kvm); | 264 | r = kvm_iommu_map_memslots(kvm); |
260 | if (r) | 265 | if (r) |
261 | goto out_unmap; | 266 | kvm_iommu_unmap_memslots(kvm); |
262 | |||
263 | return 0; | ||
264 | 267 | ||
265 | out_unmap: | 268 | out_unlock: |
266 | kvm_iommu_unmap_memslots(kvm); | 269 | mutex_unlock(&kvm->slots_lock); |
267 | return r; | 270 | return r; |
268 | } | 271 | } |
269 | 272 | ||
@@ -340,7 +343,11 @@ int kvm_iommu_unmap_guest(struct kvm *kvm) | |||
340 | if (!domain) | 343 | if (!domain) |
341 | return 0; | 344 | return 0; |
342 | 345 | ||
346 | mutex_lock(&kvm->slots_lock); | ||
343 | kvm_iommu_unmap_memslots(kvm); | 347 | kvm_iommu_unmap_memslots(kvm); |
348 | kvm->arch.iommu_domain = NULL; | ||
349 | mutex_unlock(&kvm->slots_lock); | ||
350 | |||
344 | iommu_domain_free(domain); | 351 | iommu_domain_free(domain); |
345 | return 0; | 352 | return 0; |
346 | } | 353 | } |