kernel BUG at sched.c:944! only with CONFIG_PREEMPT=y]
A message that is not in the archive (sent off-list or not yet received): [email protected]
A message that is not in the archive (sent off-list or not yet received): [email protected]
PATCH 1/1 kernel BUG at sched.c:944! only with CONFIG_PREEMPT=y]
Quoted 10 lines · Steven Cole
Yes. Sorry, didn't catch this reply until now.
I backed out Changeset 1.606 which Linus did tokernel/sched.cdid this:(quoted diff) +1
-1- if (unlikely(in_interrupt())) + if (unlikely(in_atomic()))and 2.5.34-mm2 was able to boot with
CONFIG_PREEMPT=y.As I said in a response to myself on lkml, I know this isn't a fix, it just shows there is a problem somewhere with preempt.
No, there is not a problem in preempt... what this change does is BUG() out if schedule() is called while being in any way non-atomic.
While this sounds like a great debugging check, it is not useful in general since we surely have some bad code that calls schedule() with locks held. Further, since the atomic accounting only includes locks if CONFIG_PREEMPT is set, you only see this with kernel preemption enabled.
Linus, please back this out... attached patch is against current BK.
Yeah, I know we can change the BUG() to a show_stack() ... but I still think it will be too much and just deter people from using kernel preemption which is the opposite of what I want.
Robert Love
kernel/sched.c +1 -2
@@ -940,8 +940,7 @@struct list_head *queue;int idx; -if (unlikely (in_atomic ())) -BUG (); +BUG_ON (in_interrupt ());#if CONFIG_DEBUG_HIGHMEM check_highmem_ptes ();
Quoted 4 lines · Robert Love
While this sounds like a great debugging check, it is not useful in general since we surely have some bad code that calls
schedule()with locks held. Further, since the atomic accounting only includes locks ifCONFIG_PREEMPTis set, you only see this with kernel preemption enabled.
it *is* a great debugging check, at zero added cost. Scheduling from an atomic region *is* a critical bug that can and will cause problems in 99% of the cases. Rather fix the asserts that got triggered instead of backing out useful debugging checks ...
Ingo
Quoted 4 lines · Ingo Molnar
it *is* a great debugging check, at zero added cost. Scheduling from an atomic region *is* a critical bug that can and will cause problems in 99% of the cases. Rather fix the asserts that got triggered instead of backing out useful debugging checks ...
There are a lot of shitty drivers that this is going to catch. Yes, that is great... but we cannot BUG(). There really are a LOT of them. In the least, we need to show_trace().
Anyhow, this currently will catch _all_ kernel preemptions because the PREEMPT_ACTIVE flag is set.
We need to do something like the attached (untested), at the very least...
I would prefer to make this a kernel debugging check, however. Or, make using kernel preemption the default. Using the "free" abilities of kernel preemption is great, but not at the expense of its users.
Robert Love
kernel/sched.c +5 -3
@@ -940,8 +940,10 @@struct list_head *queue;int idx; -if (unlikely (in_atomic ())) -BUG (); +if (unlikely (in_atomic () &&preempt_count () !=PREEMPT_ACTIVE )) { +printk (KERN_ERROR "schedule() called while non-atomic!\n" ); +show_stack (NULL ); + }#if CONFIG_DEBUG_HIGHMEM check_highmem_ptes ();
@@ -959,7 +961,7 @@* if entering off of a kernel preemption go straight * to picking the next task. */ -if (unlikely (preempt_count () &PREEMPT_ACTIVE )) +if (unlikely (preempt_count () ==PREEMPT_ACTIVE )) goto pick_next_task;switch (prev->state) {
Quoted 41 lines · Robert Love
Quoted 4 lines · Ingo Molnar
it *is* a great debugging check, at zero added cost. Scheduling from an atomic region *is* a critical bug that can and will cause problems in 99% of the cases. Rather fix the asserts that got triggered instead of backing out useful debugging checks ...
There are a lot of shitty drivers that this is going to catch. Yes, that is great... but we cannot
BUG(). There really are a LOT of them. In the least, we need toshow_trace().Anyhow, this currently will catch _all_ kernel preemptions because the
PREEMPT_ACTIVEflag is set.We need to do something like the attached (untested), at the very least...
I would prefer to make this a kernel debugging check, however. Or, make using kernel preemption the default. Using the "free" abilities of kernel preemption is great, but not at the expense of its users.
Robert Love
diff -urN
linux-2.5.34/kernel/sched.clinux/kernel/sched.ckernel/sched.c +4
-2@@ -940,8 +940,10 @@struct list_head *queue;int idx; -if (unlikely (in_atomic ())) -BUG (); +if (unlikely (in_atomic () &&preempt_count () !=PREEMPT_ACTIVE )) { +printk (KERN_ERROR "schedule() called while non-atomic!\n" ); +show_stack (NULL ); + }#if CONFIG_DEBUG_HIGHMEM check_highmem_ptes ();
kernel/sched.c line 967
Quoted 8 lines
kernel/sched.c +1
-1@@ -959,7 +961,7 @@* if entering off of a kernel preemption go straight * to picking the next task. */ -if (unlikely (preempt_count () &PREEMPT_ACTIVE )) +if (unlikely (preempt_count () ==PREEMPT_ACTIVE )) goto pick_next_task;switch (prev->state) {
OK, that patch is tested now. I had to s/KERN_ERROR/KERN_ERR/, but I was able to get the system to spew out some "schedule() called while non-atomic!" messages along with the traces. I can type those into a file and run it through ksymoops if that would be helpful.
Steven
Quoted 6 lines · Robert Love
Quoted 4 lines
it *is* a great debugging check, at zero added cost. Scheduling from an atomic region *is* a critical bug that can and will cause problems in 99% of the cases. Rather fix the asserts that got triggered instead of backing out useful debugging checks ...
There are a lot of shitty drivers that this is going to catch. [...]
of course. And your point in making it in_interrupt() had what purpose - hiding that tons of code breaks preemption? [and tons of code breaks on SMP.] Your patch was removing precisely the tool that can be used to improve SMP quality on UP boxes as well.
Quoted 2 lines
[...] Yes, that is great... but we cannot
BUG(). There really are a LOT of them. In the least, we need toshow_trace().
yes. And we also need kallsyms and kksymoops in the kernel, so that people can send in meaningful traces.
Ingo
Quoted 4 lines · Ingo Molnar
of course. And your point in making it
in_interrupt()had what purpose - hiding that tons of code breaks preemption? [and tons of code breaks on SMP.] Your patch was removing precisely the tool that can be used to improve SMP quality on UP boxes as well.
Ingo, Attached is the latest patch I sent Linus. I never doubted the usefulness, just the practicality of having endusers parse so much information.
At any rate, the approach in Linus's BK is wrong because (a) the debug is hit way too often to just BUG() and (b) we have to take into account PREEMPT_ACTIVE.
Quoted 2 lines
yes. And we also need kallsyms and kksymoops in the kernel, so that people can send in meaningful traces.
Agree 100% here.
Robert Love
iff -urN linux-2.5.34/kernel/sched.c linux/kernel/sched.c
kernel/sched.c +5 -3
@@ -940,8 +940,10 @@struct list_head *queue;int idx; -if (unlikely (in_atomic ())) -BUG (); +if (unlikely (in_atomic () &&preempt_count () !=PREEMPT_ACTIVE )) { +printk (KERN_ERROR "schedule() called while non-atomic!\n" ); +show_stack (NULL ); + }#if CONFIG_DEBUG_HIGHMEM check_highmem_ptes ();
@@ -959,7 +961,7 @@* if entering off of a kernel preemption go straight * to picking the next task. */ -if (unlikely (preempt_count () &PREEMPT_ACTIVE )) +if (unlikely (preempt_count () ==PREEMPT_ACTIVE )) goto pick_next_task;switch (prev->state) {
kernel/sched.c line 946
Quoted 6 lines · Robert Love
kernel/sched.c +4
-2-if (unlikely (in_atomic ())) -BUG (); +if (unlikely (in_atomic () &&preempt_count () !=PREEMPT_ACTIVE )) { +printk (KERN_ERROR "schedule() called while non-atomic!\n" ); +show_stack (NULL ); + }
Actually, looking at this again, we probably want to still BUG() if in_interrupt() but _not_ if in_atomic().
Robert Love
Hi,
Quoted 3 lines · Robert Love
On Fri, 2002-09-13 at 03:36, Robert Love wrote:
Actually, looking at this again, we probably want to stillBUG()ifin_interrupt()but _not_ ifin_atomic().
- if (unlikely(in_atomic()))
- BUG();
+ if (unlikely((in_interrupt() || (!in_atomic())) && preempt_count() != PREEMPT_ACTIVE)) {
+ printk(KERN_ERROR "schedule() called while non-atomic, or in interrupt!\n");
+ show_stack(NULL);
+ }
?
Thunder
Signature · 4 lines
--./../...-/. -.--/---/..-/.-./..././.-../..-. .---/..-/.../- .- --/../-./..-/-/./--..-- ../.----./.-../.-.. --./../...-/. -.--/---/..- .- -/---/--/---/.-./.-./---/.--/.-.-.- --./.-/-.../.-./.././.-../.-.-.-
Quoted 8 lines · Ingo Molnar
Quoted 4 lines · Robert Love
While this sounds like a great debugging check, it is not useful in general since we surely have some bad code that calls
schedule()with locks held. Further, since the atomic accounting only includes locks ifCONFIG_PREEMPTis set, you only see this with kernel preemption enabled.
Quoted 5 lines
it *is* a great debugging check, at zero added cost. Scheduling from an atomic region *is* a critical bug that can and will cause problems in 99% of the cases. Rather fix the asserts that got triggered instead of backing out useful debugging checks ...
The problem here is that some random piece of code has bumped the preemption counter, and we've lost all trace of that at the site where the problem is detected.
So... In do_initcalls() we'd need:
do {
(*call)();
+ if (in_atomic())
+ printk("initcall at %p is buggy\n", call);
call++;
} while (call < &__initcall_end);and to diagnose this particular problem I guess we need to add
if (in_atomic())
printk("goofed at %d\n", __LINE__);to twenty or so places in start_kernel().