tech-kern archive

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

Re: shutdown hooks at panic (was Re: CVS commit: src/sys/kern)



Here are the shutdown hooks I have been running as an experiment.
They have helped me find many bugs in detach routines.  Buggy detach
routines remain.

The patch also includes a patch for i386 that allows interrupts while
the shutdown hooks run.

Dave

-- 
David Young             OJC Technologies
dyoung%ojctech.com@localhost      Urbana, IL * (217) 278-3933 ext 24
Index: kern/kern_pmf.c
===================================================================
RCS file: /cvsroot/src/sys/kern/kern_pmf.c,v
retrieving revision 1.10
diff -p -u -u -p -r1.10 kern_pmf.c
--- kern/kern_pmf.c     27 Dec 2007 16:03:10 -0000      1.10
+++ kern/kern_pmf.c     30 Jan 2008 00:40:39 -0000
@@ -88,6 +88,15 @@ typedef struct pmf_event_workitem {
        device_t                pew_device;
 } pmf_event_workitem_t;
 
+struct shutdown_state {
+       bool initialized;
+       int depth;
+       device_t prevdev;
+};
+
+static device_t shutdown_first(struct shutdown_state *);
+static device_t shutdown_next(struct shutdown_state *);
+
 static void
 pmf_event_worker(struct work *wk, void *dummy)
 {
@@ -267,40 +276,73 @@ pmf_system_suspend(void)
        return true;
 }
 
-void
-pmf_system_shutdown(void)
+static device_t
+shutdown_first(struct shutdown_state *s)
 {
-       int depth, maxdepth;
        device_t curdev;
 
-       aprint_debug("Shutting down devices:");
-
-       maxdepth = 0;
-       TAILQ_FOREACH(curdev, &alldevs, dv_list) {
-               if (curdev->dv_depth > maxdepth)
-                       maxdepth = curdev->dv_depth;
-       }
+       if (!s->initialized) {
+               s->depth = -1;
+               s->prevdev = NULL;
 
-       for (depth = maxdepth; depth >= 0; --depth) {
                TAILQ_FOREACH_REVERSE(curdev, &alldevs, devicelist, dv_list) {
-                       if (curdev->dv_depth != depth)
-                               continue;
                        if (!device_is_active(curdev))
                                continue;
+                       if (curdev->dv_depth <= s->depth)
+                               continue;
+                       s->depth = curdev->dv_depth;
+                       s->prevdev = curdev;
+               }
+               s->initialized = true;
+       }
+       return shutdown_next(s);
+}
 
-                       aprint_debug(" %s", device_xname(curdev));
+static device_t
+shutdown_next(struct shutdown_state *s)
+{
+       device_t curdev, retdev;
 
-                       if (!device_pmf_is_registered(curdev))
-                               continue;
-                       if (!device_pmf_class_suspend(curdev)) {
-                               aprint_debug("(failed)");
-                               continue;
-                       }
-                       if (!device_pmf_driver_suspend(curdev)) {
-                               aprint_debug("(failed)");
-                               continue;
-                       }
+       curdev = retdev = s->prevdev;
+
+       while (curdev != NULL) {
+               curdev = TAILQ_PREV(curdev, devicelist, dv_list);
+               if (curdev == NULL) {
+                       if (--s->depth < 0)
+                               break;
+                       if ((curdev = TAILQ_LAST(&alldevs, devicelist)) == NULL)
+                               break;
                }
+               if (curdev->dv_depth == s->depth && device_is_active(curdev))
+                       break;
+       }
+       s->prevdev = curdev;
+       return retdev;
+}
+
+void
+pmf_system_shutdown(void)
+{
+       static struct shutdown_state s;
+       device_t curdev;
+
+       if (!pmf_check_system_drivers())
+               delay(1000000);
+
+       aprint_debug("Shutting down devices:");
+
+       for (curdev = shutdown_first(&s); curdev != NULL;
+            curdev = shutdown_next(&s)) {
+               aprint_debug(" attempting %s shutdown",
+                   device_xname(curdev));
+               if (config_detach(curdev, 0) == 0)
+                       aprint_debug("(detached)");
+               else if (!device_pmf_is_registered(curdev))
+                       aprint_debug("(skipped)");
+               else if (!device_pmf_class_suspend(curdev))
+                       aprint_debug("(failed)");
+               else if (!device_pmf_driver_suspend(curdev))
+                       aprint_debug("(failed)");
        }
 
        aprint_debug(".\n");
Index: arch/i386/i386/machdep.c
===================================================================
RCS file: /cvsroot/src/sys/arch/i386/i386/machdep.c,v
retrieving revision 1.625
diff -p -u -u -p -r1.625 machdep.c
--- arch/i386/i386/machdep.c    23 Jan 2008 19:46:44 -0000      1.625
+++ arch/i386/i386/machdep.c    30 Jan 2008 00:40:39 -0000
@@ -926,6 +926,7 @@ int waittime = -1;
 void
 cpu_reboot(int howto, char *bootstr)
 {
+       int s;
 
        if (cold) {
                howto |= RB_HALT;
@@ -945,15 +946,20 @@ cpu_reboot(int howto, char *bootstr)
        }
 
        /* Disable interrupts. */
-       splhigh();
+       s = splhigh();
 
        /* Do a dump if requested. */
        if ((howto & (RB_DUMP | RB_HALT)) == RB_DUMP)
                dumpsys();
 
+       splx(s);
+
 haltsys:
        doshutdownhooks();
 
+       if (!cold)
+               splhigh();
+
 #ifdef MULTIPROCESSOR
        x86_broadcast_ipi(X86_IPI_HALT);
 #endif


Home | Main Index | Thread Index | Old Index