diff options
author | Tejun Heo <tj@kernel.org> | 2011-11-21 15:32:25 -0500 |
---|---|---|
committer | Tejun Heo <tj@kernel.org> | 2011-11-21 15:32:25 -0500 |
commit | 96ee6d8539c9fc6742908d85eb9723abb5c91854 (patch) | |
tree | 0c042d74508c777c33744e5a917ac16e057f073b /include/linux/freezer.h | |
parent | 948246f70a811c872b9d93bb4a8ab5823c4c79e0 (diff) |
freezer: fix set_freezable[_with_signal]() race
A kthread doing set_freezable*() may race with on-going PM freeze and
the freezer might think all tasks are frozen while the new freezable
kthread is merrily proceeding to execute code paths which aren't
supposed to be executing during PM freeze.
Reimplement set_freezable[_with_signal]() using __set_freezable() such
that freezable PF flags are modified under freezer_lock and
try_to_freeze() is called afterwards. This eliminates race condition
against freezing.
Note: Separated out from larger patch to resolve fix order dependency
Oleg pointed out.
Signed-off-by: Tejun Heo <tj@kernel.org>
Cc: Oleg Nesterov <oleg@redhat.com>
Diffstat (limited to 'include/linux/freezer.h')
-rw-r--r-- | include/linux/freezer.h | 9 |
1 files changed, 5 insertions, 4 deletions
diff --git a/include/linux/freezer.h b/include/linux/freezer.h index 3d50913d39d0..a0f1b3a3604f 100644 --- a/include/linux/freezer.h +++ b/include/linux/freezer.h | |||
@@ -49,6 +49,7 @@ static inline bool try_to_freeze(void) | |||
49 | } | 49 | } |
50 | 50 | ||
51 | extern bool freeze_task(struct task_struct *p, bool sig_only); | 51 | extern bool freeze_task(struct task_struct *p, bool sig_only); |
52 | extern bool __set_freezable(bool with_signal); | ||
52 | 53 | ||
53 | #ifdef CONFIG_CGROUP_FREEZER | 54 | #ifdef CONFIG_CGROUP_FREEZER |
54 | extern bool cgroup_freezing(struct task_struct *task); | 55 | extern bool cgroup_freezing(struct task_struct *task); |
@@ -106,18 +107,18 @@ static inline int freezer_should_skip(struct task_struct *p) | |||
106 | /* | 107 | /* |
107 | * Tell the freezer that the current task should be frozen by it | 108 | * Tell the freezer that the current task should be frozen by it |
108 | */ | 109 | */ |
109 | static inline void set_freezable(void) | 110 | static inline bool set_freezable(void) |
110 | { | 111 | { |
111 | current->flags &= ~PF_NOFREEZE; | 112 | return __set_freezable(false); |
112 | } | 113 | } |
113 | 114 | ||
114 | /* | 115 | /* |
115 | * Tell the freezer that the current task should be frozen by it and that it | 116 | * Tell the freezer that the current task should be frozen by it and that it |
116 | * should send a fake signal to the task to freeze it. | 117 | * should send a fake signal to the task to freeze it. |
117 | */ | 118 | */ |
118 | static inline void set_freezable_with_signal(void) | 119 | static inline bool set_freezable_with_signal(void) |
119 | { | 120 | { |
120 | current->flags &= ~(PF_NOFREEZE | PF_FREEZER_NOSIG); | 121 | return __set_freezable(true); |
121 | } | 122 | } |
122 | 123 | ||
123 | /* | 124 | /* |