Skip to content

Commit

Permalink
freezer: fix wait_event_freezable/__thaw_task races
Browse files Browse the repository at this point in the history
wait_event_freezable() and friends stop the waiting if try_to_freeze()
fails. This is not right, we can race with __thaw_task() and in this
case

	- wait_event_freezable() returns the wrong ERESTARTSYS

	- wait_event_freezable_timeout() can return the positive
	  value while condition == F

Change the code to always check __retval/condition before return.

Note: with or without this patch the timeout logic looks strange,
probably we should recalc timeout if try_to_freeze() returns T.

Signed-off-by: Oleg Nesterov <oleg@redhat.com>
Acked-by: Tejun Heo <tj@kernel.org>
  • Loading branch information
Oleg Nesterov authored and Tejun Heo committed Nov 23, 2011
1 parent 34b087e commit 24b7ead
Showing 1 changed file with 10 additions and 8 deletions.
18 changes: 10 additions & 8 deletions include/linux/freezer.h
Original file line number Diff line number Diff line change
Expand Up @@ -122,28 +122,30 @@ static inline int freezer_should_skip(struct task_struct *p)
#define wait_event_freezable(wq, condition) \
({ \
int __retval; \
do { \
for (;;) { \
__retval = wait_event_interruptible(wq, \
(condition) || freezing(current)); \
if (__retval && !freezing(current)) \
if (__retval || (condition)) \
break; \
else if (!(condition)) \
__retval = -ERESTARTSYS; \
} while (try_to_freeze()); \
try_to_freeze(); \
} \
__retval; \
})


#define wait_event_freezable_timeout(wq, condition, timeout) \
({ \
long __retval = timeout; \
do { \
for (;;) { \
__retval = wait_event_interruptible_timeout(wq, \
(condition) || freezing(current), \
__retval); \
} while (try_to_freeze()); \
if (__retval <= 0 || (condition)) \
break; \
try_to_freeze(); \
} \
__retval; \
})

#else /* !CONFIG_FREEZER */
static inline bool frozen(struct task_struct *p) { return false; }
static inline bool freezing(struct task_struct *p) { return false; }
Expand Down

0 comments on commit 24b7ead

Please sign in to comment.