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.
Unified · Split
| @@ -21,8 +21,13 @@ static void drop_pagecache_sb(struct super_block *sb, void *unused) · 20 unmodified lines | |||
| 21 | spin_lock(&sb->s_inode_list_lock); | 21 | spin_lock(&sb->s_inode_list_lock); |
| 22 | list_for_each_entry(inode, &sb->s_inodes, i_sb_list) { | 22 | list_for_each_entry(inode, &sb->s_inodes, i_sb_list) { |
| 23 | spin_lock(&inode->i_lock); | 23 | spin_lock(&inode->i_lock); |
| 24 | /* | ||
| 25 | * We must skip inodes in unusual state. We may also skip | ||
| 26 | * inodes without pages but we deliberately won't in case | ||
| 27 | * we need to reschedule to avoid softlockups. | ||
| 28 | */ | ||
| 24 | if ((inode->i_state & (I_FREEING|I_WILL_FREE|I_NEW)) || | 29 | if ((inode->i_state & (I_FREEING|I_WILL_FREE|I_NEW)) || |
| 25 | (inode->i_mapping->nrpages == 0)) { | 30 | (inode->i_mapping->nrpages == 0 && !need_resched())) { |
| 26 | spin_unlock(&inode->i_lock); | 31 | spin_unlock(&inode->i_lock); |
| 27 | continue; | 32 | continue; |
| 28 | } | 33 | } |
| @@ -30,6 +35,7 @@ static void drop_pagecache_sb(struct super_block *sb, void *unused) · 1 unmodified line | |||
| 30 | spin_unlock(&inode->i_lock); | 35 | spin_unlock(&inode->i_lock); |
| 31 | spin_unlock(&sb->s_inode_list_lock); | 36 | spin_unlock(&sb->s_inode_list_lock); |
| 32 | 37 | ||
| 38 | cond_resched(); | ||
| 33 | invalidate_mapping_pages(inode->i_mapping, 0, -1); | 39 | invalidate_mapping_pages(inode->i_mapping, 0, -1); |
| 34 | iput(toput_inode); | 40 | iput(toput_inode); |
| 35 | toput_inode = inode; | 41 | toput_inode = inode; |