Skip to content

Commit dca6c88

Browse files
yamahatabonzini
authored andcommitted
KVM: Add member to struct kvm_gfn_range to indicate private/shared
Add new members to strut kvm_gfn_range to indicate which mapping (private-vs-shared) to operate on: enum kvm_gfn_range_filter attr_filter. Update the core zapping operations to set them appropriately. TDX utilizes two GPA aliases for the same memslots, one for memory that is for private memory and one that is for shared. For private memory, KVM cannot always perform the same operations it does on memory for default VMs, such as zapping pages and having them be faulted back in, as this requires guest coordination. However, some operations such as guest driven conversion of memory between private and shared should zap private memory. Internally to the MMU, private and shared mappings are tracked on separate roots. Mapping and zapping operations will operate on the respective GFN alias for each root (private or shared). So zapping operations will by default zap both aliases. Add fields in struct kvm_gfn_range to allow callers to specify which aliases so they can only target the aliases appropriate for their specific operation. There was feedback that target aliases should be specified such that the default value (0) is to operate on both aliases. Several options were considered. Several variations of having separate bools defined such that the default behavior was to process both aliases. They either allowed nonsensical configurations, or were confusing for the caller. A simple enum was also explored and was close, but was hard to process in the caller. Instead, use an enum with the default value (0) reserved as a disallowed value. Catch ranges that didn't have the target aliases specified by looking for that specific value. Set target alias with enum appropriately for these MMU operations: - For KVM's mmu notifier callbacks, zap shared pages only because private pages won't have a userspace mapping - For setting memory attributes, kvm_arch_pre_set_memory_attributes() chooses the aliases based on the attribute. - For guest_memfd invalidations, zap private only. Link: https://lore.kernel.org/kvm/[email protected]/ Signed-off-by: Isaku Yamahata <[email protected]> Co-developed-by: Rick Edgecombe <[email protected]> Signed-off-by: Rick Edgecombe <[email protected]> Message-ID: <[email protected]> Signed-off-by: Paolo Bonzini <[email protected]>
1 parent 35be969 commit dca6c88

File tree

4 files changed

+28
-0
lines changed

4 files changed

+28
-0
lines changed

arch/x86/kvm/mmu/mmu.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7452,6 +7452,12 @@ bool kvm_arch_pre_set_memory_attributes(struct kvm *kvm,
74527452
if (WARN_ON_ONCE(!kvm_arch_has_private_mem(kvm)))
74537453
return false;
74547454

7455+
/* Unmap the old attribute page. */
7456+
if (range->arg.attributes & KVM_MEMORY_ATTRIBUTE_PRIVATE)
7457+
range->attr_filter = KVM_FILTER_SHARED;
7458+
else
7459+
range->attr_filter = KVM_FILTER_PRIVATE;
7460+
74557461
return kvm_unmap_gfn_range(kvm, range);
74567462
}
74577463

include/linux/kvm_host.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,11 +255,17 @@ union kvm_mmu_notifier_arg {
255255
unsigned long attributes;
256256
};
257257

258+
enum kvm_gfn_range_filter {
259+
KVM_FILTER_SHARED = BIT(0),
260+
KVM_FILTER_PRIVATE = BIT(1),
261+
};
262+
258263
struct kvm_gfn_range {
259264
struct kvm_memory_slot *slot;
260265
gfn_t start;
261266
gfn_t end;
262267
union kvm_mmu_notifier_arg arg;
268+
enum kvm_gfn_range_filter attr_filter;
263269
bool may_block;
264270
};
265271
bool kvm_unmap_gfn_range(struct kvm *kvm, struct kvm_gfn_range *range);

virt/kvm/guest_memfd.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,8 @@ static void kvm_gmem_invalidate_begin(struct kvm_gmem *gmem, pgoff_t start,
118118
.end = slot->base_gfn + min(pgoff + slot->npages, end) - pgoff,
119119
.slot = slot,
120120
.may_block = true,
121+
/* guest memfd is relevant to only private mappings. */
122+
.attr_filter = KVM_FILTER_PRIVATE,
121123
};
122124

123125
if (!found_memslot) {

virt/kvm/kvm_main.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -594,6 +594,11 @@ static __always_inline kvm_mn_ret_t __kvm_handle_hva_range(struct kvm *kvm,
594594
*/
595595
gfn_range.arg = range->arg;
596596
gfn_range.may_block = range->may_block;
597+
/*
598+
* HVA-based notifications aren't relevant to private
599+
* mappings as they don't have a userspace mapping.
600+
*/
601+
gfn_range.attr_filter = KVM_FILTER_SHARED;
597602

598603
/*
599604
* {gfn(page) | page intersects with [hva_start, hva_end)} =
@@ -2408,6 +2413,14 @@ static __always_inline void kvm_handle_gfn_range(struct kvm *kvm,
24082413
gfn_range.arg = range->arg;
24092414
gfn_range.may_block = range->may_block;
24102415

2416+
/*
2417+
* If/when KVM supports more attributes beyond private .vs shared, this
2418+
* _could_ set KVM_FILTER_{SHARED,PRIVATE} appropriately if the entire target
2419+
* range already has the desired private vs. shared state (it's unclear
2420+
* if that is a net win). For now, KVM reaches this point if and only
2421+
* if the private flag is being toggled, i.e. all mappings are in play.
2422+
*/
2423+
24112424
for (i = 0; i < kvm_arch_nr_memslot_as_ids(kvm); i++) {
24122425
slots = __kvm_memslots(kvm, i);
24132426

@@ -2464,6 +2477,7 @@ static int kvm_vm_set_mem_attributes(struct kvm *kvm, gfn_t start, gfn_t end,
24642477
struct kvm_mmu_notifier_range pre_set_range = {
24652478
.start = start,
24662479
.end = end,
2480+
.arg.attributes = attributes,
24672481
.handler = kvm_pre_set_memory_attributes,
24682482
.on_lock = kvm_mmu_invalidate_begin,
24692483
.flush_on_ret = true,

0 commit comments

Comments
 (0)