Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
From: David Woodhouse <dwmw2@infradead.org>
To: Marc Zyngier <maz@kernel.org>, Oliver Upton <oupton@kernel.org>,
	Joey Gouly <joey.gouly@arm.com>,
	Suzuki K Poulose <suzuki.poulose@arm.com>,
	Zenghui Yu <yuzenghui@huawei.com>,
	Catalin Marinas <catalin.marinas@arm.com>,
	Will Deacon <will@kernel.org>,
	Sascha Bischoff <Sascha.Bischoff@arm.com>,
	Paolo Bonzini <pbonzini@redhat.com>,
	Jonathan Cameron <jic23@kernel.org>,
	Eric Auger <eric.auger@redhat.com>,
	Raghavendra Rao Ananta <rananta@google.com>,
	David Woodhouse <dwmw@amazon.co.uk>,
	Maxim Levitsky <mlevitsk@redhat.com>,
	 linux-arm-kernel@lists.infradead.org, kvmarm@lists.linux.dev,
	 kvm@vger.kernel.org
Subject: [RFC PATCH] KVM: arm64: vgic: Skip vCPU trylock for pre-init register access
Date: Sun, 10 May 2026 23:11:43 +0100	[thread overview]
Message-ID: <6564c8b967948e30a8d3f35b6ef5de79dd5feeb7.camel@infradead.org> (raw)

[-- Attachment #1: Type: text/plain, Size: 3676 bytes --]

From: David Woodhouse <dwmw@amazon.co.uk>

When creating a VM, userspace sets pre-init distributor registers such
as GICD_IIDR before the VGIC is initialized.

Strictly speaking there's no reason this couldn't be done at VM creation
time before any vCPUs exist at all, but the design of the userspace API
does require vCPU0 to have been created, as the system-wide registers
are effectively accessed via vCPU0.

So a VMM can't just set the IIDR at startup before spawning vCPU threads;
it has to be done once the vCPUs are being created.

However, kvm_trylock_all_vcpus() makes it unreliable by causing spurious
-EBUSY failures if any vCPU cannot be locked. So userspace is forced to
create the vCPUs (well, at least vCPU0), and is then forced to have a
full synchronization point and quiesce them all in order to reliably set
the IIDR.

To slightly reduce the pain of all this, skip the trylock when the VGIC
is not yet initialized. There is no need to lock the vCPUs if they can't
be accessing it anyway.

Signed-off-by: David Woodhouse <dwmw@amazon.co.uk>
---
Other options would include making it possible to set the IIDR before
creating any vCPUs, either by creating a new device-level attribute or
special-casing it not to require vCPU0 for DIST_REGS that aren't really
associated to a vCPU.

Deprecating kvm_trylock_all_vcpus() and killing every user of it with
fire would also be a good option, perhaps... :)

 arch/arm64/kvm/vgic/vgic-kvm-device.c | 38 ++++++++++++++++++++-------
 1 file changed, 29 insertions(+), 9 deletions(-)

diff --git a/arch/arm64/kvm/vgic/vgic-kvm-device.c b/arch/arm64/kvm/vgic/vgic-kvm-device.c
index a96c77dccf35..e17ea9f07f5f 100644
--- a/arch/arm64/kvm/vgic/vgic-kvm-device.c
+++ b/arch/arm64/kvm/vgic/vgic-kvm-device.c
@@ -540,7 +540,7 @@ static int vgic_v3_attr_regs_access(struct kvm_device *dev,
 	struct vgic_reg_attr reg_attr;
 	gpa_t addr;
 	struct kvm_vcpu *vcpu;
-	bool uaccess;
+	bool uaccess, vcpus_locked = false;
 	u32 val;
 	int ret;
 
@@ -566,18 +566,37 @@ static int vgic_v3_attr_regs_access(struct kvm_device *dev,
 			return -EFAULT;
 	}
 
+	if (!vgic_initialized(dev->kvm) && !reg_allowed_pre_init(attr))
+		return -EBUSY;
+
 	mutex_lock(&dev->kvm->lock);
 
-	if (kvm_trylock_all_vcpus(dev->kvm)) {
-		mutex_unlock(&dev->kvm->lock);
-		return -EBUSY;
+	/*
+	 * Pre-init registers (e.g. GICD_IIDR) don't need vCPU quiescence
+	 * since the VGIC isn't live yet.  Skip the trylock to avoid spurious
+	 * -EBUSY when vCPU threads happen to be running.
+	 */
+	if (vgic_initialized(dev->kvm)) {
+		if (kvm_trylock_all_vcpus(dev->kvm)) {
+			mutex_unlock(&dev->kvm->lock);
+			return -EBUSY;
+		}
+		vcpus_locked = true;
 	}
-
 	mutex_lock(&dev->kvm->arch.config_lock);
 
-	if (!(vgic_initialized(dev->kvm) || reg_allowed_pre_init(attr))) {
-		ret = -EBUSY;
-		goto out;
+	/*
+	 * If the VGIC becomes initialized between the above check and taking
+	 * config_lock, drop config_lock to lock the VCPUS.
+	 */
+	if (vgic_initialized(dev->kvm) && !vcpus_locked) {
+		mutex_unlock(&dev->kvm->arch.config_lock);
+		if (kvm_trylock_all_vcpus(dev->kvm)) {
+			mutex_unlock(&dev->kvm->lock);
+			return -EBUSY;
+		}
+		mutex_lock(&dev->kvm->arch.config_lock);
+		vcpus_locked = true;
 	}
 
 	switch (attr->group) {
@@ -612,7 +631,8 @@ static int vgic_v3_attr_regs_access(struct kvm_device *dev,
 
 out:
 	mutex_unlock(&dev->kvm->arch.config_lock);
-	kvm_unlock_all_vcpus(dev->kvm);
+	if (vcpus_locked)
+		kvm_unlock_all_vcpus(dev->kvm);
 	mutex_unlock(&dev->kvm->lock);
 
 	if (!ret && uaccess && !is_write) {
-- 
2.43.0



[-- Attachment #2: smime.p7s --]
[-- Type: application/pkcs7-signature, Size: 5069 bytes --]

             reply	other threads:[~2026-05-10 22:11 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-05-10 22:11 David Woodhouse [this message]
2026-05-11 11:03 ` [RFC PATCH] KVM: arm64: vgic: Skip vCPU trylock for pre-init register access Yao Yuan
2026-05-11 11:52   ` David Woodhouse

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=6564c8b967948e30a8d3f35b6ef5de79dd5feeb7.camel@infradead.org \
    --to=dwmw2@infradead.org \
    --cc=Sascha.Bischoff@arm.com \
    --cc=catalin.marinas@arm.com \
    --cc=dwmw@amazon.co.uk \
    --cc=eric.auger@redhat.com \
    --cc=jic23@kernel.org \
    --cc=joey.gouly@arm.com \
    --cc=kvm@vger.kernel.org \
    --cc=kvmarm@lists.linux.dev \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=maz@kernel.org \
    --cc=mlevitsk@redhat.com \
    --cc=oupton@kernel.org \
    --cc=pbonzini@redhat.com \
    --cc=rananta@google.com \
    --cc=suzuki.poulose@arm.com \
    --cc=will@kernel.org \
    --cc=yuzenghui@huawei.com \
    /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