public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
From: Tejun Heo <tj@kernel.org>
To: rjw@sisk.pl, menage@google.com, linux-kernel@vger.kernel.org
Cc: arnd@arndb.de, oleg@redhat.com, Tejun Heo <tj@kernel.org>,
	Jens Axboe <axboe@kernel.dk>,
	Henrique de Moraes Holschuh <ibm-acpi@hmh.eng.br>
Subject: [PATCH 04/16] freezer: implement and use kthread_freezable_should_stop()
Date: Fri, 19 Aug 2011 16:16:10 +0200	[thread overview]
Message-ID: <1313763382-12341-5-git-send-email-tj@kernel.org> (raw)
In-Reply-To: <1313763382-12341-1-git-send-email-tj@kernel.org>

Writeback and thinkpad_acpi have been using thaw_process() to prevent
deadlock between the freezer and kthread_stop(); unfortunately, this
is inherently racy - nothing prevents freezing from happening between
thaw_process() and kthread_stop().

This patch implements kthread_freezable_should_stop() which enters
refrigerator if necessary but is guaranteed to return if
kthread_stop() is invoked.  Both thaw_process() users are converted to
use the new function.

Note that this deadlock condition exists for many of freezable
kthreads.  They need to be converted to use the new should_stop or
freezable workqueue.

Tested with synthetic test case.

Signed-off-by: Tejun Heo <tj@kernel.org>
Cc: Jens Axboe <axboe@kernel.dk>
Cc: Henrique de Moraes Holschuh <ibm-acpi@hmh.eng.br>
---
 drivers/platform/x86/thinkpad_acpi.c |   15 ++++++---------
 fs/fs-writeback.c                    |    4 +---
 include/linux/freezer.h              |    6 +++---
 include/linux/kthread.h              |    1 +
 kernel/freezer.c                     |    6 ++++--
 kernel/kthread.c                     |   25 +++++++++++++++++++++++++
 mm/backing-dev.c                     |    8 ++------
 7 files changed, 42 insertions(+), 23 deletions(-)

diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c
index 7bd829f..34f167e 100644
--- a/drivers/platform/x86/thinkpad_acpi.c
+++ b/drivers/platform/x86/thinkpad_acpi.c
@@ -2456,8 +2456,9 @@ static int hotkey_kthread(void *data)
 	u32 poll_mask, event_mask;
 	unsigned int si, so;
 	unsigned long t;
-	unsigned int change_detector, must_reset;
+	unsigned int change_detector;
 	unsigned int poll_freq;
+	bool was_frozen;
 
 	mutex_lock(&hotkey_thread_mutex);
 
@@ -2488,14 +2489,14 @@ static int hotkey_kthread(void *data)
 				t = 100;	/* should never happen... */
 		}
 		t = msleep_interruptible(t);
-		if (unlikely(kthread_should_stop()))
+		if (unlikely(kthread_freezable_should_stop(&was_frozen)))
 			break;
-		must_reset = try_to_freeze();
-		if (t > 0 && !must_reset)
+
+		if (t > 0 && !was_frozen)
 			continue;
 
 		mutex_lock(&hotkey_thread_data_mutex);
-		if (must_reset || hotkey_config_change != change_detector) {
+		if (was_frozen || hotkey_config_change != change_detector) {
 			/* forget old state on thaw or config change */
 			si = so;
 			t = 0;
@@ -2528,10 +2529,6 @@ exit:
 static void hotkey_poll_stop_sync(void)
 {
 	if (tpacpi_hotkey_task) {
-		if (frozen(tpacpi_hotkey_task) ||
-		    freezing(tpacpi_hotkey_task))
-			thaw_process(tpacpi_hotkey_task);
-
 		kthread_stop(tpacpi_hotkey_task);
 		tpacpi_hotkey_task = NULL;
 		mutex_lock(&hotkey_thread_mutex);
diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c
index 04cf3b9..b36edb8 100644
--- a/fs/fs-writeback.c
+++ b/fs/fs-writeback.c
@@ -922,7 +922,7 @@ int bdi_writeback_thread(void *data)
 
 	trace_writeback_thread_start(bdi);
 
-	while (!kthread_should_stop()) {
+	while (!kthread_freezable_should_stop(NULL)) {
 		/*
 		 * Remove own delayed wake-up timer, since we are already awake
 		 * and we'll take care of the preriodic write-back.
@@ -952,8 +952,6 @@ int bdi_writeback_thread(void *data)
 			 */
 			schedule();
 		}
-
-		try_to_freeze();
 	}
 
 	/* Flush any work that raced with us exiting */
diff --git a/include/linux/freezer.h b/include/linux/freezer.h
index 3d73288..8ee31e5 100644
--- a/include/linux/freezer.h
+++ b/include/linux/freezer.h
@@ -47,7 +47,7 @@ static inline bool should_send_signal(struct task_struct *p)
 /* Takes and releases task alloc lock using task_lock() */
 extern int thaw_process(struct task_struct *p);
 
-extern bool __refrigerator(void);
+extern bool __refrigerator(bool check_kthr_stop);
 extern int freeze_processes(void);
 extern void thaw_processes(void);
 
@@ -56,7 +56,7 @@ static inline bool try_to_freeze(void)
 	might_sleep();
 	if (likely(!freezing(current)))
 		return false;
-	return __refrigerator();
+	return __refrigerator(false);
 }
 
 extern bool freeze_task(struct task_struct *p, bool sig_only);
@@ -169,7 +169,7 @@ static inline void set_freeze_flag(struct task_struct *p) {}
 static inline void clear_freeze_flag(struct task_struct *p) {}
 static inline int thaw_process(struct task_struct *p) { return 1; }
 
-static inline bool __refrigerator(void) { return false; }
+static inline bool __refrigerator(bool check_kthr_stop) { return false; }
 static inline int freeze_processes(void) { BUG(); return 0; }
 static inline void thaw_processes(void) {}
 
diff --git a/include/linux/kthread.h b/include/linux/kthread.h
index 1e923e5..6c1903d 100644
--- a/include/linux/kthread.h
+++ b/include/linux/kthread.h
@@ -35,6 +35,7 @@ struct task_struct *kthread_create_on_node(int (*threadfn)(void *data),
 void kthread_bind(struct task_struct *k, unsigned int cpu);
 int kthread_stop(struct task_struct *k);
 int kthread_should_stop(void);
+bool kthread_freezable_should_stop(bool *was_frozen);
 void *kthread_data(struct task_struct *k);
 
 int kthreadd(void *unused);
diff --git a/kernel/freezer.c b/kernel/freezer.c
index 4d59904..656492c 100644
--- a/kernel/freezer.c
+++ b/kernel/freezer.c
@@ -9,6 +9,7 @@
 #include <linux/module.h>
 #include <linux/syscalls.h>
 #include <linux/freezer.h>
+#include <linux/kthread.h>
 
 /*
  * freezing is complete, mark current process as frozen
@@ -23,7 +24,7 @@ static inline void frozen_process(void)
 }
 
 /* Refrigerator is place where frozen processes are stored :-). */
-bool __refrigerator(void)
+bool __refrigerator(bool check_kthr_stop)
 {
 	/* Hmm, should we be allowed to suspend when there are realtime
 	   processes around? */
@@ -50,7 +51,8 @@ bool __refrigerator(void)
 
 	for (;;) {
 		set_current_state(TASK_UNINTERRUPTIBLE);
-		if (!frozen(current))
+		if (!frozen(current) ||
+		    (check_kthr_stop && kthread_should_stop()))
 			break;
 		was_frozen = true;
 		schedule();
diff --git a/kernel/kthread.c b/kernel/kthread.c
index 4ba7ccc..a6cbeea 100644
--- a/kernel/kthread.c
+++ b/kernel/kthread.c
@@ -59,6 +59,31 @@ int kthread_should_stop(void)
 EXPORT_SYMBOL(kthread_should_stop);
 
 /**
+ * kthread_freezable_should_stop - should this freezable kthread return now?
+ * @was_frozen: optional out parameter, indicates whether %current was frozen
+ *
+ * kthread_should_stop() for freezable kthreads, which will enter
+ * refrigerator if necessary.  This function is safe from kthread_stop() /
+ * freezer deadlock and freezable kthreads should use this function instead
+ * of calling try_to_freeze() directly.
+ */
+bool kthread_freezable_should_stop(bool *was_frozen)
+{
+	bool frozen = false;
+
+	might_sleep();
+
+	if (unlikely(freezing(current)))
+		frozen = __refrigerator(true);
+
+	if (was_frozen)
+		*was_frozen = frozen;
+
+	return kthread_should_stop();
+}
+EXPORT_SYMBOL_GPL(kthread_freezable_should_stop);
+
+/**
  * kthread_data - return data value specified on kthread creation
  * @task: kthread task in question
  *
diff --git a/mm/backing-dev.c b/mm/backing-dev.c
index d6edf8d..d73a5aa 100644
--- a/mm/backing-dev.c
+++ b/mm/backing-dev.c
@@ -586,14 +586,10 @@ 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. Force
-	 * unfreeze of the thread before calling kthread_stop(), otherwise
-	 * it would never exet if it is currently stuck in the refrigerator.
+	 * safe anymore, since the bdi is gone from visibility.
 	 */
-	if (bdi->wb.task) {
-		thaw_process(bdi->wb.task);
+	if (bdi->wb.task)
 		kthread_stop(bdi->wb.task);
-	}
 }
 
 /*
-- 
1.7.6


  parent reply	other threads:[~2011-08-19 14:16 UTC|newest]

Thread overview: 79+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2011-08-19 14:16 [PATCHSET] freezer: fix various bugs and simplify implementation Tejun Heo
2011-08-19 14:16 ` [PATCH 01/16] freezer: fix current->state restoration race in refrigerator() Tejun Heo
2011-08-19 15:52   ` Oleg Nesterov
2011-08-19 16:11     ` Tejun Heo
2011-08-19 21:08   ` Rafael J. Wysocki
2011-08-20  8:13     ` Tejun Heo
2011-08-19 14:16 ` [PATCH 02/16] freezer: don't unnecessarily set PF_NOFREEZE explicitly Tejun Heo
2011-08-19 16:43   ` Gustavo Padovan
2011-08-22 15:05   ` Samuel Ortiz
2011-08-19 14:16 ` [PATCH 03/16] freezer: unexport refrigerator() and update try_to_freeze() slightly Tejun Heo
2011-08-19 14:16 ` Tejun Heo [this message]
2011-08-19 20:07   ` [PATCH 04/16] freezer: implement and use kthread_freezable_should_stop() Henrique de Moraes Holschuh
2011-08-21 19:14   ` Oleg Nesterov
2011-08-22  9:53     ` Tejun Heo
2011-08-23 15:42       ` Oleg Nesterov
2011-08-19 14:16 ` [PATCH 05/16] freezer: rename thaw_process() to __thaw_task() and simplify the implementation Tejun Heo
2011-08-19 15:37   ` Paul Menage
2011-08-24  2:28   ` Matt Helsley
2011-08-19 14:16 ` [PATCH 06/16] freezer: make exiting tasks properly unfreezable Tejun Heo
2011-08-23 15:52   ` Oleg Nesterov
2011-08-23 19:44     ` Tejun Heo
2011-08-24 14:14       ` Oleg Nesterov
2011-08-25 15:59         ` Tejun Heo
2011-08-25 16:56           ` Oleg Nesterov
2011-08-25 21:01             ` Rafael J. Wysocki
2011-08-25 21:54               ` Tejun Heo
2011-08-26 21:09                 ` Rafael J. Wysocki
2011-08-27 10:35                   ` Tejun Heo
2011-08-27 10:51                     ` Rafael J. Wysocki
2011-08-27 11:02                       ` Tejun Heo
2011-08-27 12:22                         ` Rafael J. Wysocki
2011-08-25 21:52             ` Tejun Heo
2011-08-24 22:34   ` Matt Helsley
2011-08-25 15:25     ` Oleg Nesterov
2011-08-25 16:11     ` Tejun Heo
2011-08-19 14:16 ` [PATCH 07/16] freezer: don't distinguish nosig tasks on thaw Tejun Heo
2011-08-19 21:14   ` Rafael J. Wysocki
2011-08-20  8:10     ` Tejun Heo
2011-08-20  8:39       ` Rafael J. Wysocki
2011-08-19 14:16 ` [PATCH 08/16] freezer: use dedicated lock instead of task_lock() + memory barrier Tejun Heo
2011-08-28 17:51   ` Oleg Nesterov
2011-08-28 18:21     ` Oleg Nesterov
2011-08-29  7:20     ` Tejun Heo
2011-08-19 14:16 ` [PATCH 09/16] freezer: make freezing indicate freeze condition in effect Tejun Heo
2011-08-28 17:56   ` Oleg Nesterov
2011-08-29  7:31     ` Tejun Heo
2011-08-29 17:44     ` Oleg Nesterov
2011-08-19 14:16 ` [PATCH 10/16] freezer: fix set_freezable[_with_signal]() race Tejun Heo
2011-08-28 18:01   ` Oleg Nesterov
2011-08-29  7:38     ` Tejun Heo
2011-08-19 14:16 ` [PATCH 11/16] freezer: kill PF_FREEZING Tejun Heo
2011-08-19 14:16 ` [PATCH 12/16] freezer: clean up freeze_processes() failure path Tejun Heo
2011-08-28 18:09   ` Oleg Nesterov
2011-08-29  7:28     ` Tejun Heo
2011-08-29  7:40       ` Rafael J. Wysocki
2011-08-19 14:16 ` [PATCH 13/16] cgroup_freezer: prepare for removal of TIF_FREEZE Tejun Heo
2011-08-19 15:40   ` Paul Menage
2011-08-28 17:39   ` Oleg Nesterov
2011-08-29  6:30     ` Tejun Heo
2011-08-19 14:16 ` [PATCH 14/16] freezer: make freezing() test freeze conditions in effect instead " Tejun Heo
2011-08-19 15:43   ` Paul Menage
2011-08-29 15:49   ` Oleg Nesterov
2011-08-29 15:56     ` Oleg Nesterov
2011-08-29 16:30       ` Oleg Nesterov
2011-08-29 16:17     ` Oleg Nesterov
2011-08-19 14:16 ` [PATCH 15/16] freezer: remove now unused TIF_FREEZE Tejun Heo
2011-08-19 14:16 ` [PATCH 16/16] freezer: remove should_send_signal() and update frozen() Tejun Heo
2011-08-19 14:23 ` [PATCHSET] freezer: fix various bugs and simplify implementation Tejun Heo
2011-08-19 15:34   ` Paul Menage
2011-08-19 16:25   ` Tejun Heo
2011-08-24  1:10     ` Matt Helsley
2011-08-19 21:00 ` Rafael J. Wysocki
2011-08-20  8:14   ` Tejun Heo
2011-09-05  8:52   ` [BUG] CPU hotplug, freezer: Freezing of tasks failed after 20.00 seconds Srivatsa S. Bhat
2011-09-05 14:15     ` Tejun Heo
2011-09-06  5:08       ` Tejun Heo
2011-09-06  6:01         ` Rafael J. Wysocki
2011-10-02 19:13           ` Srivatsa S. Bhat
2011-10-02 19:33             ` Rafael J. Wysocki

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1313763382-12341-5-git-send-email-tj@kernel.org \
    --to=tj@kernel.org \
    --cc=arnd@arndb.de \
    --cc=axboe@kernel.dk \
    --cc=ibm-acpi@hmh.eng.br \
    --cc=linux-kernel@vger.kernel.org \
    --cc=menage@google.com \
    --cc=oleg@redhat.com \
    --cc=rjw@sisk.pl \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox