| From: Jan Kara <jack@suse.cz> |
| Date: Thu, 3 May 2018 18:26:26 +0200 |
| Subject: bdi: Fix oops in wb_workfn() |
| |
| commit b8b784958eccbf8f51ebeee65282ca3fd59ea391 upstream. |
| |
| Syzbot has reported that it can hit a NULL pointer dereference in |
| wb_workfn() due to wb->bdi->dev being NULL. This indicates that |
| wb_workfn() was called for an already unregistered bdi which should not |
| happen as wb_shutdown() called from bdi_unregister() should make sure |
| all pending writeback works are completed before bdi is unregistered. |
| Except that wb_workfn() itself can requeue the work with: |
| |
| mod_delayed_work(bdi_wq, &wb->dwork, 0); |
| |
| and if this happens while wb_shutdown() is waiting in: |
| |
| flush_delayed_work(&wb->dwork); |
| |
| the dwork can get executed after wb_shutdown() has finished and |
| bdi_unregister() has cleared wb->bdi->dev. |
| |
| Make wb_workfn() use wakeup_wb() for requeueing the work which takes all |
| the necessary precautions against racing with bdi unregistration. |
| |
| CC: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp> |
| CC: Tejun Heo <tj@kernel.org> |
| Fixes: 839a8e8660b6777e7fe4e80af1a048aebe2b5977 |
| Reported-by: syzbot <syzbot+9873874c735f2892e7e9@syzkaller.appspotmail.com> |
| Reviewed-by: Dave Chinner <dchinner@redhat.com> |
| Signed-off-by: Jan Kara <jack@suse.cz> |
| Signed-off-by: Jens Axboe <axboe@kernel.dk> |
| [bwh: Backported to 3.16: |
| - Use bdi_wakeup_thread() instead of wb_wakeup() |
| - Adjust context] |
| Signed-off-by: Ben Hutchings <ben@decadent.org.uk> |
| --- |
| fs/fs-writeback.c | 2 +- |
| 1 file changed, 1 insertion(+), 1 deletion(-) |
| |
| --- a/fs/fs-writeback.c |
| +++ b/fs/fs-writeback.c |
| @@ -1071,7 +1071,7 @@ void bdi_writeback_workfn(struct work_st |
| } |
| |
| if (!list_empty(&bdi->work_list)) |
| - mod_delayed_work(bdi_wq, &wb->dwork, 0); |
| + bdi_wakeup_thread(bdi); |
| else if (wb_has_dirty_io(wb) && dirty_writeback_interval) |
| bdi_wakeup_thread_delayed(bdi); |
| |