forked from mirrors/linux
		
	fs/drop_caches.c: 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 (one of our customers hit this). Fix the problem by going to the slow path and doing cond_resched() in case the process needs rescheduling. Link: http://lkml.kernel.org/r/20190114085343.15011-1-jack@suse.cz Signed-off-by: Jan Kara <jack@suse.cz> Acked-by: Michal Hocko <mhocko@suse.com> Reviewed-by: Andrew Morton <akpm@linux-foundation.org> Cc: Al Viro <viro@ZenIV.linux.org.uk> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
		
							parent
							
								
									e0a352fabc
								
							
						
					
					
						commit
						c27d82f52f
					
				
					 1 changed files with 7 additions and 1 deletions
				
			
		| 
						 | 
					@ -21,8 +21,13 @@ static void drop_pagecache_sb(struct super_block *sb, void *unused)
 | 
				
			||||||
	spin_lock(&sb->s_inode_list_lock);
 | 
						spin_lock(&sb->s_inode_list_lock);
 | 
				
			||||||
	list_for_each_entry(inode, &sb->s_inodes, i_sb_list) {
 | 
						list_for_each_entry(inode, &sb->s_inodes, i_sb_list) {
 | 
				
			||||||
		spin_lock(&inode->i_lock);
 | 
							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)) ||
 | 
							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);
 | 
								spin_unlock(&inode->i_lock);
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
| 
						 | 
					@ -30,6 +35,7 @@ static void drop_pagecache_sb(struct super_block *sb, void *unused)
 | 
				
			||||||
		spin_unlock(&inode->i_lock);
 | 
							spin_unlock(&inode->i_lock);
 | 
				
			||||||
		spin_unlock(&sb->s_inode_list_lock);
 | 
							spin_unlock(&sb->s_inode_list_lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							cond_resched();
 | 
				
			||||||
		invalidate_mapping_pages(inode->i_mapping, 0, -1);
 | 
							invalidate_mapping_pages(inode->i_mapping, 0, -1);
 | 
				
			||||||
		iput(toput_inode);
 | 
							iput(toput_inode);
 | 
				
			||||||
		toput_inode = inode;
 | 
							toput_inode = inode;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue