KVM: PPC: Book3S HV: Migrate hot plugged memory
authorLaurent Dufour <ldufour@linux.ibm.com>
Mon, 27 Jul 2020 18:07:18 +0000 (11:07 -0700)
committerPaul Mackerras <paulus@ozlabs.org>
Tue, 28 Jul 2020 02:34:52 +0000 (12:34 +1000)
When a memory slot is hot plugged to a SVM, PFNs associated with the
GFNs in that slot must be migrated to the secure-PFNs, aka device-PFNs.

Call kvmppc_uv_migrate_mem_slot() to accomplish this.
Disable page-merge for all pages in the memory slot.

Reviewed-by: Bharata B Rao <bharata@linux.ibm.com>
Signed-off-by: Ram Pai <linuxram@us.ibm.com>
[rearranged the code, and modified the commit log]
Signed-off-by: Laurent Dufour <ldufour@linux.ibm.com>
Signed-off-by: Paul Mackerras <paulus@ozlabs.org>
arch/powerpc/include/asm/kvm_book3s_uvmem.h
arch/powerpc/kvm/book3s_hv.c
arch/powerpc/kvm/book3s_hv_uvmem.c

index 9cb7d8b..0a63194 100644 (file)
@@ -23,6 +23,10 @@ int kvmppc_send_page_to_uv(struct kvm *kvm, unsigned long gfn);
 unsigned long kvmppc_h_svm_init_abort(struct kvm *kvm);
 void kvmppc_uvmem_drop_pages(const struct kvm_memory_slot *free,
                             struct kvm *kvm, bool skip_page_out);
+int kvmppc_uvmem_memslot_create(struct kvm *kvm,
+               const struct kvm_memory_slot *new);
+void kvmppc_uvmem_memslot_delete(struct kvm *kvm,
+               const struct kvm_memory_slot *old);
 #else
 static inline int kvmppc_uvmem_init(void)
 {
@@ -82,5 +86,15 @@ static inline int kvmppc_send_page_to_uv(struct kvm *kvm, unsigned long gfn)
 static inline void
 kvmppc_uvmem_drop_pages(const struct kvm_memory_slot *free,
                        struct kvm *kvm, bool skip_page_out) { }
+
+static inline int  kvmppc_uvmem_memslot_create(struct kvm *kvm,
+               const struct kvm_memory_slot *new)
+{
+       return H_UNSUPPORTED;
+}
+
+static inline void  kvmppc_uvmem_memslot_delete(struct kvm *kvm,
+               const struct kvm_memory_slot *old) { }
+
 #endif /* CONFIG_PPC_UV */
 #endif /* __ASM_KVM_BOOK3S_UVMEM_H__ */
index d64a2dc..d9a9dd7 100644 (file)
@@ -4523,16 +4523,14 @@ static void kvmppc_core_commit_memory_region_hv(struct kvm *kvm,
 
        switch (change) {
        case KVM_MR_CREATE:
-               if (kvmppc_uvmem_slot_init(kvm, new))
-                       return;
-               uv_register_mem_slot(kvm->arch.lpid,
-                                    new->base_gfn << PAGE_SHIFT,
-                                    new->npages * PAGE_SIZE,
-                                    0, new->id);
+               /*
+                * @TODO kvmppc_uvmem_memslot_create() can fail and
+                * return error. Fix this.
+                */
+               kvmppc_uvmem_memslot_create(kvm, new);
                break;
        case KVM_MR_DELETE:
-               uv_unregister_mem_slot(kvm->arch.lpid, old->id);
-               kvmppc_uvmem_slot_free(kvm, old);
+               kvmppc_uvmem_memslot_delete(kvm, old);
                break;
        default:
                /* TODO: Handle KVM_MR_MOVE */
index a1664ae..5b917ea 100644 (file)
@@ -418,7 +418,7 @@ static int kvmppc_memslot_page_merge(struct kvm *kvm,
        return ret;
 }
 
-static void kvmppc_uvmem_memslot_delete(struct kvm *kvm,
+static void __kvmppc_uvmem_memslot_delete(struct kvm *kvm,
                const struct kvm_memory_slot *memslot)
 {
        uv_unregister_mem_slot(kvm->arch.lpid, memslot->id);
@@ -426,7 +426,7 @@ static void kvmppc_uvmem_memslot_delete(struct kvm *kvm,
        kvmppc_memslot_page_merge(kvm, memslot, true);
 }
 
-static int kvmppc_uvmem_memslot_create(struct kvm *kvm,
+static int __kvmppc_uvmem_memslot_create(struct kvm *kvm,
                const struct kvm_memory_slot *memslot)
 {
        int ret = H_PARAMETER;
@@ -478,7 +478,7 @@ unsigned long kvmppc_h_svm_init_start(struct kvm *kvm)
        /* register the memslot */
        slots = kvm_memslots(kvm);
        kvm_for_each_memslot(memslot, slots) {
-               ret = kvmppc_uvmem_memslot_create(kvm, memslot);
+               ret = __kvmppc_uvmem_memslot_create(kvm, memslot);
                if (ret)
                        break;
        }
@@ -488,7 +488,7 @@ unsigned long kvmppc_h_svm_init_start(struct kvm *kvm)
                kvm_for_each_memslot(m, slots) {
                        if (m == memslot)
                                break;
-                       kvmppc_uvmem_memslot_delete(kvm, memslot);
+                       __kvmppc_uvmem_memslot_delete(kvm, memslot);
                }
        }
 
@@ -1057,6 +1057,21 @@ out:
        return (ret == U_SUCCESS) ? RESUME_GUEST : -EFAULT;
 }
 
+int kvmppc_uvmem_memslot_create(struct kvm *kvm, const struct kvm_memory_slot *new)
+{
+       int ret = __kvmppc_uvmem_memslot_create(kvm, new);
+
+       if (!ret)
+               ret = kvmppc_uv_migrate_mem_slot(kvm, new);
+
+       return ret;
+}
+
+void kvmppc_uvmem_memslot_delete(struct kvm *kvm, const struct kvm_memory_slot *old)
+{
+       __kvmppc_uvmem_memslot_delete(kvm, old);
+}
+
 static u64 kvmppc_get_secmem_size(void)
 {
        struct device_node *np;