vfs: Avoid softlockups in drop_pagecache_sb()
Jan Kara
reviewerPATCH 1/1 vfs: Avoid softlockups in drop_pagecache_sb()
When superblock has lots of inodes without any pagecache (like is the case for /proc), drop_pagecache_sb() will iterate through all of them without dropping sb->s_inode_list_lock which can lead to softlockups.
Fix the problem by going to the slow path and doing cond_resched() in case the process needs rescheduling.
--- fs/drop_caches.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)
fs/drop_caches.c +7 -1
@@ -21,8 +21,13 @@ static void drop_pagecache_sb(struct super_block *sb, void *unused)spin_lock (&sb->s_inode_list_lock);list_for_each_entry (inode, &sb->s_inodes, i_sb_list) {spin_lock (&inode->i_lock); +/* +* We must skip inodes in unusual state. We may also skip +* inodes without pages but we deliberately won't in case +* we need to reschedule to avoid softlockups. +*/ if ((inode->i_state & (I_FREEING |I_WILL_FREE |I_NEW )) || - (inode->i_mapping->nrpages ==0 )) { + (inode->i_mapping->nrpages ==0 && !need_resched ())) {spin_unlock (&inode->i_lock);continue ; }
@@ -30,6 +35,7 @@ static void drop_pagecache_sb(struct super_block *sb, void *unused)spin_unlock (&inode->i_lock);spin_unlock (&sb->s_inode_list_lock); +cond_resched ();invalidate_mapping_pages (inode->i_mapping,0 ,-1 );iput (toput_inode); toput_inode = inode;
Signature · 1 line
2.16.4
Is this staged in any existing tree?
Quoted 6 lines · Jan Kara
When superblock has lots of inodes without any pagecache (like is the case for /proc),
drop_pagecache_sb()will iterate through all of them without droppingsb->s_inode_list_lockwhich can lead to softlockups.Fix the problem by going to the slow path and doing
cond_resched()in case the process needs rescheduling.
FWIW the patch looks good to me.
Quoted 1 line
Signed-off-by Jan Kara <[email protected]>
Quoted 33 lines
--- fs/drop_caches.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)fs/drop_caches.c +7
-1@@ -21,8 +21,13 @@ static void drop_pagecache_sb(struct super_block *sb, void *unused)spin_lock (&sb->s_inode_list_lock);list_for_each_entry (inode, &sb->s_inodes, i_sb_list) {spin_lock (&inode->i_lock); +/* +* We must skip inodes in unusual state. We may also skip +* inodes without pages but we deliberately won't in case +* we need to reschedule to avoid softlockups. +*/ if ((inode->i_state & (I_FREEING |I_WILL_FREE |I_NEW )) || - (inode->i_mapping->nrpages ==0 )) { + (inode->i_mapping->nrpages ==0 && !need_resched ())) {spin_unlock (&inode->i_lock);continue ; }@@ -30,6 +35,7 @@ static void drop_pagecache_sb(struct super_block *sb, void *unused)spin_unlock (&inode->i_lock);spin_unlock (&sb->s_inode_list_lock); +cond_resched ();invalidate_mapping_pages (inode->i_mapping,0 ,-1 );iput (toput_inode); toput_inode = inode;Signature · 1 line
2.16.4
Signature · 2 lines
Michal Hocko SUSE Labs