Skip to content

Commit 2f440b7

Browse files
Ricardo Kolleroupton
authored andcommitted
KVM: arm64: Add KVM_CAP_ARM_EAGER_SPLIT_CHUNK_SIZE
Add a capability for userspace to specify the eager split chunk size. The chunk size specifies how many pages to break at a time, using a single allocation. Bigger the chunk size, more pages need to be allocated ahead of time. Suggested-by: Oliver Upton <oliver.upton@linux.dev> Signed-off-by: Ricardo Koller <ricarkol@google.com> Reviewed-by: Gavin Shan <gshan@redhat.com> Link: https://lore.kernel.org/r/20230426172330.1439644-6-ricarkol@google.com Signed-off-by: Oliver Upton <oliver.upton@linux.dev>
1 parent 26f4571 commit 2f440b7

6 files changed

Lines changed: 94 additions & 0 deletions

File tree

Documentation/virt/kvm/api.rst

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8445,6 +8445,33 @@ structure.
84458445
When getting the Modified Change Topology Report value, the attr->addr
84468446
must point to a byte where the value will be stored or retrieved from.
84478447

8448+
8.40 KVM_CAP_ARM_EAGER_SPLIT_CHUNK_SIZE
8449+
---------------------------------------
8450+
8451+
:Capability: KVM_CAP_ARM_EAGER_SPLIT_CHUNK_SIZE
8452+
:Architectures: arm64
8453+
:Type: vm
8454+
:Parameters: arg[0] is the new split chunk size.
8455+
:Returns: 0 on success, -EINVAL if any memslot was already created.
8456+
8457+
This capability sets the chunk size used in Eager Page Splitting.
8458+
8459+
Eager Page Splitting improves the performance of dirty-logging (used
8460+
in live migrations) when guest memory is backed by huge-pages. It
8461+
avoids splitting huge-pages (into PAGE_SIZE pages) on fault, by doing
8462+
it eagerly when enabling dirty logging (with the
8463+
KVM_MEM_LOG_DIRTY_PAGES flag for a memory region), or when using
8464+
KVM_CLEAR_DIRTY_LOG.
8465+
8466+
The chunk size specifies how many pages to break at a time, using a
8467+
single allocation for each chunk. Bigger the chunk size, more pages
8468+
need to be allocated ahead of time.
8469+
8470+
The chunk size needs to be a valid block size. The list of acceptable
8471+
block sizes is exposed in KVM_CAP_ARM_SUPPORTED_BLOCK_SIZES as a
8472+
64-bit bitmap (each bit describing a block size). The default value is
8473+
0, to disable the eager page splitting.
8474+
84488475
9. Known KVM API problems
84498476
=========================
84508477

arch/arm64/include/asm/kvm_host.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,21 @@ struct kvm_s2_mmu {
159159
/* The last vcpu id that ran on each physical CPU */
160160
int __percpu *last_vcpu_ran;
161161

162+
#define KVM_ARM_EAGER_SPLIT_CHUNK_SIZE_DEFAULT 0
163+
/*
164+
* Memory cache used to split
165+
* KVM_CAP_ARM_EAGER_SPLIT_CHUNK_SIZE worth of huge pages. It
166+
* is used to allocate stage2 page tables while splitting huge
167+
* pages. The choice of KVM_CAP_ARM_EAGER_SPLIT_CHUNK_SIZE
168+
* influences both the capacity of the split page cache, and
169+
* how often KVM reschedules. Be wary of raising CHUNK_SIZE
170+
* too high.
171+
*
172+
* Protected by kvm->slots_lock.
173+
*/
174+
struct kvm_mmu_memory_cache split_page_cache;
175+
uint64_t split_page_chunk_size;
176+
162177
struct kvm_arch *arch;
163178
};
164179

arch/arm64/include/asm/kvm_pgtable.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,24 @@ static inline bool kvm_level_supports_block_mapping(u32 level)
9292
return level >= KVM_PGTABLE_MIN_BLOCK_LEVEL;
9393
}
9494

95+
static inline u32 kvm_supported_block_sizes(void)
96+
{
97+
u32 level = KVM_PGTABLE_MIN_BLOCK_LEVEL;
98+
u32 r = 0;
99+
100+
for (; level < KVM_PGTABLE_MAX_LEVELS; level++)
101+
r |= BIT(kvm_granule_shift(level));
102+
103+
return r;
104+
}
105+
106+
static inline bool kvm_is_block_size_supported(u64 size)
107+
{
108+
bool is_power_of_two = IS_ALIGNED(size, size);
109+
110+
return is_power_of_two && (size & kvm_supported_block_sizes());
111+
}
112+
95113
/**
96114
* struct kvm_pgtable_mm_ops - Memory management callbacks.
97115
* @zalloc_page: Allocate a single zeroed memory page.

arch/arm64/kvm/arm.c

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ int kvm_vm_ioctl_enable_cap(struct kvm *kvm,
6565
struct kvm_enable_cap *cap)
6666
{
6767
int r;
68+
u64 new_cap;
6869

6970
if (cap->flags)
7071
return -EINVAL;
@@ -89,6 +90,24 @@ int kvm_vm_ioctl_enable_cap(struct kvm *kvm,
8990
r = 0;
9091
set_bit(KVM_ARCH_FLAG_SYSTEM_SUSPEND_ENABLED, &kvm->arch.flags);
9192
break;
93+
case KVM_CAP_ARM_EAGER_SPLIT_CHUNK_SIZE:
94+
new_cap = cap->args[0];
95+
96+
mutex_lock(&kvm->slots_lock);
97+
/*
98+
* To keep things simple, allow changing the chunk
99+
* size only when no memory slots have been created.
100+
*/
101+
if (!kvm_are_all_memslots_empty(kvm)) {
102+
r = -EINVAL;
103+
} else if (new_cap && !kvm_is_block_size_supported(new_cap)) {
104+
r = -EINVAL;
105+
} else {
106+
r = 0;
107+
kvm->arch.mmu.split_page_chunk_size = new_cap;
108+
}
109+
mutex_unlock(&kvm->slots_lock);
110+
break;
92111
default:
93112
r = -EINVAL;
94113
break;
@@ -302,6 +321,15 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
302321
case KVM_CAP_ARM_PTRAUTH_GENERIC:
303322
r = system_has_full_ptr_auth();
304323
break;
324+
case KVM_CAP_ARM_EAGER_SPLIT_CHUNK_SIZE:
325+
if (kvm)
326+
r = kvm->arch.mmu.split_page_chunk_size;
327+
else
328+
r = KVM_ARM_EAGER_SPLIT_CHUNK_SIZE_DEFAULT;
329+
break;
330+
case KVM_CAP_ARM_SUPPORTED_BLOCK_SIZES:
331+
r = kvm_supported_block_sizes();
332+
break;
305333
default:
306334
r = 0;
307335
}

arch/arm64/kvm/mmu.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -775,6 +775,10 @@ int kvm_init_stage2_mmu(struct kvm *kvm, struct kvm_s2_mmu *mmu, unsigned long t
775775
for_each_possible_cpu(cpu)
776776
*per_cpu_ptr(mmu->last_vcpu_ran, cpu) = -1;
777777

778+
/* The eager page splitting is disabled by default */
779+
mmu->split_page_chunk_size = KVM_ARM_EAGER_SPLIT_CHUNK_SIZE_DEFAULT;
780+
mmu->split_page_cache.gfp_zero = __GFP_ZERO;
781+
778782
mmu->pgt = pgt;
779783
mmu->pgd_phys = __pa(pgt->pgd);
780784
return 0;

include/uapi/linux/kvm.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1190,6 +1190,8 @@ struct kvm_ppc_resize_hpt {
11901190
#define KVM_CAP_DIRTY_LOG_RING_WITH_BITMAP 225
11911191
#define KVM_CAP_PMU_EVENT_MASKED_EVENTS 226
11921192
#define KVM_CAP_COUNTER_OFFSET 227
1193+
#define KVM_CAP_ARM_EAGER_SPLIT_CHUNK_SIZE 228
1194+
#define KVM_CAP_ARM_SUPPORTED_BLOCK_SIZES 229
11931195

11941196
#ifdef KVM_CAP_IRQ_ROUTING
11951197

0 commit comments

Comments
 (0)