aboutsummaryrefslogtreecommitdiffstats
path: root/fs/fs-writeback.c
diff options
context:
space:
mode:
authorNick Piggin <npiggin@suse.de>2009-09-15 15:37:55 -0400
committerJens Axboe <jens.axboe@oracle.com>2009-09-16 09:18:53 -0400
commit1ef7d9aa32a8ee054c4d4fdcd2ea537c04d61b2f (patch)
tree69c570a78f37760ead0c8cad2eda25991c3fcd4c /fs/fs-writeback.c
parent77b9d059cb3ddb8b1246d5878e81d52926550b23 (diff)
writeback: fix possible bdi writeback refcounting problem
wb_clear_pending AFAIKS should not be called after the item has been put on the list, except by the worker threads. It could lead to the situation where the refcount is decremented below 0 and cause lots of problems. Presumably the !wb_has_dirty_io case is not a common one, so it can be discovered when the thread wakes up to check? Also add a comment in bdi_work_clear. Signed-off-by: Nick Piggin <npiggin@suse.de> Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
Diffstat (limited to 'fs/fs-writeback.c')
-rw-r--r--fs/fs-writeback.c13
1 files changed, 6 insertions, 7 deletions
diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c
index 7eba7326b9b9..8e1e5e19d21e 100644
--- a/fs/fs-writeback.c
+++ b/fs/fs-writeback.c
@@ -97,6 +97,11 @@ static void bdi_work_clear(struct bdi_work *work)
97{ 97{
98 clear_bit(WS_USED_B, &work->state); 98 clear_bit(WS_USED_B, &work->state);
99 smp_mb__after_clear_bit(); 99 smp_mb__after_clear_bit();
100 /*
101 * work can have disappeared at this point. bit waitq functions
102 * should be able to tolerate this, provided bdi_sched_wait does
103 * not dereference it's pointer argument.
104 */
100 wake_up_bit(&work->state, WS_USED_B); 105 wake_up_bit(&work->state, WS_USED_B);
101} 106}
102 107
@@ -169,13 +174,7 @@ static void bdi_queue_work(struct backing_dev_info *bdi, struct bdi_work *work)
169 else { 174 else {
170 struct bdi_writeback *wb = &bdi->wb; 175 struct bdi_writeback *wb = &bdi->wb;
171 176
172 /* 177 if (wb->task)
173 * End work now if this wb has no dirty IO pending. Otherwise
174 * wakeup the handling thread
175 */
176 if (!wb_has_dirty_io(wb))
177 wb_clear_pending(wb, work);
178 else if (wb->task)
179 wake_up_process(wb->task); 178 wake_up_process(wb->task);
180 } 179 }
181} 180}