diff options
author | Wu Fengguang <fengguang.wu@intel.com> | 2009-06-16 18:33:17 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-06-16 22:47:45 -0400 |
commit | 84a892456046921a40646114deed65e2df93a1bc (patch) | |
tree | 2639b6031e55988b8780960c023618c381d61c55 | |
parent | 81236810226f71bd9ff77321c8e8276dae7efc61 (diff) |
writeback: skip new or to-be-freed inodes
1) I_FREEING tests should be coupled with I_CLEAR
The two I_FREEING tests are racy because clear_inode() can set i_state to
I_CLEAR between the clear of I_SYNC and the test of I_FREEING.
2) skip I_WILL_FREE inodes in generic_sync_sb_inodes() to avoid possible
races with generic_forget_inode()
generic_forget_inode() sets I_WILL_FREE call writeback on its own, so
generic_sync_sb_inodes() shall not try to step in and create possible races:
generic_forget_inode
inode->i_state |= I_WILL_FREE;
spin_unlock(&inode_lock);
generic_sync_sb_inodes()
spin_lock(&inode_lock);
__iget(inode);
__writeback_single_inode
// see non zero i_count
may WARN here ==> WARN_ON(inode->i_state & I_WILL_FREE);
spin_unlock(&inode_lock);
may call generic_forget_inode again ==> iput(inode);
The above race and warning didn't turn up because writeback_inodes() holds
the s_umount lock, so generic_forget_inode() finds MS_ACTIVE and returns
early. But we are not sure the UBIFS calls and future callers will
guarantee that. So skip I_WILL_FREE inodes for the sake of safety.
Cc: Eric Sandeen <sandeen@sandeen.net>
Acked-by: Jeff Layton <jlayton@redhat.com>
Cc: Masayoshi MIZUMA <m.mizuma@jp.fujitsu.com>
Signed-off-by: Wu Fengguang <fengguang.wu@intel.com>
Cc: Artem Bityutskiy <dedekind1@gmail.com>
Cc: Christoph Hellwig <hch@infradead.org>
Acked-by: Jan Kara <jack@suse.cz>
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>
-rw-r--r-- | fs/fs-writeback.c | 6 |
1 files changed, 3 insertions, 3 deletions
diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c index 40308e98c6a4..caf049146ca2 100644 --- a/fs/fs-writeback.c +++ b/fs/fs-writeback.c | |||
@@ -321,7 +321,7 @@ __sync_single_inode(struct inode *inode, struct writeback_control *wbc) | |||
321 | 321 | ||
322 | spin_lock(&inode_lock); | 322 | spin_lock(&inode_lock); |
323 | inode->i_state &= ~I_SYNC; | 323 | inode->i_state &= ~I_SYNC; |
324 | if (!(inode->i_state & I_FREEING)) { | 324 | if (!(inode->i_state & (I_FREEING | I_CLEAR))) { |
325 | if (!(inode->i_state & I_DIRTY) && | 325 | if (!(inode->i_state & I_DIRTY) && |
326 | mapping_tagged(mapping, PAGECACHE_TAG_DIRTY)) { | 326 | mapping_tagged(mapping, PAGECACHE_TAG_DIRTY)) { |
327 | /* | 327 | /* |
@@ -492,7 +492,7 @@ void generic_sync_sb_inodes(struct super_block *sb, | |||
492 | break; | 492 | break; |
493 | } | 493 | } |
494 | 494 | ||
495 | if (inode->i_state & I_NEW) { | 495 | if (inode->i_state & (I_NEW | I_WILL_FREE)) { |
496 | requeue_io(inode); | 496 | requeue_io(inode); |
497 | continue; | 497 | continue; |
498 | } | 498 | } |
@@ -523,7 +523,7 @@ void generic_sync_sb_inodes(struct super_block *sb, | |||
523 | if (current_is_pdflush() && !writeback_acquire(bdi)) | 523 | if (current_is_pdflush() && !writeback_acquire(bdi)) |
524 | break; | 524 | break; |
525 | 525 | ||
526 | BUG_ON(inode->i_state & I_FREEING); | 526 | BUG_ON(inode->i_state & (I_FREEING | I_CLEAR)); |
527 | __iget(inode); | 527 | __iget(inode); |
528 | pages_skipped = wbc->pages_skipped; | 528 | pages_skipped = wbc->pages_skipped; |
529 | __writeback_single_inode(inode, wbc); | 529 | __writeback_single_inode(inode, wbc); |