Skip to content

Commit fccb7bb

Browse files
Hugh Dickinsgregkh
authored andcommitted
shmem: fix possible deadlocks on shmlock_user_lock
[ Upstream commit ea0dfeb ] Recent commit 71725ed ("mm: huge tmpfs: try to split_huge_page() when punching hole") has allowed syzkaller to probe deeper, uncovering a long-standing lockdep issue between the irq-unsafe shmlock_user_lock, the irq-safe xa_lock on mapping->i_pages, and shmem inode's info->lock which nests inside xa_lock (or tree_lock) since 4.8's shmem_uncharge(). user_shm_lock(), servicing SysV shmctl(SHM_LOCK), wants shmlock_user_lock while its caller shmem_lock() holds info->lock with interrupts disabled; but hugetlbfs_file_setup() calls user_shm_lock() with interrupts enabled, and might be interrupted by a writeback endio wanting xa_lock on i_pages. This may not risk an actual deadlock, since shmem inodes do not take part in writeback accounting, but there are several easy ways to avoid it. Requiring interrupts disabled for shmlock_user_lock would be easy, but it's a high-level global lock for which that seems inappropriate. Instead, recall that the use of info->lock to guard info->flags in shmem_lock() dates from pre-3.1 days, when races with SHMEM_PAGEIN and SHMEM_TRUNCATE could occur: nowadays it serves no purpose, the only flag added or removed is VM_LOCKED itself, and calls to shmem_lock() an inode are already serialized by the caller. Take info->lock out of the chain and the possibility of deadlock or lockdep warning goes away. Fixes: 4595ef8 ("shmem: make shmem_inode_info::lock irq-safe") Reported-by: [email protected] Reported-by: [email protected] Signed-off-by: Hugh Dickins <[email protected]> Signed-off-by: Andrew Morton <[email protected]> Acked-by: Yang Shi <[email protected]> Cc: Yang Shi <[email protected]> Link: http://lkml.kernel.org/r/[email protected] Link: https://lore.kernel.org/lkml/[email protected]/ Link: https://lore.kernel.org/lkml/[email protected]/ Signed-off-by: Linus Torvalds <[email protected]> Signed-off-by: Sasha Levin <[email protected]>
1 parent 31db643 commit fccb7bb

File tree

1 file changed

+5
-2
lines changed

1 file changed

+5
-2
lines changed

mm/shmem.c

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2082,7 +2082,11 @@ int shmem_lock(struct file *file, int lock, struct user_struct *user)
20822082
struct shmem_inode_info *info = SHMEM_I(inode);
20832083
int retval = -ENOMEM;
20842084

2085-
spin_lock_irq(&info->lock);
2085+
/*
2086+
* What serializes the accesses to info->flags?
2087+
* ipc_lock_object() when called from shmctl_do_lock(),
2088+
* no serialization needed when called from shm_destroy().
2089+
*/
20862090
if (lock && !(info->flags & VM_LOCKED)) {
20872091
if (!user_shm_lock(inode->i_size, user))
20882092
goto out_nomem;
@@ -2097,7 +2101,6 @@ int shmem_lock(struct file *file, int lock, struct user_struct *user)
20972101
retval = 0;
20982102

20992103
out_nomem:
2100-
spin_unlock_irq(&info->lock);
21012104
return retval;
21022105
}
21032106

0 commit comments

Comments
 (0)