[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH v4 10/12] KVM: Register private memslot to memory backing store
From: |
Chao Peng |
Subject: |
[PATCH v4 10/12] KVM: Register private memslot to memory backing store |
Date: |
Tue, 18 Jan 2022 21:21:19 +0800 |
Add 'notifier' to memslot to make it a memfile_notifier node and then
register it to memory backing store via memfile_register_notifier() when
memslot gets created. When memslot is deleted, do the reverse with
memfile_unregister_notifier(). Note each KVM memslot can be registered
to different memory backing stores (or the same backing store but at
different offset) independently.
Signed-off-by: Yu Zhang <yu.c.zhang@linux.intel.com>
Signed-off-by: Chao Peng <chao.p.peng@linux.intel.com>
---
include/linux/kvm_host.h | 1 +
virt/kvm/kvm_main.c | 75 ++++++++++++++++++++++++++++++++++++----
2 files changed, 70 insertions(+), 6 deletions(-)
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
index 927e7f44a02a..667efe839767 100644
--- a/include/linux/kvm_host.h
+++ b/include/linux/kvm_host.h
@@ -462,6 +462,7 @@ struct kvm_memory_slot {
struct file *private_file;
loff_t private_offset;
struct memfile_pfn_ops *pfn_ops;
+ struct memfile_notifier notifier;
};
static inline bool kvm_slot_is_private(const struct kvm_memory_slot *slot)
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index ecf94e2548f7..6b78ddef7880 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -846,6 +846,37 @@ static int kvm_init_mmu_notifier(struct kvm *kvm)
#endif /* CONFIG_MMU_NOTIFIER && KVM_ARCH_WANT_MMU_NOTIFIER */
+#ifdef CONFIG_MEMFILE_NOTIFIER
+static inline int kvm_memfile_register(struct kvm_memory_slot *slot)
+{
+ return memfile_register_notifier(file_inode(slot->private_file),
+ &slot->notifier,
+ &slot->pfn_ops);
+}
+
+static inline void kvm_memfile_unregister(struct kvm_memory_slot *slot)
+{
+ if (slot->private_file) {
+ memfile_unregister_notifier(file_inode(slot->private_file),
+ &slot->notifier);
+ fput(slot->private_file);
+ slot->private_file = NULL;
+ }
+}
+
+#else /* !CONFIG_MEMFILE_NOTIFIER */
+
+static inline int kvm_memfile_register(struct kvm_memory_slot *slot)
+{
+ return -EOPNOTSUPP;
+}
+
+static inline void kvm_memfile_unregister(struct kvm_memory_slot *slot)
+{
+}
+
+#endif /* CONFIG_MEMFILE_NOTIFIER */
+
#ifdef CONFIG_HAVE_KVM_PM_NOTIFIER
static int kvm_pm_notifier_call(struct notifier_block *bl,
unsigned long state,
@@ -890,6 +921,9 @@ static void kvm_destroy_dirty_bitmap(struct kvm_memory_slot
*memslot)
/* This does not remove the slot from struct kvm_memslots data structures */
static void kvm_free_memslot(struct kvm *kvm, struct kvm_memory_slot *slot)
{
+ if (slot->flags & KVM_MEM_PRIVATE)
+ kvm_memfile_unregister(slot);
+
kvm_destroy_dirty_bitmap(slot);
kvm_arch_free_memslot(kvm, slot);
@@ -1744,6 +1778,12 @@ static int kvm_set_memslot(struct kvm *kvm,
kvm_invalidate_memslot(kvm, old, invalid_slot);
}
+ if (new->flags & KVM_MEM_PRIVATE && change == KVM_MR_CREATE) {
+ r = kvm_memfile_register(new);
+ if (r)
+ return r;
+ }
+
r = kvm_prepare_memory_region(kvm, old, new, change);
if (r) {
/*
@@ -1758,6 +1798,10 @@ static int kvm_set_memslot(struct kvm *kvm,
} else {
mutex_unlock(&kvm->slots_arch_lock);
}
+
+ if (new->flags & KVM_MEM_PRIVATE && change == KVM_MR_CREATE)
+ kvm_memfile_unregister(new);
+
return r;
}
@@ -1823,6 +1867,7 @@ int __kvm_set_memory_region(struct kvm *kvm,
enum kvm_mr_change change;
unsigned long npages;
gfn_t base_gfn;
+ struct file *file = NULL;
int as_id, id;
int r;
@@ -1896,14 +1941,24 @@ int __kvm_set_memory_region(struct kvm *kvm,
return 0;
}
+ if (mem->flags & KVM_MEM_PRIVATE) {
+ file = fdget(region_ext->private_fd).file;
+ if (!file)
+ return -EINVAL;
+ }
+
if ((change == KVM_MR_CREATE || change == KVM_MR_MOVE) &&
- kvm_check_memslot_overlap(slots, id, base_gfn, base_gfn + npages))
- return -EEXIST;
+ kvm_check_memslot_overlap(slots, id, base_gfn, base_gfn + npages)) {
+ r = -EEXIST;
+ goto out;
+ }
/* Allocate a slot that will persist in the memslot. */
new = kzalloc(sizeof(*new), GFP_KERNEL_ACCOUNT);
- if (!new)
- return -ENOMEM;
+ if (!new) {
+ r = -ENOMEM;
+ goto out;
+ }
new->as_id = as_id;
new->id = id;
@@ -1911,10 +1966,18 @@ int __kvm_set_memory_region(struct kvm *kvm,
new->npages = npages;
new->flags = mem->flags;
new->userspace_addr = mem->userspace_addr;
+ new->private_file = file;
+ new->private_offset = mem->flags & KVM_MEM_PRIVATE ?
+ region_ext->private_offset : 0;
r = kvm_set_memslot(kvm, old, new, change);
- if (r)
- kfree(new);
+ if (!r)
+ return r;
+
+ kfree(new);
+out:
+ if (file)
+ fput(file);
return r;
}
EXPORT_SYMBOL_GPL(__kvm_set_memory_region);
--
2.17.1
- [PATCH v4 02/12] mm/memfd: Introduce MFD_INACCESSIBLE flag, (continued)
- [PATCH v4 02/12] mm/memfd: Introduce MFD_INACCESSIBLE flag, Chao Peng, 2022/01/18
- [PATCH v4 03/12] mm: Introduce memfile_notifier, Chao Peng, 2022/01/18
- [PATCH v4 04/12] mm/shmem: Support memfile_notifier, Chao Peng, 2022/01/18
- [PATCH v4 05/12] KVM: Extend the memslot to support fd-based private memory, Chao Peng, 2022/01/18
- [PATCH v4 06/12] KVM: Use kvm_userspace_memory_region_ext, Chao Peng, 2022/01/18
- [PATCH v4 07/12] KVM: Add KVM_EXIT_MEMORY_ERROR exit, Chao Peng, 2022/01/18
- [PATCH v4 08/12] KVM: Use memfile_pfn_ops to obtain pfn for private pages, Chao Peng, 2022/01/18
- [PATCH v4 09/12] KVM: Handle page fault for private memory, Chao Peng, 2022/01/18
- [PATCH v4 10/12] KVM: Register private memslot to memory backing store,
Chao Peng <=
- [PATCH v4 11/12] KVM: Zap existing KVM mappings when pages changed in the private fd, Chao Peng, 2022/01/18
- [PATCH v4 12/12] KVM: Expose KVM_MEM_PRIVATE, Chao Peng, 2022/01/18
- Re: [PATCH v4 00/12] KVM: mm: fd-based approach for supporting KVM guest private memory, Steven Price, 2022/01/28