diff options
| author | Oleg Nesterov <oleg@redhat.com> | 2011-11-23 09:28:17 -0800 | 
|---|---|---|
| committer | Tejun Heo <tj@kernel.org> | 2011-11-23 09:28:17 -0800 | 
| commit | 24b7ead3fb0bae267c2ee50898eb4c13aedd1e9f (patch) | |
| tree | 899a48d29daebb6e2eb9398797304985e5961fc8 | |
| parent | 34b087e48367c252e343c2f8de65676a78af1e4a (diff) | |
| download | olio-linux-3.10-24b7ead3fb0bae267c2ee50898eb4c13aedd1e9f.tar.xz olio-linux-3.10-24b7ead3fb0bae267c2ee50898eb4c13aedd1e9f.zip  | |
freezer: fix wait_event_freezable/__thaw_task races
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>
| -rw-r--r-- | include/linux/freezer.h | 18 | 
1 files changed, 10 insertions, 8 deletions
diff --git a/include/linux/freezer.h b/include/linux/freezer.h index a33550fc05c..09570ac22be 100644 --- a/include/linux/freezer.h +++ b/include/linux/freezer.h @@ -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; }  |