diff options
| author | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2013-06-28 07:00:53 -0400 |
|---|---|---|
| committer | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2013-06-28 07:00:53 -0400 |
| commit | 207bc1181b1c03ab6ecb55bca5b307606dd1d6bc (patch) | |
| tree | 018365e826918d709beae86717db5ee9e4215bc6 /include | |
| parent | e8b6cb3947430d62538d88f615c007a51aeb23fe (diff) | |
| parent | 2b15af6f953012aac49984ead3f8ec744d941540 (diff) | |
Merge branch 'freezer'
* freezer:
af_unix: use freezable blocking calls in read
sigtimedwait: use freezable blocking call
nanosleep: use freezable blocking call
futex: use freezable blocking call
select: use freezable blocking call
epoll: use freezable blocking call
binder: use freezable blocking calls
freezer: add new freezable helpers using freezer_do_not_count()
freezer: convert freezable helpers to static inline where possible
freezer: convert freezable helpers to freezer_do_not_count()
freezer: skip waking up tasks with PF_FREEZER_SKIP set
freezer: shorten freezer sleep time using exponential backoff
lockdep: check that no locks held at freeze time
lockdep: remove task argument from debug_check_no_locks_held
freezer: add unsafe versions of freezable helpers for CIFS
freezer: add unsafe versions of freezable helpers for NFS
Diffstat (limited to 'include')
| -rw-r--r-- | include/linux/debug_locks.h | 4 | ||||
| -rw-r--r-- | include/linux/freezer.h | 171 |
2 files changed, 142 insertions, 33 deletions
diff --git a/include/linux/debug_locks.h b/include/linux/debug_locks.h index 21ca773f77bf..822c1354f3a6 100644 --- a/include/linux/debug_locks.h +++ b/include/linux/debug_locks.h | |||
| @@ -51,7 +51,7 @@ struct task_struct; | |||
| 51 | extern void debug_show_all_locks(void); | 51 | extern void debug_show_all_locks(void); |
| 52 | extern void debug_show_held_locks(struct task_struct *task); | 52 | extern void debug_show_held_locks(struct task_struct *task); |
| 53 | extern void debug_check_no_locks_freed(const void *from, unsigned long len); | 53 | extern void debug_check_no_locks_freed(const void *from, unsigned long len); |
| 54 | extern void debug_check_no_locks_held(struct task_struct *task); | 54 | extern void debug_check_no_locks_held(void); |
| 55 | #else | 55 | #else |
| 56 | static inline void debug_show_all_locks(void) | 56 | static inline void debug_show_all_locks(void) |
| 57 | { | 57 | { |
| @@ -67,7 +67,7 @@ debug_check_no_locks_freed(const void *from, unsigned long len) | |||
| 67 | } | 67 | } |
| 68 | 68 | ||
| 69 | static inline void | 69 | static inline void |
| 70 | debug_check_no_locks_held(struct task_struct *task) | 70 | debug_check_no_locks_held(void) |
| 71 | { | 71 | { |
| 72 | } | 72 | } |
| 73 | #endif | 73 | #endif |
diff --git a/include/linux/freezer.h b/include/linux/freezer.h index e70df40d84f6..7fd81b8c4897 100644 --- a/include/linux/freezer.h +++ b/include/linux/freezer.h | |||
| @@ -3,6 +3,7 @@ | |||
| 3 | #ifndef FREEZER_H_INCLUDED | 3 | #ifndef FREEZER_H_INCLUDED |
| 4 | #define FREEZER_H_INCLUDED | 4 | #define FREEZER_H_INCLUDED |
| 5 | 5 | ||
| 6 | #include <linux/debug_locks.h> | ||
| 6 | #include <linux/sched.h> | 7 | #include <linux/sched.h> |
| 7 | #include <linux/wait.h> | 8 | #include <linux/wait.h> |
| 8 | #include <linux/atomic.h> | 9 | #include <linux/atomic.h> |
| @@ -46,7 +47,11 @@ extern int freeze_kernel_threads(void); | |||
| 46 | extern void thaw_processes(void); | 47 | extern void thaw_processes(void); |
| 47 | extern void thaw_kernel_threads(void); | 48 | extern void thaw_kernel_threads(void); |
| 48 | 49 | ||
| 49 | static inline bool try_to_freeze(void) | 50 | /* |
| 51 | * DO NOT ADD ANY NEW CALLERS OF THIS FUNCTION | ||
| 52 | * If try_to_freeze causes a lockdep warning it means the caller may deadlock | ||
| 53 | */ | ||
| 54 | static inline bool try_to_freeze_unsafe(void) | ||
| 50 | { | 55 | { |
| 51 | might_sleep(); | 56 | might_sleep(); |
| 52 | if (likely(!freezing(current))) | 57 | if (likely(!freezing(current))) |
| @@ -54,6 +59,13 @@ static inline bool try_to_freeze(void) | |||
| 54 | return __refrigerator(false); | 59 | return __refrigerator(false); |
| 55 | } | 60 | } |
| 56 | 61 | ||
| 62 | static inline bool try_to_freeze(void) | ||
| 63 | { | ||
| 64 | if (!(current->flags & PF_NOFREEZE)) | ||
| 65 | debug_check_no_locks_held(); | ||
| 66 | return try_to_freeze_unsafe(); | ||
| 67 | } | ||
| 68 | |||
| 57 | extern bool freeze_task(struct task_struct *p); | 69 | extern bool freeze_task(struct task_struct *p); |
| 58 | extern bool set_freezable(void); | 70 | extern bool set_freezable(void); |
| 59 | 71 | ||
| @@ -115,6 +127,14 @@ static inline void freezer_count(void) | |||
| 115 | try_to_freeze(); | 127 | try_to_freeze(); |
| 116 | } | 128 | } |
| 117 | 129 | ||
| 130 | /* DO NOT ADD ANY NEW CALLERS OF THIS FUNCTION */ | ||
| 131 | static inline void freezer_count_unsafe(void) | ||
| 132 | { | ||
| 133 | current->flags &= ~PF_FREEZER_SKIP; | ||
| 134 | smp_mb(); | ||
| 135 | try_to_freeze_unsafe(); | ||
| 136 | } | ||
| 137 | |||
| 118 | /** | 138 | /** |
| 119 | * freezer_should_skip - whether to skip a task when determining frozen | 139 | * freezer_should_skip - whether to skip a task when determining frozen |
| 120 | * state is reached | 140 | * state is reached |
| @@ -139,28 +159,86 @@ static inline bool freezer_should_skip(struct task_struct *p) | |||
| 139 | } | 159 | } |
| 140 | 160 | ||
| 141 | /* | 161 | /* |
| 142 | * These macros are intended to be used whenever you want allow a sleeping | 162 | * These functions are intended to be used whenever you want allow a sleeping |
| 143 | * task to be frozen. Note that neither return any clear indication of | 163 | * task to be frozen. Note that neither return any clear indication of |
| 144 | * whether a freeze event happened while in this function. | 164 | * whether a freeze event happened while in this function. |
| 145 | */ | 165 | */ |
| 146 | 166 | ||
| 147 | /* Like schedule(), but should not block the freezer. */ | 167 | /* Like schedule(), but should not block the freezer. */ |
| 148 | #define freezable_schedule() \ | 168 | static inline void freezable_schedule(void) |
| 149 | ({ \ | 169 | { |
| 150 | freezer_do_not_count(); \ | 170 | freezer_do_not_count(); |
| 151 | schedule(); \ | 171 | schedule(); |
| 152 | freezer_count(); \ | 172 | freezer_count(); |
| 153 | }) | 173 | } |
| 174 | |||
| 175 | /* DO NOT ADD ANY NEW CALLERS OF THIS FUNCTION */ | ||
| 176 | static inline void freezable_schedule_unsafe(void) | ||
| 177 | { | ||
| 178 | freezer_do_not_count(); | ||
| 179 | schedule(); | ||
| 180 | freezer_count_unsafe(); | ||
| 181 | } | ||
| 182 | |||
| 183 | /* | ||
| 184 | * Like freezable_schedule_timeout(), but should not block the freezer. Do not | ||
| 185 | * call this with locks held. | ||
| 186 | */ | ||
| 187 | static inline long freezable_schedule_timeout(long timeout) | ||
| 188 | { | ||
| 189 | long __retval; | ||
| 190 | freezer_do_not_count(); | ||
| 191 | __retval = schedule_timeout(timeout); | ||
| 192 | freezer_count(); | ||
| 193 | return __retval; | ||
| 194 | } | ||
| 195 | |||
| 196 | /* | ||
| 197 | * Like schedule_timeout_interruptible(), but should not block the freezer. Do not | ||
| 198 | * call this with locks held. | ||
| 199 | */ | ||
| 200 | static inline long freezable_schedule_timeout_interruptible(long timeout) | ||
| 201 | { | ||
| 202 | long __retval; | ||
| 203 | freezer_do_not_count(); | ||
| 204 | __retval = schedule_timeout_interruptible(timeout); | ||
| 205 | freezer_count(); | ||
| 206 | return __retval; | ||
| 207 | } | ||
| 154 | 208 | ||
| 155 | /* Like schedule_timeout_killable(), but should not block the freezer. */ | 209 | /* Like schedule_timeout_killable(), but should not block the freezer. */ |
| 156 | #define freezable_schedule_timeout_killable(timeout) \ | 210 | static inline long freezable_schedule_timeout_killable(long timeout) |
| 157 | ({ \ | 211 | { |
| 158 | long __retval; \ | 212 | long __retval; |
| 159 | freezer_do_not_count(); \ | 213 | freezer_do_not_count(); |
| 160 | __retval = schedule_timeout_killable(timeout); \ | 214 | __retval = schedule_timeout_killable(timeout); |
| 161 | freezer_count(); \ | 215 | freezer_count(); |
| 162 | __retval; \ | 216 | return __retval; |
| 163 | }) | 217 | } |
| 218 | |||
| 219 | /* DO NOT ADD ANY NEW CALLERS OF THIS FUNCTION */ | ||
| 220 | static inline long freezable_schedule_timeout_killable_unsafe(long timeout) | ||
| 221 | { | ||
| 222 | long __retval; | ||
| 223 | freezer_do_not_count(); | ||
| 224 | __retval = schedule_timeout_killable(timeout); | ||
| 225 | freezer_count_unsafe(); | ||
| 226 | return __retval; | ||
| 227 | } | ||
| 228 | |||
| 229 | /* | ||
| 230 | * Like schedule_hrtimeout_range(), but should not block the freezer. Do not | ||
| 231 | * call this with locks held. | ||
| 232 | */ | ||
| 233 | static inline int freezable_schedule_hrtimeout_range(ktime_t *expires, | ||
| 234 | unsigned long delta, const enum hrtimer_mode mode) | ||
| 235 | { | ||
| 236 | int __retval; | ||
| 237 | freezer_do_not_count(); | ||
| 238 | __retval = schedule_hrtimeout_range(expires, delta, mode); | ||
| 239 | freezer_count(); | ||
| 240 | return __retval; | ||
| 241 | } | ||
| 164 | 242 | ||
| 165 | /* | 243 | /* |
| 166 | * Freezer-friendly wrappers around wait_event_interruptible(), | 244 | * Freezer-friendly wrappers around wait_event_interruptible(), |
| @@ -177,33 +255,45 @@ static inline bool freezer_should_skip(struct task_struct *p) | |||
| 177 | __retval; \ | 255 | __retval; \ |
| 178 | }) | 256 | }) |
| 179 | 257 | ||
| 258 | /* DO NOT ADD ANY NEW CALLERS OF THIS FUNCTION */ | ||
| 259 | #define wait_event_freezekillable_unsafe(wq, condition) \ | ||
| 260 | ({ \ | ||
| 261 | int __retval; \ | ||
| 262 | freezer_do_not_count(); \ | ||
| 263 | __retval = wait_event_killable(wq, (condition)); \ | ||
| 264 | freezer_count_unsafe(); \ | ||
| 265 | __retval; \ | ||
| 266 | }) | ||
| 267 | |||
| 180 | #define wait_event_freezable(wq, condition) \ | 268 | #define wait_event_freezable(wq, condition) \ |
| 181 | ({ \ | 269 | ({ \ |
| 182 | int __retval; \ | 270 | int __retval; \ |
| 183 | for (;;) { \ | 271 | freezer_do_not_count(); \ |
| 184 | __retval = wait_event_interruptible(wq, \ | 272 | __retval = wait_event_interruptible(wq, (condition)); \ |
| 185 | (condition) || freezing(current)); \ | 273 | freezer_count(); \ |
| 186 | if (__retval || (condition)) \ | ||
| 187 | break; \ | ||
| 188 | try_to_freeze(); \ | ||
| 189 | } \ | ||
| 190 | __retval; \ | 274 | __retval; \ |
| 191 | }) | 275 | }) |
| 192 | 276 | ||
| 193 | #define wait_event_freezable_timeout(wq, condition, timeout) \ | 277 | #define wait_event_freezable_timeout(wq, condition, timeout) \ |
| 194 | ({ \ | 278 | ({ \ |
| 195 | long __retval = timeout; \ | 279 | long __retval = timeout; \ |
| 196 | for (;;) { \ | 280 | freezer_do_not_count(); \ |
| 197 | __retval = wait_event_interruptible_timeout(wq, \ | 281 | __retval = wait_event_interruptible_timeout(wq, (condition), \ |
| 198 | (condition) || freezing(current), \ | 282 | __retval); \ |
| 199 | __retval); \ | 283 | freezer_count(); \ |
| 200 | if (__retval <= 0 || (condition)) \ | ||
| 201 | break; \ | ||
| 202 | try_to_freeze(); \ | ||
| 203 | } \ | ||
| 204 | __retval; \ | 284 | __retval; \ |
| 205 | }) | 285 | }) |
| 206 | 286 | ||
| 287 | #define wait_event_freezable_exclusive(wq, condition) \ | ||
| 288 | ({ \ | ||
| 289 | int __retval; \ | ||
| 290 | freezer_do_not_count(); \ | ||
| 291 | __retval = wait_event_interruptible_exclusive(wq, condition); \ | ||
| 292 | freezer_count(); \ | ||
| 293 | __retval; \ | ||
| 294 | }) | ||
| 295 | |||
| 296 | |||
| 207 | #else /* !CONFIG_FREEZER */ | 297 | #else /* !CONFIG_FREEZER */ |
| 208 | static inline bool frozen(struct task_struct *p) { return false; } | 298 | static inline bool frozen(struct task_struct *p) { return false; } |
| 209 | static inline bool freezing(struct task_struct *p) { return false; } | 299 | static inline bool freezing(struct task_struct *p) { return false; } |
| @@ -225,18 +315,37 @@ static inline void set_freezable(void) {} | |||
| 225 | 315 | ||
| 226 | #define freezable_schedule() schedule() | 316 | #define freezable_schedule() schedule() |
| 227 | 317 | ||
| 318 | #define freezable_schedule_unsafe() schedule() | ||
| 319 | |||
| 320 | #define freezable_schedule_timeout(timeout) schedule_timeout(timeout) | ||
| 321 | |||
| 322 | #define freezable_schedule_timeout_interruptible(timeout) \ | ||
| 323 | schedule_timeout_interruptible(timeout) | ||
| 324 | |||
| 228 | #define freezable_schedule_timeout_killable(timeout) \ | 325 | #define freezable_schedule_timeout_killable(timeout) \ |
| 229 | schedule_timeout_killable(timeout) | 326 | schedule_timeout_killable(timeout) |
| 230 | 327 | ||
| 328 | #define freezable_schedule_timeout_killable_unsafe(timeout) \ | ||
| 329 | schedule_timeout_killable(timeout) | ||
| 330 | |||
| 331 | #define freezable_schedule_hrtimeout_range(expires, delta, mode) \ | ||
| 332 | schedule_hrtimeout_range(expires, delta, mode) | ||
| 333 | |||
| 231 | #define wait_event_freezable(wq, condition) \ | 334 | #define wait_event_freezable(wq, condition) \ |
| 232 | wait_event_interruptible(wq, condition) | 335 | wait_event_interruptible(wq, condition) |
| 233 | 336 | ||
| 234 | #define wait_event_freezable_timeout(wq, condition, timeout) \ | 337 | #define wait_event_freezable_timeout(wq, condition, timeout) \ |
| 235 | wait_event_interruptible_timeout(wq, condition, timeout) | 338 | wait_event_interruptible_timeout(wq, condition, timeout) |
| 236 | 339 | ||
| 340 | #define wait_event_freezable_exclusive(wq, condition) \ | ||
| 341 | wait_event_interruptible_exclusive(wq, condition) | ||
| 342 | |||
| 237 | #define wait_event_freezekillable(wq, condition) \ | 343 | #define wait_event_freezekillable(wq, condition) \ |
| 238 | wait_event_killable(wq, condition) | 344 | wait_event_killable(wq, condition) |
| 239 | 345 | ||
| 346 | #define wait_event_freezekillable_unsafe(wq, condition) \ | ||
| 347 | wait_event_killable(wq, condition) | ||
| 348 | |||
| 240 | #endif /* !CONFIG_FREEZER */ | 349 | #endif /* !CONFIG_FREEZER */ |
| 241 | 350 | ||
| 242 | #endif /* FREEZER_H_INCLUDED */ | 351 | #endif /* FREEZER_H_INCLUDED */ |
