Skip to content

Commit f9e82f9

Browse files
youngjuniakpm00
authored andcommitted
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: 686ea51 ("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>
1 parent 12f0cd3 commit f9e82f9

1 file changed

Lines changed: 9 additions & 5 deletions

File tree

mm/swapfile.c

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1387,19 +1387,23 @@ static bool swap_sync_discard(void)
13871387
bool ret = false;
13881388
struct swap_info_struct *si, *next;
13891389

1390-
spin_lock(&swap_avail_lock);
1391-
plist_for_each_entry_safe(si, next, &swap_avail_head, avail_list) {
1392-
spin_unlock(&swap_avail_lock);
1390+
spin_lock(&swap_lock);
1391+
start_over:
1392+
plist_for_each_entry_safe(si, next, &swap_active_head, list) {
1393+
spin_unlock(&swap_lock);
13931394
if (get_swap_device_info(si)) {
13941395
if (si->flags & SWP_PAGE_DISCARD)
13951396
ret = swap_do_scheduled_discard(si);
13961397
put_swap_device(si);
13971398
}
13981399
if (ret)
13991400
return true;
1400-
spin_lock(&swap_avail_lock);
1401+
1402+
spin_lock(&swap_lock);
1403+
if (plist_node_empty(&next->list))
1404+
goto start_over;
14011405
}
1402-
spin_unlock(&swap_avail_lock);
1406+
spin_unlock(&swap_lock);
14031407

14041408
return false;
14051409
}

0 commit comments

Comments
 (0)