* [PATCH v2 0/4] irqchip/gic-v4, KVM: arm64: Fix the vgic init error paths
@ 2026-08-24 7:42 Fuad Tabba
2026-08-24 7:42 ` [PATCH v2 1/4] irqchip/gic-v4: Clear the domain and fwnode pointers after freeing them Fuad Tabba
` (3 more replies)
0 siblings, 4 replies; 9+ messages in thread
From: Fuad Tabba @ 2026-08-24 7:42 UTC (permalink / raw)
To: Marc Zyngier, Oliver Upton
Cc: Thomas Gleixner, Eric Auger, Joey Gouly, Steffen Eiden,
Suzuki K Poulose, Zenghui Yu, Will Deacon, Sascha Bischoff,
Sebastian Ene, Fuad Tabba, kvmarm, linux-arm-kernel, linux-kernel
Hi folks,
Changes since v1 [1]:
- New patch 4: restore its_vm.nr_vpes in vgic_v4_teardown() so that
its_free_vcpu_irqs() frees every vPE. (sashiko, Marc)
- Patch 2: corrected the commit message. Skipping a vPE with no SGI
domain avoids a wrong free, not a warning.
- Patch 3: added a second Fixes: tag. The SPI-array leak arrived with
the routing call, well before the vPE one.
- No code changes to patches 1 to 3.
Four fixes on the paths that run when vgic init fails partway. Each one
needs an allocation failure to reach.
Sashiko reported the vgic_init() case [2] while reviewing the SPI-array
leak fix, and the two irq-gic-v4.c fixes came out of chasing the first
[3]. Then, just when I thought I'd squashed every bug Sashiko could
find, it turned up one more in its v1 review: the pre-existing nr_vpes
one, fixed in patch 4 as Marc suggested [4].
Patch 1 clears the irq domain and fwnode pointers at the four GICv4
sites that free them and leave them set. Patch 2 makes
its_alloc_vcpu_irqs() release what it allocated when the SGI loop
fails, which is both the SGI domains and the vPE irqs, wider than the
SGI-domain leak I described before posting v1 [3]. Patch 3 releases the
SPI array and the vPEs on vgic_init()'s later failure paths, so
KVM_DEV_ARM_VGIC_CTRL_INIT is all or nothing and a retry starts from
scratch. Patch 4 is Marc's suggested fix [4] for the nr_vpes overload.
These patches run across two subsystems, but ordering matters, which is
why this is one series. Patch 2 reuses its_free_sgi_irqs() from an
error path, which only works once patch 1 has cleared the pointers.
Patch 3 runs vgic_v4_teardown() on a path it never ran on before, which
adds a route into what patch 1 fixes. Patch 4 is only correct on top of
patch 3, which is what stops online_vcpus outgrowing the vPE array.
Based on kvmarm/next (aa8e5dc6a7a2a).
Cheers,
/fuad
[1] https://lore.kernel.org/all/20260820125053.2951078-1-fuad.tabba@linux.dev/
[2] https://lore.kernel.org/all/20260807105558.73D701F000E9@smtp.kernel.org/
[3] https://lore.kernel.org/all/CA+EHjTyDix+y6NTLTsXP5j9Sn2VLOZcsw94LntQxg_etRBJZuA@mail.gmail.com/
[4] https://lore.kernel.org/all/87ik51np8e.wl-maz@kernel.org/
Fuad Tabba (4):
irqchip/gic-v4: Clear the domain and fwnode pointers after freeing
them
irqchip/gic-v4: Unwind what its_alloc_vcpu_irqs() allocated on failure
KVM: arm64: vgic: Tear down what vgic_init() created when it fails
KVM: arm64: vgic-v4: Restore nr_vpes before freeing the vPE resources
arch/arm64/kvm/vgic/vgic-init.c | 11 +++++++++--
arch/arm64/kvm/vgic/vgic-v4.c | 3 +++
drivers/irqchip/irq-gic-v4.c | 34 +++++++++++++++++++++++++++------
3 files changed, 40 insertions(+), 8 deletions(-)
base-commit: aa8e5dc6a7a2a1141ab40706a51010adcd0e57d2
--
2.39.5
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH v2 1/4] irqchip/gic-v4: Clear the domain and fwnode pointers after freeing them
2026-08-24 7:42 [PATCH v2 0/4] irqchip/gic-v4, KVM: arm64: Fix the vgic init error paths Fuad Tabba
@ 2026-08-24 7:42 ` Fuad Tabba
2026-08-25 8:52 ` Yao Yuan
2026-08-24 7:42 ` [PATCH v2 2/4] irqchip/gic-v4: Unwind what its_alloc_vcpu_irqs() allocated on failure Fuad Tabba
` (2 subsequent siblings)
3 siblings, 1 reply; 9+ messages in thread
From: Fuad Tabba @ 2026-08-24 7:42 UTC (permalink / raw)
To: Marc Zyngier, Oliver Upton
Cc: Thomas Gleixner, Eric Auger, Joey Gouly, Steffen Eiden,
Suzuki K Poulose, Zenghui Yu, Will Deacon, Sascha Bischoff,
Sebastian Ene, Fuad Tabba, kvmarm, linux-arm-kernel, linux-kernel
The GICv4 allocation and teardown paths free their irq domains and
fwnodes but leave the pointers set, and the allocation error paths test
those pointers before removing them. struct its_vm and struct its_vpe
are embedded in KVM's per-VM and per-vCPU state, so nothing re-zeroes
them between two attempts, and an error path taken after an earlier one
already freed the domain calls irq_domain_remove() on freed memory.
Reaching this takes two allocation failures, one to leave the stale
pointer behind and one to send the next attempt down the error path.
Fixes: 7de5c0af9c7c ("irqchip/gic-v4: Add per-VM VPE domain creation")
Fixes: 6d31b6ff985d ("irqchip/gic-v4.1: Add VSGI allocation/teardown")
Signed-off-by: Fuad Tabba <fuad.tabba@linux.dev>
---
drivers/irqchip/irq-gic-v4.c | 20 ++++++++++++++++----
1 file changed, 16 insertions(+), 4 deletions(-)
diff --git a/drivers/irqchip/irq-gic-v4.c b/drivers/irqchip/irq-gic-v4.c
index 8455b4a5fbb0d..754839e409f88 100644
--- a/drivers/irqchip/irq-gic-v4.c
+++ b/drivers/irqchip/irq-gic-v4.c
@@ -147,10 +147,14 @@ static int its_alloc_vcpu_sgis(struct its_vpe *vpe, int idx)
return 0;
err:
- if (vpe->sgi_domain)
+ if (vpe->sgi_domain) {
irq_domain_remove(vpe->sgi_domain);
- if (vpe->fwnode)
+ vpe->sgi_domain = NULL;
+ }
+ if (vpe->fwnode) {
irq_domain_free_fwnode(vpe->fwnode);
+ vpe->fwnode = NULL;
+ }
kfree(name);
return -ENOMEM;
}
@@ -191,10 +195,14 @@ int its_alloc_vcpu_irqs(struct its_vm *vm)
return 0;
err:
- if (vm->domain)
+ if (vm->domain) {
irq_domain_remove(vm->domain);
- if (vm->fwnode)
+ vm->domain = NULL;
+ }
+ if (vm->fwnode) {
irq_domain_free_fwnode(vm->fwnode);
+ vm->fwnode = NULL;
+ }
return -ENOMEM;
}
@@ -215,6 +223,8 @@ static void its_free_sgi_irqs(struct its_vm *vm)
irq_domain_free_irqs(irq, 16);
irq_domain_remove(vm->vpes[i]->sgi_domain);
irq_domain_free_fwnode(vm->vpes[i]->fwnode);
+ vm->vpes[i]->sgi_domain = NULL;
+ vm->vpes[i]->fwnode = NULL;
}
}
@@ -224,6 +234,8 @@ void its_free_vcpu_irqs(struct its_vm *vm)
irq_domain_free_irqs(vm->vpes[0]->irq, vm->nr_vpes);
irq_domain_remove(vm->domain);
irq_domain_free_fwnode(vm->fwnode);
+ vm->domain = NULL;
+ vm->fwnode = NULL;
}
static int its_send_vpe_cmd(struct its_vpe *vpe, struct its_cmd_info *info)
--
2.39.5
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH v2 2/4] irqchip/gic-v4: Unwind what its_alloc_vcpu_irqs() allocated on failure
2026-08-24 7:42 [PATCH v2 0/4] irqchip/gic-v4, KVM: arm64: Fix the vgic init error paths Fuad Tabba
2026-08-24 7:42 ` [PATCH v2 1/4] irqchip/gic-v4: Clear the domain and fwnode pointers after freeing them Fuad Tabba
@ 2026-08-24 7:42 ` Fuad Tabba
2026-08-25 9:10 ` Yao Yuan
2026-08-24 7:42 ` [PATCH v2 3/4] KVM: arm64: vgic: Tear down what vgic_init() created when it fails Fuad Tabba
2026-08-24 7:42 ` [PATCH v2 4/4] KVM: arm64: vgic-v4: Restore nr_vpes before freeing the vPE resources Fuad Tabba
3 siblings, 1 reply; 9+ messages in thread
From: Fuad Tabba @ 2026-08-24 7:42 UTC (permalink / raw)
To: Marc Zyngier, Oliver Upton
Cc: Thomas Gleixner, Eric Auger, Joey Gouly, Steffen Eiden,
Suzuki K Poulose, Zenghui Yu, Will Deacon, Sascha Bischoff,
Sebastian Ene, Fuad Tabba, kvmarm, linux-arm-kernel, linux-kernel
A failure in the its_alloc_vcpu_sgis() loop leaves behind both the SGI
domains created for the vPEs below the failing index and the vPE irqs
allocated before the loop, since irq_domain_remove() frees neither. Each
leaked vPE takes its ITS state with it, a vpe_id and an LPI pending
table.
Free both from a second label before the existing unwind. With the
freed pointers now cleared, its_free_sgi_irqs() can skip a vPE with no
SGI domain and be reused there. The check has to precede the lookup:
irq_find_mapping(NULL, 0) falls back to irq_default_domain, and the
live irq it returns would then be freed.
Fixes: 6d31b6ff985d ("irqchip/gic-v4.1: Add VSGI allocation/teardown")
Signed-off-by: Fuad Tabba <fuad.tabba@linux.dev>
---
drivers/irqchip/irq-gic-v4.c | 14 ++++++++++++--
1 file changed, 12 insertions(+), 2 deletions(-)
diff --git a/drivers/irqchip/irq-gic-v4.c b/drivers/irqchip/irq-gic-v4.c
index 754839e409f88..f707a3cb281aa 100644
--- a/drivers/irqchip/irq-gic-v4.c
+++ b/drivers/irqchip/irq-gic-v4.c
@@ -159,6 +159,8 @@ static int its_alloc_vcpu_sgis(struct its_vpe *vpe, int idx)
return -ENOMEM;
}
+static void its_free_sgi_irqs(struct its_vm *vm);
+
int its_alloc_vcpu_irqs(struct its_vm *vm)
{
int vpe_base_irq, i;
@@ -189,11 +191,14 @@ int its_alloc_vcpu_irqs(struct its_vm *vm)
vm->vpes[i]->irq = vpe_base_irq + i;
ret = its_alloc_vcpu_sgis(vm->vpes[i], i);
if (ret)
- goto err;
+ goto err_free_irqs;
}
return 0;
+err_free_irqs:
+ its_free_sgi_irqs(vm);
+ irq_domain_free_irqs(vpe_base_irq, vm->nr_vpes);
err:
if (vm->domain) {
irq_domain_remove(vm->domain);
@@ -215,8 +220,13 @@ static void its_free_sgi_irqs(struct its_vm *vm)
return;
for (i = 0; i < vm->nr_vpes; i++) {
- unsigned int irq = irq_find_mapping(vm->vpes[i]->sgi_domain, 0);
+ unsigned int irq;
+ /* irq_find_mapping() falls back to the default domain on NULL. */
+ if (!vm->vpes[i]->sgi_domain)
+ continue;
+
+ irq = irq_find_mapping(vm->vpes[i]->sgi_domain, 0);
if (WARN_ON(!irq))
continue;
--
2.39.5
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH v2 3/4] KVM: arm64: vgic: Tear down what vgic_init() created when it fails
2026-08-24 7:42 [PATCH v2 0/4] irqchip/gic-v4, KVM: arm64: Fix the vgic init error paths Fuad Tabba
2026-08-24 7:42 ` [PATCH v2 1/4] irqchip/gic-v4: Clear the domain and fwnode pointers after freeing them Fuad Tabba
2026-08-24 7:42 ` [PATCH v2 2/4] irqchip/gic-v4: Unwind what its_alloc_vcpu_irqs() allocated on failure Fuad Tabba
@ 2026-08-24 7:42 ` Fuad Tabba
2026-08-25 9:18 ` Yao Yuan
2026-08-24 7:42 ` [PATCH v2 4/4] KVM: arm64: vgic-v4: Restore nr_vpes before freeing the vPE resources Fuad Tabba
3 siblings, 1 reply; 9+ messages in thread
From: Fuad Tabba @ 2026-08-24 7:42 UTC (permalink / raw)
To: Marc Zyngier, Oliver Upton
Cc: Thomas Gleixner, Eric Auger, Joey Gouly, Steffen Eiden,
Suzuki K Poulose, Zenghui Yu, Will Deacon, Sascha Bischoff,
Sebastian Ene, Fuad Tabba, kvmarm, linux-arm-kernel, linux-kernel
Once kvm_vgic_dist_init() has succeeded, every later failure in
vgic_init() returns with the SPI array still allocated. A failure after
vgic_v4_init() has also succeeded, which today means only
kvm_vgic_setup_default_irq_routing(), leaves the vPE array behind as
well.
A failed vgic_init() leaves kvm_arch_vcpu_precreate() admitting new
vCPUs, so a retry of KVM_DEV_ARM_VGIC_CTRL_INIT reaches
vgic_v4_init()'s early return with an array that no longer covers every
vCPU, and vgic_v3_load()'s WARN_ON(vgic_v4_load()) fires on the first
one it misses.
Release both on the two paths that can reach them, so the ioctl is all
or nothing and a retry starts from scratch. dist->nr_spis stays frozen,
since the SPI count cannot change once vgic_init() has supplied it.
Fixes: 180ae7b11823 ("KVM: arm/arm64: Enable irqchip routing")
Fixes: 74fe55dc9ab7 ("KVM: arm/arm64: GICv4: Add init/teardown of the per-VM vPE irq domain")
Reported-by: Sashiko <sashiko-bot@kernel.org>
Closes: https://lore.kernel.org/all/20260807105558.73D701F000E9@smtp.kernel.org/
Signed-off-by: Fuad Tabba <fuad.tabba@linux.dev>
---
arch/arm64/kvm/vgic/vgic-init.c | 11 +++++++++--
1 file changed, 9 insertions(+), 2 deletions(-)
diff --git a/arch/arm64/kvm/vgic/vgic-init.c b/arch/arm64/kvm/vgic/vgic-init.c
index 4012df6002ea6..7493fded53acc 100644
--- a/arch/arm64/kvm/vgic/vgic-init.c
+++ b/arch/arm64/kvm/vgic/vgic-init.c
@@ -462,7 +462,7 @@ int vgic_init(struct kvm *kvm)
if (vgic_supports_direct_irqs(kvm)) {
ret = vgic_v4_init(kvm);
if (ret)
- return ret;
+ goto out_teardown;
}
} else {
ret = vgic_v5_init(kvm);
@@ -475,12 +475,19 @@ int vgic_init(struct kvm *kvm)
ret = kvm_vgic_setup_default_irq_routing(kvm);
if (ret)
- return ret;
+ goto out_teardown;
vgic_debug_init(kvm);
dist->initialized = true;
return 0;
+
+out_teardown:
+ vgic_v4_teardown(kvm);
+ kfree(dist->spis);
+ dist->spis = NULL;
+
+ return ret;
}
static void kvm_vgic_dist_destroy(struct kvm *kvm)
--
2.39.5
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH v2 4/4] KVM: arm64: vgic-v4: Restore nr_vpes before freeing the vPE resources
2026-08-24 7:42 [PATCH v2 0/4] irqchip/gic-v4, KVM: arm64: Fix the vgic init error paths Fuad Tabba
` (2 preceding siblings ...)
2026-08-24 7:42 ` [PATCH v2 3/4] KVM: arm64: vgic: Tear down what vgic_init() created when it fails Fuad Tabba
@ 2026-08-24 7:42 ` Fuad Tabba
3 siblings, 0 replies; 9+ messages in thread
From: Fuad Tabba @ 2026-08-24 7:42 UTC (permalink / raw)
To: Marc Zyngier, Oliver Upton
Cc: Thomas Gleixner, Eric Auger, Joey Gouly, Steffen Eiden,
Suzuki K Poulose, Zenghui Yu, Will Deacon, Sascha Bischoff,
Sebastian Ene, Fuad Tabba, kvmarm, linux-arm-kernel, linux-kernel
vgic_v4_init() truncates its_vm.nr_vpes to the failing index to bound
vgic_v4_teardown()'s free_irq() loop, but its_free_vcpu_irqs() reads
the same field: the vPE irqs and the v4.1 SGI domains at or above that
index are never freed, each one leaking a vpe_id and an LPI pending
table.
Restore the count from online_vcpus before that call. This depends on
the previous patch: a failed vgic_init() keeps admitting vCPUs, so
without that patch's teardown the vPE array outlives the failure while
online_vcpus grows past the size it was allocated with.
Fixes: bdb2d2ccac65 ("KVM: arm/arm64: GICv4: Add doorbell interrupt handling")
Reported-by: Sashiko <sashiko-bot@kernel.org>
Closes: https://lore.kernel.org/all/20260820130616.1A7241F000E9@smtp.kernel.org/
Suggested-by: Marc Zyngier <maz@kernel.org>
Signed-off-by: Fuad Tabba <fuad.tabba@linux.dev>
---
arch/arm64/kvm/vgic/vgic-v4.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/arch/arm64/kvm/vgic/vgic-v4.c b/arch/arm64/kvm/vgic/vgic-v4.c
index ed236f083f0d7..30e1de3fc7d9d 100644
--- a/arch/arm64/kvm/vgic/vgic-v4.c
+++ b/arch/arm64/kvm/vgic/vgic-v4.c
@@ -333,6 +333,9 @@ void vgic_v4_teardown(struct kvm *kvm)
free_irq(irq, vcpu);
}
+ /* Make sure we free all VM-wide, per-CPU resources */
+ its_vm->nr_vpes = atomic_read(&kvm->online_vcpus);
+
its_free_vcpu_irqs(its_vm);
kfree(its_vm->vpes);
its_vm->nr_vpes = 0;
--
2.39.5
^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [PATCH v2 1/4] irqchip/gic-v4: Clear the domain and fwnode pointers after freeing them
2026-08-24 7:42 ` [PATCH v2 1/4] irqchip/gic-v4: Clear the domain and fwnode pointers after freeing them Fuad Tabba
@ 2026-08-25 8:52 ` Yao Yuan
0 siblings, 0 replies; 9+ messages in thread
From: Yao Yuan @ 2026-08-25 8:52 UTC (permalink / raw)
To: Fuad Tabba
Cc: Marc Zyngier, Oliver Upton, Thomas Gleixner, Eric Auger,
Joey Gouly, Steffen Eiden, Suzuki K Poulose, Zenghui Yu,
Will Deacon, Sascha Bischoff, Sebastian Ene, Fuad Tabba, kvmarm,
linux-arm-kernel, linux-kernel
On Mon, Aug 24, 2026 at 08:42:42AM +0800, Fuad Tabba wrote:
> The GICv4 allocation and teardown paths free their irq domains and
> fwnodes but leave the pointers set, and the allocation error paths test
> those pointers before removing them. struct its_vm and struct its_vpe
> are embedded in KVM's per-VM and per-vCPU state, so nothing re-zeroes
> them between two attempts, and an error path taken after an earlier one
> already freed the domain calls irq_domain_remove() on freed memory.
Hi Tabba,
Real nice finding!
Reviewed-by: Yuan Yao <yaoyuan@linux.alibaba.com>
>
> Reaching this takes two allocation failures, one to leave the stale
> pointer behind and one to send the next attempt down the error path.
>
> Fixes: 7de5c0af9c7c ("irqchip/gic-v4: Add per-VM VPE domain creation")
> Fixes: 6d31b6ff985d ("irqchip/gic-v4.1: Add VSGI allocation/teardown")
> Signed-off-by: Fuad Tabba <fuad.tabba@linux.dev>
> ---
> drivers/irqchip/irq-gic-v4.c | 20 ++++++++++++++++----
> 1 file changed, 16 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/irqchip/irq-gic-v4.c b/drivers/irqchip/irq-gic-v4.c
> index 8455b4a5fbb0d..754839e409f88 100644
> --- a/drivers/irqchip/irq-gic-v4.c
> +++ b/drivers/irqchip/irq-gic-v4.c
> @@ -147,10 +147,14 @@ static int its_alloc_vcpu_sgis(struct its_vpe *vpe, int idx)
> return 0;
>
> err:
> - if (vpe->sgi_domain)
> + if (vpe->sgi_domain) {
> irq_domain_remove(vpe->sgi_domain);
> - if (vpe->fwnode)
> + vpe->sgi_domain = NULL;
> + }
> + if (vpe->fwnode) {
> irq_domain_free_fwnode(vpe->fwnode);
> + vpe->fwnode = NULL;
> + }
> kfree(name);
> return -ENOMEM;
> }
> @@ -191,10 +195,14 @@ int its_alloc_vcpu_irqs(struct its_vm *vm)
> return 0;
>
> err:
> - if (vm->domain)
> + if (vm->domain) {
> irq_domain_remove(vm->domain);
> - if (vm->fwnode)
> + vm->domain = NULL;
> + }
> + if (vm->fwnode) {
> irq_domain_free_fwnode(vm->fwnode);
> + vm->fwnode = NULL;
> + }
>
> return -ENOMEM;
> }
> @@ -215,6 +223,8 @@ static void its_free_sgi_irqs(struct its_vm *vm)
> irq_domain_free_irqs(irq, 16);
> irq_domain_remove(vm->vpes[i]->sgi_domain);
> irq_domain_free_fwnode(vm->vpes[i]->fwnode);
> + vm->vpes[i]->sgi_domain = NULL;
> + vm->vpes[i]->fwnode = NULL;
> }
> }
>
> @@ -224,6 +234,8 @@ void its_free_vcpu_irqs(struct its_vm *vm)
> irq_domain_free_irqs(vm->vpes[0]->irq, vm->nr_vpes);
> irq_domain_remove(vm->domain);
> irq_domain_free_fwnode(vm->fwnode);
> + vm->domain = NULL;
> + vm->fwnode = NULL;
> }
>
> static int its_send_vpe_cmd(struct its_vpe *vpe, struct its_cmd_info *info)
> --
> 2.39.5
>
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH v2 2/4] irqchip/gic-v4: Unwind what its_alloc_vcpu_irqs() allocated on failure
2026-08-24 7:42 ` [PATCH v2 2/4] irqchip/gic-v4: Unwind what its_alloc_vcpu_irqs() allocated on failure Fuad Tabba
@ 2026-08-25 9:10 ` Yao Yuan
0 siblings, 0 replies; 9+ messages in thread
From: Yao Yuan @ 2026-08-25 9:10 UTC (permalink / raw)
To: Fuad Tabba
Cc: Marc Zyngier, Oliver Upton, Thomas Gleixner, Eric Auger,
Joey Gouly, Steffen Eiden, Suzuki K Poulose, Zenghui Yu,
Will Deacon, Sascha Bischoff, Sebastian Ene, Fuad Tabba, kvmarm,
linux-arm-kernel, linux-kernel
On Mon, Aug 24, 2026 at 08:42:43AM +0800, Fuad Tabba wrote:
> A failure in the its_alloc_vcpu_sgis() loop leaves behind both the SGI
> domains created for the vPEs below the failing index and the vPE irqs
> allocated before the loop, since irq_domain_remove() frees neither. Each
> leaked vPE takes its ITS state with it, a vpe_id and an LPI pending
> table.
>
> Free both from a second label before the existing unwind. With the
> freed pointers now cleared, its_free_sgi_irqs() can skip a vPE with no
> SGI domain and be reused there. The check has to precede the lookup:
> irq_find_mapping(NULL, 0) falls back to irq_default_domain, and the
> live irq it returns would then be freed.
Reviewed-by: Yuan Yao <yaoyuan@linux.alibaba.com>
>
> Fixes: 6d31b6ff985d ("irqchip/gic-v4.1: Add VSGI allocation/teardown")
> Signed-off-by: Fuad Tabba <fuad.tabba@linux.dev>
> ---
> drivers/irqchip/irq-gic-v4.c | 14 ++++++++++++--
> 1 file changed, 12 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/irqchip/irq-gic-v4.c b/drivers/irqchip/irq-gic-v4.c
> index 754839e409f88..f707a3cb281aa 100644
> --- a/drivers/irqchip/irq-gic-v4.c
> +++ b/drivers/irqchip/irq-gic-v4.c
> @@ -159,6 +159,8 @@ static int its_alloc_vcpu_sgis(struct its_vpe *vpe, int idx)
> return -ENOMEM;
> }
>
> +static void its_free_sgi_irqs(struct its_vm *vm);
> +
> int its_alloc_vcpu_irqs(struct its_vm *vm)
> {
> int vpe_base_irq, i;
> @@ -189,11 +191,14 @@ int its_alloc_vcpu_irqs(struct its_vm *vm)
> vm->vpes[i]->irq = vpe_base_irq + i;
> ret = its_alloc_vcpu_sgis(vm->vpes[i], i);
> if (ret)
> - goto err;
> + goto err_free_irqs;
> }
>
> return 0;
>
> +err_free_irqs:
> + its_free_sgi_irqs(vm);
> + irq_domain_free_irqs(vpe_base_irq, vm->nr_vpes);
> err:
> if (vm->domain) {
> irq_domain_remove(vm->domain);
> @@ -215,8 +220,13 @@ static void its_free_sgi_irqs(struct its_vm *vm)
> return;
>
> for (i = 0; i < vm->nr_vpes; i++) {
> - unsigned int irq = irq_find_mapping(vm->vpes[i]->sgi_domain, 0);
> + unsigned int irq;
>
> + /* irq_find_mapping() falls back to the default domain on NULL. */
> + if (!vm->vpes[i]->sgi_domain)
> + continue;
> +
> + irq = irq_find_mapping(vm->vpes[i]->sgi_domain, 0);
> if (WARN_ON(!irq))
> continue;
>
> --
> 2.39.5
>
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH v2 3/4] KVM: arm64: vgic: Tear down what vgic_init() created when it fails
2026-08-24 7:42 ` [PATCH v2 3/4] KVM: arm64: vgic: Tear down what vgic_init() created when it fails Fuad Tabba
@ 2026-08-25 9:18 ` Yao Yuan
2026-08-25 9:47 ` Fuad Tabba
0 siblings, 1 reply; 9+ messages in thread
From: Yao Yuan @ 2026-08-25 9:18 UTC (permalink / raw)
To: Fuad Tabba
Cc: Marc Zyngier, Oliver Upton, Thomas Gleixner, Eric Auger,
Joey Gouly, Steffen Eiden, Suzuki K Poulose, Zenghui Yu,
Will Deacon, Sascha Bischoff, Sebastian Ene, Fuad Tabba, kvmarm,
linux-arm-kernel, linux-kernel
On Mon, Aug 24, 2026 at 08:42:44AM +0800, Fuad Tabba wrote:
> Once kvm_vgic_dist_init() has succeeded, every later failure in
> vgic_init() returns with the SPI array still allocated. A failure after
> vgic_v4_init() has also succeeded, which today means only
> kvm_vgic_setup_default_irq_routing(), leaves the vPE array behind as
> well.
>
> A failed vgic_init() leaves kvm_arch_vcpu_precreate() admitting new
> vCPUs, so a retry of KVM_DEV_ARM_VGIC_CTRL_INIT reaches
> vgic_v4_init()'s early return with an array that no longer covers every
> vCPU, and vgic_v3_load()'s WARN_ON(vgic_v4_load()) fires on the first
> one it misses.
>
> Release both on the two paths that can reach them, so the ioctl is all
> or nothing and a retry starts from scratch. dist->nr_spis stays frozen,
> since the SPI count cannot change once vgic_init() has supplied it.
>
> Fixes: 180ae7b11823 ("KVM: arm/arm64: Enable irqchip routing")
> Fixes: 74fe55dc9ab7 ("KVM: arm/arm64: GICv4: Add init/teardown of the per-VM vPE irq domain")
> Reported-by: Sashiko <sashiko-bot@kernel.org>
> Closes: https://lore.kernel.org/all/20260807105558.73D701F000E9@smtp.kernel.org/
> Signed-off-by: Fuad Tabba <fuad.tabba@linux.dev>
> ---
> arch/arm64/kvm/vgic/vgic-init.c | 11 +++++++++--
> 1 file changed, 9 insertions(+), 2 deletions(-)
>
> diff --git a/arch/arm64/kvm/vgic/vgic-init.c b/arch/arm64/kvm/vgic/vgic-init.c
> index 4012df6002ea6..7493fded53acc 100644
> --- a/arch/arm64/kvm/vgic/vgic-init.c
> +++ b/arch/arm64/kvm/vgic/vgic-init.c
> @@ -462,7 +462,7 @@ int vgic_init(struct kvm *kvm)
> if (vgic_supports_direct_irqs(kvm)) {
> ret = vgic_v4_init(kvm);
> if (ret)
Hi Tabba,
> - return ret;
> + goto out_teardown;
The vigc_v4_init already called vgic_v4_teardown() in error path,
thus I think just free dist->spis is enough yet ?
> }
> } else {
> ret = vgic_v5_init(kvm);
> @@ -475,12 +475,19 @@ int vgic_init(struct kvm *kvm)
>
> ret = kvm_vgic_setup_default_irq_routing(kvm);
> if (ret)
> - return ret;
> + goto out_teardown;
>
> vgic_debug_init(kvm);
> dist->initialized = true;
>
> return 0;
> +
> +out_teardown:
> + vgic_v4_teardown(kvm);
> + kfree(dist->spis);
> + dist->spis = NULL;
> +
> + return ret;
> }
>
> static void kvm_vgic_dist_destroy(struct kvm *kvm)
> --
> 2.39.5
>
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH v2 3/4] KVM: arm64: vgic: Tear down what vgic_init() created when it fails
2026-08-25 9:18 ` Yao Yuan
@ 2026-08-25 9:47 ` Fuad Tabba
0 siblings, 0 replies; 9+ messages in thread
From: Fuad Tabba @ 2026-08-25 9:47 UTC (permalink / raw)
To: Yao Yuan
Cc: Marc Zyngier, Oliver Upton, Thomas Gleixner, Eric Auger,
Joey Gouly, Steffen Eiden, Suzuki K Poulose, Zenghui Yu,
Will Deacon, Sascha Bischoff, Sebastian Ene, kvmarm,
linux-arm-kernel, linux-kernel
Hi Yuan,
On Tue, 25 Aug 2026 at 10:18, Yao Yuan <yaoyuan@linux.alibaba.com> wrote:
...
> > diff --git a/arch/arm64/kvm/vgic/vgic-init.c b/arch/arm64/kvm/vgic/vgic-init.c
> > index 4012df6002ea6..7493fded53acc 100644
> > --- a/arch/arm64/kvm/vgic/vgic-init.c
> > +++ b/arch/arm64/kvm/vgic/vgic-init.c
> > @@ -462,7 +462,7 @@ int vgic_init(struct kvm *kvm)
> > if (vgic_supports_direct_irqs(kvm)) {
> > ret = vgic_v4_init(kvm);
> > if (ret)
>
> Hi Tabba,
>
> > - return ret;
> > + goto out_teardown;
>
> The vigc_v4_init already called vgic_v4_teardown() in error path,
> thus I think just free dist->spis is enough yet ?
vgic_v4_init() unwinds its own state on every error return, so
vgic_v4_teardown() is a no-op there and freeing the SPI array would be
enough. I'll fold the label split in if I respin.
Thanks for the reviews!
/fuad
>
> > }
> > } else {
> > ret = vgic_v5_init(kvm);
> > @@ -475,12 +475,19 @@ int vgic_init(struct kvm *kvm)
> >
> > ret = kvm_vgic_setup_default_irq_routing(kvm);
> > if (ret)
> > - return ret;
> > + goto out_teardown;
> >
> > vgic_debug_init(kvm);
> > dist->initialized = true;
> >
> > return 0;
> > +
> > +out_teardown:
> > + vgic_v4_teardown(kvm);
> > + kfree(dist->spis);
> > + dist->spis = NULL;
> > +
> > + return ret;
> > }
> >
> > static void kvm_vgic_dist_destroy(struct kvm *kvm)
> > --
> > 2.39.5
> >
^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2026-08-25 9:48 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-24 7:42 [PATCH v2 0/4] irqchip/gic-v4, KVM: arm64: Fix the vgic init error paths Fuad Tabba
2026-08-24 7:42 ` [PATCH v2 1/4] irqchip/gic-v4: Clear the domain and fwnode pointers after freeing them Fuad Tabba
2026-08-25 8:52 ` Yao Yuan
2026-08-24 7:42 ` [PATCH v2 2/4] irqchip/gic-v4: Unwind what its_alloc_vcpu_irqs() allocated on failure Fuad Tabba
2026-08-25 9:10 ` Yao Yuan
2026-08-24 7:42 ` [PATCH v2 3/4] KVM: arm64: vgic: Tear down what vgic_init() created when it fails Fuad Tabba
2026-08-25 9:18 ` Yao Yuan
2026-08-25 9:47 ` Fuad Tabba
2026-08-24 7:42 ` [PATCH v2 4/4] KVM: arm64: vgic-v4: Restore nr_vpes before freeing the vPE resources Fuad Tabba
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox