From: Lian Wang <lianux.mm@gmail.com>
To: linux-mm@kvack.org
Cc: linux-kernel@vger.kernel.org,
Andrew Morton <akpm@linux-foundation.org>,
Chris Li <chrisl@kernel.org>, Nhat Pham <nphamcs@gmail.com>,
Baoquan He <baoquan.he@linux.dev>, Barry Song <baohua@kernel.org>,
Youngjun Park <youngjun.park@lge.com>,
Kemeng Shi <shikemeng@huaweicloud.com>,
Kairui Song <kasong@tencent.com>, Jihan LIN <linjh22s@gmail.com>,
Kunwu Chan <kunwu.chan@linux.dev>, Kees Cook <kees@kernel.org>,
"Gustavo A. R. Silva" <gustavoars@kernel.org>,
Thomas Gleixner <tglx@kernel.org>,
linux-hardening@vger.kernel.org
Subject: [RFC PATCH v4 13/18] mm/swap: drop swap active plist
Date: Sat, 14 Nov 2026 22:51:44 +0800 [thread overview]
Message-ID: <9ccd81f6f036eb1c3e50d396b44b5e43cff77d2a.1794666741.git.lianux.mm@gmail.com> (raw)
In-Reply-To: <cover.1794666741.git.lianux.mm@gmail.com>
From: Kairui Song <kasong@tencent.com>
Remove swap_active_head and the associated plist_node. Device identity
lookups can use the writable swap_info iterator without ordering.
Keep priority ordering for the block-cgroup swap throttle target by
walking the priority queue under the topology reader. Choose the first
unmasked, writable, non-offlist device with a backing block device.
Check OFFLIST as well as the pointer tag because full transitions can
temporarily leave an unmasked entry, and keep the explicit WRITEOK
check. The disable transition already publishes its mask before
releasing the topology writer.
This read-only lookup does not consume per-CPU allocation quotas or
change retry cursors. It avoids making the throttle disk depend on
swapon's swap-type assignment order when devices have different
priorities.
Signed-off-by: Kairui Song <kasong@tencent.com>
Signed-off-by: Lian Wang <lianux.mm@gmail.com>
---
include/linux/swap.h | 1 -
mm/swapfile.c | 60 +++++++++++++++++++++++---------------------
2 files changed, 32 insertions(+), 29 deletions(-)
diff --git a/include/linux/swap.h b/include/linux/swap.h
index d31f3f023d36..ce8a800751ca 100644
--- a/include/linux/swap.h
+++ b/include/linux/swap.h
@@ -263,7 +263,6 @@ struct swap_info_struct {
struct percpu_ref users; /* indicate and keep swap device valid. */
unsigned long flags; /* SWP_USED etc: see above */
signed short prio; /* swap priority of this type */
- struct plist_node list; /* entry in swap_active_head */
signed char type; /* strange name for an index */
unsigned int max; /* size of this swap device */
struct swap_cluster_info *cluster_info; /* array, one entry per cluster */
diff --git a/mm/swapfile.c b/mm/swapfile.c
index 6b2dbaf33cb6..bd098114ee4b 100644
--- a/mm/swapfile.c
+++ b/mm/swapfile.c
@@ -42,7 +42,6 @@
#include <linux/completion.h>
#include <linux/suspend.h>
#include <linux/zswap.h>
-#include <linux/plist.h>
#include <asm/tlbflush.h>
#include <linux/leafops.h>
@@ -91,12 +90,6 @@ bool swap_migration_ad_supported;
static const char Bad_file[] = "Bad swap file entry ";
static const char Bad_offset[] = "Bad swap offset entry ";
-/*
- * all active swap_info_structs
- * protected with swapon_rwsem, and ordered by priority.
- */
-static PLIST_HEAD(swap_active_head);
-
static inline struct swap_info_struct *__swap_iter(int *i, unsigned long flag)
{
lockdep_assert_held(&swapon_rwsem);
@@ -3535,7 +3528,6 @@ static void __swap_device_enable(struct swap_info_struct *si)
spin_unlock(&si->lock);
atomic_long_add(si->pages, &nr_swap_pages);
total_swap_pages += si->pages;
- plist_add(&si->list, &swap_active_head);
add_to_avail_list(si);
}
@@ -3555,9 +3547,8 @@ static int swap_device_disable(struct address_space *mapping,
int err = -EINVAL;
percpu_down_write(&swapon_rwsem);
- plist_for_each_entry(si, &swap_active_head, list) {
- if ((si->flags & SWP_WRITEOK) &&
- si->swap_file->f_mapping == mapping) {
+ for_each_avail_swap(si) {
+ if (si->swap_file->f_mapping == mapping) {
err = 0;
break;
}
@@ -3583,8 +3574,6 @@ static int swap_device_disable(struct address_space *mapping,
spin_lock(&si->lock);
del_from_avail_list(si, true);
spin_unlock(&si->lock);
-
- plist_del(&si->list, &swap_active_head);
total_swap_pages -= si->pages;
atomic_long_sub(si->pages, &nr_swap_pages);
@@ -3913,7 +3902,6 @@ static struct swap_info_struct *alloc_swap_info(void)
*/
}
p->swap_extent_root = RB_ROOT;
- plist_node_init(&p->list, 0);
p->flags = SWP_USED;
percpu_up_write(&swapon_rwsem);
if (defer) {
@@ -4323,12 +4311,7 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags)
if (swap_flags & SWAP_FLAG_PREFER)
prio = swap_flags & SWAP_FLAG_PRIO_MASK;
- /*
- * The plist prio is negated because plist ordering is
- * low-to-high, while swap ordering is high-to-low
- */
si->prio = prio;
- si->list.prio = -si->prio;
/*
* Publish swap_file before making the percpu ref live, then add the device
@@ -4454,7 +4437,33 @@ int swap_dup_entry_direct(swp_entry_t entry)
#if defined(CONFIG_MEMCG) && defined(CONFIG_BLK_CGROUP)
static bool __has_usable_swap(void)
{
- return !plist_head_empty(&swap_active_head);
+ return READ_ONCE(total_swap_pages) > 0;
+}
+
+static struct swap_info_struct *swap_queue_first_usable_bdev(void)
+{
+ struct swap_prio_ring *ring;
+ struct swap_info_struct *si;
+ unsigned int ring_idx, dev_idx;
+
+ lockdep_assert_held(&swapon_rwsem);
+ for (ring_idx = 0; ring_idx < swap_queue_len; ring_idx++) {
+ ring = swap_queue[ring_idx];
+ for (dev_idx = 0; dev_idx < ring->size; dev_idx++) {
+ si = READ_ONCE(ring->dev[dev_idx]);
+ if (swap_device_masked(si))
+ continue;
+ si = swap_device_unmask_ptr(si);
+ if (!(READ_ONCE(si->flags) & SWP_WRITEOK))
+ continue;
+ if (atomic_long_read(&si->inuse_pages) &
+ SWAP_USAGE_OFFLIST_BIT)
+ continue;
+ if (si->bdev)
+ return si;
+ }
+ }
+ return NULL;
}
void __folio_throttle_swaprate(struct folio *folio, gfp_t gfp)
@@ -4478,14 +4487,9 @@ void __folio_throttle_swaprate(struct folio *folio, gfp_t gfp)
return;
percpu_down_read(&swapon_rwsem);
- plist_for_each_entry(si, &swap_active_head, list) {
- if ((si->flags & SWP_WRITEOK) &&
- !(atomic_long_read(&si->inuse_pages) &
- SWAP_USAGE_OFFLIST_BIT) && si->bdev) {
- blkcg_schedule_throttle(si->bdev->bd_disk, true);
- break;
- }
- }
+ si = swap_queue_first_usable_bdev();
+ if (si)
+ blkcg_schedule_throttle(si->bdev->bd_disk, true);
percpu_up_read(&swapon_rwsem);
}
#endif
next prev parent reply other threads:[~2026-11-14 14:51 UTC|newest]
Thread overview: 19+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-14 14:47 [RFC PATCH v4 00/18] mm/swap: introduce priority queues for swap device allocation Lian Wang
2026-11-14 14:48 ` [RFC PATCH v4 01/18] mm/swap: remove unused parameter for reading swap header Lian Wang
2026-11-14 14:49 ` [RFC PATCH v4 02/18] mm/swap: clean up hibernation error handling Lian Wang
2026-11-14 14:49 ` [RFC PATCH v4 03/18] mm/swap: cleanup and document swap device availability flag usage Lian Wang
2026-11-14 14:49 ` [RFC PATCH v4 04/18] mm/swap: introduce swap device iteration helper Lian Wang
2026-11-14 14:49 ` [RFC PATCH v4 05/18] mm/swap: change the swapon lock into a percpu rwsem Lian Wang
2026-11-14 14:49 ` [RFC PATCH v4 06/18] mm/swap: serialize swap publication before removing swapon mutex Lian Wang
2026-11-14 14:50 ` [RFC PATCH v4 07/18] mm/swap: consolidate swap inuse accounting helpers Lian Wang
2026-11-14 14:50 ` [RFC PATCH v4 08/18] mm/swap: change back to use each swap device's percpu cluster Lian Wang
2026-11-14 14:50 ` [RFC PATCH v4 09/18] mm/swap: avoid direct reclaim when populating swap cluster metadata Lian Wang
2026-11-14 14:50 ` [RFC PATCH v4 10/18] mm/swap: add priority queue for swap device allocation Lian Wang
2026-11-14 14:51 ` [RFC PATCH v4 11/18] mm/swap: remove available list Lian Wang
2026-11-14 14:51 ` [RFC PATCH v4 12/18] mm/swap: bound synchronous discard outside the allocation reader Lian Wang
2026-11-14 14:51 ` Lian Wang [this message]
2026-11-14 14:51 ` [RFC PATCH v4 14/18] lib/plist.c: remove requeue function Lian Wang
2026-11-14 14:52 ` [RFC PATCH v4 15/18] mm/swap: reuse per-CPU queue readers across priority changes Lian Wang
2026-11-14 14:52 ` [RFC PATCH v4 16/18] mm/swap: advance the global queue cursor directly between priority rings Lian Wang
2026-11-14 14:52 ` [RFC PATCH v4 17/18] mm/swap: skip reader rotation for single-device " Lian Wang
2026-11-14 14:52 ` [RFC PATCH v4 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=9ccd81f6f036eb1c3e50d396b44b5e43cff77d2a.1794666741.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®