4.0.0-rc4: panic in free_block
Subsystems (2)
I can easily reproduce the panic below doing a kernel build with make -j N, N=128, 256, etc. This is a 1024 cpu system running 4.0.0-rc4.
The top 3 frames are consistently:
free_block+0x60
cache_flusharray+0xac
kmem_cache_free+0xfcAfter that one path has been from __mmdrop and the others are like below, from remove_vma.
Unable to handle kernel paging request at virtual address 0006100000000000
tsk->{mm,active_mm}->context = 00000000000000ce
tsk->{mm,active_mm}->pgd = fff8803b56698000
\|/ ____ \|/
"@'/ .. \`@"
/_| \__/ |_\
\__U_/
sh(173167): Oops [#1]
CPU: 760 PID: 173167 Comm: sh Not tainted 4.0.0-rc4+ #1
task: fff8803b4e928b00 ti: fff8803b51800000 task.ti: fff8803b51800000
TSTATE: 0000009911e01601 TPC: 000000000055de88 TNPC: 000000000055de8c Y: 000003f0 Not tainted
TPC: <free_block+0x60/0x16c>
g0: fff1ffef00000001 g1: fff8803b75826e00 g2: 0000000000100100 g3: 0000100000000000
g4: fff8803b4e928b00 g5: fff8803b76664000 g6: fff8803b51800000 g7: 0006000000000000
o0: 0000000000008000 o1: 0000000000000046 o2: 0000000000000023 o3: 00060100767db6a0
o4: 0000000000000000 o5: 0000000000000015 sp: fff8803b51802d11 ret_pc: fff8803b75826e08RPC: <0xfff8803b75826e08>
l0: 0000000000200200 l1: 0000000000c005e8 l2: 0000000000d7e2b8 l3: fff8803b3edb4000
l4: 0000000000000007 l5: 0000000000000001 l6: 00000000000000b1 l7: ffffffffffefffff
i0: fff8000050409c60 i1: fff8803b7738f168 i2: 000000000000003c i3: fff8803b75826e28
i4: fff8803b51803670 i5: 0000000000000000 i6: fff8803b51802dc1 i7: 000000000055eaa4
I7: <cache_flusharray+0xac/0xf4>
Call Trace: [000000000055eaa4] cache_flusharray+0xac/0xf4 [000000000055e66c] kmem_cache_free+0xfc/0x1ac [000000000054139c] remove_vma+0x68/0x78 [00000000005414ac] exit_mmap+0x100/0x130 [000000000045acb4] mmput+0x50/0xe8 [000000000056c284] flush_old_exec+0x500/0x5d8 [00000000005b0614] load_elf_binary+0x254/0xff4 [000000000056ba70] search_binary_handler+0xa4/0x28c [000000000056d068] do_execveat_common+0x44c/0x624 [000000000056d3e0] do_execve+0x34/0x48 [000000000056d40c] SyS_execve+0x18/0x2c [0000000000406254] linux_sparc_syscall+0x34/0x44
Disabling lock debugging due to kernel taint
Caller[000000000055eaa4]: cache_flusharray+0xac/0xf4
Caller[000000000055e66c]: kmem_cache_free+0xfc/0x1ac
Caller[000000000054139c]: remove_vma+0x68/0x78
Caller[00000000005414ac]: exit_mmap+0x100/0x130
Caller[000000000045acb4]: mmput+0x50/0xe8
Caller[000000000056c284]: flush_old_exec+0x500/0x5d8
Caller[00000000005b0614]: load_elf_binary+0x254/0xff4
Caller[000000000056ba70]: search_binary_handler+0xa4/0x28c
Caller[000000000056d068]: do_execveat_common+0x44c/0x624
Caller[000000000056d3e0]: do_execve+0x34/0x48
Caller[000000000056d40c]: SyS_execve+0x18/0x2c
Caller[0000000000406254]: linux_sparc_syscall+0x34/0x44
Caller[fff80001004134c8]: 0xfff80001004134c8
Instruction DUMP: 86230003 8730f00d 8728f006 <d658c007> 8600c007 8e0ac008 2ac1c002 c658e030 d458e028
####
objdump for free_block on the vmlinux:
vmlinux-4.0.0-rc4+: file format elf64-sparc
Disassembly of section .text:
000000000055de28 <free_block>:free_block():
...free_block():/opt/dahern/linux.git/kbuild/../mm/slab.c:3265
55de64: 10 68 00 47 b %xcc, 55df80 <free_block+0x158> 55de68: 85 30 b0 02 srlx %g2, 2, %g2 clear_obj_pfmemalloc(): /opt/dahern/linux.git/kbuild/../mm/slab.c:224 55de6c: 98 0b 3f fe and %o4, -2, %o4 55de70: d8 76 40 00 stx %o4, [ %i1 ] virt_to_head_page(): /opt/dahern/linux.git/kbuild/../include/linux/mm.h:554 55de74: c6 5c 80 00 ldx [ %l2 ], %g3 55de78: ce 5c 40 00 ldx [ %l1 ], %g7 55de7c: 86 23 00 03 sub %o4, %g3, %g3 55de80: 87 30 f0 0d srlx %g3, 0xd, %g3 55de84: 87 28 f0 06 sllx %g3, 6, %g3
test_bit():/opt/dahern/linux.git/kbuild/../include/asm-generic/bitops/non-atomic.h:105
55de88: d6 58 c0 07 ldx [ %g3 + %g7 ], %o3virt_to_head_page():/opt/dahern/linux.git/kbuild/../include/linux/mm.h:554
55de8c: 86 00 c0 07 add %g3, %g7, %g3
...
Let me know if you need anything else.
[ Added Davem and the sparc mailing list, since it happens on sparc and that just makes me suspicious ]
Quoted 2 lines · David Ahern
I can easily reproduce the panic below doing a kernel build with make -j N, N8, 256, etc. This is a 1024 cpu system running 4.0.0-rc4.
3.19 is fine? Because I dont' think I've seen any reports like this for others, and what stands out is sparc (and to a lesser degree "1024 cpus", which obviously gets a lot less testing)
Quoted 9 lines
The top 3 frames are consistently:
free_block+0x60 cache_flusharray+0xac kmem_cache_free+0xfcAfter that one path has been from
__mmdropand the others are like below, fromremove_vma.Unable to handle kernel paging request at virtual address 0006100000000000
One thing you *might* check is if the problem goes away if you select CONFIG_SLUB instead of CONFIG_SLAB. I'd really like to just get rid of SLAB. The whole "we have multiple different allocators" is a mess and causes test coverage issues.
Apart from testing with CONFIG_SLUB, if 3.19 is ok and you seem to be able to "easily reproduce" this, the obvious thing to do is to try to bisect it.
Linus
Quoted 10 lines · Linus Torvalds
[ Added Davem and the sparc mailing list, since it happens on sparc and that just makes me suspicious ]
Quoted 2 lines · David Ahern
I can easily reproduce the panic below doing a kernel build with make -j N, N8, 256, etc. This is a 1024 cpu system running 4.0.0-rc4.
3.19 is fine? Because I dont' think I've seen any reports like this for others, and what stands out is sparc (and to a lesser degree "1024 cpus", which obviously gets a lot less testing)
I haven't tried 3.19 yet. Just backed up to 3.18 and it shows the same problem. And I can reproduce the 4.0 crash in a 128 cpu ldom (VM).
Quoted 11 lines
Quoted 10 lines
The top 3 frames are consistently:
free_block+0x60 cache_flusharray+0xac kmem_cache_free+0xfcAfter that one path has been from
__mmdropand the others are like below, fromremove_vma.Unable to handle kernel paging request at virtual address 0006100000000000
Quoted 8 lines
One thing you *might* check is if the problem goes away if you select
CONFIG_SLUBinstead ofCONFIG_SLAB. I'd really like to just get rid of SLAB. The whole "we have multiple different allocators" is a mess and causes test coverage issues.Apart from testing with
CONFIG_SLUB, if 3.19 is ok and you seem to be able to "easily reproduce" this, the obvious thing to do is to try to bisect it.
I'll try SLUB. The ldom reboots 1000 times faster then resetting the h/w so a better chance of bisecting - if I can find a known good release.
David
Quoted 3 lines · David Ahern
I haven't tried 3.19 yet. Just backed up to 3.18 and it shows the same problem. And I can reproduce the 4.0 crash in a 128 cpu ldom (VM).
Ok, so if 3.18 also has it, then trying 3.19 is pointless, this is obviously an old problem. Which makes it even more likely that it's sparc-related.
128 cpu's is still "unusual", of course, but by no means unheard of, and I'f have expected others to report it too if it was wasy to trigger on x86-64.
That said, SLAB is probably also almost unheard of in high-CPU configurations, since slub has all the magical unlocked lists etc for scalability. So maybe it's a generic SLAB bug, and nobody with lots of CPU's is testing SLAB.
Linus
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 5 lines · Linus Torvalds
That said, SLAB is probably also almost unheard of in high-CPU configurations, since slub has all the magical unlocked lists etc for scalability. So maybe it's a generic SLAB bug, and nobody with lots of CPU's is testing SLAB.
Evidently, it is a well known problem internally that goes back to at least 2.6.39.
To this point I have not paid attention to the allocators. At what point is SLUB considered stable for large systems? Is 2.6.39 stable?
As for SLAB it is not clear if this is a sparc only problem. Perhaps the config should have a warning? It looks like SLAB is still the default for most arch.
DaveM: do you mind if I submit a patch to change the default for sparc to SLUB?
Now that the monster is unleashed, off to other problems...
Thanks,
David
Quoted 6 lines · David Ahern
Evidently, it is a well known problem internally that goes back to at least 2.6.39.
To this point I have not paid attention to the allocators. At what point is SLUB considered stable for large systems? Is 2.6.39 stable?
SLUB should definitely be considered a stable allocator. It's the default allocator for at least Fedora, and that presumably means all of Redhat.
SuSE seems to use SLAB still, though, so it must be getting lots of testing on x86 too.
Did you test with SLUB? Does it work there?
Quoted 3 lines
As for SLAB it is not clear if this is a sparc only problem. Perhaps the config should have a warning? It looks like SLAB is still the default for most arch.
I definitely think SLAB should work (although I *would* like to get rid of the duplicate allocators), and I still do think it's likely a sparc issue. Especially as it apparently goes way back. x86 gets a *lot* more testing, and I don't really recall anything like this.
I'm not comfy enough reading sparc asm code to really pinpoint exactly what looks to go wrong, so I have very little input on what the problem could be.
Linus
Quoted 8 lines · Linus Torvalds
SLUB should definitely be considered a stable allocator. It's the default allocator for at least Fedora, and that presumably means all of Redhat.
SuSE seems to use SLAB still, though, so it must be getting lots of testing on x86 too.
Did you test with SLUB? Does it work there?
sorry, forgot to add that detail in the last response: it works fine. No panics at all with SLUB.
David
David Miller
maintainerFrom: David Ahern <[email protected]>
Date: Fri, 20 Mar 2015 12:05:05 -0600
Quoted 2 lines
DaveM: do you mind if I submit a patch to change the default for sparc to SLUB?
I think we're jumping the gun about all of this, and doing anything with default Kconfig settings would be entirely premature until we know what the real bug is.
On my T4-2 I've used nothing but SLAB and haven't hit any of these problems. I can't even remember the last time I turned SLUB on, and it's just because I'm lazy.
Quoted 9 lines · David Miller
From: David Ahern <[email protected]>
Date: Fri, 20 Mar 2015 12:05:05 -0600Quoted 2 lines
DaveM: do you mind if I submit a patch to change the default for sparc to SLUB?
I think we're jumping the gun about all of this, and doing anything with default
Kconfigsettings would be entirely premature until we know what the real bug is.
The suggestion to change to SLUB as the default was based on Linus' comment "SLAB is probably also almost unheard of in high-CPU configurations, since slub has all the magical unlocked lists etc for scalability."
Quoted 5 lines
On my T4-2 I've used nothing but SLAB and haven't hit any of these problems. I can't even remember the last time I turned SLUB on, and it's just because I'm lazy.
Interesting. With -j <64 and talking softly it completes. But -j 128 and higher always ends in a panic.
David Miller
maintainerFrom: David Ahern <[email protected]>
Date: Fri, 20 Mar 2015 13:54:09 -0600
Quoted 2 lines
Interesting. With -j <64 and talking softly it completes. But -j 128 and higher always ends in a panic.
Please share more details of your configuration.
David Miller
maintainerFrom: Linus Torvalds <[email protected]>
Date: Fri, 20 Mar 2015 09:58:25 -0700
Quoted 1 line
128 cpu's is still "unusual"
As unusual as the system I do all of my kernel builds on :-)
Quoted 3 lines · Linus Torvalds
128 cpu's is still "unusual", of course, but by no means unheard of, and I'f have expected others to report it too if it was wasy to trigger on x86-64.
FWIW, I configured a kernel with SLAB and kicked off a bunch of compiles on a 160-thread x86_64 system. It definitely doesn't die _quickly_. It's been running for an hour or two.
Quoted 1 line · David Ahern
Instruction DUMP: 86230003
8730f00d8728f006<d658c007>8600c0078e0ac0082ac1c002c658e030d458e028
Ok, so it's d658c007 that faults, which is that
ldx [ %g3 + %g7 ], %o3
instruction.
Looking at your objdump:
Quoted 15 lines
free_block():/opt/dahern/linux.git/kbuild/../mm/slab.c:326555de64: 10 68 00 47 b %xcc, 55df80 <free_block+0x158> 55de68: 85 30 b0 02 srlx %g2, 2, %g2 clear_obj_pfmemalloc(): /opt/dahern/linux.git/kbuild/../mm/slab.c:224 55de6c: 98 0b 3f fe and %o4, -2, %o4 55de70: d8 76 40 00 stx %o4, [ %i1 ] virt_to_head_page(): /opt/dahern/linux.git/kbuild/../include/linux/mm.h:554 55de74: c6 5c 80 00 ldx [ %l2 ], %g3 55de78: ce 5c 40 00 ldx [ %l1 ], %g7 55de7c: 86 23 00 03 sub %o4, %g3, %g3 55de80: 87 30 f0 0d srlx %g3, 0xd, %g3 55de84: 87 28 f0 06 sllx %g3, 6, %g3
Quoted 6 lines
test_bit():/opt/dahern/linux.git/kbuild/../include/asm-generic/bitops/non-atomic.h:105
55de88: d6 58 c0 07 ldx [ %g3 + %g7 ], %o3virt_to_head_page():/opt/dahern/linux.git/kbuild/../include/linux/mm.h:554
55de8c: 86 00 c0 07 add %g3, %g7, %g3
I think that's the load of "page->flags" which is almost certainly part of that initial
page = virt_to_head_page(objp);
at the top of the loop in free_block(). In fact, it's probably from compound_head_fast() which does
if (unlikely(PageTail(page)))
if (likely(__get_page_tail(page)))
return;so I think it's about to test the PG_tail bit.
So it's the virt_to_page(x) that has returned 0006100000000000. For sparc64, that's
#define virt_to_page(kaddr) pfn_to_page(__pa(kaddr)>>PAGE_SHIFT)
Looking at the code generation, I think %g7 (0x0006000000000000) is VMEMMAP_BASE, and %g3 is "pfn << 6", where the "<< 6" is because a "struct page" is 64 bytes.
And looking at that
sub %o4, %g3, %g3
I think that's "__pa(x)", so I think %o4 is 'x'. That also matches the "and %o4, -2, %o4", which would be the clear_obj_pfmemalloc().
And %o4 is 0.
In other words, if I read that sparc asm right (and it is very likely that I do *not*), then "objp" is NULL, and that's why you crash.
That's odd, because we know that objp cannot be NULL in kmem_slab_free() (even if we allowed it, like with kfree(), remove_vma() cannot possibly have a NULL vma, since ti dereferences it multiple times).
So I must be misreading this completely. Somebody with better sparc debugging mojo should double-check my logic. How would objp be NULL?
Linus
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 2 lines · Linus Torvalds
In other words, if I read that sparc asm right (and it is very likely that I do *not*), then "objp" is NULL, and that's why you crash.
That does appear to be why. I put a WARN_ON before clear_obj_pfmemalloc() if objpp[i] is NULL. I got 2 splats during an 'allyesconfig' build and the system stayed up.
Quoted 8 lines
That's odd, because we know that objp cannot be NULL in
kmem_slab_free()(even if we allowed it, like withkfree(),remove_vma()cannot possibly have a NULL vma, since ti dereferences it multiple times).So I must be misreading this completely. Somebody with better sparc debugging mojo should double-check my logic. How would objp be NULL?
I'll add checks to higher layers and see if it reveals anything.
I did ask around and apparently this bug is hit only with the new M7 processors. DaveM: that's why you are not hitting this.
David
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 14 lines · David Ahern
Quoted 2 lines · Linus Torvalds
In other words, if I read that sparc asm right (and it is very likely that I do *not*), then "objp" is NULL, and that's why you crash.
That does appear to be why. I put a
WARN_ONbeforeclear_obj_pfmemalloc()if objpp[i] is NULL. I got 2 splats during an 'allyesconfig' build and the system stayed up.Quoted 6 lines
That's odd, because we know that objp cannot be NULL in
kmem_slab_free()(even if we allowed it, like withkfree(),remove_vma()cannot possibly have a NULL vma, since ti dereferences it multiple times).
Quoted 7 lines
Quoted 2 lines
So I must be misreading this completely. Somebody with better sparc debugging mojo should double-check my logic. How would objp be NULL?
I'll add checks to higher layers and see if it reveals anything.
I did ask around and apparently this bug is hit only with the new M7 processors. DaveM: that's why you are not hitting this.
Here's another data point: If I disable NUMA I don't see the problem. Performance drops, but no NULL pointer splats which would have been panics.
The 128 cpu ldom with NUMA enabled shows the problem every single time I do a kernel compile (-j 128). With NUMA disabled I have done 3 allyesconfig compiles without hitting the problem. I'll put the compiles into a loop while I head out for dinner.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 8 lines · David Ahern
Here's another data point: If I disable NUMA I don't see the problem. Performance drops, but no NULL pointer splats which would have been panics.
The 128 cpu ldom with NUMA enabled shows the problem every single time I do a kernel compile (-j 128). With NUMA disabled I have done 3 allyesconfig compiles without hitting the problem. I'll put the compiles into a loop while I head out for dinner.
It might be helpful to enable CONFIG_DEBUG_SLAB if you're reproducing it.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 5 lines · David Rientjes
Quoted 3 lines · David Ahern
Here's another data point: If I disable NUMA I don't see the problem. Performance drops, but no NULL pointer splats which would have been panics.
Quoted 8 lines
Quoted 5 lines
The 128 cpu ldom with NUMA enabled shows the problem every single time I do a kernel compile (-j 128). With NUMA disabled I have done 3 allyesconfig compiles without hitting the problem. I'll put the compiles into a loop while I head out for dinner.
It might be helpful to enable
CONFIG_DEBUG_SLABif you're reproducing it.
I enabled that and a few other DEBUG configs earlier -- nothing popped out. I'll do it again -- and others when I return.
Quoted 4 lines · David Ahern
Quoted 3 lines · David Ahern
I did ask around and apparently this bug is hit only with the new M7 processors. DaveM: that's why you are not hitting this.
Quite frankly, this smells even more like an architecture bug. It could be anywhere: it could be a CPU memory ordering issue, a compiler bug, or a missing barrier or other thing.
How confident are you in the M7 memory ordering rules? It's a fairly new core, no? With new speculative reads etc? Maybe the Linux spinlocks don't have the right serialization, and more aggressive reordering in the new core shows a bug?
Looking at this code, if this is a race, I see a few things that are worth checking out
- it does a very much overlapping "memmove()". Thesparc/lib/memmove.S file looks suspiciously bad (is that a byte-at-a-time loop? Is it even correctly checking overlap?)
- it relies on both percpu data and a spinlock. I'm sure the sparc
spinlock code has been tested *extensively* with old cores, but maybe some new speculative read ends up breaking them?
I'm assuming M7 still TSO and 'ldsub' has acquire semantics? Is it configurable like some sparc versions? I'm wondering whether the Solaris locks might have some extra memory barriers due to supporting the other (weaker) sparc memory models, and maybe they hid some M7 "feature" by mistake...
*Some* of the sparc memcpy routines have odd membar's in them. Why would a TSO machine need a memory barrier inside a memcpy. That just makes me go "Ehh?"
Quoted 2 lines
Here's another data point: If I disable NUMA I don't see the problem. Performance drops, but no NULL pointer splats which would have been panics.
So the NUMA case triggers the per-node "n->shared" logic, which *should* be protected by "n->list_lock". Maybe there is some bug there
- but since that code seems to do ok on x86-64 (and apparently older sparc too), I really would look at arch-specific issues first.
Linus
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 8 lines · Linus Torvalds
Quoted 3 lines
Here's another data point: If I disable NUMA I don't see the problem. Performance drops, but no NULL pointer splats which would have been panics.
So the NUMA case triggers the per-node "
n->shared" logic, which *should* be protected by "n->list_lock". Maybe there is some bug there
- but since that code seems to do ok on x86-64 (and apparently older sparc too), I really would look at arch-specific issues first.
You raise a lot of valid questions and something to look into. But if the root cause were such a fundamental issue (CPU memory ordering, compiler bug, etc) why would it only occur on this one code path -- free with SLAB and NUMA -- and so consistently?
Continuing to poke around, but open to any suggestions. I have enabled every DEBUG I can find in the memory code and nothing is popping out. In terms of races wouldn't all the DEBUG checks affect timing? Yet, I am still seeing the same stack traces due to the same root cause.
David
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 5 lines · David Ahern
You raise a lot of valid questions and something to look into. But if the root cause were such a fundamental issue (CPU memory ordering, compiler bug, etc) why would it only occur on this one code path -- free with SLAB and NUMA -- and so consistently?
So the consistency could easily come from a compiler bug (or a missing barrier in the kernel code) that just happens to trigger in a single place (or in a few places, but then that's the only place that gets exercised heavily enough to show it).
I agree that an actual hardware bug is unlikely, although that too is
possible: I can pretty much guarantee that if it were a CPU bug, it wouldn't be some "memory ordering is entirely broken" bug in general, it would be some very specific case that only happens with just the right instruction timing and mix.
That said, while I bring up a CPU bug as a possibility, I really do agree that it is *very* unlikely. Memory ordering is hard, and yes, you can get it wrong, but at the same time CPU designers very much know about it and tend to be pretty damn good about it. And as you say, it generally wouldn't be *that* consistent. It might be consistent for one particular kernel build (due to very particular instruction mix and timings), but over lots of versions of the code and many different debug options? Very very very unlikely.
Quoted 4 lines
Continuing to poke around, but open to any suggestions. I have enabled every DEBUG I can find in the memory code and nothing is popping out. In terms of races wouldn't all the DEBUG checks affect timing? Yet, I am still seeing the same stack traces due to the same root cause.
Yes, generally debug options would change timings sufficiently that any particular low-level race would certainly go away or at least become much harder to hit. So if you have enabled spinlock debugging etc, I don't really believe in a hw bug. It's more likely that there is some kernel architecture-specific code that triggers it. Or even generic code that just happens to work on other cases due to random issues (ie memory alignment etc).
I *would* suggest looking at that "memmove()" code. It really looks like crap. It seems to do things byte-at-a-time for the overlapping case, and the code seems to depend on memcpy always doing things low-to-high, but there are multiple different memcpy implementations so I don't know that that is always true. If one of the memcpy functions sometimes copies the other way depending on size etc, it could screw up.
Basically, that sparc64 memmove() implementation looks like it was written by a dyslexic 5-year-old as a throw-away hack, and then never got fixed.
Davem? I don't read sparc assembly, so I'm *really* not going to try to verify that (a) all the memcpy implementations always copy low-to-high and (b) that I even read the address comparisons in memmove.S right.
I mention memmove just because it's actually fairly unusual for the kernel. At the same time, if it really is broken for overlapping regions, I'd expect *some* other places to show breakage too. So it's probably fine, even if it does look very very bad to do things one byte at a time backwards as a fallback.
Linus
David Miller
maintainerFrom: Linus Torvalds <[email protected]>
Date: Sat, 21 Mar 2015 11:49:12 -0700
Quoted 4 lines
Davem? I don't read sparc assembly, so I'm *really* not going to try to verify that (a) all the memcpy implementations always copy low-to-high and (b) that I even read the address comparisons in
memmove.Sright.
All of the sparc memcpy implementations copy from low to high. I'll eat my hat if they don't. :-)
The guard tests at the beginning of memmove() are saying:
if (dst <= src) memcpy(...); if (src + len <= dst) memcpy(...);
And then the reverse copy loop (and we do have to copy in reverse for correctness) is basically:
src = (src + len - 1); dst = (dst + len - 1);
1: tmp = *(u8 *)src; len -= 1; src -= 1; *(u8 *)dst = tmp; dst -= 1; if (len != 0) goto 1b;
And then we return the original 'dst' pointer.
So at first glance it looks at least correct.
memmove() is a good idea to look into though, as SLAB and SLUB are the only really heavy users of it, and they do so with overlapping contents.
And they end up using that byte-at-a-time code, since SLAB and SLUB do mmemove() calls of the form:
memmove(X + N, X, LEN);
In which case neither of the memcpy() guard tests will pass.
Maybe there is some subtle bug in there I just don't see right now.
David Miller wrote: [Sun Mar 22 2015, 01:36:03PM EDT]
Quoted 40 lines
From: Linus Torvalds <[email protected]>
Date: Sat, 21 Mar 2015 11:49:12 -0700Quoted 4 lines
Davem? I don't read sparc assembly, so I'm *really* not going to try to verify that (a) all the memcpy implementations always copy low-to-high and (b) that I even read the address comparisons in
memmove.Sright.All of the sparc memcpy implementations copy from low to high. I'll eat my hat if they don't. :-)
The guard tests at the beginning of
memmove()are saying:if (dst <= src) memcpy(...); if (src + len <= dst) memcpy(...);And then the reverse copy loop (and we do have to copy in reverse for correctness) is basically:
src = (src + len - 1); dst = (dst + len - 1);1: tmp = *(u8 *)src; len -= 1; src -= 1; *(u8 *)dst = tmp; dst -= 1; if (len != 0) goto 1b;And then we return the original 'dst' pointer.
So at first glance it looks at least correct.
memmove()is a good idea to look into though, as SLAB and SLUB are the only really heavy users of it, and they do so with overlapping contents.
Quoted 8 lines
And they end up using that byte-at-a-time code, since SLAB and SLUB do
mmemove()calls of the form:memmove(X + N, X, LEN);In which case neither of the
memcpy()guard tests will pass.Maybe there is some subtle bug in there I just don't see right now.
My original pursuit of this issue focused on transfers to and from the shared array. Basically substituting memcpy-s with a primitive unsigned long memory mover. This might have been incorrect.
There were substantial doubts because of large modifications to 2.6.39 too. Unstabile hardware cause(d|s) issue too.
Eliminating the shared array functions correctly. Though this removal changes performance and timing dramatically.
This afternoon I included modification of two memmove-s and no issue thus far. The issue APPEARS to come from memmove-s within cache_flusharray() and/or drain_array(). Now we are covering moves within an array_cache.
The above was done on 2.6.39.
Quoted 5 lines · David Miller
And they end up using that byte-at-a-time code, since SLAB and SLUB do
mmemove()calls of the form:memmove(X + N, X, LEN);
Actually, the common case in slab is overlapping but of the form
memmove(p, p+x, len);
which goes to memcpy. It's basically re-compacting the array at the beginning.
Which was why I was asking how sure you are that memcpy *always* copies from low to high.
I don't even know which version of memcpy ends up being used on M7. Some of them do things like use VIS. I can follow some regular sparc asm, there's no way I'm even *looking* at that. Is it really ok to use VIS registers in random contexts?
Linus
David Miller
maintainerFrom: Linus Torvalds <[email protected]>
Date: Sun, 22 Mar 2015 12:47:08 -0700
Quoted 2 lines
Which was why I was asking how sure you are that memcpy *always* copies from low to high.
Yeah I'm pretty sure.
Quoted 4 lines
I don't even know which version of memcpy ends up being used on M7. Some of them do things like use VIS. I can follow some regular sparc asm, there's no way I'm even *looking* at that. Is it really ok to use VIS registers in random contexts?
Yes, using VIS how we do is alright, and in fact I did an audit of this about 1 year ago. This is another one of those "if this is wrong, so much stuff would break"
The only thing funny some of these routines do is fetch 2 64-byte blocks of data ahead in the inner loops, but that should be fine right?
On the M7 we'll use the Niagara-4 memcpy.
Hmmm... I'll run this silly sparc kernel memmove through the glibc testsuite and see if it barfs.
Quoted 9 lines · David Miller
Quoted 4 lines
I don't even know which version of memcpy ends up being used on M7. Some of them do things like use VIS. I can follow some regular sparc asm, there's no way I'm even *looking* at that. Is it really ok to use VIS registers in random contexts?
Yes, using VIS how we do is alright, and in fact I did an audit of this about 1 year ago. This is another one of those "if this is wrong, so much stuff would break"
Quoted 9 lines
The only thing funny some of these routines do is fetch 2 64-byte blocks of data ahead in the inner loops, but that should be fine right?
On the M7 we'll use the Niagara-4 memcpy.
Hmmm... I'll run this silly sparc kernel memmove through the glibc testsuite and see if it barfs.
I don't know if you caught Bob's message; he has a hack to bypass memcpy and memmove in mm/slab.c use a for loop to move entries. With the hack he is not seeing the problem.
This is the hack:
+static void move_entries(void *dest, void *src, int nr) +{
+ unsigned long *dp = dest;
+ unsigned long *sp = src;
+
+ for (; nr; nr--, dp++, sp++)
+ *dp = *sp;
+}
+
and then replace the mempy and memmove calls in transfer_objects, cache_flusharray and drain_array to use move_entries.
I just put it on 4.0.0-rc4 and ditto -- problem goes away, so it clearly suggests the memcpy or memmove are the root cause.
David
David Miller
maintainerFrom: David Ahern <[email protected]>
Date: Sun, 22 Mar 2015 17:35:49 -0600
Quoted 16 lines
I don't know if you caught Bob's message; he has a hack to bypass memcpy and memmove in
mm/slab.cuse a for loop to move entries. With the hack he is not seeing the problem.This is the hack:
(quoted diff) +9
-0+static void move_entries(void *dest, void *src, int nr) +{ + unsigned long *dp = dest; + unsigned long *sp = src; + + for (; nr; nr--, dp++, sp++) + *dp = *sp; +} +
Quoted 5 lines
and then replace the mempy and memmove calls in
transfer_objects,cache_flusharrayanddrain_arrayto usemove_entries.I just put it on 4.0.0-rc4 and ditto -- problem goes away, so it clearly suggests the memcpy or memmove are the root cause.
Thanks, didn't notice that.
So, something is amuck.
Quoted 6 lines · David Miller
Quoted 2 lines
I just put it on 4.0.0-rc4 and ditto -- problem goes away, so it clearly suggests the memcpy or memmove are the root cause.
Thanks, didn't notice that.
So, something is amuck.
to continue to refine the problem ... I modified only the memmove lines (not the memcpy) and it works fine. So its the memmove.
I'm sure this will get whitespaced damaged on the copy and paste but to be clear this is the patch I am currently running and system is stable. On Friday it failed on every single; with this patch I have allyesconfig builds with -j 128 in a loop (clean in between) and nothing -- no panics.
mm/slab.c +0 -0
@@ -802,6 +802,16 @@ static inline void ac_put_obj(struct kmem_cache
*cachep, struct array_cache *ac,
ac->entry[ac->avail++] = objp;
}
+static void move_entries(void *dest, void *src, int nr) +{
+ unsigned long *dp = dest;
+ unsigned long *sp = src;
+
+ for (; nr; nr--, dp++, sp++)
+ *dp = *sp;
+}
+
+
/*
* Transfer objects in one arraycache to another.
* Locking must be handled by the caller.
@@ -3344,7 +3354,7 @@ free_done:
spin_unlock(&n->list_lock);
slabs_destroy(cachep, &list);
ac->avail -= batchcount;- memmove(ac->entry, &(ac->entry[batchcount]), sizeof(void
*)*ac->avail);
+ move_entries(ac->entry, &(ac->entry[batchcount]), ac->avail);
}
/*
@@ -3817,8 +3827,7 @@ static void drain_array(struct kmem_cache *cachep, struct kmem_cache_node *n,
tofree = (ac->avail + 1) / 2;
free_block(cachep, ac->entry, tofree, node, &list);
ac->avail -= tofree;
- memmove(ac->entry, &(ac->entry[tofree]),
- sizeof(void *) * ac->avail);
+ move_entries(ac->entry, &(ac->entry[tofree]),
ac->avail);
}
spin_unlock_irq(&n->list_lock);
slabs_destroy(cachep, &list);David Miller
maintainerFrom: David Ahern <[email protected]>
Date: Sun, 22 Mar 2015 18:03:30 -0600
Quoted 8 lines · David Miller
Quoted 6 lines
Quoted 2 lines
I just put it on 4.0.0-rc4 and ditto -- problem goes away, so it clearly suggests the memcpy or memmove are the root cause.
Thanks, didn't notice that.
So, something is amuck.
Quoted 8 lines
to continue to refine the problem ... I modified only the memmove lines (not the memcpy) and it works fine. So its the memmove.
I'm sure this will get whitespaced damaged on the copy and paste but to be clear this is the patch I am currently running and system is stable. On Friday it failed on every single; with this patch I have allyesconfig builds with -j 128 in a loop (clean in between) and nothing -- no panics.
Can you just try calling memcpy(), that should work because I think we agree that if the memcpy() implementation copies from low to high it should work.
I wonder if the triggering factor is configuring for a high number of cpus. I always have NR_CPUS8 since that's the largest machine I have. I'll give NR_CPUS24 a spin.
David Miller
maintainerNevermind I think I figured out the problem.
It's the cache initializing stores, we can't do overlapping copies where dst <= src in all cases because of them.
A store to a address modulo the cache line size (which for these instructions is 64 bytes), clears that whole line.
But when we're doing these memmove() calls in SLAB/SLUB, we can clear some bytes at the end of the line before they've been read in.
And reading over NG4memcpy, this _can_ happen, the main unrolled loop begins like this:
load src + 0x00 load src + 0x08 load src + 0x10 load src + 0x18 load src + 0x20 store dst + 0x00
Assume dst is 64 byte aligned and let's say that dst is src - 8 for this memcpy() call, right? That store at the end there is the one to the first line in the cache line, thus clearing the whole line, which thus clobbers "src + 0x28" before it even gets loaded.
I'm pretty sure this is what's happening.
And it's only going to trigger if the memcpy() is 128 bytes or larger.
I'll work on a fix.
David Miller
maintainerFrom: David Miller <[email protected]>
Date: Sun, 22 Mar 2015 22:19:06 -0400 (EDT)
Quoted 1 line
I'll work on a fix.
Ok, here is what I committed. David et al., let me know if you still
see the crashes with this applied.
Of course, I'll queue this up for -stable as well.
Thanks!
==========
[PATCH] sparc64: Fix several bugs in memmove().
Firstly, handle zero length calls properly. Believe it or not there are a few of these happening during early boot.
Next, we can't just drop to a memcpy() call in the forward copy case where dst <= src. The reason is that the cache initializing stores used in the Niagara memcpy() implementations can end up clearing out cache lines before we've sourced their original contents completely.
For example, considering NG4memcpy, the main unrolled loop begins like this:
load src + 0x00
load src + 0x08
load src + 0x10
load src + 0x18
load src + 0x20
store dst + 0x00Assume dst is 64 byte aligned and let's say that dst is src - 8 for this memcpy() call. That store at the end there is the one to the first line in the cache line, thus clearing the whole line, which thus clobbers "src + 0x28" before it even gets loaded.
To avoid this, just fall through to a simple copy only mildly optimized for the case where src and dst are 8 byte aligned and the length is a multiple of 8 as well. We could get fancy and call GENmemcpy() but this is good enough for how this thing is actually used.
--- arch/sparc/lib/memmove.S | 35 ++++++++++++++++++++++++++++++++--- 1 file changed, 32 insertions(+), 3 deletions(-)
arch/sparc/lib/memmove.S +32 -3
@@ -8,9 +8,11 @@ .text ENTRY(memmove) /* o0=dst o1=src o2=len */ - mov %o0, %g1 + brz,pn %o2, 99f + mov %o0, %g1 + cmp %o0, %o1 - bleu,pt %xcc, memcpy + bleu,pt %xcc, 2f add %o1, %o2, %g7 cmp %g7, %o0 bleu,pt %xcc, memcpy
@@ -24,7 +26,34 @@ ENTRY(memmove) /* o0=dst o1=src o2=len */ stb %g7, [%o0] bne,pt %icc, 1b sub %o0, 1, %o0 - +99: retl mov %g1, %o0 + + /* We can't just call memcpy for these memmove cases. On some + * chips the memcpy uses cache initializing stores and when dst + * and src are close enough, those can clobber the source data + * before we've loaded it in. + */ +2: or %o0, %o1, %g7 + or %o2, %g7, %g7 + andcc %g7, 0x7, %g0 + bne,pn %xcc, 4f + nop + +3: ldx [%o1], %g7 + add %o1, 8, %o1 + subcc %o2, 8, %o2 + add %o0, 8, %o0 + bne,pt %icc, 3b + stx %g7, [%o0 - 0x8] + ba,a,pt %xcc, 99b + +4: ldub [%o1], %g7 + add %o1, 1, %o1 + subcc %o2, 1, %o2 + add %o0, 1, %o0 + bne,pt %icc, 4b + stb %g7, [%o0 - 0x1] + ba,a,pt %xcc, 99b ENDPROC(memmove)
Signature · 1 line
1.7.11.7
David> ==========
David> [PATCH] sparc64: Fix several bugs in memmove().
David> Firstly, handle zero length calls properly. Believe it or not there David> are a few of these happening during early boot.
David> Next, we can't just drop to a memcpy() call in the forward copy case David> where dst <= src. The reason is that the cache initializing stores David> used in the Niagara memcpy() implementations can end up clearing out David> cache lines before we've sourced their original contents completely.
David> For example, considering NG4memcpy, the main unrolled loop begins like David> this:
David> load src + 0x00 David> load src + 0x08 David> load src + 0x10 David> load src + 0x18 David> load src + 0x20 David> store dst + 0x00
David> Assume dst is 64 byte aligned and let's say that dst is src - 8 for David> this memcpy() call. That store at the end there is the one to the David> first line in the cache line, thus clearing the whole line, which thus David> clobbers "src + 0x28" before it even gets loaded.
David> To avoid this, just fall through to a simple copy only mildly David> optimized for the case where src and dst are 8 byte aligned and the David> length is a multiple of 8 as well. We could get fancy and call David> GENmemcpy() but this is good enough for how this thing is actually David> used.
Would it make sense to have some memmove()/memcopy() tests on bootup to catch problems like this? I know this is a strange case, and probably not too common, but how hard would it be to wire up tests that go through 1 to 128 byte memmove() on bootup to make sure things work properly?
This seems like one of those critical, but subtle things to be checked. And doing it only on bootup wouldn't slow anything down and would (ideally) automatically get us coverage when people add new archs or update the code.
John
David Miller
maintainerFrom: "John Stoffel" <[email protected]>
Date: Mon, 23 Mar 2015 12:51:03 -0400
Quoted 10 lines
Would it make sense to have some memmove()/memcopy() tests on bootup to catch problems like this? I know this is a strange case, and probably not too common, but how hard would it be to wire up tests that go through 1 to 128 byte
memmove()on bootup to make sure things work properly?This seems like one of those critical, but subtle things to be checked. And doing it only on bootup wouldn't slow anything down and would (ideally) automatically get us coverage when people add new archs or update the code.
One of two things is already happening.
There have been assembler memcpy/memset development test harnesses around that most arch developers are using, and those test things rather extensively.
Also, the memcpy/memset routines on sparc in particular are completely shared with glibc, we use the same exact code in both trees. So it's getting tested there too.
memmove() is just not handled this way.
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
"David" = David Miller <[email protected]> writes:
David> From: "John Stoffel" <[email protected]>
David> Date: Mon, 23 Mar 2015 12:51:03 -0400
Quoted 10 lines
Quoted 10 lines
Would it make sense to have some memmove()/memcopy() tests on bootup to catch problems like this? I know this is a strange case, and probably not too common, but how hard would it be to wire up tests that go through 1 to 128 byte
memmove()on bootup to make sure things work properly?This seems like one of those critical, but subtle things to be checked. And doing it only on bootup wouldn't slow anything down and would (ideally) automatically get us coverage when people add new archs or update the code.
David> One of two things is already happening.
David> There have been assembler memcpy/memset development test harnesses David> around that most arch developers are using, and those test things David> rather extensively.
David> Also, the memcpy/memset routines on sparc in particular are completely David> shared with glibc, we use the same exact code in both trees. So it's David> getting tested there too.
Thats' good to know. I wasn't sure.
David> memmove() is just not handled this way.
Bummers. So why isn't this covered by the glibc tests too? Not accusing, not at all! Just wondering.
Thanks for all your work David, I've been amazed at your energy here!
David Miller
maintainerFrom: "John Stoffel" <[email protected]>
Date: Mon, 23 Mar 2015 15:56:02 -0400
Quoted 26 lines
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
"David" = David Miller <[email protected]> writes:
David> From: "John Stoffel" <[email protected]>
David> Date: Mon, 23 Mar 2015 12:51:03 -0400Quoted 10 lines
Quoted 10 lines
Would it make sense to have some memmove()/memcopy() tests on bootup to catch problems like this? I know this is a strange case, and probably not too common, but how hard would it be to wire up tests that go through 1 to 128 byte
memmove()on bootup to make sure things work properly?This seems like one of those critical, but subtle things to be checked. And doing it only on bootup wouldn't slow anything down and would (ideally) automatically get us coverage when people add new archs or update the code.
David> One of two things is already happening.
David> There have been assembler memcpy/memset development test harnesses David> around that most arch developers are using, and those test things David> rather extensively.
David> Also, the memcpy/memset routines on sparc in particular are completely David> shared with glibc, we use the same exact code in both trees. So it's David> getting tested there too.
Quoted 5 lines
Thats' good to know. I wasn't sure.
David>
memmove()is just not handled this way.Bummers. So why isn't this covered by the glibc tests too?
Because the kernel's memmove() is different from the one we use in glibc on sparc. In fact, we use the generic C version in glibc which expands to forward and backward word copies.
Quoted 2 lines · David Miller
Ok, here is what I committed.
So I wonder - looking at that assembly, I get the feeling that it isn't any better code than gcc could generate from simple C code.
Would it perhaps be better to turn memmove() into C?
That's particularly true because if I read this code right, it now seems to seriously pessimise non-overlapping memmove's, in that it now *always* uses that slow downward copy if the destination is below the source.
Now, admittedly, the kernel doesn't use a lot of memmov's, but this still falls back on the "byte at a time" model for a lot of cases (all non-64-bit-aligned ones). I could imagine those existing. And some people (reasonably) hate memcpy because they've been burnt by the overlapping case and end up using memmove as a "safe alternative", so it's not necessarily just the overlapping case that might trigger this.
Maybe the code could be something like
void *memmove(void *dst, const void *src, size_t n);
{
// non-overlapping cases
if (src + n <= dst)
return memcpy(dst, src, n);
if (dst + n <= src)
return memcpy(dst, src, n);
// overlapping, but we know we
// (a) copy upwards
// (b) initialize the result in at most chunks of 64
if (dst+64 <= src)
return memcpy(dst, src, n);
.. do the backwards thing ..
}(ok, maybe I got it wrong, but you get the idea).
I *think* gcc should do ok on the above kind of code, and not generate wildly different code from your handcoded version.
Linus
David Miller
maintainerFrom: Linus Torvalds <[email protected]>
Date: Mon, 23 Mar 2015 10:00:02 -0700
Quoted 19 lines
Maybe the code could be something like
void *memmove(void *dst, const void *src, size_t n); { // non-overlapping cases if (src + n <= dst) return memcpy(dst, src, n); if (dst + n <= src) return memcpy(dst, src, n); // overlapping, but we know we // (a) copy upwards // (b) initialize the result in at most chunks of 64 if (dst+64 <= src) return memcpy(dst, src, n); .. do the backwards thing .. }
Quoted 4 lines
(ok, maybe I got it wrong, but you get the idea).
I *think* gcc should do ok on the above kind of code, and not generate wildly different code from your handcoded version.
Sure you could do that in C, but I really want to avoid using memcpy() if dst and src overlap in any way at all.
Said another way, I don't want to codify that "64" thing. The next chip could do 128 byte initializing stores.
Quoted 6 lines · David Miller
Sure you could do that in C, but I really want to avoid using
memcpy()if dst and src overlap in any way at all.Said another way, I don't want to codify that "64" thing. The next chip could do 128 byte initializing stores.
But David, THAT IS NOT WHAT YOUR BROKEN ASM DOES ANYWAY!
Read it again. Your asm code does not check for overlap. Look at this:
cmp %o0, %o1
bleu,pt %xcc, 2f
and ponder. It's wrong.
So even if you don't want to take that "allow overlap more than 64 bytes apart" thing, my C version actually is *better* than the broken asm version you have.
The new asm version is better than the old one, because the new breakage is about really bad performance rather than actively breaking, but still..
Linus
David Miller
maintainerFrom: Linus Torvalds <[email protected]>
Date: Mon, 23 Mar 2015 12:47:49 -0700
Quoted 8 lines · David Miller
Quoted 6 lines
Sure you could do that in C, but I really want to avoid using
memcpy()if dst and src overlap in any way at all.Said another way, I don't want to codify that "64" thing. The next chip could do 128 byte initializing stores.
Quoted 8 lines
But David, THAT IS NOT WHAT YOUR BROKEN ASM DOES ANYWAY!
Read it again. Your asm code does not check for overlap. Look at this:
cmp %o0, %o1
bleu,pt %xcc, 2fand ponder. It's wrong.
Right, it's not checking for overlap. It's checking for "does a forward copy work?"
That's the standard test for this, and it's what glibc uses in it's generic memmove() implementation FWIW. (granted, I know glibc is not generally a good source for "right way to do things :-)
Quoted 3 lines
The new asm version is better than the old one, because the new breakage is about really bad performance rather than actively breaking, but still..
I accept that it's suboptimal.
Quoted 31 lines · David Miller
[PATCH] sparc64: Fix several bugs in
memmove().Firstly, handle zero length calls properly. Believe it or not there are a few of these happening during early boot.
Next, we can't just drop to a
memcpy()call in the forward copy case where dst <= src. The reason is that the cache initializing stores used in the Niagaramemcpy()implementations can end up clearing out cache lines before we've sourced their original contents completely.For example, considering NG4memcpy, the main unrolled loop begins like this:
load src + 0x00 load src + 0x08 load src + 0x10 load src + 0x18 load src + 0x20 store dst + 0x00Assume dst is 64 byte aligned and let's say that dst is src - 8 for this
memcpy()call. That store at the end there is the one to the first line in the cache line, thus clearing the whole line, which thus clobbers "src +0x28" before it even gets loaded.To avoid this, just fall through to a simple copy only mildly optimized for the case where src and dst are 8 byte aligned and the length is a multiple of 8 as well. We could get fancy and call
GENmemcpy()but this is good enough for how this thing is actually used.
Quoted 3 lines
Reported-by David Ahern <[email protected]>Reported-by Bob Picco <[email protected]>Signed-off-by David S. Miller <[email protected]>
seems like a formality at this point, but this resolves the panic on the M7-based ldom and baremetal. The T5-8 failed to boot, but it could be a different problem.
Thanks for the fast turnaround,
David
David Miller
maintainerFrom: David Ahern <[email protected]>
Date: Mon, 23 Mar 2015 11:34:34 -0600
Quoted 3 lines
seems like a formality at this point, but this resolves the panic on the M7-based ldom and baremetal. The T5-8 failed to boot, but it could be a different problem.
Specifically, does the T5-8 boot without my patch applied?
Quoted 9 lines · David Miller
From: David Ahern <[email protected]>
Date: Mon, 23 Mar 2015 11:34:34 -0600Quoted 3 lines
seems like a formality at this point, but this resolves the panic on the M7-based ldom and baremetal. The T5-8 failed to boot, but it could be a different problem.
Specifically, does the T5-8 boot without my patch applied?
I am running around in circles with it... it takes 15 minutes after a hard reset to get logged in, and I forgot that the 2.6.39 can't handle -j 1024 either (task scheduler problem), and then I wasted time waiting for sandwich shop to learn how to use mobile app ordering, ...
I'll respond as soon as I can.
Quoted 9 lines · David Miller
From: David Ahern <[email protected]>
Date: Mon, 23 Mar 2015 11:34:34 -0600Quoted 3 lines
seems like a formality at this point, but this resolves the panic on the M7-based ldom and baremetal. The T5-8 failed to boot, but it could be a different problem.
Specifically, does the T5-8 boot without my patch applied?
The T5-8 is having problems; has to be unrelated to this commit. T5-2 (256 cpus) boots fine, and make -j 256 on an allyesconfig builds fine.
David Miller wrote: [Mon Mar 23 2015, 12:25:30PM EDT]
Quoted 44 lines
From: David Miller <[email protected]>
Date: Sun, 22 Mar 2015 22:19:06 -0400 (EDT)Quoted 1 line
I'll work on a fix.
Ok, here is what I committed. David et al., let me know if you still
see the crashes with this applied.Of course, I'll queue this up for -stable as well.
Thanks!
==========
[PATCH] sparc64: Fix several bugs inmemmove().Firstly, handle zero length calls properly. Believe it or not there are a few of these happening during early boot.
Next, we can't just drop to a
memcpy()call in the forward copy case where dst <= src. The reason is that the cache initializing stores used in the Niagaramemcpy()implementations can end up clearing out cache lines before we've sourced their original contents completely.For example, considering NG4memcpy, the main unrolled loop begins like this:
load src + 0x00 load src + 0x08 load src + 0x10 load src + 0x18 load src + 0x20 store dst + 0x00Assume dst is 64 byte aligned and let's say that dst is src - 8 for this
memcpy()call. That store at the end there is the one to the first line in the cache line, thus clearing the whole line, which thus clobbers "src +0x28" before it even gets loaded.To avoid this, just fall through to a simple copy only mildly optimized for the case where src and dst are 8 byte aligned and the length is a multiple of 8 as well. We could get fancy and call
GENmemcpy()but this is good enough for how this thing is actually used.
Quoted 4 lines
Reported-by David Ahern <[email protected]>Reported-by Bob Picco <[email protected]>Signed-off-by David S. Miller <[email protected]>---
Seems solid with 2.6.39 on M7-4. Jalap?no is happy with current sparc.git.
David Miller
maintainerFrom: Bob Picco <[email protected]>
Date: Tue, 24 Mar 2015 10:57:53 -0400
Quoted 1 line
Seems solid with 2.6.39 on M7-4. Jalap?no is happy with current sparc.git.
Thanks for all the testing, it's been integrated into the -stable queues as well.
Quoted 4 lines · David Miller
Yes, using VIS how we do is alright, and in fact I did an audit of this about 1 year ago. This is another one of those "if this is wrong, so much stuff would break"
Maybe. But it does seem like Bob Picco has narrowed it down to memmove().
It also bothers me enormously - and perhaps unreasonably - how that memcpy code has memory barriers in it. I can see _zero_ reason for a memory barrier inside a memcpy, unless the memcpy does something that isn't valid to begin with. Are the VIS operatiosn perhaps using some kind of non-temporal form that doesn't follow the TSO rules? Kind of like the "movnt" that Intel has?
That kind of stuff makes me worry. For example, the only reason I see for
membar #StoreLoad | #StoreStore
after that VIS loop is that the stxa doesn't honor normal memory store ordering rules, but if that's true, then shouldn't we have a membar *before* the loop too? How about "ldx"? Does that also do some unordered loads?
So the memory barriers in there just make me nervous, because they are either entirely bogus or superfluous, or they are not - and if they aren't, then that implies that some of the code does something really odd with memory ordering.
I dunno. I really can't read that code at all, so I'm going entirely by gut instinct here.
Linus
David Miller
maintainerFrom: Linus Torvalds <[email protected]>
Date: Sun, 22 Mar 2015 16:49:51 -0700
Quoted 6 lines · David Miller
Quoted 4 lines
Yes, using VIS how we do is alright, and in fact I did an audit of this about 1 year ago. This is another one of those "if this is wrong, so much stuff would break"
Quoted 8 lines
Maybe. But it does seem like Bob Picco has narrowed it down to
memmove().It also bothers me enormously - and perhaps unreasonably - how that memcpy code has memory barriers in it. I can see _zero_ reason for a memory barrier inside a memcpy, unless the memcpy does something that isn't valid to begin with. Are the VIS operatiosn perhaps using some kind of non-temporal form that doesn't follow the TSO rules? Kind of like the "movnt" that Intel has?
The special cache line clearing stores (the ASI_BLK_INIT_QUAD_LDD_P stuff) do not adhere to the memory model.
I had elided the memory barriers originally, but it caused memory corruption.
So yes, this is similar to the 'movnt' situation.