Skip to content

Commit

Permalink
backing-dev: fix wakeup timer races with bdi_unregister()
Browse files Browse the repository at this point in the history
While 7a401a9 ("backing-dev: ensure wakeup_timer is deleted")
addressed the problem of the bdi being freed with a queued wakeup
timer, there are other races that could happen if the wakeup timer
expires after/during bdi_unregister(), before bdi_destroy() is called.

wakeup_timer_fn() could attempt to wakeup a task which has already has
been freed, or could access a NULL bdi->dev via the wake_forker_thread
tracepoint.

Cc: <[email protected]>
Cc: Jens Axboe <[email protected]>
Reported-by: Chanho Min <[email protected]>
Reviewed-by: Namjae Jeon <[email protected]>
Signed-off-by: Rabin Vincent <[email protected]>
Signed-off-by: Wu Fengguang <[email protected]>
  • Loading branch information
vitkyrka authored and Wu Fengguang committed Feb 1, 2012
1 parent 62aa2b5 commit 2673b4c
Showing 1 changed file with 18 additions and 5 deletions.
23 changes: 18 additions & 5 deletions mm/backing-dev.c
Original file line number Diff line number Diff line change
Expand Up @@ -318,7 +318,7 @@ static void wakeup_timer_fn(unsigned long data)
if (bdi->wb.task) {
trace_writeback_wake_thread(bdi);
wake_up_process(bdi->wb.task);
} else {
} else if (bdi->dev) {
/*
* When bdi tasks are inactive for long time, they are killed.
* In this case we have to wake-up the forker thread which
Expand Down Expand Up @@ -584,6 +584,8 @@ EXPORT_SYMBOL(bdi_register_dev);
*/
static void bdi_wb_shutdown(struct backing_dev_info *bdi)
{
struct task_struct *task;

if (!bdi_cap_writeback_dirty(bdi))
return;

Expand All @@ -602,8 +604,13 @@ static void bdi_wb_shutdown(struct backing_dev_info *bdi)
* Finally, kill the kernel thread. We don't need to be RCU
* safe anymore, since the bdi is gone from visibility.
*/
if (bdi->wb.task)
kthread_stop(bdi->wb.task);
spin_lock_bh(&bdi->wb_lock);
task = bdi->wb.task;
bdi->wb.task = NULL;
spin_unlock_bh(&bdi->wb_lock);

if (task)
kthread_stop(task);
}

/*
Expand All @@ -623,7 +630,9 @@ static void bdi_prune_sb(struct backing_dev_info *bdi)

void bdi_unregister(struct backing_dev_info *bdi)
{
if (bdi->dev) {
struct device *dev = bdi->dev;

if (dev) {
bdi_set_min_ratio(bdi, 0);
trace_writeback_bdi_unregister(bdi);
bdi_prune_sb(bdi);
Expand All @@ -632,8 +641,12 @@ void bdi_unregister(struct backing_dev_info *bdi)
if (!bdi_cap_flush_forker(bdi))
bdi_wb_shutdown(bdi);
bdi_debug_unregister(bdi);
device_unregister(bdi->dev);

spin_lock_bh(&bdi->wb_lock);
bdi->dev = NULL;
spin_unlock_bh(&bdi->wb_lock);

device_unregister(dev);
}
}
EXPORT_SYMBOL(bdi_unregister);
Expand Down

0 comments on commit 2673b4c

Please sign in to comment.