Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

sched/core: Robustify preemption leak checks

When we warn about a preempt_count leak; reset the preempt_count to
the known good value such that the problem does not ripple forward.

This is most important on x86 which has a per cpu preempt_count that is
not saved/restored (after this series). So if you schedule with an
invalid (!2*PREEMPT_DISABLE_OFFSET) preempt_count the next task is
messed up too.

Enforcing this invariant limits the borkage to just the one task.

Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Reviewed-by: Frederic Weisbecker <fweisbec@gmail.com>
Reviewed-by: Thomas Gleixner <tglx@linutronix.de>
Reviewed-by: Steven Rostedt <rostedt@goodmis.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: linux-kernel@vger.kernel.org
Signed-off-by: Ingo Molnar <mingo@kernel.org>

authored by

Peter Zijlstra and committed by
Ingo Molnar
1dc0fffc 3d8f74dd

+6 -2
+3 -1
kernel/exit.c
··· 706 706 smp_mb(); 707 707 raw_spin_unlock_wait(&tsk->pi_lock); 708 708 709 - if (unlikely(in_atomic())) 709 + if (unlikely(in_atomic())) { 710 710 pr_info("note: %s[%d] exited with preempt_count %d\n", 711 711 current->comm, task_pid_nr(current), 712 712 preempt_count()); 713 + preempt_count_set(PREEMPT_ENABLED); 714 + } 713 715 714 716 /* sync mm's RSS info before statistics gathering */ 715 717 if (tsk->mm)
+3 -1
kernel/sched/core.c
··· 2968 2968 BUG_ON(unlikely(task_stack_end_corrupted(prev))); 2969 2969 #endif 2970 2970 2971 - if (unlikely(in_atomic_preempt_off())) 2971 + if (unlikely(in_atomic_preempt_off())) { 2972 2972 __schedule_bug(prev); 2973 + preempt_count_set(PREEMPT_DISABLED); 2974 + } 2973 2975 rcu_sleep_check(); 2974 2976 2975 2977 profile_hit(SCHED_PROFILING, __builtin_return_address(0));