diff options
Diffstat (limited to 'virt')
-rw-r--r-- | virt/kvm/kvm_main.c | 28 |
1 files changed, 24 insertions, 4 deletions
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index 5e709ebb7c40..3fec2cdd951b 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c | |||
@@ -731,6 +731,7 @@ int __kvm_set_memory_region(struct kvm *kvm, | |||
731 | struct kvm_memory_slot *slot; | 731 | struct kvm_memory_slot *slot; |
732 | struct kvm_memory_slot old, new; | 732 | struct kvm_memory_slot old, new; |
733 | struct kvm_memslots *slots = NULL, *old_memslots; | 733 | struct kvm_memslots *slots = NULL, *old_memslots; |
734 | bool old_iommu_mapped; | ||
734 | 735 | ||
735 | r = check_memory_region_flags(mem); | 736 | r = check_memory_region_flags(mem); |
736 | if (r) | 737 | if (r) |
@@ -772,6 +773,8 @@ int __kvm_set_memory_region(struct kvm *kvm, | |||
772 | new.npages = npages; | 773 | new.npages = npages; |
773 | new.flags = mem->flags; | 774 | new.flags = mem->flags; |
774 | 775 | ||
776 | old_iommu_mapped = old.npages; | ||
777 | |||
775 | /* | 778 | /* |
776 | * Disallow changing a memory slot's size or changing anything about | 779 | * Disallow changing a memory slot's size or changing anything about |
777 | * zero sized slots that doesn't involve making them non-zero. | 780 | * zero sized slots that doesn't involve making them non-zero. |
@@ -835,6 +838,7 @@ int __kvm_set_memory_region(struct kvm *kvm, | |||
835 | 838 | ||
836 | /* slot was deleted or moved, clear iommu mapping */ | 839 | /* slot was deleted or moved, clear iommu mapping */ |
837 | kvm_iommu_unmap_pages(kvm, &old); | 840 | kvm_iommu_unmap_pages(kvm, &old); |
841 | old_iommu_mapped = false; | ||
838 | /* From this point no new shadow pages pointing to a deleted, | 842 | /* From this point no new shadow pages pointing to a deleted, |
839 | * or moved, memslot will be created. | 843 | * or moved, memslot will be created. |
840 | * | 844 | * |
@@ -863,11 +867,27 @@ int __kvm_set_memory_region(struct kvm *kvm, | |||
863 | goto out_free; | 867 | goto out_free; |
864 | } | 868 | } |
865 | 869 | ||
866 | /* map new memory slot into the iommu */ | 870 | /* |
871 | * IOMMU mapping: New slots need to be mapped. Old slots need to be | ||
872 | * un-mapped and re-mapped if their base changes or if flags that the | ||
873 | * iommu cares about change (read-only). Base change unmapping is | ||
874 | * handled above with slot deletion, so we only unmap incompatible | ||
875 | * flags here. Anything else the iommu might care about for existing | ||
876 | * slots (size changes, userspace addr changes) is disallowed above, | ||
877 | * so any other attribute changes getting here can be skipped. | ||
878 | */ | ||
867 | if (npages) { | 879 | if (npages) { |
868 | r = kvm_iommu_map_pages(kvm, &new); | 880 | if (old_iommu_mapped && |
869 | if (r) | 881 | ((new.flags ^ old.flags) & KVM_MEM_READONLY)) { |
870 | goto out_slots; | 882 | kvm_iommu_unmap_pages(kvm, &old); |
883 | old_iommu_mapped = false; | ||
884 | } | ||
885 | |||
886 | if (!old_iommu_mapped) { | ||
887 | r = kvm_iommu_map_pages(kvm, &new); | ||
888 | if (r) | ||
889 | goto out_slots; | ||
890 | } | ||
871 | } | 891 | } |
872 | 892 | ||
873 | /* actual memory is freed via old in kvm_free_physmem_slot below */ | 893 | /* actual memory is freed via old in kvm_free_physmem_slot below */ |