All of lore.kernel.org
 help / color / mirror / Atom feed
From: Yize Wang <wangyize7@huawei.com>
To: <maz@kernel.org>, <kvmarm@lists.linux.dev>,
	<linux-arm-kernel@lists.infradead.org>,
	<linux-kernel@vger.kernel.org>
Cc: <oupton@kernel.org>, <catalin.marinas@arm.com>, <will@kernel.org>,
	<fuad.tabba@linux.dev>, <joey.gouly@arm.com>,
	<seiden@linux.ibm.com>, <suzuki.poulose@arm.com>,
	<yuzenghui@huawei.com>, <mark.rutland@arm.com>,
	<zhengchuan@huawei.com>, <jiangjiacheng@huawei.com>,
	<wangyize7@huawei.com>, <yize_w1110@163.com>
Subject: [PATCH 2/2] KVM: arm64: Add VGIC v3 batch register access implementation
Date: Fri, 18 Sep 2026 16:18:15 +0800	[thread overview]
Message-ID: <20260918081930.4014735-3-wangyize7@huawei.com> (raw)
In-Reply-To: <20260918081930.4014735-1-wangyize7@huawei.com>

Add vgic_v3_batch_access() to allow userspace to read or write
multiple VGIC registers in a single system call.

Introduce KVM_DEV_ARM_VGIC_ATTR_FLAG_LOCKED to modify the locking
and unlocking logic in vgic_v3_attr_regs_access to prevent repeated
locking and unlocking.

Wire up KVM_DEV_ARM_VGIC_GRP_BATCH_REGS in vgic_v3_set_attr(),
vgic_v3_get_attr(), and vgic_v3_has_attr().

Signed-off-by: Chuan Zheng <zhengchuan@huawei.com>
Signed-off-by: Yize Wang <wangyize7@huawei.com>
---
 arch/arm64/kvm/vgic/vgic-kvm-device.c | 113 ++++++++++++++++++++++++--
 1 file changed, 104 insertions(+), 9 deletions(-)

diff --git a/arch/arm64/kvm/vgic/vgic-kvm-device.c b/arch/arm64/kvm/vgic/vgic-kvm-device.c
index 90be99443df3..ef0b2e8f68b2 100644
--- a/arch/arm64/kvm/vgic/vgic-kvm-device.c
+++ b/arch/arm64/kvm/vgic/vgic-kvm-device.c
@@ -566,14 +566,21 @@ static int vgic_v3_attr_regs_access(struct kvm_device *dev,
 			return -EFAULT;
 	}
 
-	mutex_lock(&dev->kvm->lock);
+	/* If the caller has not indicated that it already holds the necessary locks
+	 * (e.g., via KVM_DEV_ARM_VGIC_ATTR_FLAG_LOCKED), we must acquire the VM lock
+	 * and pause all VCPUs to ensure consistent access to VGIC state. This prevents
+	 * race conditions with concurrent interrupt injection or VCPU execution.
+	 */
+	if (attr->flags != KVM_DEV_ARM_VGIC_ATTR_FLAG_LOCKED) {
+		mutex_lock(&dev->kvm->lock);
 
-	if (kvm_trylock_all_vcpus(dev->kvm)) {
-		mutex_unlock(&dev->kvm->lock);
-		return -EBUSY;
-	}
+		if (kvm_trylock_all_vcpus(dev->kvm)) {
+			mutex_unlock(&dev->kvm->lock);
+			return -EBUSY;
+		}
 
-	mutex_lock(&dev->kvm->arch.config_lock);
+		mutex_lock(&dev->kvm->arch.config_lock);
+	}
 
 	if (!(vgic_initialized(dev->kvm) || reg_allowed_pre_init(attr))) {
 		ret = -EBUSY;
@@ -611,9 +618,15 @@ 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);
-	mutex_unlock(&dev->kvm->lock);
+	/* Release the locks acquired at the beginning of this function,
+	 * but only if we actually acquired them.
+	 * The order of unlocking must be the reverse of locking.
+	 */
+	if (attr->flags != KVM_DEV_ARM_VGIC_ATTR_FLAG_LOCKED) {
+		mutex_unlock(&dev->kvm->arch.config_lock);
+		kvm_unlock_all_vcpus(dev->kvm);
+		mutex_unlock(&dev->kvm->lock);
+	}
 
 	if (!ret && uaccess && !is_write) {
 		u32 __user *uaddr = (u32 __user *)(unsigned long)attr->addr;
@@ -623,6 +636,81 @@ static int vgic_v3_attr_regs_access(struct kvm_device *dev,
 	return ret;
 }
 
+/* vgic_v3_batch_access - Batch access to VGIC registers
+ *
+ * @dev: The VGIC device
+ * @attr: The device attribute containing the batch entries
+ * @is_write: True for write, false for read
+ *
+ * This function allows userspace to read or write multiple VGIC registers
+ * in a single system call, reducing overhead during live migration.
+ *
+ * Returns: 0 on success, or the first error encountered.
+ * Individual entry errors are stored in entries[i].error.
+ */
+static int vgic_v3_batch_access(struct kvm_device *dev,
+				struct kvm_device_attr *attr, bool is_write)
+{
+	struct kvm_dev_arm_vgic_batch_entry __user *uentries;
+	struct kvm_dev_arm_vgic_batch_entry *entries;
+	struct kvm_device_attr sub_attr;
+	u32 count = attr->attr;
+	int ret = 0, i;
+
+	if (!count || count > KVM_DEV_ARM_VGIC_BATCH_MAX)
+		return -EINVAL;
+
+	entries = kvmalloc_array(count, sizeof(*entries), GFP_KERNEL);
+	if (!entries)
+		return -ENOMEM;
+
+	uentries = (void __user *)attr->addr;
+	if (copy_from_user(entries, uentries, count * sizeof(*entries))) {
+		kvfree(entries);
+		return -EFAULT;
+	}
+
+	mutex_lock(&dev->kvm->lock);
+	if (kvm_trylock_all_vcpus(dev->kvm)) {
+		mutex_unlock(&dev->kvm->lock);
+		kvfree(entries);
+		return -EBUSY;
+	}
+	mutex_lock(&dev->kvm->arch.config_lock);
+
+	/* Process each entry in the batch */
+	for (i = 0; i < count; i++) {
+		int err;
+
+		sub_attr.group = entries[i].group;
+		sub_attr.attr = entries[i].attr;
+		sub_attr.addr = (unsigned long)uentries +
+			i * sizeof(struct kvm_dev_arm_vgic_batch_entry) +
+			offsetof(struct kvm_dev_arm_vgic_batch_entry, val);
+
+		/* Set flag to indicate that locks are already held.
+		 * This prevents vgic_v3_attr_regs_access from acquiring locks again,
+		 * avoiding deadlock and overhead.
+		 */
+		sub_attr.flags = KVM_DEV_ARM_VGIC_ATTR_FLAG_LOCKED;
+
+		err = vgic_v3_attr_regs_access(dev, &sub_attr, is_write);
+
+		if (err) {
+			pr_err("group %d attr %lld get err %d\n",
+				sub_attr.group, sub_attr.attr, err);
+			ret = err;
+		}
+	}
+
+	mutex_unlock(&dev->kvm->arch.config_lock);
+	kvm_unlock_all_vcpus(dev->kvm);
+	mutex_unlock(&dev->kvm->lock);
+
+	kvfree(entries);
+	return ret;
+}
+
 static int vgic_v3_set_attr(struct kvm_device *dev,
 			    struct kvm_device_attr *attr)
 {
@@ -649,6 +737,8 @@ static int vgic_v3_set_attr(struct kvm_device *dev,
 		dev->kvm->arch.vgic.mi_intid = val;
 		return 0;
 	}
+	case KVM_DEV_ARM_VGIC_GRP_BATCH_REGS:
+		return vgic_v3_batch_access(dev, attr, true);
 	default:
 		return vgic_set_common_attr(dev, attr);
 	}
@@ -669,6 +759,8 @@ static int vgic_v3_get_attr(struct kvm_device *dev,
 		guard(mutex)(&dev->kvm->arch.config_lock);
 		return put_user(dev->kvm->arch.vgic.mi_intid, uaddr);
 	}
+	case KVM_DEV_ARM_VGIC_GRP_BATCH_REGS:
+		return vgic_v3_batch_access(dev, attr, false);
 	default:
 		return vgic_get_common_attr(dev, attr);
 	}
@@ -707,6 +799,9 @@ static int vgic_v3_has_attr(struct kvm_device *dev,
 		case KVM_DEV_ARM_VGIC_SAVE_PENDING_TABLES:
 			return 0;
 		}
+		break;
+	case KVM_DEV_ARM_VGIC_GRP_BATCH_REGS:
+		return 0;
 	}
 	return -ENXIO;
 }
-- 
2.43.0


  parent reply	other threads:[~2026-09-18  8:23 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-18  8:18 [PATCH 0/2] Batch register access for live migration optimization Yize Wang
2026-09-18  8:18 ` [PATCH 1/2] KVM: arm64: Add batch group constant and data structure to UAPI header Yize Wang
2026-09-18  8:27   ` sashiko-bot
2026-09-18  8:18 ` Yize Wang [this message]
2026-09-18  8:33   ` [PATCH 2/2] KVM: arm64: Add VGIC v3 batch register access implementation sashiko-bot
2026-09-18 12:08 ` [PATCH 0/2] Batch register access for live migration optimization Marc Zyngier
2026-09-20 12:12   ` [RESEND][PATCH " Yize Wang
2026-09-23  7:57     ` Yize Wang
     [not found]   ` <f70c6fe3-e3c5-4912-b4bb-8a418fec4346@huawei.com>
2026-10-03 14:53     ` [PATCH " Marc Zyngier
2026-10-08  8:32       ` Yize Wang
2026-10-08 12:50       ` [RESEND][PATCH " Yize Wang
2026-10-12 11:04         ` Yize Wang
2026-10-12 11:31         ` Marc Zyngier

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=20260918081930.4014735-3-wangyize7@huawei.com \
    --to=wangyize7@huawei.com \
    --cc=catalin.marinas@arm.com \
    --cc=fuad.tabba@linux.dev \
    --cc=jiangjiacheng@huawei.com \
    --cc=joey.gouly@arm.com \
    --cc=kvmarm@lists.linux.dev \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mark.rutland@arm.com \
    --cc=maz@kernel.org \
    --cc=oupton@kernel.org \
    --cc=seiden@linux.ibm.com \
    --cc=suzuki.poulose@arm.com \
    --cc=will@kernel.org \
    --cc=yize_w1110@163.com \
    --cc=yuzenghui@huawei.com \
    --cc=zhengchuan@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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.