From: Lian Wang <lianux.mm@gmail.com>
To: linux-mm@kvack.org
Cc: linux-kernel@vger.kernel.org, akpm@linux-foundation.org,
chrisl@kernel.org, nphamcs@gmail.com, baoquan.he@linux.dev,
baohua@kernel.org, youngjun.park@lge.com,
shikemeng@huaweicloud.com, kasong@tencent.com,
linjh22s@gmail.com, kunwu.chan@linux.dev, kees@kernel.org,
gustavoars@kernel.org, tglx@kernel.org,
linux-hardening@vger.kernel.org
Subject: [RFC PATCH v3 15/18] mm/swap: reuse per-CPU queue readers across priority changes
Date: Wed, 28 Oct 2026 00:12:17 +0800 [thread overview]
Message-ID: <bea2aebe1693ded274563505d92c48c4b63db46a.1793106426.git.lianux.mm@gmail.com> (raw)
In-Reply-To: <cover.1793106426.git.lianux.mm@gmail.com>
Inserting a new priority allocates a replacement per-CPU reader array
even when earlier ring removal left enough storage. An unnecessary
allocation can add swapon work or fail despite sufficient capacity.
Track the installed reader capacity and retain its high-water mark
until the queue becomes empty. Reuse existing storage when the new ring
fits, initializing every valid ring index for the new topology. Prepare
larger storage outside the writer only when growth is required and
recheck capacity under the writer before publishing.
Preserve the existing prepare/install ownership and failure rollback
protocol. Device removal continues to avoid per-CPU shrinking allocation
under the writer.
Signed-off-by: Lian Wang <lianux.mm@gmail.com>
---
mm/swapfile.c | 28 ++++++++++++++++++----------
1 file changed, 18 insertions(+), 10 deletions(-)
diff --git a/mm/swapfile.c b/mm/swapfile.c
index 7b3520ce1e41..5b6492b1bdc6 100644
--- a/mm/swapfile.c
+++ b/mm/swapfile.c
@@ -201,6 +201,8 @@ struct swap_queue_cursor {
};
static __percpu struct swap_queue_reader *swap_queue_readers;
+/* Keep the high-water capacity until the last priority ring is removed. */
+static unsigned int swap_queue_readers_capacity;
static inline bool swap_device_masked(struct swap_info_struct *si)
{
@@ -240,7 +242,7 @@ static bool swap_queue_needs_readers(int prio)
return false;
}
- return true;
+ return swap_queue_len >= swap_queue_readers_capacity;
}
/*
@@ -288,13 +290,15 @@ static void swap_queue_reset_readers(void)
}
}
-static void swap_queue_install_readers(struct swap_queue_reader __percpu *readers)
+static void swap_queue_install_readers(struct swap_queue_reader __percpu *readers,
+ unsigned int capacity)
{
int cpu;
lockdep_assert_held_write(&swapon_rwsem);
free_percpu(swap_queue_readers);
swap_queue_readers = readers;
+ swap_queue_readers_capacity = capacity;
if (!readers)
return;
@@ -431,7 +435,8 @@ static int swap_queue_add(struct swap_info_struct *si,
}
/* No ring at this priority: insert a new one at pos. */
- if (!*readers || nr_readers <= swap_queue_len)
+ if (swap_queue_len >= swap_queue_readers_capacity &&
+ (!*readers || nr_readers <= swap_queue_len))
goto failed;
new_queue = kmalloc_array(swap_queue_len + 1, sizeof(*swap_queue), gfp);
if (!new_queue)
@@ -459,8 +464,12 @@ static int swap_queue_add(struct swap_info_struct *si,
memalloc_noreclaim_restore(noreclaim_flag);
kfree(old_queue);
- swap_queue_install_readers(*readers);
- *readers = NULL;
+ if (swap_queue_len > swap_queue_readers_capacity) {
+ swap_queue_install_readers(*readers, nr_readers);
+ *readers = NULL;
+ } else {
+ swap_queue_reset_readers();
+ }
return 0;
add_to_ring:
@@ -503,10 +512,9 @@ static void swap_queue_del(struct swap_info_struct *si)
}
/*
- * Shrinking the small topology arrays is optional. Keep reader storage
- * until a new priority is inserted or the queue is empty: per-CPU
- * allocation must not run under this writer's noreclaim scope, which
- * can grant backing pages reserve access.
+ * Shrinking the small topology arrays is optional. Keep reader capacity
+ * until the queue is empty: per-CPU allocation must not run under this
+ * writer's noreclaim scope, which can grant backing pages reserve access.
*/
gfp = GFP_NOIO | __GFP_HIGH | __GFP_NOMEMALLOC;
noreclaim_flag = memalloc_noreclaim_save();
@@ -549,7 +557,7 @@ static void swap_queue_del(struct swap_info_struct *si)
swap_queue = NULL;
}
if (!swap_queue_len)
- swap_queue_install_readers(NULL);
+ swap_queue_install_readers(NULL, 0);
}
spin_unlock(&swap_queue_update_lock);
next prev parent reply other threads:[~2026-10-27 16:12 UTC|newest]
Thread overview: 19+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-27 15:58 [RFC PATCH v3 00/18] mm/swap: introduce priority queues for swap device allocation Lian Wang
2026-10-27 16:03 ` [RFC PATCH v3 01/18] mm/swap: remove unused parameter for reading swap header Lian Wang
2026-10-27 16:03 ` [RFC PATCH v3 02/18] mm/swap: slightly cleanup the code for hibernation error handling Lian Wang
2026-10-27 16:04 ` [RFC PATCH v3 03/18] mm/swap: cleanup and document swap device availability flag usage Lian Wang
2026-10-27 16:05 ` [RFC PATCH v3 04/18] mm/swap: introduce swap device iteration helper Lian Wang
2026-10-27 16:05 ` [RFC PATCH v3 05/18] mm/swap: change the swapon lock into a percpu rwsem Lian Wang
2026-10-27 16:06 ` [RFC PATCH v3 06/18] mm/swap: serialize swap publication before removing swapon mutex Lian Wang
2026-10-27 16:07 ` [RFC PATCH v3 07/18] mm/swap: consolidate swap inuse accounting helpers Lian Wang
2026-10-27 16:07 ` [RFC PATCH v3 08/18] mm/swap: change back to use each swap device's percpu cluster Lian Wang
2026-10-27 16:08 ` [RFC PATCH v3 09/18] mm/swap: avoid direct reclaim when populating swap cluster metadata Lian Wang
2026-10-27 16:08 ` [RFC PATCH v3 10/18] mm/swap: add priority queue for swap device allocation Lian Wang
2026-10-27 16:09 ` [RFC PATCH v3 11/18] mm/swap: remove available list Lian Wang
2026-10-27 16:10 ` [RFC PATCH v3 12/18] mm/swap: bound synchronous discard during allocation Lian Wang
2026-10-27 16:11 ` [RFC PATCH v3 13/18] mm/swap: drop swap active plist Lian Wang
2026-10-27 16:11 ` [RFC PATCH v3 14/18] lib/plist.c: remove requeue function Lian Wang
2026-10-27 16:12 ` Lian Wang [this message]
2026-10-27 16:12 ` [RFC PATCH v3 16/18] mm/swap: advance the global queue cursor directly between priority rings Lian Wang
2026-10-27 16:13 ` [RFC PATCH v3 17/18] mm/swap: skip reader rotation for single-device " Lian Wang
2026-10-27 16:14 ` [RFC PATCH v3 18/18] mm/swap: redistribute queue readers after membership changes Lian Wang
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=bea2aebe1693ded274563505d92c48c4b63db46a.1793106426.git.lianux.mm@gmail.com \
--to=lianux.mm@gmail.com \
--cc=akpm@linux-foundation.org \
--cc=baohua@kernel.org \
--cc=baoquan.he@linux.dev \
--cc=chrisl@kernel.org \
--cc=gustavoars@kernel.org \
--cc=kasong@tencent.com \
--cc=kees@kernel.org \
--cc=kunwu.chan@linux.dev \
--cc=linjh22s@gmail.com \
--cc=linux-hardening@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-mm@kvack.org \
--cc=nphamcs@gmail.com \
--cc=shikemeng@huaweicloud.com \
--cc=tglx@kernel.org \
--cc=youngjun.park@lge.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
all inboxes | Powered by JetHome®