Commit 1ef7d9aa authored by Nick Piggin's avatar Nick Piggin Committed by Jens Axboe

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: default avatarNick Piggin <npiggin@suse.de>
Signed-off-by: default avatarJens Axboe <jens.axboe@oracle.com>
parent 77b9d059
...@@ -97,6 +97,11 @@ static void bdi_work_clear(struct bdi_work *work) ...@@ -97,6 +97,11 @@ static void bdi_work_clear(struct bdi_work *work)
{ {
clear_bit(WS_USED_B, &work->state); clear_bit(WS_USED_B, &work->state);
smp_mb__after_clear_bit(); smp_mb__after_clear_bit();
/*
* work can have disappeared at this point. bit waitq functions
* should be able to tolerate this, provided bdi_sched_wait does
* not dereference it's pointer argument.
*/
wake_up_bit(&work->state, WS_USED_B); wake_up_bit(&work->state, WS_USED_B);
} }
...@@ -169,13 +174,7 @@ static void bdi_queue_work(struct backing_dev_info *bdi, struct bdi_work *work) ...@@ -169,13 +174,7 @@ static void bdi_queue_work(struct backing_dev_info *bdi, struct bdi_work *work)
else { else {
struct bdi_writeback *wb = &bdi->wb; struct bdi_writeback *wb = &bdi->wb;
/* if (wb->task)
* End work now if this wb has no dirty IO pending. Otherwise
* wakeup the handling thread
*/
if (!wb_has_dirty_io(wb))
wb_clear_pending(wb, work);
else if (wb->task)
wake_up_process(wb->task); wake_up_process(wb->task);
} }
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment