kernel - Fix marker in sysctl_kern_proc()
authorMatthew Dillon <dillon@apollo.backplane.com>
Fri, 18 Nov 2011 16:09:11 +0000 (08:09 -0800)
committerMatthew Dillon <dillon@apollo.backplane.com>
Fri, 18 Nov 2011 16:09:11 +0000 (08:09 -0800)
* The marker wasn't being marked as a marker, resulting in a
  kernel panic when two or more 'ps' commands are running concurrently
  and one blocks.

sys/kern/kern_proc.c

index eea0ede..871a9b9 100644 (file)
@@ -1004,6 +1004,7 @@ sysctl_kern_proc(SYSCTL_HANDLER_ARGS)
                goto post_threads;
 
        marker = kmalloc(sizeof(struct thread), M_TEMP, M_WAITOK|M_ZERO);
+       marker->td_flags = TDF_MARKER;
        error = 0;
 
        for (n = 1; n <= ncpus; ++n) {
@@ -1018,27 +1019,17 @@ sysctl_kern_proc(SYSCTL_HANDLER_ARGS)
 
                crit_enter();
                TAILQ_INSERT_TAIL(&rgd->gd_tdallq, marker, td_allq);
-               crit_exit();
 
                while ((td = TAILQ_PREV(marker, lwkt_queue, td_allq)) != NULL) {
-                       crit_enter();
-                       if (td != TAILQ_PREV(marker, lwkt_queue, td_allq)) {
-                               crit_exit();
-                               continue;
-                       }
                        TAILQ_REMOVE(&rgd->gd_tdallq, marker, td_allq);
                        TAILQ_INSERT_BEFORE(td, marker, td_allq);
-                       lwkt_hold(td);
-                       crit_exit();
-
-                       if (td->td_flags & TDF_MARKER) {
-                               lwkt_rele(td);
+                       if (td->td_flags & TDF_MARKER)
                                continue;
-                       }
-                       if (td->td_proc) {
-                               lwkt_rele(td);
+                       if (td->td_proc)
                                continue;
-                       }
+
+                       lwkt_hold(td);
+                       crit_exit();
 
                        switch (oid) {
                        case KERN_PROC_PGRP:
@@ -1052,10 +1043,10 @@ sysctl_kern_proc(SYSCTL_HANDLER_ARGS)
                                break;
                        }
                        lwkt_rele(td);
+                       crit_enter();
                        if (error)
                                break;
                }
-               crit_enter();
                TAILQ_REMOVE(&rgd->gd_tdallq, marker, td_allq);
                crit_exit();