kvm.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v4 0/4] KVM: x86/mmu: Rework TDP MMU eager page splitting SP allocations
@ 2024-06-11 22:05 David Matlack
  2024-06-11 22:05 ` [PATCH v4 1/4] KVM: x86/mmu: Always drop mmu_lock to allocate TDP MMU SPs for eager splitting David Matlack
                   ` (4 more replies)
  0 siblings, 5 replies; 6+ messages in thread
From: David Matlack @ 2024-06-11 22:05 UTC (permalink / raw)
  To: Paolo Bonzini, Sean Christopherson; +Cc: kvm, David Matlack, Bibo Mao

Rework the TDP MMU eager page splitting code to always drop mmu_lock
when allocation shadow pages, to avoid causing lock contention with vCPU
threads during CLEAR_DIRTY_LOG (where mmu_lock is held for write).

The first patch changes KVM to always drop mmu_lock lock and the
subsequent patches clean up and simplify the code now that conditional
locking is gone.

v4:
 - Use kmem_cache_zalloc() instead of __GFP_ZERO [Sean]
 - Move mmu_lock and RCU acquire/release into the loop [Sean]
 - Avoid unnecessary reaquire of RCU read lock [Sean]

v3: https://lore.kernel.org/kvm/20240509181133.837001-1-dmatlack@google.com/
 - Only drop mmu_lock during TDP MMU eager page splitting. This fixes
   the performance regression without regressing CLEAR_DIRTY_LOG
   performance on other architectures from frequent lock dropping.

v2: https://lore.kernel.org/kvm/20240402213656.3068504-1-dmatlack@google.com/
 - Rebase onto kvm/queue [Marc]

v1: https://lore.kernel.org/kvm/20231205181645.482037-1-dmatlack@google.com/

Cc: Bibo Mao <maobibo@loongson.cn>
Cc: Sean Christopherson <seanjc@google.com>

David Matlack (4):
  KVM: x86/mmu: Always drop mmu_lock to allocate TDP MMU SPs for eager
    splitting
  KVM: x86/mmu: Hard code GFP flags for TDP MMU eager split allocations
  KVM: x86/mmu: Unnest TDP MMU helpers to allocate SPs for eager
    splitting
  KVM: x86/mmu: Avoid reacquiring RCU if TDP MMU fails to allocate an SP

 arch/x86/kvm/mmu/tdp_mmu.c | 78 ++++++++++++--------------------------
 1 file changed, 24 insertions(+), 54 deletions(-)


base-commit: af0903ab52ee6d6f0f63af67fa73d5eb00f79b9a
-- 
2.45.2.505.gda0bf45e8d-goog


^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH v4 1/4] KVM: x86/mmu: Always drop mmu_lock to allocate TDP MMU SPs for eager splitting
  2024-06-11 22:05 [PATCH v4 0/4] KVM: x86/mmu: Rework TDP MMU eager page splitting SP allocations David Matlack
@ 2024-06-11 22:05 ` David Matlack
  2024-06-11 22:05 ` [PATCH v4 2/4] KVM: x86/mmu: Hard code GFP flags for TDP MMU eager split allocations David Matlack
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 6+ messages in thread
From: David Matlack @ 2024-06-11 22:05 UTC (permalink / raw)
  To: Paolo Bonzini, Sean Christopherson; +Cc: kvm, David Matlack, Bibo Mao

Always drop mmu_lock to allocate shadow pages in the TDP MMU when doing
eager page splitting. Dropping mmu_lock during eager page splitting is
cheap since KVM does not have to flush remote TLBs, and avoids stalling
vCPU threads that are taking page faults while KVM is eager splitting
under mmu_lock held for write.

This change reduces 20%+ dips in MySQL throughput during live migration
in a 160 vCPU VM while userspace is issuing CLEAR_DIRTY_LOG ioctls
(tested with 1GiB and 8GiB CLEARs). Userspace could issue finer-grained
CLEARs, which would also reduce contention on mmu_lock, but doing so
will increase the rate of remote TLB flushing, since KVM must flush TLBs
before returning from CLEAR_DITY_LOG.

When there isn't contention on mmu_lock[1], this change does not regress
the time it takes to perform eager page splitting.

[1] Tested with dirty_log_perf_test, which does not run vCPUs during
eager page splitting, and with a 16 vCPU VM Live Migration with
manual-protect disabled (where mmu_lock is held for read).

Cc: Bibo Mao <maobibo@loongson.cn>
Cc: Sean Christopherson <seanjc@google.com>
Signed-off-by: David Matlack <dmatlack@google.com>
---
 arch/x86/kvm/mmu/tdp_mmu.c | 16 +---------------
 1 file changed, 1 insertion(+), 15 deletions(-)

diff --git a/arch/x86/kvm/mmu/tdp_mmu.c b/arch/x86/kvm/mmu/tdp_mmu.c
index 36539c1b36cd..c1f3b3798764 100644
--- a/arch/x86/kvm/mmu/tdp_mmu.c
+++ b/arch/x86/kvm/mmu/tdp_mmu.c
@@ -1366,19 +1366,6 @@ static struct kvm_mmu_page *tdp_mmu_alloc_sp_for_split(struct kvm *kvm,
 
 	kvm_lockdep_assert_mmu_lock_held(kvm, shared);
 
-	/*
-	 * Since we are allocating while under the MMU lock we have to be
-	 * careful about GFP flags. Use GFP_NOWAIT to avoid blocking on direct
-	 * reclaim and to avoid making any filesystem callbacks (which can end
-	 * up invoking KVM MMU notifiers, resulting in a deadlock).
-	 *
-	 * If this allocation fails we drop the lock and retry with reclaim
-	 * allowed.
-	 */
-	sp = __tdp_mmu_alloc_sp_for_split(GFP_NOWAIT | __GFP_ACCOUNT);
-	if (sp)
-		return sp;
-
 	rcu_read_unlock();
 
 	if (shared)
@@ -1478,8 +1465,7 @@ static int tdp_mmu_split_huge_pages_root(struct kvm *kvm,
 				break;
 			}
 
-			if (iter.yielded)
-				continue;
+			continue;
 		}
 
 		tdp_mmu_init_child_sp(sp, &iter);
-- 
2.45.2.505.gda0bf45e8d-goog


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH v4 2/4] KVM: x86/mmu: Hard code GFP flags for TDP MMU eager split allocations
  2024-06-11 22:05 [PATCH v4 0/4] KVM: x86/mmu: Rework TDP MMU eager page splitting SP allocations David Matlack
  2024-06-11 22:05 ` [PATCH v4 1/4] KVM: x86/mmu: Always drop mmu_lock to allocate TDP MMU SPs for eager splitting David Matlack
@ 2024-06-11 22:05 ` David Matlack
  2024-06-11 22:05 ` [PATCH v4 3/4] KVM: x86/mmu: Unnest TDP MMU helpers to allocate SPs for eager splitting David Matlack
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 6+ messages in thread
From: David Matlack @ 2024-06-11 22:05 UTC (permalink / raw)
  To: Paolo Bonzini, Sean Christopherson; +Cc: kvm, David Matlack, Bibo Mao

Hard code GFP_KERNEL_ACCOUNT when allocating shadow pages during eager
page splitting in the TDP MMU. Opportunistically replace use of
__GFP_ZERO with allocations that zero to improve readability.

No functional change intended.

Suggested-by: Sean Christopherson <seanjc@google.com>
Signed-off-by: David Matlack <dmatlack@google.com>
---
 arch/x86/kvm/mmu/tdp_mmu.c | 10 ++++------
 1 file changed, 4 insertions(+), 6 deletions(-)

diff --git a/arch/x86/kvm/mmu/tdp_mmu.c b/arch/x86/kvm/mmu/tdp_mmu.c
index c1f3b3798764..09c6b16630ac 100644
--- a/arch/x86/kvm/mmu/tdp_mmu.c
+++ b/arch/x86/kvm/mmu/tdp_mmu.c
@@ -1339,17 +1339,15 @@ bool kvm_tdp_mmu_wrprot_slot(struct kvm *kvm,
 	return spte_set;
 }
 
-static struct kvm_mmu_page *__tdp_mmu_alloc_sp_for_split(gfp_t gfp)
+static struct kvm_mmu_page *__tdp_mmu_alloc_sp_for_split(void)
 {
 	struct kvm_mmu_page *sp;
 
-	gfp |= __GFP_ZERO;
-
-	sp = kmem_cache_alloc(mmu_page_header_cache, gfp);
+	sp = kmem_cache_zalloc(mmu_page_header_cache, GFP_KERNEL_ACCOUNT);
 	if (!sp)
 		return NULL;
 
-	sp->spt = (void *)__get_free_page(gfp);
+	sp->spt = (void *)get_zeroed_page(GFP_KERNEL_ACCOUNT);
 	if (!sp->spt) {
 		kmem_cache_free(mmu_page_header_cache, sp);
 		return NULL;
@@ -1374,7 +1372,7 @@ static struct kvm_mmu_page *tdp_mmu_alloc_sp_for_split(struct kvm *kvm,
 		write_unlock(&kvm->mmu_lock);
 
 	iter->yielded = true;
-	sp = __tdp_mmu_alloc_sp_for_split(GFP_KERNEL_ACCOUNT);
+	sp = __tdp_mmu_alloc_sp_for_split();
 
 	if (shared)
 		read_lock(&kvm->mmu_lock);
-- 
2.45.2.505.gda0bf45e8d-goog


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH v4 3/4] KVM: x86/mmu: Unnest TDP MMU helpers to allocate SPs for eager splitting
  2024-06-11 22:05 [PATCH v4 0/4] KVM: x86/mmu: Rework TDP MMU eager page splitting SP allocations David Matlack
  2024-06-11 22:05 ` [PATCH v4 1/4] KVM: x86/mmu: Always drop mmu_lock to allocate TDP MMU SPs for eager splitting David Matlack
  2024-06-11 22:05 ` [PATCH v4 2/4] KVM: x86/mmu: Hard code GFP flags for TDP MMU eager split allocations David Matlack
@ 2024-06-11 22:05 ` David Matlack
  2024-06-11 22:05 ` [PATCH v4 4/4] KVM: x86/mmu: Avoid reacquiring RCU if TDP MMU fails to allocate an SP David Matlack
  2024-06-15  0:02 ` [PATCH v4 0/4] KVM: x86/mmu: Rework TDP MMU eager page splitting SP allocations Sean Christopherson
  4 siblings, 0 replies; 6+ messages in thread
From: David Matlack @ 2024-06-11 22:05 UTC (permalink / raw)
  To: Paolo Bonzini, Sean Christopherson; +Cc: kvm, David Matlack, Bibo Mao

Move the implementation of tdp_mmu_alloc_sp_for_split() to its one and
only caller to reduce unnecessary nesting and make it more clear why the
eager split loop continues after allocating a new SP.

Opportunistically drop the double-underscores from
__tdp_mmu_alloc_sp_for_split() now that its parent is gone.

No functional change intended.

Suggested-by: Sean Christopherson <seanjc@google.com>
Signed-off-by: David Matlack <dmatlack@google.com>
---
 arch/x86/kvm/mmu/tdp_mmu.c | 48 ++++++++++++++------------------------
 1 file changed, 18 insertions(+), 30 deletions(-)

diff --git a/arch/x86/kvm/mmu/tdp_mmu.c b/arch/x86/kvm/mmu/tdp_mmu.c
index 09c6b16630ac..7e89a0dc7df7 100644
--- a/arch/x86/kvm/mmu/tdp_mmu.c
+++ b/arch/x86/kvm/mmu/tdp_mmu.c
@@ -1339,7 +1339,7 @@ bool kvm_tdp_mmu_wrprot_slot(struct kvm *kvm,
 	return spte_set;
 }
 
-static struct kvm_mmu_page *__tdp_mmu_alloc_sp_for_split(void)
+static struct kvm_mmu_page *tdp_mmu_alloc_sp_for_split(void)
 {
 	struct kvm_mmu_page *sp;
 
@@ -1356,34 +1356,6 @@ static struct kvm_mmu_page *__tdp_mmu_alloc_sp_for_split(void)
 	return sp;
 }
 
-static struct kvm_mmu_page *tdp_mmu_alloc_sp_for_split(struct kvm *kvm,
-						       struct tdp_iter *iter,
-						       bool shared)
-{
-	struct kvm_mmu_page *sp;
-
-	kvm_lockdep_assert_mmu_lock_held(kvm, shared);
-
-	rcu_read_unlock();
-
-	if (shared)
-		read_unlock(&kvm->mmu_lock);
-	else
-		write_unlock(&kvm->mmu_lock);
-
-	iter->yielded = true;
-	sp = __tdp_mmu_alloc_sp_for_split();
-
-	if (shared)
-		read_lock(&kvm->mmu_lock);
-	else
-		write_lock(&kvm->mmu_lock);
-
-	rcu_read_lock();
-
-	return sp;
-}
-
 /* Note, the caller is responsible for initializing @sp. */
 static int tdp_mmu_split_huge_page(struct kvm *kvm, struct tdp_iter *iter,
 				   struct kvm_mmu_page *sp, bool shared)
@@ -1454,7 +1426,22 @@ static int tdp_mmu_split_huge_pages_root(struct kvm *kvm,
 			continue;
 
 		if (!sp) {
-			sp = tdp_mmu_alloc_sp_for_split(kvm, &iter, shared);
+			rcu_read_unlock();
+
+			if (shared)
+				read_unlock(&kvm->mmu_lock);
+			else
+				write_unlock(&kvm->mmu_lock);
+
+			sp = tdp_mmu_alloc_sp_for_split();
+
+			if (shared)
+				read_lock(&kvm->mmu_lock);
+			else
+				write_lock(&kvm->mmu_lock);
+
+			rcu_read_lock();
+
 			if (!sp) {
 				ret = -ENOMEM;
 				trace_kvm_mmu_split_huge_page(iter.gfn,
@@ -1463,6 +1450,7 @@ static int tdp_mmu_split_huge_pages_root(struct kvm *kvm,
 				break;
 			}
 
+			iter.yielded = true;
 			continue;
 		}
 
-- 
2.45.2.505.gda0bf45e8d-goog


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH v4 4/4] KVM: x86/mmu: Avoid reacquiring RCU if TDP MMU fails to allocate an SP
  2024-06-11 22:05 [PATCH v4 0/4] KVM: x86/mmu: Rework TDP MMU eager page splitting SP allocations David Matlack
                   ` (2 preceding siblings ...)
  2024-06-11 22:05 ` [PATCH v4 3/4] KVM: x86/mmu: Unnest TDP MMU helpers to allocate SPs for eager splitting David Matlack
@ 2024-06-11 22:05 ` David Matlack
  2024-06-15  0:02 ` [PATCH v4 0/4] KVM: x86/mmu: Rework TDP MMU eager page splitting SP allocations Sean Christopherson
  4 siblings, 0 replies; 6+ messages in thread
From: David Matlack @ 2024-06-11 22:05 UTC (permalink / raw)
  To: Paolo Bonzini, Sean Christopherson; +Cc: kvm, David Matlack, Bibo Mao

Avoid needlessly reacquiring the RCU read lock if the TDP MMU fails to
allocate a shadow page during eager page splitting. Opportunistically
drop the local variable ret as well now that it's no longer necessary.

Suggested-by: Sean Christopherson <seanjc@google.com>
Signed-off-by: David Matlack <dmatlack@google.com>
---
 arch/x86/kvm/mmu/tdp_mmu.c | 12 +++++-------
 1 file changed, 5 insertions(+), 7 deletions(-)

diff --git a/arch/x86/kvm/mmu/tdp_mmu.c b/arch/x86/kvm/mmu/tdp_mmu.c
index 7e89a0dc7df7..142a36d91e05 100644
--- a/arch/x86/kvm/mmu/tdp_mmu.c
+++ b/arch/x86/kvm/mmu/tdp_mmu.c
@@ -1402,7 +1402,6 @@ static int tdp_mmu_split_huge_pages_root(struct kvm *kvm,
 {
 	struct kvm_mmu_page *sp = NULL;
 	struct tdp_iter iter;
-	int ret = 0;
 
 	rcu_read_lock();
 
@@ -1440,16 +1439,15 @@ static int tdp_mmu_split_huge_pages_root(struct kvm *kvm,
 			else
 				write_lock(&kvm->mmu_lock);
 
-			rcu_read_lock();
-
 			if (!sp) {
-				ret = -ENOMEM;
 				trace_kvm_mmu_split_huge_page(iter.gfn,
 							      iter.old_spte,
-							      iter.level, ret);
-				break;
+							      iter.level, -ENOMEM);
+				return -ENOMEM;
 			}
 
+			rcu_read_lock();
+
 			iter.yielded = true;
 			continue;
 		}
@@ -1472,7 +1470,7 @@ static int tdp_mmu_split_huge_pages_root(struct kvm *kvm,
 	if (sp)
 		tdp_mmu_free_sp(sp);
 
-	return ret;
+	return 0;
 }
 
 
-- 
2.45.2.505.gda0bf45e8d-goog


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [PATCH v4 0/4] KVM: x86/mmu: Rework TDP MMU eager page splitting SP allocations
  2024-06-11 22:05 [PATCH v4 0/4] KVM: x86/mmu: Rework TDP MMU eager page splitting SP allocations David Matlack
                   ` (3 preceding siblings ...)
  2024-06-11 22:05 ` [PATCH v4 4/4] KVM: x86/mmu: Avoid reacquiring RCU if TDP MMU fails to allocate an SP David Matlack
@ 2024-06-15  0:02 ` Sean Christopherson
  4 siblings, 0 replies; 6+ messages in thread
From: Sean Christopherson @ 2024-06-15  0:02 UTC (permalink / raw)
  To: Sean Christopherson, Paolo Bonzini, David Matlack; +Cc: kvm, Bibo Mao

On Tue, 11 Jun 2024 15:05:08 -0700, David Matlack wrote:
> Rework the TDP MMU eager page splitting code to always drop mmu_lock
> when allocation shadow pages, to avoid causing lock contention with vCPU
> threads during CLEAR_DIRTY_LOG (where mmu_lock is held for write).
> 
> The first patch changes KVM to always drop mmu_lock lock and the
> subsequent patches clean up and simplify the code now that conditional
> locking is gone.
> 
> [...]

Applied to kvm-x86 mmu, thanks!

[1/4] KVM: x86/mmu: Always drop mmu_lock to allocate TDP MMU SPs for eager splitting
      https://github.com/kvm-x86/linux/commit/cf3ff0ee24d6
[2/4] KVM: x86/mmu: Hard code GFP flags for TDP MMU eager split allocations
      https://github.com/kvm-x86/linux/commit/e1c04f7a9f42
[3/4] KVM: x86/mmu: Unnest TDP MMU helpers to allocate SPs for eager splitting
      https://github.com/kvm-x86/linux/commit/3d4a5a45ca26
[4/4] KVM: x86/mmu: Avoid reacquiring RCU if TDP MMU fails to allocate an SP
      https://github.com/kvm-x86/linux/commit/0089c055b560

--
https://github.com/kvm-x86/linux/tree/next

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2024-06-15  0:03 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-06-11 22:05 [PATCH v4 0/4] KVM: x86/mmu: Rework TDP MMU eager page splitting SP allocations David Matlack
2024-06-11 22:05 ` [PATCH v4 1/4] KVM: x86/mmu: Always drop mmu_lock to allocate TDP MMU SPs for eager splitting David Matlack
2024-06-11 22:05 ` [PATCH v4 2/4] KVM: x86/mmu: Hard code GFP flags for TDP MMU eager split allocations David Matlack
2024-06-11 22:05 ` [PATCH v4 3/4] KVM: x86/mmu: Unnest TDP MMU helpers to allocate SPs for eager splitting David Matlack
2024-06-11 22:05 ` [PATCH v4 4/4] KVM: x86/mmu: Avoid reacquiring RCU if TDP MMU fails to allocate an SP David Matlack
2024-06-15  0:02 ` [PATCH v4 0/4] KVM: x86/mmu: Rework TDP MMU eager page splitting SP allocations Sean Christopherson

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).