diff options
author | Paul E. McKenney | 2014-10-23 20:41:22 +0200 |
---|---|---|
committer | Paul E. McKenney | 2014-10-29 18:07:04 +0100 |
commit | eca1a08986f622c11b75b3b44d561a1f901c9cec (patch) | |
tree | 15a635d885e693d2ee86aed4bcf988e8269d3606 | |
parent | rcu: Make rcu_barrier() understand about missing rcuo kthreads (diff) | |
download | kernel-qcow2-linux-eca1a08986f622c11b75b3b44d561a1f901c9cec.tar.gz kernel-qcow2-linux-eca1a08986f622c11b75b3b44d561a1f901c9cec.tar.xz kernel-qcow2-linux-eca1a08986f622c11b75b3b44d561a1f901c9cec.zip |
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>
-rw-r--r-- | kernel/signal.c | 30 |
1 files changed, 14 insertions, 16 deletions
diff --git a/kernel/signal.c b/kernel/signal.c index 8f0876f9f6dd..54820984a872 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -1331,23 +1331,21 @@ int kill_pid_info(int sig, struct siginfo *info, struct pid *pid) int error = -ESRCH; struct task_struct *p; - rcu_read_lock(); -retry: - p = pid_task(pid, PIDTYPE_PID); - if (p) { - error = group_send_sig_info(sig, info, p); - if (unlikely(error == -ESRCH)) - /* - * 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. - */ - goto retry; - } - rcu_read_unlock(); + for (;;) { + rcu_read_lock(); + p = pid_task(pid, PIDTYPE_PID); + if (p) + error = group_send_sig_info(sig, info, p); + rcu_read_unlock(); + if (likely(!p || error != -ESRCH)) + return error; - 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) |