[PATCH 0/3] kernfs, driver core: Cut per-node lock traffic in bulk registration

From: Pavol Sakac

Date: Fri Sep 11 2026 - 13:28:52 EST


Registering VFs in parallel, introduced in [1], runs into three lock
costs in kernfs and the driver core. Two scale with the number of
sysfs nodes created: the kernfs root rwsem is write-taken twice per
node, and every inode ID is allocated under kernfs_idr_lock. The third
scales with the number of devices: get_device_parent()'s glue
directory lookup walks a flat list under the global gdp_mutex.

The glue directory is how the driver core groups class devices under a
parent that is not itself a class device: when vfio-pci binds, each VF
gets a "vfio-dev" glue directory holding its vfio-dev class device.
get_device_parent() finds or creates it by walking the class's flat
glue_dirs list under gdp_mutex, so with thousands of VFs each
registration walks thousands of entries - quadratic work, serialized
on one global mutex.

Patch 1 (kernfs) activates a new node inside the same kernfs_rwsem
write hold that links it: one write acquisition per node instead of
two. Patch 2 (driver core) indexes glue directories by parent kobject
in an rbtree, replacing the linear walk; gdp_mutex still serializes as
before. Patch 3 (kernfs) pre-allocates inode IDs in batches of 16,
caches them per CPU, and installs the node pointer with an RCU store
via idr_replace(), cutting kernfs_idr_lock acquisitions 16x.

Lock statistics and SR-IOV init time for 4x PF (NVMe, 255 VFs each), on
the reproducer from the parallel VF initialization cover letter [1]:

lock_stat:
Lock wait: Before After contentions: Before After
iommu_probe_device_lock 10471 ms 9154 ms 841 783
&vfio.group_lock 3614 ms 3823 ms 736 730
&root->kernfs_rwsem 1834 ms 1285 ms 116316 55459
&root->kernfs_idr_lock 5 ms 0 ms 4580 77

iommu_probe_device_lock and vfio.group_lock are shown for scale;
neither is touched by this series - they are addressed by the
IOMMU [2] and VFIO [3] series posted separately.

kernfs_rwsem write acquisitions 168302 (2/node) -> 84661 (1/node)
kernfs_idr_lock acquisitions 83641 -> 5229 (batch 16)
gdp_mutex avg hold 18 -> 7 us (2040 acq. both arms)

Stage SR-IOV init time:
S0 (baseline) 3027 ms
S1 999 ms
S2 995 ms
S3 (this series) 991 ms

Reproducer disclaimer:
I lean primarily on lock_stat numbers to defend the improvements. In
the reproducer, the residual iommu_probe_device_lock dominates the
window and masks the later series' wall-time gains; reducing that lock
further is out of scope for this set. On real hardware the five series
together cut SR-IOV initialization by 65%, more in [1].

The staged sysfs RFC [4] builds on top of these changes (mainly the
IDR batching).

This series adds a KUnit suite. The lock_stat and timing figures come
from the public reproducer. The full series has also been tested on
current datacenter server hardware with thousands of VFs.


[1] https://lore.kernel.org/r/20260911-vfopt-s1-v1-0-693271dc0226@xxxxxxxxx
[2] https://lore.kernel.org/r/20260911-vfopt-s2-v1-0-fff3db7e01c2@xxxxxxxxx
[3] https://lore.kernel.org/r/20260911-vfopt-s4-v1-0-98ba1d2ef7ab@xxxxxxxxx
[4] https://lore.kernel.org/r/20260911-vfopt-s5-v1-0-fa4cacdb6ca8@xxxxxxxxx

Pavol Sakac (3):
kernfs: activate nodes while linking them
driver core: Index class glue directories by parent kobject
kernfs: batch inode ID allocation per CPU

drivers/base/base.h | 4 +
drivers/base/core.c | 112 +++++--
drivers/base/test/.kunitconfig | 1 +
drivers/base/test/Kconfig | 12 +
drivers/base/test/Makefile | 2 +
drivers/base/test/glue-dir-test.c | 466 +++++++++++++++++++++++++++
drivers/base/test/root-device-test.c | 215 ++++++++++++
fs/kernfs/dir.c | 139 +++++++-
fs/kernfs/kernfs-internal.h | 3 +
fs/sysfs/mount.c | 3 +-
include/linux/kernfs.h | 13 +
11 files changed, 930 insertions(+), 40 deletions(-)
create mode 100644 drivers/base/test/glue-dir-test.c


base-commit: cee9395acd8043be0644b25c34bfa86623f2b935
--
2.47.3