Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 24b7ead3 authored by Oleg Nesterov's avatar Oleg Nesterov Committed by Tejun Heo
Browse files

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: default avatarOleg Nesterov <oleg@redhat.com>
Acked-by: default avatarTejun Heo <tj@kernel.org>
parent 34b087e4
Loading
Loading
Loading
Loading
+10 −8
Original line number Original line Diff line number Diff line
@@ -122,28 +122,30 @@ static inline int freezer_should_skip(struct task_struct *p)
#define wait_event_freezable(wq, condition)				\
#define wait_event_freezable(wq, condition)				\
({									\
({									\
	int __retval;							\
	int __retval;							\
	do {								\
	for (;;) {							\
		__retval = wait_event_interruptible(wq, 		\
		__retval = wait_event_interruptible(wq, 		\
				(condition) || freezing(current));	\
				(condition) || freezing(current));	\
		if (__retval && !freezing(current))			\
		if (__retval || (condition))				\
			break;						\
			break;						\
		else if (!(condition))					\
		try_to_freeze();					\
			__retval = -ERESTARTSYS;			\
	}								\
	} while (try_to_freeze());					\
	__retval;							\
	__retval;							\
})
})



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

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