Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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>

authored by

Youngjun Park and committed by
Andrew Morton
f9e82f99 12f0cd39

+9 -5
+9 -5
mm/swapfile.c
··· 1387 1387 bool ret = false; 1388 1388 struct swap_info_struct *si, *next; 1389 1389 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); 1393 1394 if (get_swap_device_info(si)) { 1394 1395 if (si->flags & SWP_PAGE_DISCARD) 1395 1396 ret = swap_do_scheduled_discard(si); ··· 1398 1397 } 1399 1398 if (ret) 1400 1399 return true; 1401 - spin_lock(&swap_avail_lock); 1400 + 1401 + spin_lock(&swap_lock); 1402 + if (plist_node_empty(&next->list)) 1403 + goto start_over; 1402 1404 } 1403 - spin_unlock(&swap_avail_lock); 1405 + spin_unlock(&swap_lock); 1404 1406 1405 1407 return false; 1406 1408 }