[PATCH v2 2/2] LoongArch: KVM: Fix resource leak in kvm_loongarch_env_init() error path

From: Chaithanya Lagisetty

Date: Wed Sep 02 2026 - 03:14:52 EST


kvm_loongarch_env_init() allocates the per-CPU kvm_context (vmcs) and
kvm_loongarch_ops, registers the perf callbacks, and then registers the
IPI/EIOINTC/PCH-PIC/DMSINTC KVM devices. If any of those device
registrations fails, the function returned the error directly, leaving
everything acquired so far in place: vmcs and kvm_loongarch_ops are
never freed, the perf callbacks stay registered, and previously
registered KVM device ops remain registered. kvm_loongarch_init()
propagates the error without calling kvm_loongarch_env_exit(), so
nothing else cleans up either.

Unwind the error path in reverse order of registration, so that each
failure only undoes what had actually been set up. Use the same helpers
in kvm_loongarch_env_exit() to remove the device registrations during
normal teardown as well.

Fixes: c532de5a67a7 ("LoongArch: KVM: Add IPI device support")
Signed-off-by: Chaithanya Lagisetty <nagachaithanya9911@xxxxxxxxx>
---
arch/loongarch/kvm/main.c | 32 ++++++++++++++++++++++++++++----
1 file changed, 28 insertions(+), 4 deletions(-)

diff --git a/arch/loongarch/kvm/main.c b/arch/loongarch/kvm/main.c
index 3e1005526f4b..c9cb3fc2e560 100644
--- a/arch/loongarch/kvm/main.c
+++ b/arch/loongarch/kvm/main.c
@@ -385,27 +385,51 @@ static int kvm_loongarch_env_init(void)
/* Register LoongArch IPI interrupt controller interface. */
ret = kvm_loongarch_register_ipi_device();
if (ret)
- return ret;
+ goto err_env;

/* Register LoongArch EIOINTC interrupt controller interface. */
ret = kvm_loongarch_register_eiointc_device();
if (ret)
- return ret;
+ goto err_ipi;

/* Register LoongArch PCH-PIC interrupt controller interface. */
ret = kvm_loongarch_register_pch_pic_device();
if (ret)
- return ret;
+ goto err_eiointc;

/* Register LoongArch DMSINTC interrupt contrroller interface */
- if (cpu_has_msgint)
+ if (cpu_has_msgint) {
ret = kvm_loongarch_register_dmsintc_device();
+ if (ret)
+ goto err_pch_pic;
+ }
+
+ return 0;
+
+err_pch_pic:
+ kvm_loongarch_unregister_pch_pic_device();
+err_eiointc:
+ kvm_loongarch_unregister_eiointc_device();
+err_ipi:
+ kvm_loongarch_unregister_ipi_device();
+err_env:
+ kvm_unregister_perf_callbacks();
+ kfree(kvm_loongarch_ops);
+ kvm_loongarch_ops = NULL;
+ free_percpu(vmcs);
+ vmcs = NULL;

return ret;
}

static void kvm_loongarch_env_exit(void)
{
+ if (cpu_has_msgint)
+ kvm_loongarch_unregister_dmsintc_device();
+ kvm_loongarch_unregister_pch_pic_device();
+ kvm_loongarch_unregister_eiointc_device();
+ kvm_loongarch_unregister_ipi_device();
+
if (vmcs)
free_percpu(vmcs);

--
2.43.0