Skip to content

Commit 3f778ab

Browse files
Kemeng Shiakpm00
authored andcommitted
mm/shmem: fix potential dead loop in shmem_unuse()
If multi shmem_unuse() for different swap type is called concurrently, a dead loop could occur as following: shmem_unuse(typeA) shmem_unuse(typeB) mutex_lock(&shmem_swaplist_mutex) list_for_each_entry_safe(info, next, ...) ... mutex_unlock(&shmem_swaplist_mutex) /* info->swapped may drop to 0 */ shmem_unuse_inode(&info->vfs_inode, type) mutex_lock(&shmem_swaplist_mutex) list_for_each_entry(info, next, ...) if (!info->swapped) list_del_init(&info->swaplist) ... mutex_unlock(&shmem_swaplist_mutex) mutex_lock(&shmem_swaplist_mutex) /* iterate with offlist entry and encounter a dead loop */ next = list_next_entry(info, swaplist); ... Restart the iteration if the inode is already off shmem_swaplist list to fix the issue. Link: https://lkml.kernel.org/r/[email protected] Fixes: b56a2d8 ("mm: rid swapoff of quadratic complexity") Signed-off-by: Kemeng Shi <[email protected]> Reviewed-by: Baolin Wang <[email protected]> Cc: Hugh Dickins <[email protected]> Cc: Kairui Song <[email protected]> Cc: kernel test robot <[email protected]> Signed-off-by: Andrew Morton <[email protected]>
1 parent 594ec2a commit 3f778ab

File tree

1 file changed

+6
-3
lines changed

1 file changed

+6
-3
lines changed

mm/shmem.c

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1505,6 +1505,7 @@ int shmem_unuse(unsigned int type)
15051505
return 0;
15061506

15071507
mutex_lock(&shmem_swaplist_mutex);
1508+
start_over:
15081509
list_for_each_entry_safe(info, next, &shmem_swaplist, swaplist) {
15091510
if (!info->swapped) {
15101511
list_del_init(&info->swaplist);
@@ -1523,13 +1524,15 @@ int shmem_unuse(unsigned int type)
15231524
cond_resched();
15241525

15251526
mutex_lock(&shmem_swaplist_mutex);
1526-
next = list_next_entry(info, swaplist);
1527-
if (!info->swapped)
1528-
list_del_init(&info->swaplist);
15291527
if (atomic_dec_and_test(&info->stop_eviction))
15301528
wake_up_var(&info->stop_eviction);
15311529
if (error)
15321530
break;
1531+
if (list_empty(&info->swaplist))
1532+
goto start_over;
1533+
next = list_next_entry(info, swaplist);
1534+
if (!info->swapped)
1535+
list_del_init(&info->swaplist);
15331536
}
15341537
mutex_unlock(&shmem_swaplist_mutex);
15351538

0 commit comments

Comments
 (0)