]>
git.saurik.com Git - apple/xnu.git/blob - bsd/kern/kern_shutdown.c
2 * Copyright (c) 2000-2006 Apple Computer, Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
29 * File: bsd/kern/kern_shutdown.c
31 * Copyright (C) 1989, NeXT, Inc.
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/kernel.h>
39 #include <sys/proc_internal.h>
41 #include <sys/reboot.h>
43 #include <sys/vnode_internal.h>
44 #include <sys/file_internal.h>
45 #include <sys/clist.h>
46 #include <sys/callout.h>
48 #include <sys/msgbuf.h>
49 #include <sys/ioctl.h>
50 #include <sys/signal.h>
52 #include <kern/task.h>
53 #include <sys/quota.h>
54 #include <vm/vm_kern.h>
55 #include <mach/vm_param.h>
56 #include <sys/filedesc.h>
57 #include <mach/host_priv.h>
58 #include <mach/host_reboot.h>
60 #include <security/audit/audit.h>
62 #include <kern/sched_prim.h> /* for thread_block() */
63 #include <kern/host.h> /* for host_priv_self() */
64 #include <net/if_var.h> /* for if_down_all() */
65 #include <sys/buf_internal.h> /* for count_busy_buffers() */
66 #include <sys/mount_internal.h> /* for vfs_unmountall() */
67 #include <mach/task.h> /* for task_suspend() */
68 #include <sys/sysproto.h> /* abused for sync() */
69 #include <kern/clock.h> /* for delay_for_interval() */
70 #include <libkern/OSAtomic.h>
72 #include <sys/kdebug.h>
74 uint32_t system_inshutdown
= 0;
76 /* XXX should be in a header file somewhere, but isn't */
77 extern void md_prepare_for_shutdown(int, int, char *);
78 extern void (*unmountroot_pre_hook
)(void);
80 unsigned int proc_shutdown_exitcount
= 0;
82 static int sd_openlog(vfs_context_t
);
83 static int sd_closelog(vfs_context_t
);
84 static void sd_log(vfs_context_t
, const char *, ...);
85 static void proc_shutdown(void);
87 extern void IOSystemShutdownNotification(void);
96 int signo
; /* the signal to be posted */
97 int setsdstate
; /* shutdown state to be set */
98 int countproc
; /* count processes on action */
99 int activecount
; /* number of processes on which action was done */
102 static vnode_t sd_logvp
= NULLVP
;
103 static off_t sd_log_offset
= 0;
106 static int sd_filt1(proc_t
, void *);
107 static int sd_filt2(proc_t
, void *);
108 static int sd_callback1(proc_t p
, void * arg
);
109 static int sd_callback2(proc_t p
, void * arg
);
110 static int sd_callback3(proc_t p
, void * arg
);
113 boot(int paniced
, int howto
, char *command
)
115 struct proc
*p
= current_proc(); /* XXX */
116 int hostboot_option
=0;
118 if (!OSCompareAndSwap(0, 1, &system_inshutdown
)) {
119 if ( (howto
&RB_QUICK
) == RB_QUICK
)
124 * Temporary hack to notify the power management root domain
125 * that the system will shut down.
127 IOSystemShutdownNotification();
129 md_prepare_for_shutdown(paniced
, howto
, command
);
131 if ((howto
&RB_QUICK
)==RB_QUICK
) {
132 printf("Quick reboot...\n");
133 if ((howto
&RB_NOSYNC
)==0) {
134 sync(p
, (void *)NULL
, (int *)NULL
);
137 else if ((howto
&RB_NOSYNC
)==0) {
140 printf("syncing disks... ");
143 * Release vnodes held by texts before sync.
146 /* handle live procs (deallocate their root and current directories). */
153 if (unmountroot_pre_hook
!= NULL
)
154 unmountroot_pre_hook();
156 sync(p
, (void *)NULL
, (int *)NULL
);
159 * Now that all processes have been terminated and system is
160 * sync'ed up, suspend init
163 if (initproc
&& p
!= initproc
)
164 task_suspend(initproc
->task
);
167 kdbg_dump_trace_to_file("/var/log/shutdown/shutdown.trace");
170 * Unmount filesystems
174 /* Wait for the buffer cache to clean remaining dirty buffers */
175 for (iter
= 0; iter
< 100; iter
++) {
176 nbusy
= count_busy_buffers();
179 printf("%d ", nbusy
);
180 delay_for_interval( 1 * nbusy
, 1000 * 1000);
183 printf("giving up\n");
189 * Can't just use an splnet() here to disable the network
190 * because that will lock out softints which the disk
191 * drivers depend on to finish DMAs.
194 #endif /* NETWORKING */
197 if (howto
& RB_POWERDOWN
)
198 hostboot_option
= HOST_REBOOT_HALT
;
200 hostboot_option
= HOST_REBOOT_HALT
;
201 if (paniced
== RB_PANIC
)
202 hostboot_option
= HOST_REBOOT_HALT
;
204 if (howto
& RB_UPSDELAY
) {
205 hostboot_option
= HOST_REBOOT_UPSDELAY
;
208 host_reboot(host_priv_self(), hostboot_option
);
210 * should not be reached
216 sd_openlog(vfs_context_t ctx
)
221 /* Open shutdown log */
222 if ((error
= vnode_open(PROC_SHUTDOWN_LOG
, (O_CREAT
| FWRITE
| O_NOFOLLOW
), 0644, 0, &sd_logvp
, ctx
))) {
223 printf("Failed to open %s: error %d\n", PROC_SHUTDOWN_LOG
, error
);
228 vnode_setsize(sd_logvp
, (off_t
)0, 0, ctx
);
230 /* Write a little header */
232 sd_log(ctx
, "Process shutdown log. Current time is %lu (in seconds).\n\n", tv
.tv_sec
);
238 sd_closelog(vfs_context_t ctx
)
241 if (sd_logvp
!= NULLVP
) {
242 VNOP_FSYNC(sd_logvp
, MNT_WAIT
, ctx
);
243 error
= vnode_close(sd_logvp
, FWRITE
, ctx
);
250 sd_log(vfs_context_t ctx
, const char *fmt
, ...)
252 int resid
, log_error
, len
;
256 /* If the log isn't open yet, open it */
257 if (sd_logvp
== NULLVP
) {
258 if (sd_openlog(ctx
) != 0) {
259 /* Couldn't open, we fail out */
264 va_start(arglist
, fmt
);
265 len
= vsnprintf(logbuf
, sizeof(logbuf
), fmt
, arglist
);
266 log_error
= vn_rdwr(UIO_WRITE
, sd_logvp
, (caddr_t
)logbuf
, len
, sd_log_offset
,
267 UIO_SYSSPACE
, IO_UNIT
| IO_NOAUTH
, vfs_context_ucred(ctx
), &resid
, vfs_context_proc(ctx
));
268 if (log_error
== EIO
|| log_error
== 0) {
269 sd_log_offset
+= (len
- resid
);
277 sd_filt1(proc_t p
, void * args
)
279 proc_t self
= current_proc();
280 struct sd_filterargs
* sf
= (struct sd_filterargs
*)args
;
281 int delayterm
= sf
-> delayterm
;
282 int shutdownstate
= sf
->shutdownstate
;
284 if (((p
->p_flag
&P_SYSTEM
) != 0) || (p
->p_ppid
== 0)
285 ||(p
== self
) || (p
->p_stat
== SZOMB
)
286 || (p
->p_shutdownstate
!= shutdownstate
)
287 ||((delayterm
== 0) && ((p
->p_lflag
& P_LDELAYTERM
) == P_LDELAYTERM
))
288 || ((p
->p_sigcatch
& sigmask(SIGTERM
))== 0)) {
297 sd_callback1(proc_t p
, void * args
)
299 struct sd_iterargs
* sd
= (struct sd_iterargs
*)args
;
300 int signo
= sd
->signo
;
301 int setsdstate
= sd
->setsdstate
;
302 int countproc
= sd
->countproc
;
305 p
->p_shutdownstate
= setsdstate
;
306 if (p
->p_stat
!= SZOMB
) {
308 if (countproc
!= 0) {
310 p
->p_listflag
|= P_LIST_EXITCOUNT
;
311 proc_shutdown_exitcount
++;
320 return(PROC_RETURNED
);
324 sd_filt2(proc_t p
, void * args
)
326 proc_t self
= current_proc();
327 struct sd_filterargs
* sf
= (struct sd_filterargs
*)args
;
328 int delayterm
= sf
-> delayterm
;
329 int shutdownstate
= sf
->shutdownstate
;
331 if (((p
->p_flag
&P_SYSTEM
) != 0) || (p
->p_ppid
== 0)
332 ||(p
== self
) || (p
->p_stat
== SZOMB
)
333 || (p
->p_shutdownstate
== shutdownstate
)
334 ||((delayterm
== 0) && ((p
->p_lflag
& P_LDELAYTERM
) == P_LDELAYTERM
))) {
342 sd_callback2(proc_t p
, void * args
)
344 struct sd_iterargs
* sd
= (struct sd_iterargs
*)args
;
345 int signo
= sd
->signo
;
346 int setsdstate
= sd
->setsdstate
;
347 int countproc
= sd
->countproc
;
350 p
->p_shutdownstate
= setsdstate
;
351 if (p
->p_stat
!= SZOMB
) {
353 if (countproc
!= 0) {
355 p
->p_listflag
|= P_LIST_EXITCOUNT
;
356 proc_shutdown_exitcount
++;
365 return(PROC_RETURNED
);
370 sd_callback3(proc_t p
, void * args
)
372 struct sd_iterargs
* sd
= (struct sd_iterargs
*)args
;
373 vfs_context_t ctx
= vfs_context_current();
375 int setsdstate
= sd
->setsdstate
;
378 p
->p_shutdownstate
= setsdstate
;
379 if (p
->p_stat
!= SZOMB
) {
381 * NOTE: following code ignores sig_lock and plays
382 * with exit_thread correctly. This is OK unless we
383 * are a multiprocessor, in which case I do not
384 * understand the sig_lock. This needs to be fixed.
387 if (p
->exit_thread
) { /* someone already doing it */
389 /* give him a chance */
390 thread_block(THREAD_CONTINUE_NULL
);
392 p
->exit_thread
= current_thread();
395 sd_log(ctx
, "%s[%d] had to be forced closed with exit1().\n", p
->p_comm
, p
->p_pid
);
398 KERNEL_DEBUG_CONSTANT(BSDDBG_CODE(DBG_BSD_PROC
, BSD_PROC_FRCEXIT
) | DBG_FUNC_NONE
,
399 p
->p_pid
, 0, 1, 0, 0);
401 exit1(p
, 1, (int *)NULL
);
406 return(PROC_RETURNED
);
413 * Shutdown down proc system (release references to current and root
414 * dirs for each process).
416 * POSIX modifications:
418 * For POSIX fcntl() file locking call vno_lockrelease() on
419 * the file to release all of its record locks, if any.
425 vfs_context_t ctx
= vfs_context_current();
426 struct proc
*p
, *self
;
428 struct sd_filterargs sfargs
;
429 struct sd_iterargs sdargs
;
434 * Kill as many procs as we can. (Except ourself...)
436 self
= (struct proc
*)current_proc();
439 * Signal the init with SIGTERM so that he does not launch
443 if (p
&& p
!= self
) {
448 printf("Killing all processes ");
452 * send SIGTERM to those procs interested in catching one
454 sfargs
.delayterm
= delayterm
;
455 sfargs
.shutdownstate
= 0;
456 sdargs
.signo
= SIGTERM
;
457 sdargs
.setsdstate
= 1;
458 sdargs
.countproc
= 1;
459 sdargs
.activecount
= 0;
462 /* post a SIGTERM to all that catch SIGTERM and not marked for delay */
463 proc_rebootscan(sd_callback1
, (void *)&sdargs
, sd_filt1
, (void *)&sfargs
);
465 if (sdargs
.activecount
!= 0 && proc_shutdown_exitcount
!= 0) {
467 if (proc_shutdown_exitcount
!= 0) {
469 * now wait for up to 30 seconds to allow those procs catching SIGTERM
471 * as soon as these procs have exited, we'll continue on to the next step
475 error
= msleep(&proc_shutdown_exitcount
, proc_list_mlock
, PWAIT
, "shutdownwait", &ts
);
477 for (p
= allproc
.lh_first
; p
; p
= p
->p_list
.le_next
) {
478 if ((p
->p_listflag
& P_LIST_EXITCOUNT
) == P_LIST_EXITCOUNT
)
479 p
->p_listflag
&= ~P_LIST_EXITCOUNT
;
481 for (p
= zombproc
.lh_first
; p
; p
= p
->p_list
.le_next
) {
482 if ((p
->p_listflag
& P_LIST_EXITCOUNT
) == P_LIST_EXITCOUNT
)
483 p
->p_listflag
&= ~P_LIST_EXITCOUNT
;
490 if (error
== ETIMEDOUT
) {
492 * log the names of the unresponsive tasks
498 for (p
= allproc
.lh_first
; p
; p
= p
->p_list
.le_next
) {
499 if (p
->p_shutdownstate
== 1) {
500 printf("%s[%d]: didn't act on SIGTERM\n", p
->p_comm
, p
->p_pid
);
501 sd_log(ctx
, "%s[%d]: didn't act on SIGTERM\n", p
->p_comm
, p
->p_pid
);
507 delay_for_interval(1000 * 5, 1000 * 1000);
511 * send a SIGKILL to all the procs still hanging around
513 sfargs
.delayterm
= delayterm
;
514 sfargs
.shutdownstate
= 2;
515 sdargs
.signo
= SIGKILL
;
516 sdargs
.setsdstate
= 2;
517 sdargs
.countproc
= 1;
518 sdargs
.activecount
= 0;
520 /* post a SIGKILL to all that catch SIGTERM and not marked for delay */
521 proc_rebootscan(sd_callback2
, (void *)&sdargs
, sd_filt2
, (void *)&sfargs
);
523 if (sdargs
.activecount
!= 0 && proc_shutdown_exitcount
!= 0) {
525 if (proc_shutdown_exitcount
!= 0) {
527 * wait for up to 60 seconds to allow these procs to exit normally
529 * History: The delay interval was changed from 100 to 200
530 * for NFS requests in particular.
534 error
= msleep(&proc_shutdown_exitcount
, proc_list_mlock
, PWAIT
, "shutdownwait", &ts
);
536 for (p
= allproc
.lh_first
; p
; p
= p
->p_list
.le_next
) {
537 if ((p
->p_listflag
& P_LIST_EXITCOUNT
) == P_LIST_EXITCOUNT
)
538 p
->p_listflag
&= ~P_LIST_EXITCOUNT
;
540 for (p
= zombproc
.lh_first
; p
; p
= p
->p_list
.le_next
) {
541 if ((p
->p_listflag
& P_LIST_EXITCOUNT
) == P_LIST_EXITCOUNT
)
542 p
->p_listflag
&= ~P_LIST_EXITCOUNT
;
550 * if we still have procs that haven't exited, then brute force 'em
552 sfargs
.delayterm
= delayterm
;
553 sfargs
.shutdownstate
= 3;
555 sdargs
.setsdstate
= 3;
556 sdargs
.countproc
= 0;
557 sdargs
.activecount
= 0;
559 /* post a SIGTERM to all that catch SIGTERM and not marked for delay */
560 proc_rebootscan(sd_callback3
, (void *)&sdargs
, sd_filt2
, (void *)&sfargs
);
563 /* Now start the termination of processes that are marked for delayed termn */
564 if (delayterm
== 0) {
571 /* drop the ref on initproc */
573 printf("continuing\n");