KVM: arm64: Split huge pages during KVM_CLEAR_DIRTY_LOG
authorRicardo Koller <ricarkol@google.com>
Wed, 26 Apr 2023 17:23:29 +0000 (17:23 +0000)
committerOliver Upton <oliver.upton@linux.dev>
Tue, 16 May 2023 17:39:19 +0000 (17:39 +0000)
This is the arm64 counterpart of commit cb00a70bd4b7 ("KVM: x86/mmu:
Split huge pages mapped by the TDP MMU during KVM_CLEAR_DIRTY_LOG"),
which has the benefit of splitting the cost of splitting a memslot
across multiple ioctls.

Split huge pages on the range specified using KVM_CLEAR_DIRTY_LOG.
And do not split when enabling dirty logging if
KVM_DIRTY_LOG_INITIALLY_SET is set.

Signed-off-by: Ricardo Koller <ricarkol@google.com>
Reviewed-by: Gavin Shan <gshan@redhat.com>
Link: https://lore.kernel.org/r/20230426172330.1439644-12-ricarkol@google.com
Signed-off-by: Oliver Upton <oliver.upton@linux.dev>
arch/arm64/kvm/mmu.c

index 272558f54101b71340aa6c5e20535c95bc729902..3386bd28d26705875ec7fafbdc9281bb43b8589f 100644 (file)
@@ -1114,8 +1114,8 @@ static void kvm_mmu_split_memory_region(struct kvm *kvm, int slot)
  * @mask:      The mask of pages at offset 'gfn_offset' in this memory
  *             slot to enable dirty logging on
  *
- * Writes protect selected pages to enable dirty logging for them. Caller must
- * acquire kvm->mmu_lock.
+ * Writes protect selected pages to enable dirty logging, and then
+ * splits them to PAGE_SIZE. Caller must acquire kvm->mmu_lock.
  */
 void kvm_arch_mmu_enable_log_dirty_pt_masked(struct kvm *kvm,
                struct kvm_memory_slot *slot,
@@ -1128,6 +1128,17 @@ void kvm_arch_mmu_enable_log_dirty_pt_masked(struct kvm *kvm,
        lockdep_assert_held_write(&kvm->mmu_lock);
 
        stage2_wp_range(&kvm->arch.mmu, start, end);
+
+       /*
+        * Eager-splitting is done when manual-protect is set.  We
+        * also check for initially-all-set because we can avoid
+        * eager-splitting if initially-all-set is false.
+        * Initially-all-set equal false implies that huge-pages were
+        * already split when enabling dirty logging: no need to do it
+        * again.
+        */
+       if (kvm_dirty_log_manual_protect_and_init_set(kvm))
+               kvm_mmu_split_huge_pages(kvm, start, end);
 }
 
 static void kvm_send_hwpoison_signal(unsigned long address, short lsb)