aboutsummaryrefslogtreecommitdiffstats
path: root/virt
diff options
context:
space:
mode:
Diffstat (limited to 'virt')
-rw-r--r--virt/kvm/kvm_main.c64
1 files changed, 44 insertions, 20 deletions
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index a83ca63d26fc..64c5dc37c6a1 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -719,6 +719,24 @@ static struct kvm_memslots *install_new_memslots(struct kvm *kvm,
719} 719}
720 720
721/* 721/*
722 * KVM_SET_USER_MEMORY_REGION ioctl allows the following operations:
723 * - create a new memory slot
724 * - delete an existing memory slot
725 * - modify an existing memory slot
726 * -- move it in the guest physical memory space
727 * -- just change its flags
728 *
729 * Since flags can be changed by some of these operations, the following
730 * differentiation is the best we can do for __kvm_set_memory_region():
731 */
732enum kvm_mr_change {
733 KVM_MR_CREATE,
734 KVM_MR_DELETE,
735 KVM_MR_MOVE,
736 KVM_MR_FLAGS_ONLY,
737};
738
739/*
722 * Allocate some memory and give it an address in the guest physical address 740 * Allocate some memory and give it an address in the guest physical address
723 * space. 741 * space.
724 * 742 *
@@ -737,6 +755,7 @@ int __kvm_set_memory_region(struct kvm *kvm,
737 struct kvm_memory_slot old, new; 755 struct kvm_memory_slot old, new;
738 struct kvm_memslots *slots = NULL, *old_memslots; 756 struct kvm_memslots *slots = NULL, *old_memslots;
739 bool old_iommu_mapped; 757 bool old_iommu_mapped;
758 enum kvm_mr_change change;
740 759
741 r = check_memory_region_flags(mem); 760 r = check_memory_region_flags(mem);
742 if (r) 761 if (r)
@@ -780,17 +799,30 @@ int __kvm_set_memory_region(struct kvm *kvm,
780 799
781 old_iommu_mapped = old.npages; 800 old_iommu_mapped = old.npages;
782 801
783 /*
784 * Disallow changing a memory slot's size or changing anything about
785 * zero sized slots that doesn't involve making them non-zero.
786 */
787 r = -EINVAL; 802 r = -EINVAL;
788 if (npages && old.npages && npages != old.npages) 803 if (npages) {
789 goto out; 804 if (!old.npages)
790 if (!npages && !old.npages) 805 change = KVM_MR_CREATE;
806 else { /* Modify an existing slot. */
807 if ((mem->userspace_addr != old.userspace_addr) ||
808 (npages != old.npages))
809 goto out;
810
811 if (base_gfn != old.base_gfn)
812 change = KVM_MR_MOVE;
813 else if (new.flags != old.flags)
814 change = KVM_MR_FLAGS_ONLY;
815 else { /* Nothing to change. */
816 r = 0;
817 goto out;
818 }
819 }
820 } else if (old.npages) {
821 change = KVM_MR_DELETE;
822 } else /* Modify a non-existent slot: disallowed. */
791 goto out; 823 goto out;
792 824
793 if ((npages && !old.npages) || (base_gfn != old.base_gfn)) { 825 if ((change == KVM_MR_CREATE) || (change == KVM_MR_MOVE)) {
794 /* Check for overlaps */ 826 /* Check for overlaps */
795 r = -EEXIST; 827 r = -EEXIST;
796 kvm_for_each_memslot(slot, kvm->memslots) { 828 kvm_for_each_memslot(slot, kvm->memslots) {
@@ -808,20 +840,12 @@ int __kvm_set_memory_region(struct kvm *kvm,
808 new.dirty_bitmap = NULL; 840 new.dirty_bitmap = NULL;
809 841
810 r = -ENOMEM; 842 r = -ENOMEM;
811 843 if (change == KVM_MR_CREATE) {
812 /*
813 * Allocate if a slot is being created. If modifying a slot,
814 * the userspace_addr cannot change.
815 */
816 if (!old.npages) {
817 new.user_alloc = user_alloc; 844 new.user_alloc = user_alloc;
818 new.userspace_addr = mem->userspace_addr; 845 new.userspace_addr = mem->userspace_addr;
819 846
820 if (kvm_arch_create_memslot(&new, npages)) 847 if (kvm_arch_create_memslot(&new, npages))
821 goto out_free; 848 goto out_free;
822 } else if (npages && mem->userspace_addr != old.userspace_addr) {
823 r = -EINVAL;
824 goto out_free;
825 } 849 }
826 850
827 /* Allocate page dirty bitmap if needed */ 851 /* Allocate page dirty bitmap if needed */
@@ -830,7 +854,7 @@ int __kvm_set_memory_region(struct kvm *kvm,
830 goto out_free; 854 goto out_free;
831 } 855 }
832 856
833 if (!npages || base_gfn != old.base_gfn) { 857 if ((change == KVM_MR_DELETE) || (change == KVM_MR_MOVE)) {
834 r = -ENOMEM; 858 r = -ENOMEM;
835 slots = kmemdup(kvm->memslots, sizeof(struct kvm_memslots), 859 slots = kmemdup(kvm->memslots, sizeof(struct kvm_memslots),
836 GFP_KERNEL); 860 GFP_KERNEL);
@@ -881,7 +905,7 @@ int __kvm_set_memory_region(struct kvm *kvm,
881 * slots (size changes, userspace addr changes) is disallowed above, 905 * slots (size changes, userspace addr changes) is disallowed above,
882 * so any other attribute changes getting here can be skipped. 906 * so any other attribute changes getting here can be skipped.
883 */ 907 */
884 if (npages) { 908 if (change != KVM_MR_DELETE) {
885 if (old_iommu_mapped && 909 if (old_iommu_mapped &&
886 ((new.flags ^ old.flags) & KVM_MEM_READONLY)) { 910 ((new.flags ^ old.flags) & KVM_MEM_READONLY)) {
887 kvm_iommu_unmap_pages(kvm, &old); 911 kvm_iommu_unmap_pages(kvm, &old);
@@ -896,7 +920,7 @@ int __kvm_set_memory_region(struct kvm *kvm,
896 } 920 }
897 921
898 /* actual memory is freed via old in kvm_free_physmem_slot below */ 922 /* actual memory is freed via old in kvm_free_physmem_slot below */
899 if (!npages) { 923 if (change == KVM_MR_DELETE) {
900 new.dirty_bitmap = NULL; 924 new.dirty_bitmap = NULL;
901 memset(&new.arch, 0, sizeof(new.arch)); 925 memset(&new.arch, 0, sizeof(new.arch));
902 } 926 }