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>
This commit is contained in:
parent
2225fd5604
commit
21a1416a1c
|
@ -240,9 +240,13 @@ int kvm_iommu_map_guest(struct kvm *kvm)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mutex_lock(&kvm->slots_lock);
|
||||||
|
|
||||||
kvm->arch.iommu_domain = iommu_domain_alloc(&pci_bus_type);
|
kvm->arch.iommu_domain = iommu_domain_alloc(&pci_bus_type);
|
||||||
if (!kvm->arch.iommu_domain)
|
if (!kvm->arch.iommu_domain) {
|
||||||
return -ENOMEM;
|
r = -ENOMEM;
|
||||||
|
goto out_unlock;
|
||||||
|
}
|
||||||
|
|
||||||
if (!allow_unsafe_assigned_interrupts &&
|
if (!allow_unsafe_assigned_interrupts &&
|
||||||
!iommu_domain_has_cap(kvm->arch.iommu_domain,
|
!iommu_domain_has_cap(kvm->arch.iommu_domain,
|
||||||
|
@ -253,17 +257,16 @@ int kvm_iommu_map_guest(struct kvm *kvm)
|
||||||
" module option.\n", __func__);
|
" module option.\n", __func__);
|
||||||
iommu_domain_free(kvm->arch.iommu_domain);
|
iommu_domain_free(kvm->arch.iommu_domain);
|
||||||
kvm->arch.iommu_domain = NULL;
|
kvm->arch.iommu_domain = NULL;
|
||||||
return -EPERM;
|
r = -EPERM;
|
||||||
|
goto out_unlock;
|
||||||
}
|
}
|
||||||
|
|
||||||
r = kvm_iommu_map_memslots(kvm);
|
r = kvm_iommu_map_memslots(kvm);
|
||||||
if (r)
|
if (r)
|
||||||
goto out_unmap;
|
kvm_iommu_unmap_memslots(kvm);
|
||||||
|
|
||||||
return 0;
|
out_unlock:
|
||||||
|
mutex_unlock(&kvm->slots_lock);
|
||||||
out_unmap:
|
|
||||||
kvm_iommu_unmap_memslots(kvm);
|
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -340,7 +343,11 @@ int kvm_iommu_unmap_guest(struct kvm *kvm)
|
||||||
if (!domain)
|
if (!domain)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
mutex_lock(&kvm->slots_lock);
|
||||||
kvm_iommu_unmap_memslots(kvm);
|
kvm_iommu_unmap_memslots(kvm);
|
||||||
|
kvm->arch.iommu_domain = NULL;
|
||||||
|
mutex_unlock(&kvm->slots_lock);
|
||||||
|
|
||||||
iommu_domain_free(domain);
|
iommu_domain_free(domain);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue