| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103 |
- From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
- From: "Kirill A. Shutemov" <[email protected]>
- Date: Fri, 23 Mar 2018 09:19:21 +0100
- Subject: [PATCH] mm/shmem: do not wait for lock_page() in
- shmem_unused_huge_shrink()
- MIME-Version: 1.0
- Content-Type: text/plain; charset=UTF-8
- Content-Transfer-Encoding: 8bit
- 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: 779750d20b93 ("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 <>
- (cherry-picked from https://git.kernel.org/pub/scm/linux/kernel/git/mhocko/mm.git/commit/?h=since-4.15&id=73eccc61c701ee7b4223aea2079542a712feeea7)
- Signed-off-by: Fabian Grünbichler <[email protected]>
- ---
- mm/shmem.c | 31 ++++++++++++++++++++-----------
- 1 file changed, 20 insertions(+), 11 deletions(-)
- diff --git a/mm/shmem.c b/mm/shmem.c
- index f6695c111086..800482fe6ed6 100644
- --- a/mm/shmem.c
- +++ b/mm/shmem.c
- @@ -497,36 +497,45 @@ static unsigned long shmem_unused_huge_shrink(struct shmem_sb_info *sbinfo,
- info = list_entry(pos, struct shmem_inode_info, shrinklist);
- inode = &info->vfs_inode;
-
- - if (nr_to_split && split >= nr_to_split) {
- - iput(inode);
- - continue;
- - }
- + if (nr_to_split && split >= nr_to_split)
- + goto leave;
-
- - page = find_lock_page(inode->i_mapping,
- + page = find_get_page(inode->i_mapping,
- (inode->i_size & HPAGE_PMD_MASK) >> PAGE_SHIFT);
- if (!page)
- goto drop;
-
- + /* No huge page at the end of the file: nothing to split */
- if (!PageTransHuge(page)) {
- - unlock_page(page);
- put_page(page);
- goto drop;
- }
-
- + /*
- + * Leave the inode on the list if we failed to lock
- + * the page at this time.
- + *
- + * Waiting for the lock may lead to deadlock in the
- + * reclaim path.
- + */
- + if (!trylock_page(page)) {
- + put_page(page);
- + goto leave;
- + }
- +
- ret = split_huge_page(page);
- unlock_page(page);
- put_page(page);
-
- - if (ret) {
- - /* split failed: leave it on the list */
- - iput(inode);
- - continue;
- - }
- + /* If split failed leave the inode on the list */
- + if (ret)
- + goto leave;
-
- split++;
- drop:
- list_del_init(&info->shrinklist);
- removed++;
- +leave:
- iput(inode);
- }
-
- --
- 2.14.2
|