]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/kern/kern_shutdown.c
xnu-4903.221.2.tar.gz
[apple/xnu.git] / bsd / kern / kern_shutdown.c
index 3858ce83e10ed21b146a0a5f050d8a50e7ad697b..936fd61e28212a1dc46596999941ee4df3be1b2a 100644 (file)
@@ -68,6 +68,7 @@
 #include <sys/sysproto.h>              /* abused for sync() */
 #include <kern/clock.h>                        /* for delay_for_interval() */
 #include <libkern/OSAtomic.h>
+#include <IOKit/IOPlatformExpert.h>
 
 #include <sys/kdebug.h>
 
@@ -82,8 +83,12 @@ static int  sd_openlog(vfs_context_t);
 static int  sd_closelog(vfs_context_t);
 static void sd_log(vfs_context_t, const char *, ...);
 static void proc_shutdown(void);
-static void kernel_hwm_panic_info(void);
-extern void IOSystemShutdownNotification(void);
+static void zprint_panic_info(void);
+extern void halt_log_enter(const char * what, const void * pc, uint64_t time);
+
+#if DEVELOPMENT || DEBUG
+extern boolean_t kdp_has_polled_corefile(void);
+#endif /* DEVELOPMENT || DEBUG */
 
 struct sd_filterargs{
        int delayterm;
@@ -104,42 +109,60 @@ static off_t sd_log_offset = 0;
 
 static int sd_filt1(proc_t, void *);
 static int sd_filt2(proc_t, void *);
-static int  sd_callback1(proc_t p, void * arg);
-static int  sd_callback2(proc_t p, void * arg);
-static int  sd_callback3(proc_t p, void * arg);
+static int sd_callback1(proc_t p, void * arg);
+static int sd_callback2(proc_t p, void * arg);
+static int sd_callback3(proc_t p, void * arg);
 
 extern boolean_t panic_include_zprint;
-extern vm_offset_t panic_kext_memory_info;
-extern vm_size_t panic_kext_memory_size; 
+extern mach_memory_info_t *panic_kext_memory_info;
+extern vm_size_t panic_kext_memory_size;
 
 static void
-kernel_hwm_panic_info(void)
+zprint_panic_info(void)
 {
-       mach_memory_info_t      *memory_info;
-       unsigned int            num_sites;
-       kern_return_t           kr;
+       unsigned int  num_sites;
+       kern_return_t kr;
 
        panic_include_zprint = TRUE;
-       panic_kext_memory_info = 0;
+       panic_kext_memory_info = NULL;
        panic_kext_memory_size = 0;
 
-       num_sites = VM_KERN_MEMORY_COUNT + VM_KERN_COUNTER_COUNT;
-       panic_kext_memory_size = round_page(num_sites * sizeof(mach_zone_info_t));
-       
-       kr = kmem_alloc(kernel_map, (vm_offset_t *) &panic_kext_memory_info, panic_kext_memory_size, VM_KERN_MEMORY_OSFMK);
+       num_sites = vm_page_diagnose_estimate();
+       panic_kext_memory_size = num_sites * sizeof(panic_kext_memory_info[0]);
+
+       kr = kmem_alloc(kernel_map, (vm_offset_t *)&panic_kext_memory_info, round_page(panic_kext_memory_size), VM_KERN_MEMORY_OSFMK);
        if (kr != KERN_SUCCESS) {
-               panic_kext_memory_info = 0;
+               panic_kext_memory_info = NULL;
                return;
        }
-       memory_info = (mach_memory_info_t *)panic_kext_memory_info;
-       vm_page_diagnose(memory_info, num_sites);
-       return;
+
+       vm_page_diagnose(panic_kext_memory_info, num_sites, 0);
+}
+
+int
+get_system_inshutdown()
+{
+       return (system_inshutdown);
+}
+
+static void
+panic_kernel(int howto, char *message)
+{
+       if ((howto & RB_PANIC_ZPRINT) == RB_PANIC_ZPRINT) {
+               zprint_panic_info();
+       }
+       panic("userspace panic: %s", message);
 }
 
 int
 reboot_kernel(int howto, char *message)
 {
        int hostboot_option=0;
+       uint64_t startTime;
+
+       if ((howto & (RB_PANIC | RB_QUICK)) == (RB_PANIC | RB_QUICK)) {
+               panic_kernel(howto, message);
+       }
 
        if (!OSCompareAndSwap(0, 1, &system_inshutdown)) {
                if ( (howto&RB_QUICK) == RB_QUICK)
@@ -147,10 +170,9 @@ reboot_kernel(int howto, char *message)
                return (EBUSY);
        }
        /*
-        * Temporary hack to notify the power management root domain
-        * that the system will shut down.
+        * Notify the power management root domain that the system will shut down.
         */
-       IOSystemShutdownNotification();
+       IOSystemShutdownNotification(kIOSystemShutdownNotificationStageProcessExit);
 
        if ((howto&RB_QUICK)==RB_QUICK) {
                printf("Quick reboot...\n");
@@ -168,26 +190,46 @@ reboot_kernel(int howto, char *message)
                 */
 
                /* handle live procs (deallocate their root and current directories), suspend initproc */
+
+               startTime = mach_absolute_time();
                proc_shutdown();
+               halt_log_enter("proc_shutdown", 0, mach_absolute_time() - startTime);
 
 #if CONFIG_AUDIT
+               startTime = mach_absolute_time();
                audit_shutdown();
+               halt_log_enter("audit_shutdown", 0, mach_absolute_time() - startTime);
 #endif
 
                if (unmountroot_pre_hook != NULL)
                        unmountroot_pre_hook();
 
+               startTime = mach_absolute_time();
                sync((proc_t)NULL, (void *)NULL, (int *)NULL);
 
-               if (kdebug_enable)
+               if (kdebug_enable) {
+                       startTime = mach_absolute_time();
                        kdbg_dump_trace_to_file("/var/log/shutdown/shutdown.trace");
+                       halt_log_enter("shutdown.trace", 0, mach_absolute_time() - startTime);
+               }
+
+               IOSystemShutdownNotification(kIOSystemShutdownNotificationStageRootUnmount);
 
                /*
                 * Unmount filesystems
                 */
-               vfs_unmountall();
+
+#if DEVELOPMENT || DEBUG
+               if (!(howto & RB_PANIC) || !kdp_has_polled_corefile())
+#endif /* DEVELOPMENT || DEBUG */
+               {
+                       startTime = mach_absolute_time();
+                       vfs_unmountall();
+                       halt_log_enter("vfs_unmountall", 0, mach_absolute_time() - startTime);
+               }
 
                /* Wait for the buffer cache to clean remaining dirty buffers */
+               startTime = mach_absolute_time();
                for (iter = 0; iter < 100; iter++) {
                        nbusy = count_busy_buffers();
                        if (nbusy == 0)
@@ -199,6 +241,7 @@ reboot_kernel(int howto, char *message)
                        printf("giving up\n");
                else
                        printf("done\n");
+               halt_log_enter("bufferclean", 0, mach_absolute_time() - startTime);
        }
 #if NETWORKING
        /*
@@ -206,16 +249,15 @@ reboot_kernel(int howto, char *message)
         * because that will lock out softints which the disk
         * drivers depend on to finish DMAs.
         */
+       startTime = mach_absolute_time();
        if_down_all();
+       halt_log_enter("if_down_all", 0, mach_absolute_time() - startTime);
 #endif /* NETWORKING */
 
 force_reboot:
 
        if (howto & RB_PANIC) {
-               if (strncmp(message, "Kernel memory has exceeded limits", 33) == 0) {
-                       kernel_hwm_panic_info();
-               }
-               panic ("userspace panic: %s", message);
+               panic_kernel(howto, message);
        }
 
        if (howto & RB_POWERDOWN)
@@ -315,7 +357,7 @@ sd_filt1(proc_t p, void * args)
 }
 
 
-static int  
+static int
 sd_callback1(proc_t p, void * args)
 {
        struct sd_iterargs * sd = (struct sd_iterargs *)args;
@@ -337,9 +379,11 @@ sd_callback1(proc_t p, void * args)
                psignal(p, signo);
                if (countproc !=  0)
                        sd->activecount++;
-       } else
+       } else {
                proc_unlock(p);
-       return(PROC_RETURNED);
+       }
+
+       return PROC_RETURNED;
 }
 
 static int
@@ -360,7 +404,7 @@ sd_filt2(proc_t p, void * args)
                 return(1);
 }
 
-static int  
+static int
 sd_callback2(proc_t p, void * args)
 {
        struct sd_iterargs * sd = (struct sd_iterargs *)args;
@@ -381,14 +425,14 @@ sd_callback2(proc_t p, void * args)
                psignal(p, signo);
                if (countproc !=  0)
                        sd->activecount++;
-       } else
+       } else {
                proc_unlock(p);
+       }
 
-       return(PROC_RETURNED);
-
+       return PROC_RETURNED;
 }
 
-static int  
+static int
 sd_callback3(proc_t p, void * args)
 {
        struct sd_iterargs * sd = (struct sd_iterargs *)args;
@@ -422,10 +466,11 @@ sd_callback3(proc_t p, void * args)
                        sd->activecount++;
                        exit1(p, 1, (int *)NULL);
                }
-       } else
+       } else {
                proc_unlock(p);
+       }
 
-       return(PROC_RETURNED);
+       return PROC_RETURNED;
 }
 
 
@@ -437,7 +482,7 @@ sd_callback3(proc_t p, void * args)
  *
  * POSIX modifications:
  *
- *     For POSIX fcntl() file locking call vno_lockrelease() on 
+ *     For POSIX fcntl() file locking call vno_lockrelease() on
  *     the file to release all of its record locks, if any.
  */
 
@@ -456,10 +501,10 @@ proc_shutdown(void)
         *      Kill as many procs as we can.  (Except ourself...)
         */
        self = (struct proc *)current_proc();
-       
+
        /*
         * Signal the init with SIGTERM so that he does not launch
-        * new processes 
+        * new processes
         */
        p = proc_find(1);
        if (p && p != self) {
@@ -488,11 +533,11 @@ sigterm_loop:
                proc_list_lock();
                if (proc_shutdown_exitcount != 0) {
                        /*
-                       * now wait for up to 30 seconds to allow those procs catching SIGTERM
-                       * to digest it
-                       * as soon as these procs have exited, we'll continue on to the next step
-                       */
-                       ts.tv_sec = 30;
+                        * now wait for up to 3 seconds to allow those procs catching SIGTERM
+                        * to digest it
+                        * as soon as these procs have exited, we'll continue on to the next step
+                        */
+                       ts.tv_sec = 3;
                        ts.tv_nsec = 0;
                        error = msleep(&proc_shutdown_exitcount, proc_list_mlock, PWAIT, "shutdownwait", &ts);
                        if (error != 0) {
@@ -505,7 +550,6 @@ sigterm_loop:
                                                p->p_listflag &= ~P_LIST_EXITCOUNT;
                                }
                        }
-                       
                }
                proc_list_unlock();
        }
@@ -514,7 +558,6 @@ sigterm_loop:
                 * log the names of the unresponsive tasks
                 */
 
-
                proc_list_lock();
 
                for (p = allproc.lh_first; p; p = p->p_list.le_next) {
@@ -525,8 +568,6 @@ sigterm_loop:
                }
 
                proc_list_unlock();
-
-               delay_for_interval(1000 * 5, 1000 * 1000);
        }
 
        /*
@@ -542,16 +583,18 @@ sigterm_loop:
        /* post a SIGKILL to all that catch SIGTERM and not marked for delay */
        proc_rebootscan(sd_callback2, (void *)&sdargs, sd_filt2, (void *)&sfargs);
 
+       error = 0;
+
        if (sdargs.activecount != 0 && proc_shutdown_exitcount!= 0) {
                proc_list_lock();
                if (proc_shutdown_exitcount != 0) {
                        /*
-                       * wait for up to 60 seconds to allow these procs to exit normally
-                       *
-                       * History:      The delay interval was changed from 100 to 200
-                       *               for NFS requests in particular.
-                       */
-                       ts.tv_sec = 60;
+                       * wait for up to 60 seconds to allow these procs to exit normally
+                       *
+                       * History:      The delay interval was changed from 100 to 200
+                       *               for NFS requests in particular.
+                       */
+                       ts.tv_sec = 10;
                        ts.tv_nsec = 0;
                        error = msleep(&proc_shutdown_exitcount, proc_list_mlock, PWAIT, "shutdownwait", &ts);
                        if (error != 0) {
@@ -568,6 +611,23 @@ sigterm_loop:
                proc_list_unlock();
        }
 
+       if (error == ETIMEDOUT) {
+               /*
+                * log the names of the unresponsive tasks
+                */
+
+               proc_list_lock();
+
+               for (p = allproc.lh_first; p; p = p->p_list.le_next) {
+                       if (p->p_shutdownstate == 2) {
+                               printf("%s[%d]: didn't act on SIGKILL\n", p->p_comm, p->p_pid);
+                               sd_log(ctx, "%s[%d]: didn't act on SIGKILL\n", p->p_comm, p->p_pid);
+                       }
+               }
+
+               proc_list_unlock();
+       }
+
        /*
         * if we still have procs that haven't exited, then brute force 'em
         */
@@ -578,6 +638,8 @@ sigterm_loop:
        sdargs.countproc = 0;
        sdargs.activecount = 0;
 
+
+
        /* post a SIGTERM to all that catch SIGTERM and not marked for delay */
        proc_rebootscan(sd_callback3, (void *)&sdargs, sd_filt2, (void *)&sfargs);
        printf("\n");