[RFC PATCH v4 00/18] mm/swap: introduce priority queues for swap device allocation
From: Lian Wang
Date: Sat Nov 14 2026 - 09:48:44 EST
Hi all,
This is v4 of Kairui's swap priority queue RFC [1, 2], retaining the
original authorship. It separates device selection from device-local
cluster allocation to support integration with the ongoing swap tier
work, while preserving existing swap priorities, the swapon interface,
and memcg swap accounting and limits.
The global per-CPU cluster cache couples device choice to cluster
locality. Moving that cache below device selection gives each device its
own allocation hints. The available plist's shared rotation is then
replaced by a priority-ordered array of same-priority device rings, with
per-CPU starting offsets and quotas. A task-local cursor keeps each retry
walk stable. Rotational devices retain per-device sequential hints shared
across CPUs.
This remains an RFC. The current scope is global device selection under
existing priorities; no tier ABI or per-memcg device-selection control
is introduced.
The series is organized as follows:
01-04: Parameter/error-path cleanup, device-state boundaries and
iteration helpers.
05-07: Locking, writer-serialized publication and accounting.
08: Restore per-device per-CPU cluster locality.
09: Keep cluster metadata population out of direct reclaim.
10-11: Introduce the safely published queue and remove the avail plist.
12: Bound order-0 synchronous discard outside the allocation reader.
13-14: Preserve priority-aware throttle selection while removing the
active plist and unused plist_requeue API.
15-18: Reuse reader capacity, advance cursors directly, bypass singleton
rotation and redistribute reader phases on membership changes.
Changes in v4
=============
The device-disable and discard paths have been revised following the
review of v3 [4], including Sashiko feedback [5, 6]:
- Complete writable/off-list/availability transitions before releasing
the management lock or topology writer, including intermediate patches.
- Run bounded order-0 synchronous discard outside the allocation reader,
holding a live device reference across I/O, then restart selection with
a fresh cursor.
- Handle discard queued by late reclaim scans, with at most one
synchronous cluster discard per swap type for each order-0 request.
Preserve large-folio same-priority retry and split handling without
foreground synchronous discard.
Rebase
======
The series is now based on mm-unstable 24231596edf2 (7.4-rc1).
The base includes 53a6f71c147a ("mm, swap: stop cluster list scans once
swapoff clears SWP_WRITEOK"), so the former standalone scan fix is no
longer required as a prerequisite. Its si->lock serialization of
WRITEOK changes is preserved.
The metadata allocation paths have been adapted to the upstream
allocator-lock reacquisition and publish-after-revalidation contract,
including -EAGAIN handling and the tableless-cluster relocation guard.
The upstream free-cluster preference and hibernation-slot semantics
are retained.
Test results
============
The tests compare the unpatched baseline 24231596edf2 with the same
baseline plus all 18 patches, fbb87083afcc, on the same x86-64 host.
The kernel configurations differ only in LOCALVERSION.
The kernel-build tests follow the v1 workload: eight 8-GiB ZRAM devices,
make -j96, and 12 fresh-output builds per revision in each of the 2-GiB
and 3-GiB memcgs. Both revisions built the same workload source
(4dbe24720eb3), using x86 defconfig, bzImage/modules and a fixed toolchain.
The BRD case used twelve 8-GiB devices and a memcg with 24 GiB of memory,
64 GiB of swap allowance and memory.zswap.max=0:
usemem --init-time -O -y -x -n 32 1536M
There was one complete BRD invocation per revision. The BRD capacity and
memcg limit are host adaptations; v1 did not specify those parameters.
Mean system CPU time, seconds:
n/arm Before Queue (v4) change
kbuild, 2-GiB 12 4372.4983 4417.2192 +1.02%
kbuild, 3-GiB 12 2314.6025 2322.6550 +0.35%
12-BRD 1 143.5700 137.9900 -3.89%
Mean elapsed time, seconds:
n/arm Before Queue (v4) change
kbuild, 2-GiB 12 168.8092 169.1100 +0.18%
kbuild, 3-GiB 12 136.0650 136.3500 +0.21%
12-BRD 1 6.6500 6.5100 -2.11%
For the BRD invocation, mapped throughput was 7391.28 -> 7550.23 MiB/s
(+2.15%), calculated as the requested 48 GiB divided by elapsed time,
not as a sum of worker rates.
All 50 invocations completed successfully, reported no memcg OOM events
and performed swap I/O. There were no warm-ups or profiling, and all
samples are included. Before ran first on a separate boot; the 12 builds
are within-boot repeats, and the 32 BRD workers are one invocation.
The kernel-build runs show small increases in system CPU and elapsed
time. These descriptive results do not establish equivalence, absence
of regressions or a stable performance gain.
Cooperation with swap tiers
==========================
Device-local cluster hints remain below device selection, so a future
tier policy can determine the eligible candidates before those hints
are used.
The current revision keeps the refactoring under the existing global
swap priority model. Integration with Youngjun's tier infrastructure [3]
remains follow-up work. Device membership, swapon/swapoff publication
and lifetime should have one agreed authority. Within-tier priority
semantics and reader scope need agreement with that work; this series
does not define a competing tier or memcg policy.
Youngjun and Chris, I would appreciate your feedback on the integration
boundary and ordering.
Link: https://lore.kernel.org/all/20260714-swap-pcp-priq-v1-0-de9b164ed419@xxxxxxxxxxx/ [1]
Link: https://lore.kernel.org/all/20260829-swap-pcp-priq-v2-resend-0-68d3d925578c@xxxxxxxxx/ [2]
Link: https://lore.kernel.org/all/20260916183437.2946306-1-youngjun.park@xxxxxxx/ [3]
Link: https://lore.kernel.org/all/cover.1793106426.git.lianux.mm@xxxxxxxxx/ [4]
Link: https://lore.kernel.org/all/sashiko-outbox-188132@xxxxxxxxxx/ [5]
Link: https://lore.kernel.org/all/sashiko-outbox-188141@xxxxxxxxxx/ [6]
base-commit: 24231596edf2c9d5269d8efbc7007512026672f5
Best regards,
Lian Wang