diff options
author | Jan Kara <jack@suse.cz> | 2012-05-03 08:48:03 -0400 |
---|---|---|
committer | Fengguang Wu <fengguang.wu@intel.com> | 2012-05-06 01:43:41 -0400 |
commit | 169ebd90131b2ffca74bb2dbe7eeacd39fb83714 (patch) | |
tree | 513136e110970da388680947c225ef8ca05a6dd7 /include/linux/writeback.h | |
parent | dbd5768f87ff6fb0a4fe09c4d7b6c4a24de99430 (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 'include/linux/writeback.h')
-rw-r--r-- | include/linux/writeback.h | 7 |
1 files changed, 1 insertions, 6 deletions
diff --git a/include/linux/writeback.h b/include/linux/writeback.h index 3309736ff059..6d0a0fcd80e7 100644 --- a/include/linux/writeback.h +++ b/include/linux/writeback.h | |||
@@ -95,6 +95,7 @@ long writeback_inodes_wb(struct bdi_writeback *wb, long nr_pages, | |||
95 | enum wb_reason reason); | 95 | enum wb_reason reason); |
96 | long wb_do_writeback(struct bdi_writeback *wb, int force_wait); | 96 | long wb_do_writeback(struct bdi_writeback *wb, int force_wait); |
97 | void wakeup_flusher_threads(long nr_pages, enum wb_reason reason); | 97 | void wakeup_flusher_threads(long nr_pages, enum wb_reason reason); |
98 | void inode_wait_for_writeback(struct inode *inode); | ||
98 | 99 | ||
99 | /* writeback.h requires fs.h; it, too, is not included from here. */ | 100 | /* writeback.h requires fs.h; it, too, is not included from here. */ |
100 | static inline void wait_on_inode(struct inode *inode) | 101 | static inline void wait_on_inode(struct inode *inode) |
@@ -102,12 +103,6 @@ static inline void wait_on_inode(struct inode *inode) | |||
102 | might_sleep(); | 103 | might_sleep(); |
103 | wait_on_bit(&inode->i_state, __I_NEW, inode_wait, TASK_UNINTERRUPTIBLE); | 104 | wait_on_bit(&inode->i_state, __I_NEW, inode_wait, TASK_UNINTERRUPTIBLE); |
104 | } | 105 | } |
105 | static inline void inode_sync_wait(struct inode *inode) | ||
106 | { | ||
107 | might_sleep(); | ||
108 | wait_on_bit(&inode->i_state, __I_SYNC, inode_wait, | ||
109 | TASK_UNINTERRUPTIBLE); | ||
110 | } | ||
111 | 106 | ||
112 | 107 | ||
113 | /* | 108 | /* |