Skip to content

Commit b25ab9c

Browse files
committed
KVM: Fix MMU invalidation bookkeeping in guest_memfd
Acquire mmu_lock and do invalidate_{begin,end}() if and only if there is at least one memslot that overlaps the to-be-invalidated range. This fixes a bug where KVM would leave a danging in-progress invalidation as the begin() call was unconditional, but the end() was not (only performed if there was overlap). Reported-by: Binbin Wu <binbin.wu@linux.intel.com> Fixes: 1d46f95 ("KVM: Add KVM_CREATE_GUEST_MEMFD ioctl() for guest-specific backing memory") Link: https://lore.kernel.org/r/20230921203331.3746712-6-seanjc@google.com Signed-off-by: Sean Christopherson <seanjc@google.com>
1 parent 37bbf72 commit b25ab9c

File tree

1 file changed

+14
-9
lines changed

1 file changed

+14
-9
lines changed

virt/kvm/guest_mem.c

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -88,14 +88,10 @@ static struct folio *kvm_gmem_get_folio(struct inode *inode, pgoff_t index)
8888
static void kvm_gmem_invalidate_begin(struct kvm_gmem *gmem, pgoff_t start,
8989
pgoff_t end)
9090
{
91+
bool flush = false, found_memslot = false;
9192
struct kvm_memory_slot *slot;
9293
struct kvm *kvm = gmem->kvm;
9394
unsigned long index;
94-
bool flush = false;
95-
96-
KVM_MMU_LOCK(kvm);
97-
98-
kvm_mmu_invalidate_begin(kvm);
9995

10096
xa_for_each_range(&gmem->bindings, index, slot, start, end - 1) {
10197
pgoff_t pgoff = slot->gmem.pgoff;
@@ -107,24 +103,33 @@ static void kvm_gmem_invalidate_begin(struct kvm_gmem *gmem, pgoff_t start,
107103
.may_block = true,
108104
};
109105

106+
if (!found_memslot) {
107+
found_memslot = true;
108+
109+
KVM_MMU_LOCK(kvm);
110+
kvm_mmu_invalidate_begin(kvm);
111+
}
112+
110113
flush |= kvm_mmu_unmap_gfn_range(kvm, &gfn_range);
111114
}
112115

113116
if (flush)
114117
kvm_flush_remote_tlbs(kvm);
115118

116-
KVM_MMU_UNLOCK(kvm);
119+
if (found_memslot)
120+
KVM_MMU_UNLOCK(kvm);
117121
}
118122

119123
static void kvm_gmem_invalidate_end(struct kvm_gmem *gmem, pgoff_t start,
120124
pgoff_t end)
121125
{
122126
struct kvm *kvm = gmem->kvm;
123127

124-
KVM_MMU_LOCK(kvm);
125-
if (xa_find(&gmem->bindings, &start, end - 1, XA_PRESENT))
128+
if (xa_find(&gmem->bindings, &start, end - 1, XA_PRESENT)) {
129+
KVM_MMU_LOCK(kvm);
126130
kvm_mmu_invalidate_end(kvm);
127-
KVM_MMU_UNLOCK(kvm);
131+
KVM_MMU_UNLOCK(kvm);
132+
}
128133
}
129134

130135
static long kvm_gmem_punch_hole(struct inode *inode, loff_t offset, loff_t len)

0 commit comments

Comments
 (0)