public inbox for kvm@vger.kernel.org
 help / color / mirror / Atom feed
From: Keith Busch <kbusch@meta.com>
To: <pbonzini@redhat.com>, <seanjc@google.com>, <kvm@vger.kernel.org>
Cc: <x86@kernel.org>, <virtualization@lists.linux.dev>,
	<linux-kernel@vger.kernel.org>, Keith Busch <kbusch@kernel.org>
Subject: [RFC 2/2] kvm: retry nx_huge_page_recovery_thread creation
Date: Tue, 25 Feb 2025 18:43:04 -0800	[thread overview]
Message-ID: <20250226024304.1807955-1-kbusch@meta.com> (raw)

From: Keith Busch <kbusch@kernel.org>

A VMM may send a signal to its threads while they've entered KVM_RUN. If
that thread happens to be trying to make the huge page recovery vhost
task, then it fails with -ERESTARTNOINTR. We need to retry if that
happens, so we can't use call_once anymore. Replace it with a simple
mutex and return the appropriate error instead of defaulting to ENOMEM.

One downside is that everyone will retry if it fails, which can cause
some additional pressure on low memory situations. Another downside is
we're taking a mutex on every KVM run, even if we were previously
successful in starting the vhost task, but that's really not such a
common operation that needs to be optimized to avoid this lock.

Signed-off-by: Keith Busch <kbusch@kernel.org>
---
 arch/x86/include/asm/kvm_host.h |  3 +--
 arch/x86/kvm/mmu/mmu.c          | 23 +++++++++--------------
 arch/x86/kvm/x86.c              |  2 +-
 3 files changed, 11 insertions(+), 17 deletions(-)

diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index 0b7af5902ff75..597c8e66fc204 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -26,7 +26,6 @@
 #include <linux/irqbypass.h>
 #include <linux/kfifo.h>
 #include <linux/sched/vhost_task.h>
-#include <linux/call_once.h>
 
 #include <asm/apic.h>
 #include <asm/pvclock-abi.h>
@@ -1466,7 +1465,7 @@ struct kvm_arch {
 	struct kvm_x86_pmu_event_filter __rcu *pmu_event_filter;
 	struct vhost_task *nx_huge_page_recovery_thread;
 	u64 nx_huge_page_last;
-	struct once nx_once;
+	struct mutex nx_lock;
 
 #ifdef CONFIG_X86_64
 	/* The number of TDP MMU pages across all roots. */
diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c
index 18ca1ea6dc240..eb6b625f6f43a 100644
--- a/arch/x86/kvm/mmu/mmu.c
+++ b/arch/x86/kvm/mmu/mmu.c
@@ -7460,34 +7460,29 @@ static bool kvm_nx_huge_page_recovery_worker(void *data)
 	return true;
 }
 
-static void kvm_mmu_start_lpage_recovery(struct once *once)
+int kvm_mmu_post_init_vm(struct kvm *kvm)
 {
-	struct kvm_arch *ka = container_of(once, struct kvm_arch, nx_once);
-	struct kvm *kvm = container_of(ka, struct kvm, arch);
 	struct vhost_task *nx_thread;
 
+	if (nx_hugepage_mitigation_hard_disabled)
+		return 0;
+
+	guard(mutex)(&kvm->arch.nx_lock);
+	if (kvm->arch.nx_huge_page_recovery_thread)
+		return 0;
+
 	kvm->arch.nx_huge_page_last = get_jiffies_64();
 	nx_thread = vhost_task_create(kvm_nx_huge_page_recovery_worker,
 				      kvm_nx_huge_page_recovery_worker_kill,
 				      kvm, "kvm-nx-lpage-recovery");
 
 	if (IS_ERR(nx_thread))
-		return;
+		return PTR_ERR(nx_thread);
 
 	vhost_task_start(nx_thread);
 
 	/* Make the task visible only once it is fully started. */
 	WRITE_ONCE(kvm->arch.nx_huge_page_recovery_thread, nx_thread);
-}
-
-int kvm_mmu_post_init_vm(struct kvm *kvm)
-{
-	if (nx_hugepage_mitigation_hard_disabled)
-		return 0;
-
-	call_once(&kvm->arch.nx_once, kvm_mmu_start_lpage_recovery);
-	if (!kvm->arch.nx_huge_page_recovery_thread)
-		return -ENOMEM;
 	return 0;
 }
 
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 02159c967d29e..872498566b540 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -12744,7 +12744,7 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
 			     "does not run without ignore_msrs=1, please report it to kvm@vger.kernel.org.\n");
 	}
 
-	once_init(&kvm->arch.nx_once);
+	mutex_init(&kvm->arch.nx_lock);
 	return 0;
 
 out_uninit_mmu:
-- 
2.43.5


             reply	other threads:[~2025-02-26  2:43 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-02-26  2:43 Keith Busch [this message]
2025-02-26 20:13 ` [RFC 2/2] kvm: retry nx_huge_page_recovery_thread creation Sean Christopherson
2025-02-26 20:22   ` Keith Busch

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20250226024304.1807955-1-kbusch@meta.com \
    --to=kbusch@meta.com \
    --cc=kbusch@kernel.org \
    --cc=kvm@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=pbonzini@redhat.com \
    --cc=seanjc@google.com \
    --cc=virtualization@lists.linux.dev \
    --cc=x86@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox