Commit f64c0398939483eb1d8951f24fbc21e94ed54457

Authored by Takuya Yoshikawa
Committed by Marcelo Tosatti
1 parent 0c29b2293b

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>

Showing 1 changed file with 44 additions and 20 deletions Side-by-side Diff

... ... @@ -719,6 +719,24 @@
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 + */
  732 +enum kvm_mr_change {
  733 + KVM_MR_CREATE,
  734 + KVM_MR_DELETE,
  735 + KVM_MR_MOVE,
  736 + KVM_MR_FLAGS_ONLY,
  737 +};
  738 +
  739 +/*
722 740 * Allocate some memory and give it an address in the guest physical address
723 741 * space.
724 742 *
... ... @@ -737,6 +755,7 @@
737 755 struct kvm_memory_slot old, new;
738 756 struct kvm_memslots *slots = NULL, *old_memslots;
739 757 bool old_iommu_mapped;
  758 + enum kvm_mr_change change;
740 759  
741 760 r = check_memory_region_flags(mem);
742 761 if (r)
743 762  
744 763  
745 764  
... ... @@ -780,17 +799,30 @@
780 799  
781 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 802 r = -EINVAL;
788   - if (npages && old.npages && npages != old.npages)
  803 + if (npages) {
  804 + if (!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. */
789 823 goto out;
790   - if (!npages && !old.npages)
791   - 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 826 /* Check for overlaps */
795 827 r = -EEXIST;
796 828 kvm_for_each_memslot(slot, kvm->memslots) {
797 829  
... ... @@ -808,20 +840,12 @@
808 840 new.dirty_bitmap = NULL;
809 841  
810 842 r = -ENOMEM;
811   -
812   - /*
813   - * Allocate if a slot is being created. If modifying a slot,
814   - * the userspace_addr cannot change.
815   - */
816   - if (!old.npages) {
  843 + if (change == KVM_MR_CREATE) {
817 844 new.user_alloc = user_alloc;
818 845 new.userspace_addr = mem->userspace_addr;
819 846  
820 847 if (kvm_arch_create_memslot(&new, npages))
821 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 851 /* Allocate page dirty bitmap if needed */
... ... @@ -830,7 +854,7 @@
830 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 858 r = -ENOMEM;
835 859 slots = kmemdup(kvm->memslots, sizeof(struct kvm_memslots),
836 860 GFP_KERNEL);
... ... @@ -881,7 +905,7 @@
881 905 * slots (size changes, userspace addr changes) is disallowed above,
882 906 * so any other attribute changes getting here can be skipped.
883 907 */
884   - if (npages) {
  908 + if (change != KVM_MR_DELETE) {
885 909 if (old_iommu_mapped &&
886 910 ((new.flags ^ old.flags) & KVM_MEM_READONLY)) {
887 911 kvm_iommu_unmap_pages(kvm, &old);
... ... @@ -896,7 +920,7 @@
896 920 }
897 921  
898 922 /* actual memory is freed via old in kvm_free_physmem_slot below */
899   - if (!npages) {
  923 + if (change == KVM_MR_DELETE) {
900 924 new.dirty_bitmap = NULL;
901 925 memset(&new.arch, 0, sizeof(new.arch));
902 926 }