]>
Commit | Line | Data |
---|---|---|
7748c0ed SL |
1 | From fb2e3c9c2984fe5a073e12893132fd0b8dacfb72 Mon Sep 17 00:00:00 2001 |
2 | From: Jan Kara <jack@suse.cz> | |
3 | Date: Fri, 1 Feb 2019 14:21:23 -0800 | |
4 | Subject: fs/drop_caches.c: avoid softlockups in drop_pagecache_sb() | |
5 | ||
6 | [ Upstream commit c27d82f52f75fc9d8d9d40d120d2a96fdeeada5e ] | |
7 | ||
8 | When superblock has lots of inodes without any pagecache (like is the | |
9 | case for /proc), drop_pagecache_sb() will iterate through all of them | |
10 | without dropping sb->s_inode_list_lock which can lead to softlockups | |
11 | (one of our customers hit this). | |
12 | ||
13 | Fix the problem by going to the slow path and doing cond_resched() in | |
14 | case the process needs rescheduling. | |
15 | ||
16 | Link: http://lkml.kernel.org/r/20190114085343.15011-1-jack@suse.cz | |
17 | Signed-off-by: Jan Kara <jack@suse.cz> | |
18 | Acked-by: Michal Hocko <mhocko@suse.com> | |
19 | Reviewed-by: Andrew Morton <akpm@linux-foundation.org> | |
20 | Cc: Al Viro <viro@ZenIV.linux.org.uk> | |
21 | Signed-off-by: Andrew Morton <akpm@linux-foundation.org> | |
22 | Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> | |
23 | Signed-off-by: Sasha Levin <sashal@kernel.org> | |
24 | --- | |
25 | fs/drop_caches.c | 8 +++++++- | |
26 | 1 file changed, 7 insertions(+), 1 deletion(-) | |
27 | ||
28 | diff --git a/fs/drop_caches.c b/fs/drop_caches.c | |
29 | index 82377017130f..d31b6c72b476 100644 | |
30 | --- a/fs/drop_caches.c | |
31 | +++ b/fs/drop_caches.c | |
32 | @@ -21,8 +21,13 @@ static void drop_pagecache_sb(struct super_block *sb, void *unused) | |
33 | spin_lock(&sb->s_inode_list_lock); | |
34 | list_for_each_entry(inode, &sb->s_inodes, i_sb_list) { | |
35 | spin_lock(&inode->i_lock); | |
36 | + /* | |
37 | + * We must skip inodes in unusual state. We may also skip | |
38 | + * inodes without pages but we deliberately won't in case | |
39 | + * we need to reschedule to avoid softlockups. | |
40 | + */ | |
41 | if ((inode->i_state & (I_FREEING|I_WILL_FREE|I_NEW)) || | |
42 | - (inode->i_mapping->nrpages == 0)) { | |
43 | + (inode->i_mapping->nrpages == 0 && !need_resched())) { | |
44 | spin_unlock(&inode->i_lock); | |
45 | continue; | |
46 | } | |
47 | @@ -30,6 +35,7 @@ static void drop_pagecache_sb(struct super_block *sb, void *unused) | |
48 | spin_unlock(&inode->i_lock); | |
49 | spin_unlock(&sb->s_inode_list_lock); | |
50 | ||
51 | + cond_resched(); | |
52 | invalidate_mapping_pages(inode->i_mapping, 0, -1); | |
53 | iput(toput_inode); | |
54 | toput_inode = inode; | |
55 | -- | |
56 | 2.19.1 | |
57 |