Skip to content

Commit b3cd54b

Browse files
kiryltorvalds
authored andcommitted
mm/shmem: do not wait for lock_page() in shmem_unused_huge_shrink()
shmem_unused_huge_shrink() gets called from reclaim path. Waiting for page lock may lead to deadlock there. There was a bug report that may be attributed to this: http://lkml.kernel.org/r/[email protected] Replace lock_page() with trylock_page() and skip the page if we failed to lock it. We will get to the page on the next scan. We can test for the PageTransHuge() outside the page lock as we only need protection against splitting the page under us. Holding pin oni the page is enough for this. Link: http://lkml.kernel.org/r/[email protected] Fixes: 779750d ("shmem: split huge pages beyond i_size under memory pressure") Signed-off-by: Kirill A. Shutemov <[email protected]> Reported-by: Eric Wheeler <[email protected]> Acked-by: Michal Hocko <[email protected]> Reviewed-by: Andrew Morton <[email protected]> Cc: Tetsuo Handa <[email protected]> Cc: Hugh Dickins <[email protected]> Cc: <[email protected]> [4.8+] Signed-off-by: Andrew Morton <[email protected]> Signed-off-by: Linus Torvalds <[email protected]>
1 parent fa41b90 commit b3cd54b

File tree

1 file changed

+20
-11
lines changed

1 file changed

+20
-11
lines changed

mm/shmem.c

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -493,36 +493,45 @@ static unsigned long shmem_unused_huge_shrink(struct shmem_sb_info *sbinfo,
493493
info = list_entry(pos, struct shmem_inode_info, shrinklist);
494494
inode = &info->vfs_inode;
495495

496-
if (nr_to_split && split >= nr_to_split) {
497-
iput(inode);
498-
continue;
499-
}
496+
if (nr_to_split && split >= nr_to_split)
497+
goto leave;
500498

501-
page = find_lock_page(inode->i_mapping,
499+
page = find_get_page(inode->i_mapping,
502500
(inode->i_size & HPAGE_PMD_MASK) >> PAGE_SHIFT);
503501
if (!page)
504502
goto drop;
505503

504+
/* No huge page at the end of the file: nothing to split */
506505
if (!PageTransHuge(page)) {
507-
unlock_page(page);
508506
put_page(page);
509507
goto drop;
510508
}
511509

510+
/*
511+
* Leave the inode on the list if we failed to lock
512+
* the page at this time.
513+
*
514+
* Waiting for the lock may lead to deadlock in the
515+
* reclaim path.
516+
*/
517+
if (!trylock_page(page)) {
518+
put_page(page);
519+
goto leave;
520+
}
521+
512522
ret = split_huge_page(page);
513523
unlock_page(page);
514524
put_page(page);
515525

516-
if (ret) {
517-
/* split failed: leave it on the list */
518-
iput(inode);
519-
continue;
520-
}
526+
/* If split failed leave the inode on the list */
527+
if (ret)
528+
goto leave;
521529

522530
split++;
523531
drop:
524532
list_del_init(&info->shrinklist);
525533
removed++;
534+
leave:
526535
iput(inode);
527536
}
528537

0 commit comments

Comments
 (0)