for-linus-2020-01-03
-----BEGIN PGP SIGNATURE----- iHUEABYKAB0WIQRAhzRXHqcMeLMyaSiRxhvAZXjcogUCXg9C5wAKCRCRxhvAZXjc oiZXAPsGFXyDCWlKnShBpKufdFh6XugADlyZK0Si2ISWQoJJsgD/Ri1g3zg6V7YC HBG0sz8+vSk/Ys55yDQz+K1d1MTkdQ4= =8uQe -----END PGP SIGNATURE----- Merge tag 'for-linus-2020-01-03' of git://git.kernel.org/pub/scm/linux/kernel/git/brauner/linux Pull thread fixes from Christian Brauner: "Here are two fixes: - Panic earlier when global init exits to generate useable coredumps. Currently, when global init and all threads in its thread-group have exited we panic via: do_exit() -> exit_notify() -> forget_original_parent() -> find_child_reaper() This makes it hard to extract a useable coredump for global init from a kernel crashdump because by the time we panic exit_mm() will have already released global init's mm. We now panic slightly earlier. This has been a problem in certain environments such as Android. - Fix a race in assigning and reading taskstats for thread-groups with more than one thread. This patch has been waiting for quite a while since people disagreed on what the correct fix was at first" * tag 'for-linus-2020-01-03' of git://git.kernel.org/pub/scm/linux/kernel/git/brauner/linux: exit: panic before exit_mm() on global init exit taskstats: fix data-race
This commit is contained in:
commit
d9c82fd8c8
|
@ -517,10 +517,6 @@ static struct task_struct *find_child_reaper(struct task_struct *father,
|
||||||
}
|
}
|
||||||
|
|
||||||
write_unlock_irq(&tasklist_lock);
|
write_unlock_irq(&tasklist_lock);
|
||||||
if (unlikely(pid_ns == &init_pid_ns)) {
|
|
||||||
panic("Attempted to kill init! exitcode=0x%08x\n",
|
|
||||||
father->signal->group_exit_code ?: father->exit_code);
|
|
||||||
}
|
|
||||||
|
|
||||||
list_for_each_entry_safe(p, n, dead, ptrace_entry) {
|
list_for_each_entry_safe(p, n, dead, ptrace_entry) {
|
||||||
list_del_init(&p->ptrace_entry);
|
list_del_init(&p->ptrace_entry);
|
||||||
|
@ -766,6 +762,14 @@ void __noreturn do_exit(long code)
|
||||||
acct_update_integrals(tsk);
|
acct_update_integrals(tsk);
|
||||||
group_dead = atomic_dec_and_test(&tsk->signal->live);
|
group_dead = atomic_dec_and_test(&tsk->signal->live);
|
||||||
if (group_dead) {
|
if (group_dead) {
|
||||||
|
/*
|
||||||
|
* If the last thread of global init has exited, panic
|
||||||
|
* immediately to get a useable coredump.
|
||||||
|
*/
|
||||||
|
if (unlikely(is_global_init(tsk)))
|
||||||
|
panic("Attempted to kill init! exitcode=0x%08x\n",
|
||||||
|
tsk->signal->group_exit_code ?: (int)code);
|
||||||
|
|
||||||
#ifdef CONFIG_POSIX_TIMERS
|
#ifdef CONFIG_POSIX_TIMERS
|
||||||
hrtimer_cancel(&tsk->signal->real_timer);
|
hrtimer_cancel(&tsk->signal->real_timer);
|
||||||
exit_itimers(tsk->signal);
|
exit_itimers(tsk->signal);
|
||||||
|
|
|
@ -554,25 +554,33 @@ static int taskstats_user_cmd(struct sk_buff *skb, struct genl_info *info)
|
||||||
static struct taskstats *taskstats_tgid_alloc(struct task_struct *tsk)
|
static struct taskstats *taskstats_tgid_alloc(struct task_struct *tsk)
|
||||||
{
|
{
|
||||||
struct signal_struct *sig = tsk->signal;
|
struct signal_struct *sig = tsk->signal;
|
||||||
struct taskstats *stats;
|
struct taskstats *stats_new, *stats;
|
||||||
|
|
||||||
if (sig->stats || thread_group_empty(tsk))
|
/* Pairs with smp_store_release() below. */
|
||||||
goto ret;
|
stats = smp_load_acquire(&sig->stats);
|
||||||
|
if (stats || thread_group_empty(tsk))
|
||||||
|
return stats;
|
||||||
|
|
||||||
/* No problem if kmem_cache_zalloc() fails */
|
/* No problem if kmem_cache_zalloc() fails */
|
||||||
stats = kmem_cache_zalloc(taskstats_cache, GFP_KERNEL);
|
stats_new = kmem_cache_zalloc(taskstats_cache, GFP_KERNEL);
|
||||||
|
|
||||||
spin_lock_irq(&tsk->sighand->siglock);
|
spin_lock_irq(&tsk->sighand->siglock);
|
||||||
if (!sig->stats) {
|
stats = sig->stats;
|
||||||
sig->stats = stats;
|
if (!stats) {
|
||||||
stats = NULL;
|
/*
|
||||||
|
* Pairs with smp_store_release() above and order the
|
||||||
|
* kmem_cache_zalloc().
|
||||||
|
*/
|
||||||
|
smp_store_release(&sig->stats, stats_new);
|
||||||
|
stats = stats_new;
|
||||||
|
stats_new = NULL;
|
||||||
}
|
}
|
||||||
spin_unlock_irq(&tsk->sighand->siglock);
|
spin_unlock_irq(&tsk->sighand->siglock);
|
||||||
|
|
||||||
if (stats)
|
if (stats_new)
|
||||||
kmem_cache_free(taskstats_cache, stats);
|
kmem_cache_free(taskstats_cache, stats_new);
|
||||||
ret:
|
|
||||||
return sig->stats;
|
return stats;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Send pid data out on exit */
|
/* Send pid data out on exit */
|
||||||
|
|
Loading…
Reference in New Issue