| From e9516e29a1720616a9b1b244a2ef1b6c86838708 Mon Sep 17 00:00:00 2001 |
| From: Alex Williamson <alex.williamson@redhat.com> |
| Date: Tue, 17 Apr 2012 21:46:44 -0600 |
| Subject: [PATCH] KVM: lock slots_lock around device assignment |
| |
| commit 21a1416a1c945c5aeaeaf791b63c64926018eb77 upstream. |
| |
| 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> |
| [PG: drop goto for EPERM check, 2.6.34 doesn't have that code] |
| Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> |
| --- |
| virt/kvm/iommu.c | 20 +++++++++++++------- |
| 1 file changed, 13 insertions(+), 7 deletions(-) |
| |
| diff --git a/virt/kvm/iommu.c b/virt/kvm/iommu.c |
| index ac765f648218..8c510edca9c9 100644 |
| --- a/virt/kvm/iommu.c |
| +++ b/virt/kvm/iommu.c |
| @@ -174,18 +174,20 @@ int kvm_iommu_map_guest(struct kvm *kvm) |
| return -ENODEV; |
| } |
| |
| + mutex_lock(&kvm->slots_lock); |
| + |
| kvm->arch.iommu_domain = iommu_domain_alloc(); |
| - if (!kvm->arch.iommu_domain) |
| - return -ENOMEM; |
| + if (!kvm->arch.iommu_domain) { |
| + r = -ENOMEM; |
| + goto out_unlock; |
| + } |
| |
| r = kvm_iommu_map_memslots(kvm); |
| if (r) |
| - goto out_unmap; |
| - |
| - return 0; |
| + kvm_iommu_unmap_memslots(kvm); |
| |
| -out_unmap: |
| - kvm_iommu_unmap_memslots(kvm); |
| +out_unlock: |
| + mutex_unlock(&kvm->slots_lock); |
| return r; |
| } |
| |
| @@ -239,7 +241,11 @@ int kvm_iommu_unmap_guest(struct kvm *kvm) |
| if (!domain) |
| return 0; |
| |
| + mutex_lock(&kvm->slots_lock); |
| kvm_iommu_unmap_memslots(kvm); |
| + kvm->arch.iommu_domain = NULL; |
| + mutex_unlock(&kvm->slots_lock); |
| + |
| iommu_domain_free(domain); |
| return 0; |
| } |
| -- |
| 1.8.5.2 |
| |