qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH v3 kvm/queue 08/16] KVM: Special handling for fd-based memory inv


From: Chao Peng
Subject: [PATCH v3 kvm/queue 08/16] KVM: Special handling for fd-based memory invalidation
Date: Thu, 23 Dec 2021 20:30:03 +0800

For fd-based guest memory, the memory backend (e.g. the fd provider)
should notify KVM to unmap/invalidate the privated memory from KVM
secondary MMU when userspace punches hole on the fd (e.g. when
userspace converts private memory to shared memory).

To support fd-based memory invalidation, existing hva-based memory
invalidation needs to be extended. A new 'inode' for the fd is passed in
from memfd_falloc_notifier and the 'start/end' will represent start/end
offset in the fd instead of hva range. During the invalidation KVM needs
to check this inode against that in the memslot. Only when the 'inode' in
memslot equals to the passed-in 'inode' we should invalidate the mapping
in KVM.

Signed-off-by: Yu Zhang <yu.c.zhang@linux.intel.com>
Signed-off-by: Chao Peng <chao.p.peng@linux.intel.com>
---
 virt/kvm/kvm_main.c | 30 ++++++++++++++++++++++++------
 1 file changed, 24 insertions(+), 6 deletions(-)

diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index b7a1c4d7eaaa..19736a0013a0 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -494,6 +494,7 @@ typedef void (*on_lock_fn_t)(struct kvm *kvm, unsigned long 
start,
 struct kvm_useraddr_range {
        unsigned long start;
        unsigned long end;
+       struct inode *inode;
        pte_t pte;
        gfn_handler_t handler;
        on_lock_fn_t on_lock;
@@ -544,14 +545,27 @@ static __always_inline int 
__kvm_handle_useraddr_range(struct kvm *kvm,
                struct interval_tree_node *node;
 
                slots = __kvm_memslots(kvm, i);
-               useraddr_tree = &slots->hva_tree;
+               useraddr_tree = range->inode ? &slots->ofs_tree : 
&slots->hva_tree;
                kvm_for_each_memslot_in_useraddr_range(node, useraddr_tree,
                                                  range->start, range->end - 1) 
{
                        unsigned long useraddr_start, useraddr_end;
+                       unsigned long useraddr_base;
+
+                       if (range->inode) {
+                               slot = container_of(node, struct 
kvm_memory_slot,
+                                                   ofs_node[slots->node_idx]);
+                               if (!slot->file ||
+                                   slot->file->f_inode != range->inode)
+                                       continue;
+                               useraddr_base = slot->ofs;
+                       } else {
+                               slot = container_of(node, struct 
kvm_memory_slot,
+                                                   hva_node[slots->node_idx]);
+                               useraddr_base = slot->userspace_addr;
+                       }
 
-                       slot = container_of(node, struct kvm_memory_slot, 
hva_node[slots->node_idx]);
-                       useraddr_start = max(range->start, 
slot->userspace_addr);
-                       useraddr_end = min(range->end, slot->userspace_addr +
+                       useraddr_start = max(range->start, useraddr_base);
+                       useraddr_end = min(range->end, useraddr_base +
                                                       (slot->npages << 
PAGE_SHIFT));
 
                        /*
@@ -568,10 +582,10 @@ static __always_inline int 
__kvm_handle_useraddr_range(struct kvm *kvm,
                         * {gfn_start, gfn_start+1, ..., gfn_end-1}.
                         */
                        gfn_range.start = 
useraddr_to_gfn_memslot(useraddr_start,
-                                                                 slot, true);
+                                                       slot, !range->inode);
                        gfn_range.end = useraddr_to_gfn_memslot(
                                                useraddr_end + PAGE_SIZE - 1,
-                                               slot, true);
+                                               slot, !range->inode);
                        gfn_range.slot = slot;
 
                        if (!locked) {
@@ -613,6 +627,7 @@ static __always_inline int kvm_handle_hva_range(struct 
mmu_notifier *mn,
                .on_lock        = (void *)kvm_null_fn,
                .flush_on_ret   = true,
                .may_block      = false,
+               .inode          = NULL,
        };
 
        return __kvm_handle_useraddr_range(kvm, &range);
@@ -632,6 +647,7 @@ static __always_inline int 
kvm_handle_hva_range_no_flush(struct mmu_notifier *mn
                .on_lock        = (void *)kvm_null_fn,
                .flush_on_ret   = false,
                .may_block      = false,
+               .inode          = NULL,
        };
 
        return __kvm_handle_useraddr_range(kvm, &range);
@@ -700,6 +716,7 @@ static int kvm_mmu_notifier_invalidate_range_start(struct 
mmu_notifier *mn,
                .on_lock        = kvm_inc_notifier_count,
                .flush_on_ret   = true,
                .may_block      = mmu_notifier_range_blockable(range),
+               .inode          = NULL,
        };
 
        trace_kvm_unmap_hva_range(range->start, range->end);
@@ -751,6 +768,7 @@ static void kvm_mmu_notifier_invalidate_range_end(struct 
mmu_notifier *mn,
                .on_lock        = kvm_dec_notifier_count,
                .flush_on_ret   = false,
                .may_block      = mmu_notifier_range_blockable(range),
+               .inode          = NULL,
        };
        bool wake;
 
-- 
2.17.1




reply via email to

[Prev in Thread] Current Thread [Next in Thread]