mirror of
https://github.com/torvalds/linux.git
synced 2026-05-23 22:52:19 +02:00
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/20250516170939.965736-4-shikemeng@huaweicloud.com
Fixes: b56a2d8af9 ("mm: rid swapoff of quadratic complexity")
Signed-off-by: Kemeng Shi <shikemeng@huaweicloud.com>
Reviewed-by: Baolin Wang <baolin.wang@linux.alibaba.com>
Cc: Hugh Dickins <hughd@google.com>
Cc: Kairui Song <kasong@tencent.com>
Cc: kernel test robot <oliver.sang@intel.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
This commit is contained in:
parent
594ec2ab38
commit
3f778ab1b5
|
|
@ -1505,6 +1505,7 @@ int shmem_unuse(unsigned int type)
|
|||
return 0;
|
||||
|
||||
mutex_lock(&shmem_swaplist_mutex);
|
||||
start_over:
|
||||
list_for_each_entry_safe(info, next, &shmem_swaplist, swaplist) {
|
||||
if (!info->swapped) {
|
||||
list_del_init(&info->swaplist);
|
||||
|
|
@ -1523,13 +1524,15 @@ int shmem_unuse(unsigned int type)
|
|||
cond_resched();
|
||||
|
||||
mutex_lock(&shmem_swaplist_mutex);
|
||||
next = list_next_entry(info, swaplist);
|
||||
if (!info->swapped)
|
||||
list_del_init(&info->swaplist);
|
||||
if (atomic_dec_and_test(&info->stop_eviction))
|
||||
wake_up_var(&info->stop_eviction);
|
||||
if (error)
|
||||
break;
|
||||
if (list_empty(&info->swaplist))
|
||||
goto start_over;
|
||||
next = list_next_entry(info, swaplist);
|
||||
if (!info->swapped)
|
||||
list_del_init(&info->swaplist);
|
||||
}
|
||||
mutex_unlock(&shmem_swaplist_mutex);
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user