lkml.org 
[lkml]   [2022]   [Aug]   [7]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
From
Subject[PATCH v8 055/103] KVM: Add functions to track whether GFN is private or shared
Date
From: Isaku Yamahata <isaku.yamahata@intel.com>

TDX KVM support needs to track whether GFN is private or shared. Introduce
CONFIG_HAVE_KVM_PRIVATE_MEM_ATTR to add functions to track whether GFN is
private or shared. Use xarray to track it for memory efficiency in normal
usage.

Suggested-by: Sean Christopherson <seanjc@google.com>
Signed-off-by: Isaku Yamahata <isaku.yamahata@intel.com>
---
arch/x86/kvm/Kconfig | 1 +
include/linux/kvm_host.h | 16 ++++++++++++
virt/kvm/Kconfig | 3 +++
virt/kvm/kvm_main.c | 55 ++++++++++++++++++++++++++++++++++++++++
4 files changed, 75 insertions(+)

diff --git a/arch/x86/kvm/Kconfig b/arch/x86/kvm/Kconfig
index 5a59abc83179..a77830a3f371 100644
--- a/arch/x86/kvm/Kconfig
+++ b/arch/x86/kvm/Kconfig
@@ -48,6 +48,7 @@ config KVM
select SRCU
select INTERVAL_TREE
select HAVE_KVM_PM_NOTIFIER if PM
+ select HAVE_KVM_PRIVATE_MEM_ATTR if KVM_MMU_PRIVATE
help
Support hosting fully virtualized guest machines using hardware
virtualization extensions. You will need a fairly recent
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
index 025251806e70..7bc84ed44e43 100644
--- a/include/linux/kvm_host.h
+++ b/include/linux/kvm_host.h
@@ -786,8 +786,24 @@ struct kvm {
struct notifier_block pm_notifier;
#endif
char stats_id[KVM_STATS_NAME_SIZE];
+#ifdef CONFIG_HAVE_KVM_PRIVATE_MEM_ATTR
+ struct xarray mem_attr_array;
+#endif
};

+#ifdef CONFIG_HAVE_KVM_PRIVATE_MEM_ATTR
+#define KVM_MEM_ATTR_SHARED 0x1
+#define KVM_MEM_ATTR_PRIVATE 0x2
+
+/* memory attr on [start, end) */
+int kvm_vm_reserve_mem_attr(struct kvm *kvm, gfn_t start, gfn_t end);
+int kvm_vm_set_mem_attr(struct kvm *kvm, int attr, gfn_t start, gfn_t end);
+static inline bool kvm_mem_is_private(struct kvm *kvm, gfn_t gfn)
+{
+ return !xa_load(&kvm->mem_attr_array, gfn);
+}
+#endif
+
#define kvm_err(fmt, ...) \
pr_err("kvm [%i]: " fmt, task_pid_nr(current), ## __VA_ARGS__)
#define kvm_info(fmt, ...) \
diff --git a/virt/kvm/Kconfig b/virt/kvm/Kconfig
index a8c5c9f06b3c..bef6fc63f99f 100644
--- a/virt/kvm/Kconfig
+++ b/virt/kvm/Kconfig
@@ -72,3 +72,6 @@ config KVM_XFER_TO_GUEST_WORK

config HAVE_KVM_PM_NOTIFIER
bool
+
+config HAVE_KVM_PRIVATE_MEM_ATTR
+ bool
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index 3cc29fdba562..e182161baf00 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -917,6 +917,55 @@ static int kvm_init_mmu_notifier(struct kvm *kvm)

#endif /* CONFIG_MMU_NOTIFIER && KVM_ARCH_WANT_MMU_NOTIFIER */

+#ifdef CONFIG_HAVE_KVM_PRIVATE_MEM_ATTR
+/*
+ * Reserve memory for [start, end) so that the next set oepration won't fail
+ * with -ENOMEM.
+ */
+int kvm_vm_reserve_mem_attr(struct kvm *kvm, gfn_t start, gfn_t end)
+{
+ int r = 0;
+ gfn_t gfn;
+
+ xa_lock(&kvm->mem_attr_array);
+ for (gfn = start; gfn < end; gfn++) {
+ r = __xa_insert(&kvm->mem_attr_array, gfn, NULL, GFP_KERNEL_ACCOUNT);
+ if (r == -EBUSY)
+ r = 0;
+ if (r)
+ break;
+ }
+ xa_unlock(&kvm->mem_attr_array);
+
+ return r;
+}
+EXPORT_SYMBOL_GPL(kvm_vm_reserve_mem_attr);
+
+/* Set memory attr for [start, end) */
+int kvm_vm_set_mem_attr(struct kvm *kvm, int attr, gfn_t start, gfn_t end)
+{
+ void *entry;
+
+ /* By default, the entry is private. */
+ switch (attr) {
+ case KVM_MEM_ATTR_PRIVATE:
+ entry = NULL;
+ break;
+ case KVM_MEM_ATTR_SHARED:
+ entry = xa_mk_value(KVM_MEM_ATTR_SHARED);
+ break;
+ default:
+ WARN_ON_ONCE(1);
+ return -EINVAL;
+ }
+
+ WARN_ON(start >= end);
+ return xa_err(xa_store_range(&kvm->mem_attr_array, start, end - 1,
+ entry, GFP_KERNEL_ACCOUNT));
+}
+EXPORT_SYMBOL_GPL(kvm_vm_set_mem_attr);
+#endif /* CONFIG_HAVE_KVM_PRIVATE_MEM_ATTR */
+
#ifdef CONFIG_HAVE_KVM_PM_NOTIFIER
static int kvm_pm_notifier_call(struct notifier_block *bl,
unsigned long state,
@@ -1141,6 +1190,9 @@ static struct kvm *kvm_create_vm(unsigned long type)
spin_lock_init(&kvm->mn_invalidate_lock);
rcuwait_init(&kvm->mn_memslots_update_rcuwait);
xa_init(&kvm->vcpu_array);
+#ifdef CONFIG_HAVE_KVM_PRIVATE_MEM_ATTR
+ xa_init(&kvm->mem_attr_array);
+#endif

INIT_LIST_HEAD(&kvm->gpc_list);
spin_lock_init(&kvm->gpc_lock);
@@ -1308,6 +1360,9 @@ static void kvm_destroy_vm(struct kvm *kvm)
kvm_free_memslots(kvm, &kvm->__memslots[i][0]);
kvm_free_memslots(kvm, &kvm->__memslots[i][1]);
}
+#ifdef CONFIG_HAVE_KVM_PRIVATE_MEM_ATTR
+ xa_destroy(&kvm->mem_attr_array);
+#endif
cleanup_srcu_struct(&kvm->irq_srcu);
cleanup_srcu_struct(&kvm->srcu);
kvm_arch_free_vm(kvm);
--
2.25.1
\
 
 \ /
  Last update: 2022-08-08 00:07    [W:0.635 / U:0.936 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site