aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlex Williamson <alex.williamson@redhat.com>2012-04-27 17:54:08 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2012-05-07 11:56:35 -0400
commita674bcab9066a2b2541d8276f5e9ff86f50ce13e (patch)
tree9af94ff5807b7ea08528c7a0763b67aa612519cb
parent9239fabf848397ec26356b5f267c787840ba4bb7 (diff)
KVM: unmap pages from the iommu when slots are removed
commit 32f6daad4651a748a58a3ab6da0611862175722f upstream. We've been adding new mappings, but not destroying old mappings. This can lead to a page leak as pages are pinned using get_user_pages, but only unpinned with put_page if they still exist in the memslots list on vm shutdown. A memslot that is destroyed while an iommu domain is enabled for the guest will therefore result in an elevated page reference count that is never cleared. Additionally, without this fix, the iommu is only programmed with the first translation for a gpa. This can result in peer-to-peer errors if a mapping is destroyed and replaced by a new mapping at the same gpa as the iommu will still be pointing to the original, pinned memory address. Signed-off-by: Alex Williamson <alex.williamson@redhat.com> Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com> Signed-off-by: Jonathan Nieder <jrnieder@gmail.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--include/linux/kvm_host.h6
-rw-r--r--virt/kvm/iommu.c12
-rw-r--r--virt/kvm/kvm_main.c5
3 files changed, 17 insertions, 6 deletions
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
index 31ebb59cbd2..82d5476e69c 100644
--- a/include/linux/kvm_host.h
+++ b/include/linux/kvm_host.h
@@ -554,6 +554,7 @@ void kvm_free_irq_source_id(struct kvm *kvm, int irq_source_id);
554 554
555#ifdef CONFIG_IOMMU_API 555#ifdef CONFIG_IOMMU_API
556int kvm_iommu_map_pages(struct kvm *kvm, struct kvm_memory_slot *slot); 556int kvm_iommu_map_pages(struct kvm *kvm, struct kvm_memory_slot *slot);
557void kvm_iommu_unmap_pages(struct kvm *kvm, struct kvm_memory_slot *slot);
557int kvm_iommu_map_guest(struct kvm *kvm); 558int kvm_iommu_map_guest(struct kvm *kvm);
558int kvm_iommu_unmap_guest(struct kvm *kvm); 559int kvm_iommu_unmap_guest(struct kvm *kvm);
559int kvm_assign_device(struct kvm *kvm, 560int kvm_assign_device(struct kvm *kvm,
@@ -567,6 +568,11 @@ static inline int kvm_iommu_map_pages(struct kvm *kvm,
567 return 0; 568 return 0;
568} 569}
569 570
571static inline void kvm_iommu_unmap_pages(struct kvm *kvm,
572 struct kvm_memory_slot *slot)
573{
574}
575
570static inline int kvm_iommu_map_guest(struct kvm *kvm) 576static inline int kvm_iommu_map_guest(struct kvm *kvm)
571{ 577{
572 return -ENODEV; 578 return -ENODEV;
diff --git a/virt/kvm/iommu.c b/virt/kvm/iommu.c
index 62a9caf0563..fb0f6e469bb 100644
--- a/virt/kvm/iommu.c
+++ b/virt/kvm/iommu.c
@@ -285,6 +285,11 @@ static void kvm_iommu_put_pages(struct kvm *kvm,
285 } 285 }
286} 286}
287 287
288void kvm_iommu_unmap_pages(struct kvm *kvm, struct kvm_memory_slot *slot)
289{
290 kvm_iommu_put_pages(kvm, slot->base_gfn, slot->npages);
291}
292
288static int kvm_iommu_unmap_memslots(struct kvm *kvm) 293static int kvm_iommu_unmap_memslots(struct kvm *kvm)
289{ 294{
290 int i, idx; 295 int i, idx;
@@ -293,10 +298,9 @@ static int kvm_iommu_unmap_memslots(struct kvm *kvm)
293 idx = srcu_read_lock(&kvm->srcu); 298 idx = srcu_read_lock(&kvm->srcu);
294 slots = kvm_memslots(kvm); 299 slots = kvm_memslots(kvm);
295 300
296 for (i = 0; i < slots->nmemslots; i++) { 301 for (i = 0; i < slots->nmemslots; i++)
297 kvm_iommu_put_pages(kvm, slots->memslots[i].base_gfn, 302 kvm_iommu_unmap_pages(kvm, &slots->memslots[i]);
298 slots->memslots[i].npages); 303
299 }
300 srcu_read_unlock(&kvm->srcu, idx); 304 srcu_read_unlock(&kvm->srcu, idx);
301 305
302 return 0; 306 return 0;
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index 96ebc067941..6b39ba9540e 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -796,12 +796,13 @@ skip_lpage:
796 if (r) 796 if (r)
797 goto out_free; 797 goto out_free;
798 798
799 /* map the pages in iommu page table */ 799 /* map/unmap the pages in iommu page table */
800 if (npages) { 800 if (npages) {
801 r = kvm_iommu_map_pages(kvm, &new); 801 r = kvm_iommu_map_pages(kvm, &new);
802 if (r) 802 if (r)
803 goto out_free; 803 goto out_free;
804 } 804 } else
805 kvm_iommu_unmap_pages(kvm, &old);
805 806
806 r = -ENOMEM; 807 r = -ENOMEM;
807 slots = kzalloc(sizeof(struct kvm_memslots), GFP_KERNEL); 808 slots = kzalloc(sizeof(struct kvm_memslots), GFP_KERNEL);