From: Greg Kroah-Hartman Date: Tue, 14 Feb 2012 17:34:56 +0000 (-0800) Subject: 3.2-stable patches X-Git-Tag: v3.0.22~9 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=21d58d16be658f009433d8c64721d826ef381c79;p=thirdparty%2Fkernel%2Fstable-queue.git 3.2-stable patches added patches: backing-dev-fix-wakeup-timer-races-with-bdi_unregister.patch --- diff --git a/queue-3.2/backing-dev-fix-wakeup-timer-races-with-bdi_unregister.patch b/queue-3.2/backing-dev-fix-wakeup-timer-races-with-bdi_unregister.patch new file mode 100644 index 00000000000..e0a4ccdfb48 --- /dev/null +++ b/queue-3.2/backing-dev-fix-wakeup-timer-races-with-bdi_unregister.patch @@ -0,0 +1,92 @@ +From 2673b4cf5d59c3ee5e0c12f6d734d38770324dc4 Mon Sep 17 00:00:00 2001 +From: Rabin Vincent +Date: Sun, 29 Jan 2012 12:17:33 -0600 +Subject: backing-dev: fix wakeup timer races with bdi_unregister() + +From: Rabin Vincent + +commit 2673b4cf5d59c3ee5e0c12f6d734d38770324dc4 upstream. + +While 7a401a972df8e18 ("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: Jens Axboe +Reported-by: Chanho Min +Reviewed-by: Namjae Jeon +Signed-off-by: Rabin Vincent +Signed-off-by: Wu Fengguang +Signed-off-by: Greg Kroah-Hartman + +--- + mm/backing-dev.c | 25 +++++++++++++++++++------ + 1 file changed, 19 insertions(+), 6 deletions(-) + +--- a/mm/backing-dev.c ++++ b/mm/backing-dev.c +@@ -318,7 +318,7 @@ static void wakeup_timer_fn(unsigned lon + 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 +@@ -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; + +@@ -604,9 +606,14 @@ static void bdi_wb_shutdown(struct backi + * unfreeze of the thread before calling kthread_stop(), otherwise + * it would never exet if it is currently stuck in the refrigerator. + */ +- if (bdi->wb.task) { +- thaw_process(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) { ++ thaw_process(task); ++ kthread_stop(task); + } + } + +@@ -627,7 +634,9 @@ static void bdi_prune_sb(struct backing_ + + 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); +@@ -636,8 +645,12 @@ void bdi_unregister(struct backing_dev_i + 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); diff --git a/queue-3.2/series b/queue-3.2/series index 7d5484b2cf8..8fc53d0273b 100644 --- a/queue-3.2/series +++ b/queue-3.2/series @@ -19,3 +19,4 @@ cifs-request-oplock-when-doing-open-on-lookup.patch cifs-don-t-return-error-from-standard_receive3-after.patch crypto-sha512-use-binary-and-instead-of-modulus.patch crypto-sha512-avoid-stack-bloat-on-i386.patch +backing-dev-fix-wakeup-timer-races-with-bdi_unregister.patch