kernel - More threaded core dump fixes
authorMatthew Dillon <dillon@apollo.backplane.com>
Tue, 30 Aug 2016 17:25:59 +0000 (10:25 -0700)
committerMatthew Dillon <dillon@apollo.backplane.com>
Tue, 30 Aug 2016 17:25:59 +0000 (10:25 -0700)
* Try to make a more comprehensive fix for this, fixing an endless cpu
  loop in the kernel in the process due to mismatched tests.  Incorporate
  the LWP_MP_WEXIT flag into a new test, STOPLWP().

* tsleep() is now more consistent in setting lwp_stat.

* lwpsignal() needs to allow SIGKILL through during the exit sequence
  in order to wakeup any PCATCH tsleep()s.

* Fix bug in the panic coredump code where the dump_stop_usertds variable
  could cause an endless tstop() loop.

Reported-by: zrj
sys/kern/kern_exit.c
sys/kern/kern_sig.c
sys/kern/kern_synch.c
sys/platform/pc64/x86_64/trap.c
sys/sys/proc.h

index b121ef5..9dee510 100644 (file)
@@ -263,8 +263,8 @@ killlwps(struct lwp *lp)
                LWPHOLD(tlp);
                lwkt_gettoken(&tlp->lwp_token);
                if ((tlp->lwp_mpflags & LWP_MP_WEXIT) == 0) {
-                       lwpsignal(p, tlp, SIGKILL);
                        atomic_set_int(&tlp->lwp_mpflags, LWP_MP_WEXIT);
+                       lwpsignal(p, tlp, SIGKILL);
                }
                lwkt_reltoken(&tlp->lwp_token);
                LWPRELE(tlp);
@@ -925,7 +925,7 @@ loop:
         * the CONT when both are stopped and continued together.  This little
         * two-line hack restores this effect.
         */
-       while (q->p_stat == SSTOP || q->p_stat == SCORE)
+       if (STOPLWP(q, td->td_lwp))
             tstop();
 
        nfound = 0;
index fbd6b02..8f3018e 100644 (file)
@@ -1121,11 +1121,11 @@ lwpsignal(struct proc *p, struct lwp *lp, int sig)
                action = SIG_DFL;
        } else {
                /*
-                * Do not try to deliver signals to an exiting lwp.  Note
-                * that we must still deliver the signal if P_WEXIT is set
-                * in the process flags.
+                * Do not try to deliver signals to an exiting lwp other
+                * than SIGKILL.  Note that we must still deliver the signal
+                * if P_WEXIT is set in the process flags.
                 */
-               if (lp && (lp->lwp_mpflags & LWP_MP_WEXIT)) {
+               if (lp && (lp->lwp_mpflags & LWP_MP_WEXIT) && sig != SIGKILL) {
                        if (lp) {
                                lwkt_reltoken(&lp->lwp_token);
                                LWPRELE(lp);
@@ -1904,7 +1904,7 @@ issignal(struct lwp *lp, int maytrace)
                /*
                 * If this process is supposed to stop, stop this thread.
                 */
-               if (p->p_stat == SSTOP || p->p_stat == SCORE)
+               if (STOPLWP(p, lp))
                        tstop();
 
                mask = lwp_sigpend(lp);
index df157a2..788b8e3 100644 (file)
@@ -701,13 +701,11 @@ resume:
                lp->lwp_flags &= ~LWP_SINTR;
 
                /*
-                * Normally we should not be in LSSLEEP here but a pending
-                * signal related to STOP/CONT or TSTOP/TCONT can cause us
-                * to skip the sleep.  Make sure we are back in the RUN
-                * state.
+                * Unconditionally set us to LSRUN on resume.  lwp_stat could
+                * be in a weird state due to the goto resume, particularly
+                * when tsleep() is called from tstop().
                 */
-               if (lp->lwp_stat == LSSLEEP)
-                       lp->lwp_stat = LSRUN;
+               lp->lwp_stat = LSRUN;
                lwkt_reltoken(&lp->lwp_token);
        }
        logtsleep1(tsleep_end);
@@ -874,10 +872,14 @@ endtsleep(void *arg)
 
        if (lp) {
                /*
-                * callout timer should never be set in tstop() because
-                * it passes a timeout of 0.
+                * callout timer should normally never be set in tstop()
+                * because it passes a timeout of 0.  However, there is a
+                * case during thread exit (which SSTOP's all the threads)
+                * for which tstop() must break out and can (properly) leave
+                * the thread in LSSTOP.
                 */
-               KKASSERT(lp->lwp_stat != LSSTOP);
+               KKASSERT(lp->lwp_stat != LSSTOP ||
+                        (lp->lwp_mpflags & LWP_MP_WEXIT));
                setrunnable(lp);
                lwkt_reltoken(&lp->lwp_token);
        } else {
@@ -1203,13 +1205,9 @@ tstop(void)
         * Wait here while in a stopped state, interlocked with lwp_token.
         * We must break-out if the whole process is trying to exit.
         */
-       while (p->p_stat == SSTOP || p->p_stat == SCORE) {
+       while (STOPLWP(p, lp)) {
                lp->lwp_stat = LSSTOP;
-               if (lp->lwp_mpflags & LWP_MP_WEXIT)
-                       break;
                tsleep(p, 0, "stop", 0);
-               if (lp->lwp_mpflags & LWP_MP_WEXIT)
-                       break;
        }
        p->p_nstopped--;
        atomic_clear_int(&lp->lwp_mpflags, LWP_MP_WSTOP);
index 8017980..82bd915 100644 (file)
@@ -247,12 +247,15 @@ recheck:
        /*
         * Block here if we are in a stopped state.
         */
-       if (p->p_stat == SSTOP || p->p_stat == SCORE || dump_stop_usertds) {
+       if (STOPLWP(p, lp)) {
                lwkt_gettoken(&p->p_token);
                tstop();
                lwkt_reltoken(&p->p_token);
                goto recheck;
        }
+       while (dump_stop_usertds) {
+               tsleep(&dump_stop_usertds, 0, "dumpstp", 0);
+       }
 
        /*
         * Post any pending upcalls.  If running a virtual kernel be sure
@@ -331,8 +334,7 @@ userexit(struct lwp *lp)
         * Handle stop requests at kernel priority.  Any requests queued
         * after this loop will generate another AST.
         */
-       while (lp->lwp_proc->p_stat == SSTOP ||
-              lp->lwp_proc->p_stat == SCORE) {
+       while (STOPLWP(lp->lwp_proc, lp)) {
                lwkt_gettoken(&lp->lwp_proc->p_token);
                tstop();
                lwkt_reltoken(&lp->lwp_proc->p_token);
index 1654c85..18860c2 100644 (file)
@@ -484,6 +484,10 @@ extern void stopevent(struct proc*, unsigned int, unsigned int);
 #define PSTALL(p, msg, n) \
        do { if ((p)->p_lock > (n)) pstall((p), (msg), (n)); } while (0)
 
+#define STOPLWP(p, lp)                                         \
+       (((p)->p_stat == SSTOP || (p)->p_stat == SCORE) &&      \
+        ((lp)->lwp_mpflags & LWP_MP_WEXIT) == 0)
+
 /*
  * Hold lwp in memory, don't destruct, normally for ptrace/procfs work
  * atomic ops because they can occur from an IPI.