From: Pavol Sakac <sakacpav@amazon.de>
To: Bjorn Helgaas <bhelgaas@google.com>
Cc: linux-pci@vger.kernel.org, linux-kernel@vger.kernel.org,
"David Matlack" <dmatlack@google.com>,
"Ilpo Järvinen" <ilpo.jarvinen@linux.intel.com>,
"Krzysztof Wilczyński" <kwilczynski@kernel.org>,
"Kees Cook" <kees@kernel.org>,
"Madhavan Srinivasan" <maddy@linux.ibm.com>,
"Michael Ellerman" <mpe@ellerman.id.au>,
"Nicholas Piggin" <npiggin@gmail.com>,
"Christophe Leroy" <chleroy@kernel.org>,
linuxppc-dev@lists.ozlabs.org,
"Niklas Schnelle" <schnelle@linux.ibm.com>,
"Benjamin Block" <bblock@linux.ibm.com>,
"Lukas Wunner" <lukas@wunner.de>,
"Ionut Nechita" <ionut.nechita@windriver.com>,
nh-open-source@amazon.com
Subject: [RFC PATCH 2/8] PCI/IOV: Create virtfn buses up front in sriov_add_vfs()
Date: Fri, 11 Sep 2026 14:29:04 +0200 [thread overview]
Message-ID: <20260911122904.85386-1-sakacpav@amazon.de> (raw)
In-Reply-To: <20260911-vfopt-s1-v1-0-693271dc0226@amazon.de>
virtfn_add_bus() is find-then-create and therefore assumes external
serialization. Create every virtfn bus before adding any VF, taking the
bus-create path out of the per-VF loop so a later commit can run the
per-VF adds concurrently against a stable bus set. Bus numbers are
already fixed before the loop, since pci_iov_set_numvfs() has latched
offset and stride.
The cleanup pass must remove only buses this enable created, because
virtfn_remove_bus() checks that a bus is empty rather than who created
it, so virtfn_add_bus() now reports whether it created the bus and
sriov_add_vfs() records that per VF id in a bitmap. Return early for
num_vfs == 0: kvcalloc(0, ...) returns ZERO_SIZE_PTR and a later commit
dereferences buses[0] unconditionally.
Several ids can share one bus number; only the creating id's bit is set.
Assisted-by: LLM
Signed-off-by: Pavol Sakac <sakacpav@amazon.de>
---
drivers/pci/iov.c | 60 +++++++++++++++++++++++++++++++++++++++++++----
1 file changed, 56 insertions(+), 4 deletions(-)
diff --git a/drivers/pci/iov.c b/drivers/pci/iov.c
index 1826d32a2364..dda9303516f5 100644
--- a/drivers/pci/iov.c
+++ b/drivers/pci/iov.c
@@ -8,6 +8,7 @@
*/
#include <linux/bitfield.h>
+#include <linux/bitmap.h>
#include <linux/bits.h>
#include <linux/log2.h>
#include <linux/pci.h>
@@ -124,10 +125,14 @@ static int compute_max_vf_buses(struct pci_dev *dev)
return rc;
}
-static struct pci_bus *virtfn_add_bus(struct pci_bus *bus, int busnr)
+static struct pci_bus *virtfn_add_bus(struct pci_bus *bus, int busnr,
+ bool *created)
{
struct pci_bus *child;
+ if (created)
+ *created = false;
+
if (bus->number == busnr)
return bus;
@@ -140,6 +145,8 @@ static struct pci_bus *virtfn_add_bus(struct pci_bus *bus, int busnr)
return NULL;
pci_bus_insert_busn_res(child, busnr, busnr);
+ if (created)
+ *created = true;
return child;
}
@@ -394,7 +401,7 @@ int pci_iov_add_virtfn(struct pci_dev *dev, int id)
struct pci_bus *bus;
int rc;
- bus = virtfn_add_bus(dev->bus, pci_iov_virtfn_bus(dev, id));
+ bus = virtfn_add_bus(dev->bus, pci_iov_virtfn_bus(dev, id), NULL);
if (!bus)
return -ENOMEM;
@@ -632,22 +639,67 @@ int __weak pcibios_sriov_disable(struct pci_dev *pdev)
static int sriov_add_vfs(struct pci_dev *dev, u16 num_vfs)
{
+ unsigned long *created_buses;
+ struct pci_bus **buses;
+ struct pci_bus *bus;
unsigned int i;
int rc;
- if (dev->no_vf_scan)
+ if (!num_vfs || dev->no_vf_scan)
return 0;
+ buses = kvcalloc(num_vfs, sizeof(*buses), GFP_KERNEL);
+ if (!buses)
+ return -ENOMEM;
+
+ created_buses = bitmap_zalloc(num_vfs, GFP_KERNEL);
+ if (!created_buses) {
+ kvfree(buses);
+ return -ENOMEM;
+ }
+
for (i = 0; i < num_vfs; i++) {
- rc = pci_iov_add_virtfn(dev, i);
+ bool created;
+
+ buses[i] = virtfn_add_bus(dev->bus, pci_iov_virtfn_bus(dev, i),
+ &created);
+ if (!buses[i]) {
+ rc = -ENOMEM;
+ goto remove_buses;
+ }
+ if (created)
+ __set_bit(i, created_buses);
+ }
+
+ for (i = 0; i < num_vfs; i++) {
+ rc = __pci_iov_add_virtfn(dev, buses[i], i);
if (rc)
goto failed;
}
+
+ bitmap_free(created_buses);
+ kvfree(buses);
return 0;
failed:
while (i--)
pci_iov_remove_virtfn(dev, i);
+remove_buses:
+ /*
+ * Remove only buses this enable created: several ids can share one
+ * bus and only the creating id is recorded; virtfn_remove_bus()
+ * checks emptiness, not ownership. Re-look each up by number --
+ * the VF unwind above may already have freed it.
+ */
+ for_each_set_bit(i, created_buses, num_vfs) {
+ bus = pci_find_bus(pci_domain_nr(dev->bus),
+ pci_iov_virtfn_bus(dev, i));
+ if (bus)
+ virtfn_remove_bus(dev->bus, bus);
+ }
+
+ bitmap_free(created_buses);
+ kvfree(buses);
return rc;
}
--
2.47.3
next prev parent reply other threads:[~2026-09-11 12:29 UTC|newest]
Thread overview: 17+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-11 12:11 [RFC PATCH 0/8] PCI/IOV: Initialize virtual functions in parallel Pavol Sakac
2026-09-11 12:28 ` [RFC PATCH 1/8] PCI/IOV: Split virtfn bus handling out of pci_iov_add_virtfn() Pavol Sakac
2026-09-11 12:45 ` sashiko-bot
2026-09-11 12:29 ` Pavol Sakac [this message]
2026-09-11 12:46 ` [RFC PATCH 2/8] PCI/IOV: Create virtfn buses up front in sriov_add_vfs() sashiko-bot
2026-09-11 12:29 ` [RFC PATCH 3/8] PCI/PM: Convert pci_bridge_d3_update() recursion to iteration Pavol Sakac
2026-09-11 12:40 ` sashiko-bot
2026-09-11 12:30 ` [RFC PATCH 4/8] PCI/PM: Serialize pci_bridge_d3_update() Pavol Sakac
2026-09-11 12:47 ` sashiko-bot
2026-09-11 12:31 ` [RFC PATCH 5/8] powerpc/pci: Serialize pcibios_bus_add_device() Pavol Sakac
2026-09-11 12:55 ` sashiko-bot
2026-09-11 12:32 ` [RFC PATCH 6/8] PCI/IOV: Let sriov_add_vfs() own the failure unwind Pavol Sakac
2026-09-11 12:52 ` sashiko-bot
2026-09-11 12:33 ` [RFC PATCH 7/8] PCI/IOV: Initialize virtual functions in parallel Pavol Sakac
2026-09-11 12:43 ` sashiko-bot
2026-09-11 12:34 ` [RFC PATCH 8/8] PCI: Probe inline from node-local workqueue workers Pavol Sakac
2026-09-11 12:40 ` 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=20260911122904.85386-1-sakacpav@amazon.de \
--to=sakacpav@amazon.de \
--cc=bblock@linux.ibm.com \
--cc=bhelgaas@google.com \
--cc=chleroy@kernel.org \
--cc=dmatlack@google.com \
--cc=ilpo.jarvinen@linux.intel.com \
--cc=ionut.nechita@windriver.com \
--cc=kees@kernel.org \
--cc=kwilczynski@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-pci@vger.kernel.org \
--cc=linuxppc-dev@lists.ozlabs.org \
--cc=lukas@wunner.de \
--cc=maddy@linux.ibm.com \
--cc=mpe@ellerman.id.au \
--cc=nh-open-source@amazon.com \
--cc=npiggin@gmail.com \
--cc=schnelle@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 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.