mirror of
				https://github.com/torvalds/linux.git
				synced 2025-10-31 08:38:45 +02:00 
			
		
		
		
	sched: Fix TASK_state comparisons
Task state is fundamentally a bitmask; direct comparisons are probably
not working as intended. Specifically the normal wait-state have
a number of possible modifiers:
  TASK_UNINTERRUPTIBLE:	TASK_WAKEKILL, TASK_NOLOAD, TASK_FREEZABLE
  TASK_INTERRUPTIBLE:   TASK_FREEZABLE
Specifically, the addition of TASK_FREEZABLE wrecked
__wait_is_interruptible(). This however led to an audit of direct
comparisons yielding the rest of the changes.
Fixes: f5d39b0208 ("freezer,sched: Rewrite core freezer logic")
Reported-by: Christian Borntraeger <borntraeger@linux.ibm.com>
Debugged-by: Christian Borntraeger <borntraeger@linux.ibm.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Tested-by: Christian Borntraeger <borntraeger@linux.ibm.com>
			
			
This commit is contained in:
		
							parent
							
								
									7e9518baed
								
							
						
					
					
						commit
						5aec788aeb
					
				
					 3 changed files with 8 additions and 4 deletions
				
			
		|  | @ -281,7 +281,7 @@ static inline void wake_up_pollfree(struct wait_queue_head *wq_head) | |||
| 
 | ||||
| #define ___wait_is_interruptible(state)						\ | ||||
| 	(!__builtin_constant_p(state) ||					\ | ||||
| 		state == TASK_INTERRUPTIBLE || state == TASK_KILLABLE)		\ | ||||
| 	 (state & (TASK_INTERRUPTIBLE | TASK_WAKEKILL))) | ||||
| 
 | ||||
| extern void init_wait_entry(struct wait_queue_entry *wq_entry, int flags); | ||||
| 
 | ||||
|  |  | |||
|  | @ -191,6 +191,8 @@ static void check_hung_uninterruptible_tasks(unsigned long timeout) | |||
| 	hung_task_show_lock = false; | ||||
| 	rcu_read_lock(); | ||||
| 	for_each_process_thread(g, t) { | ||||
| 		unsigned int state; | ||||
| 
 | ||||
| 		if (!max_count--) | ||||
| 			goto unlock; | ||||
| 		if (time_after(jiffies, last_break + HUNG_TASK_LOCK_BREAK)) { | ||||
|  | @ -198,8 +200,10 @@ static void check_hung_uninterruptible_tasks(unsigned long timeout) | |||
| 				goto unlock; | ||||
| 			last_break = jiffies; | ||||
| 		} | ||||
| 		/* use "==" to skip the TASK_KILLABLE tasks waiting on NFS */ | ||||
| 		if (READ_ONCE(t->__state) == TASK_UNINTERRUPTIBLE) | ||||
| 		/* skip the TASK_KILLABLE tasks -- these can be killed */ | ||||
| 		state = READ_ONCE(t->__state); | ||||
| 		if ((state & TASK_UNINTERRUPTIBLE) && | ||||
| 		    !(state & TASK_WAKEKILL)) | ||||
| 			check_hung_task(t, timeout); | ||||
| 	} | ||||
|  unlock: | ||||
|  |  | |||
|  | @ -8884,7 +8884,7 @@ state_filter_match(unsigned long state_filter, struct task_struct *p) | |||
| 	 * When looking for TASK_UNINTERRUPTIBLE skip TASK_IDLE (allows | ||||
| 	 * TASK_KILLABLE). | ||||
| 	 */ | ||||
| 	if (state_filter == TASK_UNINTERRUPTIBLE && state == TASK_IDLE) | ||||
| 	if (state_filter == TASK_UNINTERRUPTIBLE && (state & TASK_NOLOAD)) | ||||
| 		return false; | ||||
| 
 | ||||
| 	return true; | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue
	
	 Peter Zijlstra
						Peter Zijlstra