]> git.baikalelectronics.ru Git - kernel.git/commitdiff
KVM: Let/force architectures to deal with arch specific memslot data
authorSean Christopherson <seanjc@google.com>
Mon, 6 Dec 2021 19:54:11 +0000 (20:54 +0100)
committerPaolo Bonzini <pbonzini@redhat.com>
Wed, 8 Dec 2021 09:24:20 +0000 (04:24 -0500)
Pass the "old" slot to kvm_arch_prepare_memory_region() and force arch
code to handle propagating arch specific data from "new" to "old" when
necessary.  This is a baby step towards dynamically allocating "new" from
the get go, and is a (very) minor performance boost on x86 due to not
unnecessarily copying arch data.

For PPC HV, copy the rmap in the !CREATE and !DELETE paths, i.e. for MOVE
and FLAGS_ONLY.  This is functionally a nop as the previous behavior
would overwrite the pointer for CREATE, and eventually discard/ignore it
for DELETE.

For x86, copy the arch data only for FLAGS_ONLY changes.  Unlike PPC HV,
x86 needs to reallocate arch data in the MOVE case as the size of x86's
allocations depend on the alignment of the memslot's gfn.

Opportunistically tweak kvm_arch_prepare_memory_region()'s param order to
match the "commit" prototype.

Signed-off-by: Sean Christopherson <seanjc@google.com>
Reviewed-by: Maciej S. Szmigiero <maciej.szmigiero@oracle.com>
[mss: add missing RISCV kvm_arch_prepare_memory_region() change]
Signed-off-by: Maciej S. Szmigiero <maciej.szmigiero@oracle.com>
Message-Id: <67dea5f11bbcfd71e3da5986f11e87f5dd4013f9.1638817639.git.maciej.szmigiero@oracle.com>

13 files changed:
arch/arm64/kvm/mmu.c
arch/mips/kvm/mips.c
arch/powerpc/include/asm/kvm_ppc.h
arch/powerpc/kvm/book3s.c
arch/powerpc/kvm/book3s_hv.c
arch/powerpc/kvm/book3s_pr.c
arch/powerpc/kvm/booke.c
arch/powerpc/kvm/powerpc.c
arch/riscv/kvm/mmu.c
arch/s390/kvm/kvm-s390.c
arch/x86/kvm/x86.c
include/linux/kvm_host.h
virt/kvm/kvm_main.c

index 326cdfec74a15df906d437773b40ea7a1ae7342d..5d474360bf6c06296046ee0f962c020df6265aab 100644 (file)
@@ -1486,8 +1486,9 @@ void kvm_arch_commit_memory_region(struct kvm *kvm,
 }
 
 int kvm_arch_prepare_memory_region(struct kvm *kvm,
-                                  struct kvm_memory_slot *memslot,
                                   const struct kvm_userspace_memory_region *mem,
+                                  const struct kvm_memory_slot *old,
+                                  struct kvm_memory_slot *new,
                                   enum kvm_mr_change change)
 {
        hva_t hva = mem->userspace_addr;
@@ -1502,7 +1503,7 @@ int kvm_arch_prepare_memory_region(struct kvm *kvm,
         * Prevent userspace from creating a memory region outside of the IPA
         * space addressable by the KVM guest IPA space.
         */
-       if ((memslot->base_gfn + memslot->npages) > (kvm_phys_size(kvm) >> PAGE_SHIFT))
+       if ((new->base_gfn + new->npages) > (kvm_phys_size(kvm) >> PAGE_SHIFT))
                return -EFAULT;
 
        mmap_read_lock(current->mm);
@@ -1536,7 +1537,7 @@ int kvm_arch_prepare_memory_region(struct kvm *kvm,
 
                if (vma->vm_flags & VM_PFNMAP) {
                        /* IO region dirty page logging not allowed */
-                       if (memslot->flags & KVM_MEM_LOG_DIRTY_PAGES) {
+                       if (new->flags & KVM_MEM_LOG_DIRTY_PAGES) {
                                ret = -EINVAL;
                                break;
                        }
index 043204cd585f3770c1581d41c637795dcb5f7795..b2ce10784eb02d8eff67925d450e22c31c99a7c9 100644 (file)
@@ -214,8 +214,9 @@ void kvm_arch_flush_shadow_memslot(struct kvm *kvm,
 }
 
 int kvm_arch_prepare_memory_region(struct kvm *kvm,
-                                  struct kvm_memory_slot *memslot,
                                   const struct kvm_userspace_memory_region *mem,
+                                  const struct kvm_memory_slot *old,
+                                  struct kvm_memory_slot *new,
                                   enum kvm_mr_change change)
 {
        return 0;
index 671fbd1a765e2a637162fed3e7fd3ee954600138..b01760dd1374dfa5fcff6a63f2a196d2e7268903 100644 (file)
@@ -200,12 +200,13 @@ extern void kvmppc_core_destroy_vm(struct kvm *kvm);
 extern void kvmppc_core_free_memslot(struct kvm *kvm,
                                     struct kvm_memory_slot *slot);
 extern int kvmppc_core_prepare_memory_region(struct kvm *kvm,
-                               struct kvm_memory_slot *memslot,
                                const struct kvm_userspace_memory_region *mem,
+                               const struct kvm_memory_slot *old,
+                               struct kvm_memory_slot *new,
                                enum kvm_mr_change change);
 extern void kvmppc_core_commit_memory_region(struct kvm *kvm,
                                const struct kvm_userspace_memory_region *mem,
-                               const struct kvm_memory_slot *old,
+                               struct kvm_memory_slot *old,
                                const struct kvm_memory_slot *new,
                                enum kvm_mr_change change);
 extern int kvm_vm_ioctl_get_smmu_info(struct kvm *kvm,
@@ -274,12 +275,13 @@ struct kvmppc_ops {
        int (*get_dirty_log)(struct kvm *kvm, struct kvm_dirty_log *log);
        void (*flush_memslot)(struct kvm *kvm, struct kvm_memory_slot *memslot);
        int (*prepare_memory_region)(struct kvm *kvm,
-                                    struct kvm_memory_slot *memslot,
                                     const struct kvm_userspace_memory_region *mem,
+                                    const struct kvm_memory_slot *old,
+                                    struct kvm_memory_slot *new,
                                     enum kvm_mr_change change);
        void (*commit_memory_region)(struct kvm *kvm,
                                     const struct kvm_userspace_memory_region *mem,
-                                    const struct kvm_memory_slot *old,
+                                    struct kvm_memory_slot *old,
                                     const struct kvm_memory_slot *new,
                                     enum kvm_mr_change change);
        bool (*unmap_gfn_range)(struct kvm *kvm, struct kvm_gfn_range *range);
index b785f67723916326874dcc1285e915cf99d4160b..8250e8308674c7967e2e9c0bface18b12325b91b 100644 (file)
@@ -847,17 +847,17 @@ void kvmppc_core_flush_memslot(struct kvm *kvm, struct kvm_memory_slot *memslot)
 }
 
 int kvmppc_core_prepare_memory_region(struct kvm *kvm,
-                               struct kvm_memory_slot *memslot,
-                               const struct kvm_userspace_memory_region *mem,
-                               enum kvm_mr_change change)
+                                     const struct kvm_userspace_memory_region *mem,
+                                     const struct kvm_memory_slot *old,
+                                     struct kvm_memory_slot *new,
+                                     enum kvm_mr_change change)
 {
-       return kvm->arch.kvm_ops->prepare_memory_region(kvm, memslot, mem,
-                                                       change);
+       return kvm->arch.kvm_ops->prepare_memory_region(kvm, mem, old, new, change);
 }
 
 void kvmppc_core_commit_memory_region(struct kvm *kvm,
                                const struct kvm_userspace_memory_region *mem,
-                               const struct kvm_memory_slot *old,
+                               struct kvm_memory_slot *old,
                                const struct kvm_memory_slot *new,
                                enum kvm_mr_change change)
 {
index 32873c6985f9a36b258f997f1625700784711bfb..d7594d49d288a3d14fbe7d2adf23d10fb053740b 100644 (file)
@@ -4854,17 +4854,20 @@ static void kvmppc_core_free_memslot_hv(struct kvm_memory_slot *slot)
 }
 
 static int kvmppc_core_prepare_memory_region_hv(struct kvm *kvm,
-                                       struct kvm_memory_slot *slot,
-                                       const struct kvm_userspace_memory_region *mem,
-                                       enum kvm_mr_change change)
+                               const struct kvm_userspace_memory_region *mem,
+                               const struct kvm_memory_slot *old,
+                               struct kvm_memory_slot *new,
+                               enum kvm_mr_change change)
 {
        unsigned long npages = mem->memory_size >> PAGE_SHIFT;
 
        if (change == KVM_MR_CREATE) {
-               slot->arch.rmap = vzalloc(array_size(npages,
-                                         sizeof(*slot->arch.rmap)));
-               if (!slot->arch.rmap)
+               new->arch.rmap = vzalloc(array_size(npages,
+                                         sizeof(*new->arch.rmap)));
+               if (!new->arch.rmap)
                        return -ENOMEM;
+       } else if (change != KVM_MR_DELETE) {
+               new->arch.rmap = old->arch.rmap;
        }
 
        return 0;
@@ -4872,7 +4875,7 @@ static int kvmppc_core_prepare_memory_region_hv(struct kvm *kvm,
 
 static void kvmppc_core_commit_memory_region_hv(struct kvm *kvm,
                                const struct kvm_userspace_memory_region *mem,
-                               const struct kvm_memory_slot *old,
+                               struct kvm_memory_slot *old,
                                const struct kvm_memory_slot *new,
                                enum kvm_mr_change change)
 {
index bb0612c49b92b1029bb78fedda2c9316b549ae53..ffb559cf25f435493e97847949c7bd6e2761f855 100644 (file)
@@ -1899,16 +1899,17 @@ static void kvmppc_core_flush_memslot_pr(struct kvm *kvm,
 }
 
 static int kvmppc_core_prepare_memory_region_pr(struct kvm *kvm,
-                                       struct kvm_memory_slot *memslot,
-                                       const struct kvm_userspace_memory_region *mem,
-                                       enum kvm_mr_change change)
+                               const struct kvm_userspace_memory_region *mem,
+                               const struct kvm_memory_slot *old,
+                               struct kvm_memory_slot *new,
+                               enum kvm_mr_change change)
 {
        return 0;
 }
 
 static void kvmppc_core_commit_memory_region_pr(struct kvm *kvm,
                                const struct kvm_userspace_memory_region *mem,
-                               const struct kvm_memory_slot *old,
+                               struct kvm_memory_slot *old,
                                const struct kvm_memory_slot *new,
                                enum kvm_mr_change change)
 {
index 8c15c90dd3a9727ce23589fed07f3194aeaefe78..93c2ac2bee0913b868f86149981cf8f91a1e2003 100644 (file)
@@ -1821,8 +1821,9 @@ void kvmppc_core_free_memslot(struct kvm *kvm, struct kvm_memory_slot *slot)
 }
 
 int kvmppc_core_prepare_memory_region(struct kvm *kvm,
-                                     struct kvm_memory_slot *memslot,
                                      const struct kvm_userspace_memory_region *mem,
+                                     const struct kvm_memory_slot *old,
+                                     struct kvm_memory_slot *new,
                                      enum kvm_mr_change change)
 {
        return 0;
@@ -1830,7 +1831,7 @@ int kvmppc_core_prepare_memory_region(struct kvm *kvm,
 
 void kvmppc_core_commit_memory_region(struct kvm *kvm,
                                const struct kvm_userspace_memory_region *mem,
-                               const struct kvm_memory_slot *old,
+                               struct kvm_memory_slot *old,
                                const struct kvm_memory_slot *new,
                                enum kvm_mr_change change)
 {
index 98f5d90ebf5aa3b4404c81c62070b81beee82216..e875874cf8367d759d2147a7637b8407cf5f5816 100644 (file)
@@ -698,11 +698,12 @@ void kvm_arch_free_memslot(struct kvm *kvm, struct kvm_memory_slot *slot)
 }
 
 int kvm_arch_prepare_memory_region(struct kvm *kvm,
-                                  struct kvm_memory_slot *memslot,
                                   const struct kvm_userspace_memory_region *mem,
+                                  const struct kvm_memory_slot *old,
+                                  struct kvm_memory_slot *new,
                                   enum kvm_mr_change change)
 {
-       return kvmppc_core_prepare_memory_region(kvm, memslot, mem, change);
+       return kvmppc_core_prepare_memory_region(kvm, mem, old, new, change);
 }
 
 void kvm_arch_commit_memory_region(struct kvm *kvm,
index fc058ff5f4b6f3ac393d58ea25d0446a19fc7664..50380f52534526fe54f1652e52552fccc0be5529 100644 (file)
@@ -477,8 +477,9 @@ void kvm_arch_commit_memory_region(struct kvm *kvm,
 }
 
 int kvm_arch_prepare_memory_region(struct kvm *kvm,
-                               struct kvm_memory_slot *memslot,
                                const struct kvm_userspace_memory_region *mem,
+                               const struct kvm_memory_slot *old,
+                               struct kvm_memory_slot *new,
                                enum kvm_mr_change change)
 {
        hva_t hva = mem->userspace_addr;
@@ -494,7 +495,7 @@ int kvm_arch_prepare_memory_region(struct kvm *kvm,
         * Prevent userspace from creating a memory region outside of the GPA
         * space addressable by the KVM guest GPA space.
         */
-       if ((memslot->base_gfn + memslot->npages) >=
+       if ((new->base_gfn + new->npages) >=
            (stage2_gpa_size >> PAGE_SHIFT))
                return -EFAULT;
 
@@ -541,7 +542,7 @@ int kvm_arch_prepare_memory_region(struct kvm *kvm,
                        pa += vm_start - vma->vm_start;
 
                        /* IO region dirty page logging not allowed */
-                       if (memslot->flags & KVM_MEM_LOG_DIRTY_PAGES) {
+                       if (new->flags & KVM_MEM_LOG_DIRTY_PAGES) {
                                ret = -EINVAL;
                                goto out;
                        }
index fd5f4ec1b4b99584e0153d4da863507724012d74..3beefadda0db2dd477cba739056670a71034c152 100644 (file)
@@ -5007,8 +5007,9 @@ vm_fault_t kvm_arch_vcpu_fault(struct kvm_vcpu *vcpu, struct vm_fault *vmf)
 
 /* Section: memory related */
 int kvm_arch_prepare_memory_region(struct kvm *kvm,
-                                  struct kvm_memory_slot *memslot,
                                   const struct kvm_userspace_memory_region *mem,
+                                  const struct kvm_memory_slot *old,
+                                  struct kvm_memory_slot *new,
                                   enum kvm_mr_change change)
 {
        /* A few sanity checks. We can have memory slots which have to be
index 96bcf2035bdcd6c94a260ac969c41c1141c3d22c..287ff4e43a13eae870f384edcb90eb06f5ffb52f 100644 (file)
@@ -11674,13 +11674,20 @@ void kvm_arch_memslots_updated(struct kvm *kvm, u64 gen)
 }
 
 int kvm_arch_prepare_memory_region(struct kvm *kvm,
-                               struct kvm_memory_slot *memslot,
-                               const struct kvm_userspace_memory_region *mem,
-                               enum kvm_mr_change change)
+                                  const struct kvm_userspace_memory_region *mem,
+                                  const struct kvm_memory_slot *old,
+                                  struct kvm_memory_slot *new,
+                                  enum kvm_mr_change change)
 {
        if (change == KVM_MR_CREATE || change == KVM_MR_MOVE)
-               return kvm_alloc_memslot_metadata(kvm, memslot,
+               return kvm_alloc_memslot_metadata(kvm, new,
                                                  mem->memory_size >> PAGE_SHIFT);
+
+       if (change == KVM_MR_FLAGS_ONLY)
+               memcpy(&new->arch, &old->arch, sizeof(old->arch));
+       else if (WARN_ON_ONCE(change != KVM_MR_DELETE))
+               return -EIO;
+
        return 0;
 }
 
index e38705359af5e436a2fa29b5c2c9ff0f28226103..cb7311dc6f32ff28020d8f061fca85c2ed00c9e9 100644 (file)
@@ -833,8 +833,9 @@ int __kvm_set_memory_region(struct kvm *kvm,
 void kvm_arch_free_memslot(struct kvm *kvm, struct kvm_memory_slot *slot);
 void kvm_arch_memslots_updated(struct kvm *kvm, u64 gen);
 int kvm_arch_prepare_memory_region(struct kvm *kvm,
-                               struct kvm_memory_slot *memslot,
                                const struct kvm_userspace_memory_region *mem,
+                               const struct kvm_memory_slot *old,
+                               struct kvm_memory_slot *new,
                                enum kvm_mr_change change);
 void kvm_arch_commit_memory_region(struct kvm *kvm,
                                const struct kvm_userspace_memory_region *mem,
index a7a1c872fe6d67e6915afa5be62111e2224d7c9a..46060cc542ef4788aa1280a469ad544138efd5ec 100644 (file)
@@ -1636,10 +1636,7 @@ static int kvm_set_memslot(struct kvm *kvm,
                old.as_id = new->as_id;
        }
 
-       /* Copy the arch-specific data, again after (re)acquiring slots_arch_lock. */
-       memcpy(&new->arch, &old.arch, sizeof(old.arch));
-
-       r = kvm_arch_prepare_memory_region(kvm, new, mem, change);
+       r = kvm_arch_prepare_memory_region(kvm, mem, &old, new, change);
        if (r)
                goto out_slots;