Port-mips archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

SMP/preempt bug in matt-nb5-mips64



Hello,
I found a problem in matt-nb5-mips64's mips/mips/spl.S, regarding
curcpu() and preemption. In both _splraise and _splsw_splhigh,
curcpu() is loaded from L_CPU(MIPS_CURLWP) in a register early,
especially before disabling interrupt. If the current IPL is 0,
the current thread can be preempted and rescheduled on another CPU,
and the new SPL is written back to the wrong cpu_info.
From there, bad things happens (what I've seen is an infinite loop
from the interrupt handler on the victim CPU, because _splsw_splhigh
thinks we're already at splhigh and do nothing, when interrupts are
really enabled).
The attached patch seems to fix it for me: it's enough to reload
curcpu() before writing back the new IPL, as for the above senario to
happen the old IPL of both CPUs has to be 0.

I suspect there's a similar issue with the use of L_CPU(MIPS_CURLWP)
in stub_lock.S, but I've not looked in details, as right now I'm
running with LOCKDEBUG and this code isn't used.

-- 
Manuel Bouyer <bouyer%antioche.eu.org@localhost>
     NetBSD: 26 ans d'experience feront toujours la difference
--
Index: spl.S
===================================================================
--- spl.S       (revision 100)
+++ spl.S       (revision 101)
@@ -76,6 +76,10 @@
        DYNAMIC_STATUS_MASK(a0,v0)              # machine dependent masking
        mtc0    zero, MIPS_COP_0_STATUS         ## disable interrupts
        COP0_SYNC
+           #reload curcpu() we may have been preemted while IPL was 0
+           #we know IPL is 0 on the new CPU or we would not be there,
+           #so no need to reload CPU_INFO_CPL in v0
+       PTR_L   a3, L_CPU(MIPS_CURLWP)
        INT_S   a1, CPU_INFO_CPL(a3)            ## save IPL in cpu_info
        mtc0    a0, MIPS_COP_0_STATUS           ## store back
        COP0_SYNC
@@ -220,6 +224,10 @@
        DYNAMIC_STATUS_MASK(a0,a2)              # machine dependent masking
        mtc0    a0, MIPS_COP_0_STATUS           ## store back
        COP0_SYNC
+           #reload curcpu() we may have been preemted while IPL was 0
+           #we know IPL is 0 on the new CPU or we would not be there,
+           #so no need to reload CPU_INFO_CPL in v0
+       PTR_L   a3, L_CPU(MIPS_CURLWP)
        INT_S   a1, CPU_INFO_CPL(a3)            ## save IPL in cpu_info
 #ifdef PARANOIA
        j       ra                              ## return


Home | Main Index | Thread Index | Old Index