Commit cf47f50b authored by Sean Christopherson's avatar Sean Christopherson Committed by Paolo Bonzini
Browse files

KVM: Move setting of memslot into helper routine



Split out the core functionality of setting a memslot into a separate
helper in preparation for moving memslot deletion into its own routine.

Tested-by: default avatarChristoffer Dall <christoffer.dall@arm.com>
Reviewed-by: default avatarPhilippe Mathieu-Daudé <f4bug@amsat.org>
Reviewed-by: default avatarPeter Xu <peterx@redhat.com>
Signed-off-by: default avatarSean Christopherson <sean.j.christopherson@intel.com>
Signed-off-by: default avatarPaolo Bonzini <pbonzini@redhat.com>
parent 71a4c30b
Loading
Loading
Loading
Loading
+63 −43
Original line number Original line Diff line number Diff line
@@ -983,6 +983,66 @@ static struct kvm_memslots *install_new_memslots(struct kvm *kvm,
	return old_memslots;
	return old_memslots;
}
}


static int kvm_set_memslot(struct kvm *kvm,
			   const struct kvm_userspace_memory_region *mem,
			   const struct kvm_memory_slot *old,
			   struct kvm_memory_slot *new, int as_id,
			   enum kvm_mr_change change)
{
	struct kvm_memory_slot *slot;
	struct kvm_memslots *slots;
	int r;

	slots = kvzalloc(sizeof(struct kvm_memslots), GFP_KERNEL_ACCOUNT);
	if (!slots)
		return -ENOMEM;
	memcpy(slots, __kvm_memslots(kvm, as_id), sizeof(struct kvm_memslots));

	if (change == KVM_MR_DELETE || change == KVM_MR_MOVE) {
		/*
		 * Note, the INVALID flag needs to be in the appropriate entry
		 * in the freshly allocated memslots, not in @old or @new.
		 */
		slot = id_to_memslot(slots, old->id);
		slot->flags |= KVM_MEMSLOT_INVALID;

		/*
		 * We can re-use the old memslots, the only difference from the
		 * newly installed memslots is the invalid flag, which will get
		 * dropped by update_memslots anyway.  We'll also revert to the
		 * old memslots if preparing the new memory region fails.
		 */
		slots = install_new_memslots(kvm, as_id, slots);

		/* From this point no new shadow pages pointing to a deleted,
		 * or moved, memslot will be created.
		 *
		 * validation of sp->gfn happens in:
		 *	- gfn_to_hva (kvm_read_guest, gfn_to_pfn)
		 *	- kvm_is_visible_gfn (mmu_check_root)
		 */
		kvm_arch_flush_shadow_memslot(kvm, slot);
	}

	r = kvm_arch_prepare_memory_region(kvm, new, mem, change);
	if (r)
		goto out_slots;

	update_memslots(slots, new, change);
	slots = install_new_memslots(kvm, as_id, slots);

	kvm_arch_commit_memory_region(kvm, mem, old, new, change);

	kvfree(slots);
	return 0;

out_slots:
	if (change == KVM_MR_DELETE || change == KVM_MR_MOVE)
		slots = install_new_memslots(kvm, as_id, slots);
	kvfree(slots);
	return r;
}

/*
/*
 * Allocate some memory and give it an address in the guest physical address
 * Allocate some memory and give it an address in the guest physical address
 * space.
 * space.
@@ -999,7 +1059,6 @@ int __kvm_set_memory_region(struct kvm *kvm,
	unsigned long npages;
	unsigned long npages;
	struct kvm_memory_slot *slot;
	struct kvm_memory_slot *slot;
	struct kvm_memory_slot old, new;
	struct kvm_memory_slot old, new;
	struct kvm_memslots *slots;
	int as_id, id;
	int as_id, id;
	enum kvm_mr_change change;
	enum kvm_mr_change change;


@@ -1086,58 +1145,19 @@ int __kvm_set_memory_region(struct kvm *kvm,
			return r;
			return r;
	}
	}


	slots = kvzalloc(sizeof(struct kvm_memslots), GFP_KERNEL_ACCOUNT);
	if (!slots) {
		r = -ENOMEM;
		goto out_bitmap;
	}
	memcpy(slots, __kvm_memslots(kvm, as_id), sizeof(struct kvm_memslots));

	if ((change == KVM_MR_DELETE) || (change == KVM_MR_MOVE)) {
		slot = id_to_memslot(slots, id);
		slot->flags |= KVM_MEMSLOT_INVALID;

		/*
		 * We can re-use the old memslots, the only difference from the
		 * newly installed memslots is the invalid flag, which will get
		 * dropped by update_memslots anyway.  We'll also revert to the
		 * old memslots if preparing the new memory region fails.
		 */
		slots = install_new_memslots(kvm, as_id, slots);

		/* From this point no new shadow pages pointing to a deleted,
		 * or moved, memslot will be created.
		 *
		 * validation of sp->gfn happens in:
		 *	- gfn_to_hva (kvm_read_guest, gfn_to_pfn)
		 *	- kvm_is_visible_gfn (mmu_check_root)
		 */
		kvm_arch_flush_shadow_memslot(kvm, slot);
	}

	r = kvm_arch_prepare_memory_region(kvm, &new, mem, change);
	if (r)
		goto out_slots;

	/* actual memory is freed via old in kvm_free_memslot below */
	/* actual memory is freed via old in kvm_free_memslot below */
	if (change == KVM_MR_DELETE) {
	if (change == KVM_MR_DELETE) {
		new.dirty_bitmap = NULL;
		new.dirty_bitmap = NULL;
		memset(&new.arch, 0, sizeof(new.arch));
		memset(&new.arch, 0, sizeof(new.arch));
	}
	}


	update_memslots(slots, &new, change);
	r = kvm_set_memslot(kvm, mem, &old, &new, as_id, change);
	slots = install_new_memslots(kvm, as_id, slots);
	if (r)

		goto out_bitmap;
	kvm_arch_commit_memory_region(kvm, mem, &old, &new, change);


	kvm_free_memslot(kvm, &old, &new);
	kvm_free_memslot(kvm, &old, &new);
	kvfree(slots);
	return 0;
	return 0;


out_slots:
	if (change == KVM_MR_DELETE || change == KVM_MR_MOVE)
		slots = install_new_memslots(kvm, as_id, slots);
	kvfree(slots);
out_bitmap:
out_bitmap:
	if (new.dirty_bitmap && !old.dirty_bitmap)
	if (new.dirty_bitmap && !old.dirty_bitmap)
		kvm_destroy_dirty_bitmap(&new);
		kvm_destroy_dirty_bitmap(&new);