summaryrefslogtreecommitdiffstats
path: root/fs/fs-writeback.c
diff options
context:
space:
mode:
authorWu Fengguang <fengguang.wu@intel.com>2011-07-11 23:08:50 -0700
committerWu Fengguang <fengguang.wu@intel.com>2011-07-24 10:46:51 +0800
commitfcc5c22218a18509a7412bf074fc9a7a5d874a8a (patch)
tree338828e4017ed7c603b93c541c34af4e4005bd31 /fs/fs-writeback.c
parent1a12d8bd7b2998be01ee55edb64e7473728abb9c (diff)
downloadlinux-fcc5c22218a18509a7412bf074fc9a7a5d874a8a.tar.gz
linux-fcc5c22218a18509a7412bf074fc9a7a5d874a8a.tar.bz2
linux-fcc5c22218a18509a7412bf074fc9a7a5d874a8a.zip
writeback: don't busy retry writeback on new/freeing inodes
Fix a system hang bug introduced by commit b7a2441f9966 ("writeback: remove writeback_control.more_io") and e8dfc3058 ("writeback: elevate queue_io() into wb_writeback()") easily reproducible with high memory pressure and lots of file creation/deletions, for example, a kernel build in limited memory. It hangs when some inode is in the I_NEW, I_FREEING or I_WILL_FREE state, the flusher will get stuck busy retrying that inode, never releasing wb->list_lock. The lock in turn blocks all kinds of other tasks when they are trying to grab it. As put by Jan, it's a safe change regarding data integrity. I_FREEING or I_WILL_FREE inodes are written back by iput_final() and it is reclaim code that is responsible for eventually removing them. So writeback code can safely ignore them. I_NEW inodes should move out of this state when they are fully set up and in the writeback round following that, we will consider them for writeback. So the change makes sense. CC: Jan Kara <jack@suse.cz> Reported-by: Hugh Dickins <hughd@google.com> Tested-by: Hugh Dickins <hughd@google.com> Signed-off-by: Wu Fengguang <fengguang.wu@intel.com>
Diffstat (limited to 'fs/fs-writeback.c')
-rw-r--r--fs/fs-writeback.c2
1 files changed, 1 insertions, 1 deletions
diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c
index 50445cf0b83a..6d49439ca31d 100644
--- a/fs/fs-writeback.c
+++ b/fs/fs-writeback.c
@@ -593,7 +593,7 @@ static long writeback_sb_inodes(struct super_block *sb,
spin_lock(&inode->i_lock);
if (inode->i_state & (I_NEW | I_FREEING | I_WILL_FREE)) {
spin_unlock(&inode->i_lock);
- requeue_io(inode, wb);
+ redirty_tail(inode, wb);
continue;
}
__iget(inode);