aboutsummaryrefslogtreecommitdiffstats
path: root/fs/inode.c
diff options
context:
space:
mode:
authorJan Kara <jack@suse.cz>2012-05-03 08:48:03 -0400
committerFengguang Wu <fengguang.wu@intel.com>2012-05-06 01:43:41 -0400
commit169ebd90131b2ffca74bb2dbe7eeacd39fb83714 (patch)
tree513136e110970da388680947c225ef8ca05a6dd7 /fs/inode.c
parentdbd5768f87ff6fb0a4fe09c4d7b6c4a24de99430 (diff)
writeback: Avoid iput() from flusher thread
Doing iput() from flusher thread (writeback_sb_inodes()) can create problems because iput() can do a lot of work - for example truncate the inode if it's the last iput on unlinked file. Some filesystems depend on flusher thread progressing (e.g. because they need to flush delay allocated blocks to reduce allocation uncertainty) and so flusher thread doing truncate creates interesting dependencies and possibilities for deadlocks. We get rid of iput() in flusher thread by using the fact that I_SYNC inode flag effectively pins the inode in memory. So if we take care to either hold i_lock or have I_SYNC set, we can get away without taking inode reference in writeback_sb_inodes(). As a side effect of these changes, we also fix possible use-after-free in wb_writeback() because inode_wait_for_writeback() call could try to reacquire i_lock on the inode that was already free. Signed-off-by: Jan Kara <jack@suse.cz> Signed-off-by: Fengguang Wu <fengguang.wu@intel.com>
Diffstat (limited to 'fs/inode.c')
-rw-r--r--fs/inode.c8
1 files changed, 7 insertions, 1 deletions
diff --git a/fs/inode.c b/fs/inode.c
index 02c0fa5e16a4..f4e145016611 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -530,7 +530,13 @@ static void evict(struct inode *inode)
530 530
531 inode_sb_list_del(inode); 531 inode_sb_list_del(inode);
532 532
533 inode_sync_wait(inode); 533 /*
534 * Wait for flusher thread to be done with the inode so that filesystem
535 * does not start destroying it while writeback is still running. Since
536 * the inode has I_FREEING set, flusher thread won't start new work on
537 * the inode. We just have to wait for running writeback to finish.
538 */
539 inode_wait_for_writeback(inode);
534 540
535 if (op->evict_inode) { 541 if (op->evict_inode) {
536 op->evict_inode(inode); 542 op->evict_inode(inode);