]> git.saurik.com Git - apple/xnu.git/blame - bsd/kern/kern_shutdown.c
xnu-517.3.15.tar.gz
[apple/xnu.git] / bsd / kern / kern_shutdown.c
CommitLineData
1c79356b
A
1/*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
43866e37 6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
1c79356b 7 *
43866e37
A
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * file.
14 *
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
1c79356b
A
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
43866e37
A
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
1c79356b
A
22 *
23 * @APPLE_LICENSE_HEADER_END@
24 */
25/*
26 * File: bsd/kern/kern_shutdown.c
27 *
28 * Copyright (C) 1989, NeXT, Inc.
29 *
30 */
31
32#include <sys/param.h>
33#include <sys/systm.h>
34#include <sys/kernel.h>
35#include <sys/vm.h>
36#include <sys/proc.h>
37#include <sys/user.h>
38#include <sys/buf.h>
39#include <sys/reboot.h>
40#include <sys/conf.h>
41#include <sys/vnode.h>
42#include <sys/file.h>
43#include <sys/clist.h>
44#include <sys/callout.h>
45#include <sys/mbuf.h>
46#include <sys/msgbuf.h>
47#include <sys/ioctl.h>
48#include <sys/signal.h>
49#include <sys/tty.h>
50#include <kern/task.h>
9bccf70c 51#include <sys/quota.h>
1c79356b
A
52#include <ufs/ufs/inode.h>
53#if NCPUS > 1
54#include <kern/processor.h>
55#include <kern/thread.h>
56#include <sys/lock.h>
57#endif /* NCPUS > 1 */
58#include <vm/vm_kern.h>
59#include <mach/vm_param.h>
60#include <sys/filedesc.h>
61#include <mach/host_reboot.h>
55e303ae 62#include <sys/kern_audit.h>
1c79356b
A
63
64int waittime = -1;
65
66void
67boot(paniced, howto, command)
68 int paniced, howto;
69 char *command;
70{
71 register int i;
72 int s;
73 struct proc *p = current_proc(); /* XXX */
74 int hostboot_option=0;
75 int funnel_state;
76
0b4e3aa0
A
77 static void proc_shutdown();
78 extern void md_prepare_for_shutdown(int paniced, int howto, char * command);
1c79356b
A
79
80 funnel_state = thread_funnel_set(kernel_flock, TRUE);
81
0b4e3aa0 82 md_prepare_for_shutdown(paniced, howto, command);
1c79356b
A
83
84 if ((howto&RB_NOSYNC)==0 && waittime < 0) {
85 int iter, nbusy;
86
87 waittime = 0;
88
89 printf("syncing disks... ");
90
91 /*
92 * Release vnodes held by texts before sync.
93 */
94
95 /* handle live procs (deallocate their root and current directories). */
96 proc_shutdown();
97
55e303ae
A
98 audit_shutdown();
99
1c79356b
A
100 sync(p, (void *)NULL, (int *)NULL);
101
102 /* Release vnodes from the VM object cache */
103 ubc_unmountall();
104
105 IOSleep( 1 * 1000 );
106
107 /*
108 * Unmount filesystems
109 */
110 if (panicstr == 0)
111 vfs_unmountall();
112
113 /* Wait for the buffer cache to clean remaining dirty buffers */
114 for (iter = 0; iter < 20; iter++) {
115 nbusy = count_busy_buffers();
116 if (nbusy == 0)
117 break;
118 printf("%d ", nbusy);
119 IOSleep( 4 * nbusy );
120 }
121 if (nbusy)
122 printf("giving up\n");
123 else
124 printf("done\n");
125 }
126
127 /*
128 * Can't just use an splnet() here to disable the network
129 * because that will lock out softints which the disk
130 * drivers depend on to finish DMAs.
131 */
132 if_down_all();
133
134 if (howto & RB_POWERDOWN)
135 hostboot_option = HOST_REBOOT_HALT;
136 if (howto & RB_HALT)
137 hostboot_option = HOST_REBOOT_HALT;
138 if (paniced == RB_PANIC)
139 hostboot_option = HOST_REBOOT_HALT;
140
141 if (hostboot_option == HOST_REBOOT_HALT)
142 IOSleep( 1 * 1000 );
143
144 host_reboot(host_priv_self(), hostboot_option);
145
146 thread_funnel_set(kernel_flock, FALSE);
147}
148
149/*
150 * proc_shutdown()
151 *
152 * Shutdown down proc system (release references to current and root
153 * dirs for each process).
154 *
155 * POSIX modifications:
156 *
157 * For POSIX fcntl() file locking call vno_lockrelease() on
158 * the file to release all of its record locks, if any.
159 */
160
161static void
162proc_shutdown()
163{
164 struct proc *p, *self;
165 struct vnode **cdirp, **rdirp, *vp;
166 int restart, i, TERM_catch;
167
168 /*
169 * Kill as many procs as we can. (Except ourself...)
170 */
0b4e3aa0 171 self = (struct proc *)current_proc();
1c79356b
A
172
173 /*
174 * Suspend /etc/init
175 */
176 p = pfind(1);
177 if (p && p != self)
178 task_suspend(p->task); /* stop init */
179
1c79356b
A
180 printf("Killing all processes ");
181
182 /*
183 * send SIGTERM to those procs interested in catching one
184 */
4a249263 185sigterm_loop:
1c79356b 186 for (p = allproc.lh_first; p; p = p->p_list.le_next) {
4a249263
A
187 if (((p->p_flag&P_SYSTEM) == 0) && (p->p_pptr->p_pid != 0) && (p != self) && (p->p_shutdownstate == 0)) {
188 if (p->p_sigcatch & sigmask(SIGTERM)) {
189 p->p_shutdownstate = 1;
1c79356b 190 psignal(p, SIGTERM);
4a249263
A
191
192 goto sigterm_loop;
193 }
1c79356b
A
194 }
195 }
196 /*
197 * now wait for up to 30 seconds to allow those procs catching SIGTERM
198 * to digest it
199 * as soon as these procs have exited, we'll continue on to the next step
200 */
201 for (i = 0; i < 300; i++) {
202 /*
203 * sleep for a tenth of a second
204 * and then check to see if the tasks that were sent a
205 * SIGTERM have exited
206 */
207 IOSleep(100);
208 TERM_catch = 0;
209
210 for (p = allproc.lh_first; p; p = p->p_list.le_next) {
4a249263
A
211 if (p->p_shutdownstate == 1)
212 TERM_catch++;
1c79356b
A
213 }
214 if (TERM_catch == 0)
215 break;
216 }
55e303ae
A
217 if (TERM_catch) {
218 /*
219 * log the names of the unresponsive tasks
220 */
55e303ae 221 for (p = allproc.lh_first; p; p = p->p_list.le_next) {
4a249263 222 if (p->p_shutdownstate == 1)
55e303ae 223 printf("%s[%d]: didn't act on SIGTERM\n", p->p_comm, p->p_pid);
55e303ae
A
224 }
225 IOSleep(1000 * 5);
226 }
1c79356b
A
227
228 /*
229 * send a SIGKILL to all the procs still hanging around
230 */
4a249263 231sigkill_loop:
1c79356b 232 for (p = allproc.lh_first; p; p = p->p_list.le_next) {
4a249263 233 if (((p->p_flag&P_SYSTEM) == 0) && (p->p_pptr->p_pid != 0) && (p != self) && (p->p_shutdownstate != 2)) {
1c79356b 234 psignal(p, SIGKILL);
4a249263
A
235 p->p_shutdownstate = 2;
236
237 goto sigkill_loop;
238 }
1c79356b
A
239 }
240 /*
241 * wait for up to 60 seconds to allow these procs to exit normally
242 */
243 for (i = 0; i < 300; i++) {
244 IOSleep(200); /* double the time from 100 to 200 for NFS requests in particular */
245
246 for (p = allproc.lh_first; p; p = p->p_list.le_next) {
4a249263 247 if (p->p_shutdownstate == 2)
1c79356b
A
248 break;
249 }
250 if (!p)
251 break;
252 }
253
254 /*
255 * if we still have procs that haven't exited, then brute force 'em
256 */
257 p = allproc.lh_first;
258 while (p) {
259 if ((p->p_flag&P_SYSTEM) || (p->p_pptr->p_pid == 0) || (p == self)) {
260 p = p->p_list.le_next;
261 }
262 else {
263 /*
264 * NOTE: following code ignores sig_lock and plays
265 * with exit_thread correctly. This is OK unless we
266 * are a multiprocessor, in which case I do not
267 * understand the sig_lock. This needs to be fixed.
268 * XXX
269 */
270 if (p->exit_thread) { /* someone already doing it */
9bccf70c
A
271 /* give him a chance */
272 thread_block(THREAD_CONTINUE_NULL);
1c79356b
A
273 }
274 else {
55e303ae 275 p->exit_thread = current_act();
1c79356b 276 printf(".");
0b4e3aa0 277 exit1(p, 1, (int *)NULL);
1c79356b
A
278 }
279 p = allproc.lh_first;
280 }
281 }
282 printf("\n");
283 /*
284 * Forcibly free resources of what's left.
285 */
4a249263 286#ifdef notyet
1c79356b
A
287 p = allproc.lh_first;
288 while (p) {
289 /*
290 * Close open files and release open-file table.
291 * This may block!
292 */
4a249263 293
1c79356b
A
294 /* panics on reboot due to "zfree: non-allocated memory in collectable zone" message */
295 fdfree(p);
1c79356b
A
296 p = p->p_list.le_next;
297 }
4a249263 298#endif /* notyet */
1c79356b
A
299 /* Wait for the reaper thread to run, and clean up what we have done
300 * before we proceed with the hardcore shutdown. This reduces the race
301 * between kill_tasks and the reaper thread.
302 */
303 /* thread_wakeup(&reaper_queue); */
304 /* IOSleep( 1 * 1000); */
305 printf("continuing\n");
306}
307