From: Farhan Ali <alifm@linux.ibm.com>
To: linux-kernel@vger.kernel.org, linux-s390@vger.kernel.org,
kvm@vger.kernel.org
Cc: alifm@linux.ibm.com, mjrosato@linux.ibm.com, borntraeger@linux.ibm.com
Subject: [PATCH v1 5/5] KVM: s390: pci: Fix AIBV and AISB spanning multiple pages
Date: Mon, 13 Jul 2026 10:26:00 -0700 [thread overview]
Message-ID: <20260713172600.1284-6-alifm@linux.ibm.com> (raw)
In-Reply-To: <20260713172600.1284-1-alifm@linux.ibm.com>
The AIBV (adapter interrupt bit vector) holds one bit per MSI-X vector for
a given function. With a maximum of 2048 MSI-X vectors per function, the
AIBV can be up to 256 bytes. Because a guest is free to place the AIBV at
any alignment, it may cross a page boundary. Pin all pages covered by the
AIBV to handle this correctly.
The AISB (adapter interrupt summary bit) holds one bit per zPCI function.
Its total size is configuration-dependent and not architecturally bounded,
so the AISB offset is used to detect whether it crosses a page boundary
and pin accordingly.
Fixes: 3c5a1b6f0a18 ("KVM: s390: pci: provide routines for enabling/disabling interrupt forwarding")
Signed-off-by: Farhan Ali <alifm@linux.ibm.com>
---
arch/s390/kvm/pci.c | 78 ++++++++++++++++++++++++++++++++++-----------
arch/s390/kvm/pci.h | 5 +++
2 files changed, 64 insertions(+), 19 deletions(-)
diff --git a/arch/s390/kvm/pci.c b/arch/s390/kvm/pci.c
index 9a16a2eac65b..5fe07181f3d6 100644
--- a/arch/s390/kvm/pci.c
+++ b/arch/s390/kvm/pci.c
@@ -229,13 +229,15 @@ static inline int account_mem(unsigned long nr_pages)
static int kvm_s390_pci_aif_enable(struct zpci_dev *zdev, struct zpci_fib *fib,
bool assist)
{
- struct page *pages[1], *aibv_page, *aisb_page = NULL;
- unsigned int msi_vecs, idx;
+ struct page *aibv_page, *aisb_page = NULL;
+ int gisc, npages, npinned, pcount = 0;
+ unsigned int msi_vecs, idx, size;
struct zpci_gaite *gaite;
unsigned long hva, bit;
+ struct kvm_zdev *kzdev;
struct kvm *kvm;
phys_addr_t gaddr;
- int rc = 0, gisc, npages, pcount = 0;
+ int rc = 0;
/*
* Interrupt forwarding is only applicable if the device is already
@@ -244,6 +246,7 @@ static int kvm_s390_pci_aif_enable(struct zpci_dev *zdev, struct zpci_fib *fib,
if (zdev->gisa == 0)
return -EINVAL;
+ kzdev = zdev->kzdev;
kvm = zdev->kzdev->kvm;
msi_vecs = min_t(unsigned int, fib->fmt0.noi, zdev->max_msi);
@@ -253,32 +256,63 @@ static int kvm_s390_pci_aif_enable(struct zpci_dev *zdev, struct zpci_fib *fib,
return gisc;
/* Replace AIBV address */
+ size = BITS_TO_LONGS(msi_vecs) * sizeof(unsigned long);
+ npages = DIV_ROUND_UP((fib->fmt0.aibv & ~PAGE_MASK) + size, PAGE_SIZE);
+ if (npages > MAX_AIF_PAGES) {
+ rc = -EINVAL;
+ goto out;
+ }
+
idx = srcu_read_lock(&kvm->srcu);
hva = gfn_to_hva(kvm, gpa_to_gfn((gpa_t)fib->fmt0.aibv));
- npages = pin_user_pages_fast(hva, 1, FOLL_WRITE | FOLL_LONGTERM, pages);
+ npinned = pin_user_pages_fast(hva, npages, FOLL_WRITE | FOLL_LONGTERM,
+ kzdev->aibv_pages);
srcu_read_unlock(&kvm->srcu, idx);
- if (npages < 1) {
+ if (npinned <= 0) {
rc = -EIO;
goto out;
}
- aibv_page = pages[0];
- pcount++;
+
+ kzdev->aibv_npages = npinned;
+ if (npinned < npages) {
+ rc = -EIO;
+ goto unpin1;
+ }
+
+ pcount += npinned;
+ aibv_page = kzdev->aibv_pages[0];
gaddr = page_to_phys(aibv_page) + (fib->fmt0.aibv & ~PAGE_MASK);
fib->fmt0.aibv = gaddr;
/* Pin the guest AISB if one was specified */
if (fib->fmt0.sum == 1) {
+ size = (fib->fmt0.aisbo / 8) + 1;
+ npages = DIV_ROUND_UP((fib->fmt0.aisb & ~PAGE_MASK) + size,
+ PAGE_SIZE);
+
+ if (npages > MAX_AIF_PAGES) {
+ rc = -EINVAL;
+ goto unpin1;
+ }
+
idx = srcu_read_lock(&kvm->srcu);
hva = gfn_to_hva(kvm, gpa_to_gfn((gpa_t)fib->fmt0.aisb));
- npages = pin_user_pages_fast(hva, 1, FOLL_WRITE | FOLL_LONGTERM,
- pages);
+ npinned = pin_user_pages_fast(hva, npages,
+ FOLL_WRITE | FOLL_LONGTERM,
+ kzdev->aisb_pages);
srcu_read_unlock(&kvm->srcu, idx);
- if (npages < 1) {
+ if (npinned <= 0) {
rc = -EIO;
goto unpin1;
}
- aisb_page = pages[0];
- pcount++;
+
+ kzdev->aisb_npages = npinned;
+ if (npinned < npages) {
+ rc = -EIO;
+ goto unpin2;
+ }
+ aisb_page = kzdev->aisb_pages[0];
+ pcount += npinned;
}
/* Account for pinned pages, roll back on failure */
@@ -366,10 +400,14 @@ static int kvm_s390_pci_aif_enable(struct zpci_dev *zdev, struct zpci_fib *fib,
unaccount_mem(pcount);
mutex_unlock(&aift->aift_lock);
unpin2:
- if (fib->fmt0.sum == 1)
- unpin_user_page(aisb_page);
+ if (fib->fmt0.sum == 1) {
+ unpin_user_pages(kzdev->aisb_pages,
+ kzdev->aisb_npages);
+ kzdev->aisb_npages = 0;
+ }
unpin1:
- unpin_user_page(aibv_page);
+ unpin_user_pages(kzdev->aibv_pages, kzdev->aibv_npages);
+ kzdev->aibv_npages = 0;
out:
kvm_s390_gisc_unregister(kvm, fib->fmt0.isc);
return rc;
@@ -426,12 +464,14 @@ static int kvm_s390_pci_aif_disable(struct zpci_dev *zdev, bool force)
kzdev->fib.fmt0.aibv = 0;
if (vpage) {
- unpin_user_page(vpage);
- pcount++;
+ unpin_user_pages(kzdev->aibv_pages, kzdev->aibv_npages);
+ pcount += kzdev->aibv_npages;
+ kzdev->aibv_npages = 0;
}
if (spage) {
- unpin_user_page(spage);
- pcount++;
+ unpin_user_pages(kzdev->aisb_pages, kzdev->aisb_npages);
+ pcount += kzdev->aisb_npages;
+ kzdev->aisb_npages = 0;
}
if (pcount > 0)
unaccount_mem(pcount);
diff --git a/arch/s390/kvm/pci.h b/arch/s390/kvm/pci.h
index ff0972dd5e71..a2d550f06b6c 100644
--- a/arch/s390/kvm/pci.h
+++ b/arch/s390/kvm/pci.h
@@ -17,10 +17,15 @@
#include <asm/airq.h>
#include <asm/cpu.h>
+#define MAX_AIF_PAGES 2
struct kvm_zdev {
struct zpci_dev *zdev;
struct kvm *kvm;
struct zpci_fib fib;
+ struct page *aibv_pages[MAX_AIF_PAGES];
+ int aibv_npages;
+ struct page *aisb_pages[MAX_AIF_PAGES];
+ int aisb_npages;
struct list_head entry;
};
--
2.43.0
next prev parent reply other threads:[~2026-07-13 17:26 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-13 17:25 [PATCH v1 0/5] KVM s390x PCI fixes Farhan Ali
2026-07-13 17:25 ` [PATCH v1 1/5] KVM: s390: pci: Fix refcount leak in memory accounting functions Farhan Ali
2026-07-13 17:41 ` sashiko-bot
2026-07-13 17:25 ` [PATCH v1 2/5] KVM: s390: pci: Fix missing error codes and memory unaccounting Farhan Ali
2026-07-13 17:41 ` sashiko-bot
2026-07-13 17:25 ` [PATCH v1 3/5] KVM: s390: pci: Fix NULL dereference on AIBV allocation failure Farhan Ali
2026-07-13 17:50 ` sashiko-bot
2026-07-13 17:25 ` [PATCH v1 4/5] KVM: s390: pci: Fix resource leak on IRQ registration failure Farhan Ali
2026-07-13 17:43 ` sashiko-bot
2026-07-13 17:26 ` Farhan Ali [this message]
2026-07-13 17:41 ` [PATCH v1 5/5] KVM: s390: pci: Fix AIBV and AISB spanning multiple pages sashiko-bot
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=20260713172600.1284-6-alifm@linux.ibm.com \
--to=alifm@linux.ibm.com \
--cc=borntraeger@linux.ibm.com \
--cc=kvm@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-s390@vger.kernel.org \
--cc=mjrosato@linux.ibm.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