From: sashiko-bot@kernel.org
To: "Lian Wang" <lianux.mm@gmail.com>, linux-mm@kvack.org
Cc: 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
Subject: Re: [RFC PATCH v3 05/18] mm/swap: change the swapon lock into a percpu rwsem
Date: Wed, 28 Oct 2026 16:14:56 +0000 [thread overview]
Message-ID: <sashiko-outbox-188134@kernel.org> (raw)
In-Reply-To: <d7120017ded998ca722ed78e1995f0d1af82e88c.1793106426.git.lianux.mm@gmail.com>
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] mm/swap: infinite loop in cluster_alloc_swap_entry() on disabled swap device
--
commit 75f9eec48d8910061cd39d390305f876926fa1d7
Author: Kairui Song <kasong@tencent.com>
mm/swap: change the swapon lock into a percpu rwsem
This commit converts swap_lock from a spinlock to a percpu rwsem named
swapon_rwsem so that readers of swap metadata can run concurrently without
contention against swapon and swapoff writers.
> diff --git a/mm/swapfile.c b/mm/swapfile.c
> index b72f4fc3e8117..4ffde6827d441 100644
> --- a/mm/swapfile.c
> +++ b/mm/swapfile.c
[ ... ]
> @@ -3152,14 +3155,14 @@ static int swap_device_disable(struct address_space *mapping,
>
> end = ALIGN(si->max, SWAPFILE_CLUSTER);
> unlock:
> - spin_unlock(&swap_lock);
> + percpu_up_write(&swapon_rwsem);
> if (err)
> return err;
>
> del_from_avail_list(si, true);
[Severity: High]
Can clearing SWP_WRITEOK and calling percpu_up_write(&swapon_rwsem) in
mm/swapfile.c:swap_device_disable() before removing si from the available
devices in del_from_avail_list(si, true) cause a concurrent order-0 swap
allocation to enter an infinite loop in cluster_alloc_swap_entry()?
In swap_device_disable(), si->flags &= ~SWP_WRITEOK is performed under
swap_avail_lock, and then both swap_avail_lock and swapon_rwsem are released
before del_from_avail_list(si, true) removes si from swap_avail_head (or
masks si in swap_queue after the later commit "mm/swap: add priority queue
for swap device allocation", where percpu_up_write(&swapon_rwsem) also wakes
readers waiting on swapon_rwsem before del_from_avail_list() runs):
mm/swapfile.c:swap_device_disable() {
...
spin_lock(&swap_avail_lock);
si->flags &= ~SWP_WRITEOK;
spin_unlock(&swap_avail_lock);
plist_del(&si->list, &swap_active_head);
total_swap_pages -= si->pages;
atomic_long_sub(si->pages, &nr_swap_pages);
end = ALIGN(si->max, SWAPFILE_CLUSTER);
unlock:
percpu_up_write(&swapon_rwsem);
if (err)
return err;
del_from_avail_list(si, true);
}
If a concurrent order-0 folio_alloc_swap() selects si while si is still
visible as available but has SWP_WRITEOK cleared, it calls
cluster_alloc_swap_entry(si, folio).
First, alloc_swap_scan_list(si, &si->nonfull_clusters[order], folio, true)
isolates each cluster ci and sets ci->flags = CLUSTER_FLAG_NONE. Inside
alloc_swap_scan_cluster(), __swap_cluster_alloc_entries() returns false
because !(si->flags & SWP_WRITEOK), and relocate_cluster() moves every
non-full cluster onto si->frag_clusters[ci->order].
Then, for an order-0 folio, cluster_alloc_swap_entry() enters the
higher-order stealing loop:
mm/swapfile.c:cluster_alloc_swap_entry() {
...
/* Order 0 stealing from higher order */
for (int o = 1; o < SWAP_NR_ORDERS; o++) {
/*
* Clusters here have at least one usable slots and can't fail order 0
* allocation, but reclaim may drop si->lock and race with another user.
*/
found = alloc_swap_scan_list(si, &si->frag_clusters[o], folio, true);
if (found)
goto done;
...
}
}
And alloc_swap_scan_list() loops while scan_all is true:
mm/swapfile.c:alloc_swap_scan_list() {
do {
struct swap_cluster_info *ci = isolate_lock_cluster(si, list);
unsigned long offset;
if (!ci)
break;
offset = cluster_offset(si, ci);
found = alloc_swap_scan_cluster(si, ci, folio, offset);
if (found)
break;
} while (scan_all);
}
Whenever si->frag_clusters[o] is non-empty, isolate_lock_cluster() pops ci
from si->frag_clusters[o] and sets ci->flags = CLUSTER_FLAG_NONE,
__swap_cluster_alloc_entries() fails because !(si->flags & SWP_WRITEOK), and
relocate_cluster() sees a non-empty, non-full cluster with
ci->flags != CLUSTER_FLAG_FRAG and appends ci right back onto
si->frag_clusters[o]. Because found is 0 and scan_all is true, wouldn't
alloc_swap_scan_list() spin forever on si->frag_clusters[o] (and also leave
nonfull_clusters drained into frag_clusters if swapoff later fails in
try_to_unuse() and re-enables the device)?
--
Sashiko AI review · https://sashiko.dev/#/patchset/cover.1793106426.git.lianux.mm@gmail.com?part=5
next prev parent reply other threads:[~2026-10-28 16:15 UTC|newest]
Thread overview: 23+ 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-28 16:14 ` sashiko-bot
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-28 16:14 ` sashiko-bot [this message]
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-28 16:14 ` sashiko-bot
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-28 16:14 ` sashiko-bot
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 ` [RFC PATCH v3 15/18] mm/swap: reuse per-CPU queue readers across priority changes Lian Wang
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=sashiko-outbox-188134@kernel.org \
--to=sashiko-bot@kernel.org \
--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=lianux.mm@gmail.com \
--cc=linjh22s@gmail.com \
--cc=linux-mm@kvack.org \
--cc=nphamcs@gmail.com \
--cc=sashiko-reviews@lists.linux.dev \
--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 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.