aboutsummaryrefslogtreecommitdiffstats
path: root/include
diff options
context:
space:
mode:
authorTejun Heo <tj@kernel.org>2011-11-21 15:32:23 -0500
committerTejun Heo <tj@kernel.org>2011-11-21 15:32:23 -0500
commit8a32c441c1609f80e55df75422324a1151208f40 (patch)
tree73884b06cc2db3ea155af9a88815bb5105a4473e /include
parenta0acae0e886d44bd5ce6d2f173c1ace0fcf0d9f6 (diff)
freezer: implement and use kthread_freezable_should_stop()
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> Acked-by: Henrique de Moraes Holschuh <ibm-acpi@hmh.eng.br> Cc: Jens Axboe <axboe@kernel.dk> Cc: Oleg Nesterov <oleg@redhat.com>
Diffstat (limited to 'include')
-rw-r--r--include/linux/freezer.h6
-rw-r--r--include/linux/kthread.h1
2 files changed, 4 insertions, 3 deletions
diff --git a/include/linux/freezer.h b/include/linux/freezer.h
index 7a9427e9fe47..d02b78448b0f 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)
47/* Takes and releases task alloc lock using task_lock() */ 47/* Takes and releases task alloc lock using task_lock() */
48extern int thaw_process(struct task_struct *p); 48extern int thaw_process(struct task_struct *p);
49 49
50extern bool __refrigerator(void); 50extern bool __refrigerator(bool check_kthr_stop);
51extern int freeze_processes(void); 51extern int freeze_processes(void);
52extern int freeze_kernel_threads(void); 52extern int freeze_kernel_threads(void);
53extern void thaw_processes(void); 53extern void thaw_processes(void);
@@ -57,7 +57,7 @@ static inline bool try_to_freeze(void)
57 might_sleep(); 57 might_sleep();
58 if (likely(!freezing(current))) 58 if (likely(!freezing(current)))
59 return false; 59 return false;
60 return __refrigerator(); 60 return __refrigerator(false);
61} 61}
62 62
63extern bool freeze_task(struct task_struct *p, bool sig_only); 63extern bool freeze_task(struct task_struct *p, bool sig_only);
@@ -180,7 +180,7 @@ static inline void set_freeze_flag(struct task_struct *p) {}
180static inline void clear_freeze_flag(struct task_struct *p) {} 180static inline void clear_freeze_flag(struct task_struct *p) {}
181static inline int thaw_process(struct task_struct *p) { return 1; } 181static inline int thaw_process(struct task_struct *p) { return 1; }
182 182
183static inline bool __refrigerator(void) { return false; } 183static inline bool __refrigerator(bool check_kthr_stop) { return false; }
184static inline int freeze_processes(void) { return -ENOSYS; } 184static inline int freeze_processes(void) { return -ENOSYS; }
185static inline int freeze_kernel_threads(void) { return -ENOSYS; } 185static inline int freeze_kernel_threads(void) { return -ENOSYS; }
186static inline void thaw_processes(void) {} 186static inline void thaw_processes(void) {}
diff --git a/include/linux/kthread.h b/include/linux/kthread.h
index 5cac19b3a266..0714b24c0e45 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),
35void kthread_bind(struct task_struct *k, unsigned int cpu); 35void kthread_bind(struct task_struct *k, unsigned int cpu);
36int kthread_stop(struct task_struct *k); 36int kthread_stop(struct task_struct *k);
37int kthread_should_stop(void); 37int kthread_should_stop(void);
38bool kthread_freezable_should_stop(bool *was_frozen);
38void *kthread_data(struct task_struct *k); 39void *kthread_data(struct task_struct *k);
39 40
40int kthreadd(void *unused); 41int kthreadd(void *unused);