[PATCH v5 5/6] KVM: s390: pci: Fix resource leak on IRQ registration failure

From: Farhan Ali

Date: Thu Jul 23 2026 - 14:40:28 EST


Currently if kvm_zpci_set_airq() fails, kvm_s390_pci_aif_enable() returns
an error code but doesn't do any resource cleanup, thus leaking resources.
Fix this by cleaning up all the resources such as the GAITE, AIBV, AISB and
unpinning any pinned pages. While at it, remove dead code that stored FIB
values that were never referenced.

As part of the cleanup, we are also holding the aift_lock while executing
the MPCIFC instruction. Though this is not strictly necessary, it means
we don't have to drop and re-acquire in the error case.

Fixes: 3c5a1b6f0a18 ("KVM: s390: pci: provide routines for enabling/disabling interrupt forwarding")
Cc: stable@xxxxxxxxxxxxxxx
Reviewed-by: Matthew Rosato <mjrosato@xxxxxxxxxxxxx>
Reviewed-by: Christian Borntraeger <borntraeger@xxxxxxxxxxxxx>
Signed-off-by: Farhan Ali <alifm@xxxxxxxxxxxxx>
---
arch/s390/kvm/pci.c | 29 +++++++++++++++++++++--------
1 file changed, 21 insertions(+), 8 deletions(-)

diff --git a/arch/s390/kvm/pci.c b/arch/s390/kvm/pci.c
index 602534e3cc10..ca8ef76bcf6b 100644
--- a/arch/s390/kvm/pci.c
+++ b/arch/s390/kvm/pci.c
@@ -344,19 +344,32 @@ static int kvm_s390_pci_aif_enable(struct zpci_dev *zdev, struct zpci_fib *fib,
aift->kzdev[zdev->aisb] = zdev->kzdev;
spin_unlock_irq(&aift->gait_lock);

- /* Update guest FIB for re-issue */
- fib->fmt0.aisbo = zdev->aisb & 63;
- fib->fmt0.aisb = virt_to_phys(aift->sbv->vector) + (zdev->aisb / 64) * 8;
- fib->fmt0.isc = gisc;
-
/* Save some guest fib values in the host for later use */
- zdev->kzdev->fib.fmt0.isc = fib->fmt0.isc;
+ zdev->kzdev->fib.fmt0.isc = gisc;
zdev->kzdev->fib.fmt0.aibv = fib->fmt0.aibv;
- mutex_unlock(&aift->aift_lock);

/* Issue the clp to setup the irq now */
rc = kvm_zpci_set_airq(zdev);
- return rc;
+ if (!rc) {
+ mutex_unlock(&aift->aift_lock);
+ return rc;
+ }
+
+ /* Start cleanup */
+ zdev->kzdev->fib.fmt0.isc = 0;
+ zdev->kzdev->fib.fmt0.aibv = 0;
+
+ spin_lock_irq(&aift->gait_lock);
+ gaite->count--;
+ gaite->aisb = 0;
+ gaite->gisc = 0;
+ gaite->aisbo = 0;
+ gaite->gisa = 0;
+ aift->kzdev[zdev->aisb] = NULL;
+ spin_unlock_irq(&aift->gait_lock);
+
+ airq_iv_release(zdev->aibv);
+ zdev->aibv = NULL;

free_aisb:
airq_iv_free_bit(aift->sbv, zdev->aisb);
--
2.43.0