signal: Exit RCU read-side critical section on each pass through loop
The kill_pid_info() can potentially loop indefinitely if tasks are created and deleted sufficiently quickly, and if this happens, this function will remain in a single RCU read-side critical section indefinitely. This commit therefore exits the RCU read-side critical section on each pass through the loop. Because a race must happen to retry the loop, this should have no performance impact in the common case. Reported-by: Dave Jones <davej@redhat.com> Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com> Acked-by: Oleg Nesterov <oleg@redhat.com> Reviewed-by: Pranith Kumar <bobby.prani@gmail.com>
This commit is contained in:
		
					parent
					
						
							
								d7e2993396
							
						
					
				
			
			
				commit
				
					
						eca1a08986
					
				
			
		
					 1 changed files with 14 additions and 16 deletions
				
			
		| 
						 | 
					@ -1331,23 +1331,21 @@ int kill_pid_info(int sig, struct siginfo *info, struct pid *pid)
 | 
				
			||||||
	int error = -ESRCH;
 | 
						int error = -ESRCH;
 | 
				
			||||||
	struct task_struct *p;
 | 
						struct task_struct *p;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rcu_read_lock();
 | 
						for (;;) {
 | 
				
			||||||
retry:
 | 
							rcu_read_lock();
 | 
				
			||||||
	p = pid_task(pid, PIDTYPE_PID);
 | 
							p = pid_task(pid, PIDTYPE_PID);
 | 
				
			||||||
	if (p) {
 | 
							if (p)
 | 
				
			||||||
		error = group_send_sig_info(sig, info, p);
 | 
								error = group_send_sig_info(sig, info, p);
 | 
				
			||||||
		if (unlikely(error == -ESRCH))
 | 
							rcu_read_unlock();
 | 
				
			||||||
			/*
 | 
							if (likely(!p || error != -ESRCH))
 | 
				
			||||||
			 * The task was unhashed in between, try again.
 | 
								return error;
 | 
				
			||||||
			 * If it is dead, pid_task() will return NULL,
 | 
					 | 
				
			||||||
			 * if we race with de_thread() it will find the
 | 
					 | 
				
			||||||
			 * new leader.
 | 
					 | 
				
			||||||
			 */
 | 
					 | 
				
			||||||
			goto retry;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	rcu_read_unlock();
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return error;
 | 
							/*
 | 
				
			||||||
 | 
							 * The task was unhashed in between, try again.  If it
 | 
				
			||||||
 | 
							 * is dead, pid_task() will return NULL, if we race with
 | 
				
			||||||
 | 
							 * de_thread() it will find the new leader.
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int kill_proc_info(int sig, struct siginfo *info, pid_t pid)
 | 
					int kill_proc_info(int sig, struct siginfo *info, pid_t pid)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue