]>
Commit | Line | Data |
---|---|---|
e866cbac FG |
1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 |
2 | From: "Kirill A. Shutemov" <kirill.shutemov@linux.intel.com> | |
3 | Date: Fri, 23 Mar 2018 09:19:21 +0100 | |
4 | Subject: [PATCH] mm/shmem: do not wait for lock_page() in | |
5 | shmem_unused_huge_shrink() | |
6 | MIME-Version: 1.0 | |
7 | Content-Type: text/plain; charset=UTF-8 | |
8 | Content-Transfer-Encoding: 8bit | |
9 | ||
10 | shmem_unused_huge_shrink() gets called from reclaim path. Waiting for | |
11 | page lock may lead to deadlock there. | |
12 | ||
13 | There was a bug report that may be attributed to this: | |
14 | ||
15 | http://lkml.kernel.org/r/alpine.LRH.2.11.1801242349220.30642@mail.ewheeler.net | |
16 | ||
17 | Replace lock_page() with trylock_page() and skip the page if we failed to | |
18 | lock it. We will get to the page on the next scan. | |
19 | ||
20 | We can test for the PageTransHuge() outside the page lock as we only need | |
21 | protection against splitting the page under us. Holding pin oni the page | |
22 | is enough for this. | |
23 | ||
24 | Link: http://lkml.kernel.org/r/20180316210830.43738-1-kirill.shutemov@linux.intel.com | |
25 | Fixes: 779750d20b93 ("shmem: split huge pages beyond i_size under memory pressure") | |
26 | Signed-off-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com> | |
27 | Reported-by: Eric Wheeler <linux-mm@lists.ewheeler.net> | |
28 | Acked-by: Michal Hocko <mhocko@suse.com> | |
29 | Reviewed-by: Andrew Morton <akpm@linux-foundation.org> | |
30 | Cc: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp> | |
31 | Cc: Hugh Dickins <hughd@google.com> | |
32 | Cc: <stable@vger.kernel.org> [4.8+] | |
33 | Signed-off-by: Andrew Morton <> | |
34 | (cherry-picked from https://git.kernel.org/pub/scm/linux/kernel/git/mhocko/mm.git/commit/?h=since-4.15&id=73eccc61c701ee7b4223aea2079542a712feeea7) | |
35 | Signed-off-by: Fabian Grünbichler <f.gruenbichler@proxmox.com> | |
36 | --- | |
37 | mm/shmem.c | 31 ++++++++++++++++++++----------- | |
38 | 1 file changed, 20 insertions(+), 11 deletions(-) | |
39 | ||
40 | diff --git a/mm/shmem.c b/mm/shmem.c | |
41 | index 859e4c224b80..2aae929eb90b 100644 | |
42 | --- a/mm/shmem.c | |
43 | +++ b/mm/shmem.c | |
44 | @@ -483,36 +483,45 @@ static unsigned long shmem_unused_huge_shrink(struct shmem_sb_info *sbinfo, | |
45 | info = list_entry(pos, struct shmem_inode_info, shrinklist); | |
46 | inode = &info->vfs_inode; | |
47 | ||
48 | - if (nr_to_split && split >= nr_to_split) { | |
49 | - iput(inode); | |
50 | - continue; | |
51 | - } | |
52 | + if (nr_to_split && split >= nr_to_split) | |
53 | + goto leave; | |
54 | ||
55 | - page = find_lock_page(inode->i_mapping, | |
56 | + page = find_get_page(inode->i_mapping, | |
57 | (inode->i_size & HPAGE_PMD_MASK) >> PAGE_SHIFT); | |
58 | if (!page) | |
59 | goto drop; | |
60 | ||
61 | + /* No huge page at the end of the file: nothing to split */ | |
62 | if (!PageTransHuge(page)) { | |
63 | - unlock_page(page); | |
64 | put_page(page); | |
65 | goto drop; | |
66 | } | |
67 | ||
68 | + /* | |
69 | + * Leave the inode on the list if we failed to lock | |
70 | + * the page at this time. | |
71 | + * | |
72 | + * Waiting for the lock may lead to deadlock in the | |
73 | + * reclaim path. | |
74 | + */ | |
75 | + if (!trylock_page(page)) { | |
76 | + put_page(page); | |
77 | + goto leave; | |
78 | + } | |
79 | + | |
80 | ret = split_huge_page(page); | |
81 | unlock_page(page); | |
82 | put_page(page); | |
83 | ||
84 | - if (ret) { | |
85 | - /* split failed: leave it on the list */ | |
86 | - iput(inode); | |
87 | - continue; | |
88 | - } | |
89 | + /* If split failed leave the inode on the list */ | |
90 | + if (ret) | |
91 | + goto leave; | |
92 | ||
93 | split++; | |
94 | drop: | |
95 | list_del_init(&info->shrinklist); | |
96 | removed++; | |
97 | +leave: | |
98 | iput(inode); | |
99 | } | |
100 | ||
101 | -- | |
102 | 2.14.2 | |
103 |