aboutsummaryrefslogtreecommitdiffstats
path: root/virt
diff options
context:
space:
mode:
authorTakuya Yoshikawa <yoshikawa_takuya_b1@lab.ntt.co.jp>2013-01-28 21:00:07 -0500
committerMarcelo Tosatti <mtosatti@redhat.com>2013-02-04 19:00:53 -0500
commitf64c0398939483eb1d8951f24fbc21e94ed54457 (patch)
treee0d3b9b109f82dbfca84f347f1848a6797a80405 /virt
parent0c29b2293b25527a1759cbd22b106f19258636b6 (diff)
KVM: set_memory_region: Identify the requested change explicitly
KVM_SET_USER_MEMORY_REGION forces __kvm_set_memory_region() to identify what kind of change is being requested by checking the arguments. The current code does this checking at various points in code and each condition being used there is not easy to understand at first glance. This patch consolidates these checks and introduces an enum to name the possible changes to clean up the code. Although this does not introduce any functional changes, there is one change which optimizes the code a bit: if we have nothing to change, the new code returns 0 immediately. Note that the return value for this case cannot be changed since QEMU relies on it: we noticed this when we changed it to -EINVAL and got a section mismatch error at the final stage of live migration. Signed-off-by: Takuya Yoshikawa <yoshikawa_takuya_b1@lab.ntt.co.jp> Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
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 }