summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYoungjun Park <youngjun.park@lge.com>2025-11-27 19:03:02 +0900
committerAndrew Morton <akpm@linux-foundation.org>2025-11-29 10:41:10 -0800
commitf9e82f99b3771eef396dbf97e0f3c76e20af60dd (patch)
treeb9277be0b5cd83f6b8ef837a0aef880b5121688d
parent12f0cd393369d700c16b47bc33e4120dc8b2c608 (diff)
mm/swapfile: fix list iteration when next node is removed during discard
Patch series "mm/swapfile: fix and cleanup swap list iterations", v2. This series fixes a potential list iteration issue in swap_sync_discard() when devices are removed, and includes a cleanup for __folio_throttle_swaprate(). This patch (of 2): When the next node is removed from the plist (e.g. by swapoff), plist_del() makes the node point to itself, causing the iteration to loop on the same entry indefinitely. Add a plist_node_empty() check to detect this case and restart iteration, allowing swap_sync_discard() to continue processing remaining swap devices that still have pending discard entries. Additionally, switch from swap_avail_lock/swap_avail_head to swap_lock/swap_active_head so that iteration is only affected by swapoff operations rather than frequent availability changes, reducing exceptional condition checks and lock contention. Link: https://lkml.kernel.org/r/20251127100303.783198-1-youngjun.park@lge.com Link: https://lkml.kernel.org/r/20251127100303.783198-2-youngjun.park@lge.com Fixes: 686ea517f471 ("mm, swap: do not perform synchronous discard during allocation") Signed-off-by: Youngjun Park <youngjun.park@lge.com> Suggested-by: Kairui Song <kasong@tencent.com> Acked-by: Kairui Song <kasong@tencent.com> Reviewed-by: Baoquan He <bhe@redhat.com> Cc: Barry Song <baohua@kernel.org> Cc: Chris Li <chrisl@kernel.org> Cc: Kemeng Shi <shikemeng@huaweicloud.com> Cc: Nhat Pham <nphamcs@gmail.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
-rw-r--r--mm/swapfile.c14
1 files changed, 9 insertions, 5 deletions
diff --git a/mm/swapfile.c b/mm/swapfile.c
index d12332423a06..8116f36e440b 100644
--- a/mm/swapfile.c
+++ b/mm/swapfile.c
@@ -1387,9 +1387,10 @@ static bool swap_sync_discard(void)
bool ret = false;
struct swap_info_struct *si, *next;
- spin_lock(&swap_avail_lock);
- plist_for_each_entry_safe(si, next, &swap_avail_head, avail_list) {
- spin_unlock(&swap_avail_lock);
+ spin_lock(&swap_lock);
+start_over:
+ plist_for_each_entry_safe(si, next, &swap_active_head, list) {
+ spin_unlock(&swap_lock);
if (get_swap_device_info(si)) {
if (si->flags & SWP_PAGE_DISCARD)
ret = swap_do_scheduled_discard(si);
@@ -1397,9 +1398,12 @@ static bool swap_sync_discard(void)
}
if (ret)
return true;
- spin_lock(&swap_avail_lock);
+
+ spin_lock(&swap_lock);
+ if (plist_node_empty(&next->list))
+ goto start_over;
}
- spin_unlock(&swap_avail_lock);
+ spin_unlock(&swap_lock);
return false;
}