]>
Commit | Line | Data |
---|---|---|
1c79356b | 1 | /* |
2d21ac55 | 2 | * Copyright (c) 2000-2006 Apple Computer, Inc. All rights reserved. |
5d5c5d0d | 3 | * |
2d21ac55 | 4 | * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ |
0a7de745 | 5 | * |
2d21ac55 A |
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. | |
0a7de745 | 14 | * |
2d21ac55 A |
15 | * Please obtain a copy of the License at |
16 | * http://www.opensource.apple.com/apsl/ and read it before using this file. | |
0a7de745 | 17 | * |
2d21ac55 A |
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 | |
8f6c56a5 A |
20 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, |
21 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
2d21ac55 A |
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. | |
0a7de745 | 25 | * |
2d21ac55 | 26 | * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ |
1c79356b A |
27 | */ |
28 | /* | |
29 | * File: bsd/kern/kern_shutdown.c | |
30 | * | |
31 | * Copyright (C) 1989, NeXT, Inc. | |
32 | * | |
33 | */ | |
34 | ||
35 | #include <sys/param.h> | |
36 | #include <sys/systm.h> | |
37 | #include <sys/kernel.h> | |
38 | #include <sys/vm.h> | |
91447636 | 39 | #include <sys/proc_internal.h> |
1c79356b | 40 | #include <sys/user.h> |
1c79356b A |
41 | #include <sys/reboot.h> |
42 | #include <sys/conf.h> | |
91447636 A |
43 | #include <sys/vnode_internal.h> |
44 | #include <sys/file_internal.h> | |
1c79356b A |
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 <vm/vm_kern.h> |
53 | #include <mach/vm_param.h> | |
54 | #include <sys/filedesc.h> | |
91447636 | 55 | #include <mach/host_priv.h> |
1c79356b | 56 | #include <mach/host_reboot.h> |
91447636 | 57 | |
b0d623f7 | 58 | #include <security/audit/audit.h> |
1c79356b | 59 | |
0a7de745 A |
60 | #include <kern/sched_prim.h> /* for thread_block() */ |
61 | #include <kern/host.h> /* for host_priv_self() */ | |
62 | #include <net/if_var.h> /* for if_down_all() */ | |
63 | #include <sys/buf_internal.h> /* for count_busy_buffers() */ | |
64 | #include <sys/mount_internal.h> /* for vfs_unmountall() */ | |
65 | #include <mach/task.h> /* for task_suspend() */ | |
66 | #include <sys/sysproto.h> /* abused for sync() */ | |
67 | #include <kern/clock.h> /* for delay_for_interval() */ | |
6d2010ae | 68 | #include <libkern/OSAtomic.h> |
a39ff7e2 | 69 | #include <IOKit/IOPlatformExpert.h> |
c3c9b80d | 70 | #include <IOKit/IOMessage.h> |
2d21ac55 | 71 | |
b0d623f7 A |
72 | #include <sys/kdebug.h> |
73 | ||
6d2010ae | 74 | uint32_t system_inshutdown = 0; |
b0d623f7 | 75 | |
f427ee49 | 76 | #if XNU_TARGET_OS_OSX |
2d21ac55 | 77 | /* XXX should be in a header file somewhere, but isn't */ |
b0d623f7 | 78 | extern void (*unmountroot_pre_hook)(void); |
f427ee49 | 79 | #endif |
2d21ac55 | 80 | |
b0d623f7 | 81 | unsigned int proc_shutdown_exitcount = 0; |
2d21ac55 | 82 | |
b0d623f7 A |
83 | static int sd_openlog(vfs_context_t); |
84 | static int sd_closelog(vfs_context_t); | |
85 | static void sd_log(vfs_context_t, const char *, ...); | |
c3c9b80d | 86 | static void proc_shutdown(int only_non_dext); |
d26ffc64 | 87 | static void zprint_panic_info(void); |
5ba3f43e A |
88 | extern void halt_log_enter(const char * what, const void * pc, uint64_t time); |
89 | ||
490019cf A |
90 | #if DEVELOPMENT || DEBUG |
91 | extern boolean_t kdp_has_polled_corefile(void); | |
92 | #endif /* DEVELOPMENT || DEBUG */ | |
2d21ac55 | 93 | |
0a7de745 | 94 | struct sd_filterargs { |
2d21ac55 A |
95 | int delayterm; |
96 | int shutdownstate; | |
c3c9b80d | 97 | int only_non_dext; |
2d21ac55 A |
98 | }; |
99 | ||
100 | ||
101 | struct sd_iterargs { | |
0a7de745 A |
102 | int signo; /* the signal to be posted */ |
103 | int setsdstate; /* shutdown state to be set */ | |
104 | int countproc; /* count processes on action */ | |
105 | int activecount; /* number of processes on which action was done */ | |
2d21ac55 A |
106 | }; |
107 | ||
b0d623f7 A |
108 | static vnode_t sd_logvp = NULLVP; |
109 | static off_t sd_log_offset = 0; | |
110 | ||
111 | ||
2d21ac55 A |
112 | static int sd_filt1(proc_t, void *); |
113 | static int sd_filt2(proc_t, void *); | |
39037602 A |
114 | static int sd_callback1(proc_t p, void * arg); |
115 | static int sd_callback2(proc_t p, void * arg); | |
116 | static int sd_callback3(proc_t p, void * arg); | |
1c79356b | 117 | |
c3c9b80d | 118 | extern bool panic_include_zprint; |
5ba3f43e A |
119 | extern mach_memory_info_t *panic_kext_memory_info; |
120 | extern vm_size_t panic_kext_memory_size; | |
3e170ce0 A |
121 | |
122 | static void | |
d26ffc64 | 123 | zprint_panic_info(void) |
3e170ce0 | 124 | { |
5ba3f43e A |
125 | unsigned int num_sites; |
126 | kern_return_t kr; | |
3e170ce0 A |
127 | |
128 | panic_include_zprint = TRUE; | |
5ba3f43e | 129 | panic_kext_memory_info = NULL; |
3e170ce0 A |
130 | panic_kext_memory_size = 0; |
131 | ||
5ba3f43e A |
132 | num_sites = vm_page_diagnose_estimate(); |
133 | panic_kext_memory_size = num_sites * sizeof(panic_kext_memory_info[0]); | |
134 | ||
135 | kr = kmem_alloc(kernel_map, (vm_offset_t *)&panic_kext_memory_info, round_page(panic_kext_memory_size), VM_KERN_MEMORY_OSFMK); | |
3e170ce0 | 136 | if (kr != KERN_SUCCESS) { |
5ba3f43e | 137 | panic_kext_memory_info = NULL; |
3e170ce0 A |
138 | return; |
139 | } | |
5ba3f43e A |
140 | |
141 | vm_page_diagnose(panic_kext_memory_info, num_sites, 0); | |
3e170ce0 A |
142 | } |
143 | ||
813fb2f6 A |
144 | int |
145 | get_system_inshutdown() | |
146 | { | |
0a7de745 | 147 | return system_inshutdown; |
813fb2f6 A |
148 | } |
149 | ||
cb323159 | 150 | __abortlike |
d26ffc64 A |
151 | static void |
152 | panic_kernel(int howto, char *message) | |
153 | { | |
154 | if ((howto & RB_PANIC_ZPRINT) == RB_PANIC_ZPRINT) { | |
155 | zprint_panic_info(); | |
156 | } | |
157 | panic("userspace panic: %s", message); | |
158 | } | |
159 | ||
cb323159 A |
160 | extern boolean_t compressor_store_stop_compaction; |
161 | extern lck_mtx_t vm_swap_data_lock; | |
162 | extern int vm_swapfile_create_thread_running; | |
163 | extern int vm_swapfile_gc_thread_running; | |
164 | ||
6d2010ae | 165 | int |
3e170ce0 | 166 | reboot_kernel(int howto, char *message) |
1c79356b | 167 | { |
0a7de745 | 168 | int hostboot_option = 0; |
5ba3f43e | 169 | uint64_t startTime; |
1c79356b | 170 | |
d26ffc64 A |
171 | if ((howto & (RB_PANIC | RB_QUICK)) == (RB_PANIC | RB_QUICK)) { |
172 | panic_kernel(howto, message); | |
173 | } | |
174 | ||
6d2010ae | 175 | if (!OSCompareAndSwap(0, 1, &system_inshutdown)) { |
0a7de745 | 176 | if ((howto & RB_QUICK) == RB_QUICK) { |
6d2010ae | 177 | goto force_reboot; |
0a7de745 A |
178 | } |
179 | return EBUSY; | |
6d2010ae | 180 | } |
cb323159 A |
181 | |
182 | lck_mtx_lock(&vm_swap_data_lock); | |
183 | ||
184 | /* Turn OFF future swapfile reclaimation / compaction etc.*/ | |
185 | compressor_store_stop_compaction = TRUE; | |
186 | ||
187 | /* wait for any current swapfile work to end */ | |
188 | while (vm_swapfile_create_thread_running || vm_swapfile_gc_thread_running) { | |
189 | assert_wait((event_t)&compressor_store_stop_compaction, THREAD_UNINT); | |
190 | ||
191 | lck_mtx_unlock(&vm_swap_data_lock); | |
192 | ||
193 | thread_block(THREAD_CONTINUE_NULL); | |
194 | ||
195 | lck_mtx_lock(&vm_swap_data_lock); | |
196 | } | |
197 | ||
198 | lck_mtx_unlock(&vm_swap_data_lock); | |
199 | ||
6d2010ae | 200 | /* |
a39ff7e2 | 201 | * Notify the power management root domain that the system will shut down. |
6d2010ae | 202 | */ |
a39ff7e2 | 203 | IOSystemShutdownNotification(kIOSystemShutdownNotificationStageProcessExit); |
2d21ac55 | 204 | |
0a7de745 | 205 | if ((howto & RB_QUICK) == RB_QUICK) { |
b0d623f7 | 206 | printf("Quick reboot...\n"); |
0a7de745 | 207 | if ((howto & RB_NOSYNC) == 0) { |
3e170ce0 | 208 | sync((proc_t)NULL, (void *)NULL, (int *)NULL); |
b0d623f7 | 209 | } |
0a7de745 | 210 | } else if ((howto & RB_NOSYNC) == 0) { |
1c79356b A |
211 | int iter, nbusy; |
212 | ||
1c79356b A |
213 | printf("syncing disks... "); |
214 | ||
215 | /* | |
216 | * Release vnodes held by texts before sync. | |
217 | */ | |
218 | ||
3e170ce0 | 219 | /* handle live procs (deallocate their root and current directories), suspend initproc */ |
5ba3f43e A |
220 | |
221 | startTime = mach_absolute_time(); | |
c3c9b80d | 222 | proc_shutdown(TRUE); |
5ba3f43e | 223 | halt_log_enter("proc_shutdown", 0, mach_absolute_time() - startTime); |
1c79356b | 224 | |
b0d623f7 | 225 | #if CONFIG_AUDIT |
5ba3f43e | 226 | startTime = mach_absolute_time(); |
6d2010ae | 227 | audit_shutdown(); |
5ba3f43e | 228 | halt_log_enter("audit_shutdown", 0, mach_absolute_time() - startTime); |
2d21ac55 | 229 | #endif |
55e303ae | 230 | |
f427ee49 | 231 | #if XNU_TARGET_OS_OSX |
0a7de745 | 232 | if (unmountroot_pre_hook != NULL) { |
b0d623f7 | 233 | unmountroot_pre_hook(); |
0a7de745 | 234 | } |
f427ee49 | 235 | #endif |
b0d623f7 | 236 | |
5ba3f43e | 237 | startTime = mach_absolute_time(); |
3e170ce0 | 238 | sync((proc_t)NULL, (void *)NULL, (int *)NULL); |
1c79356b | 239 | |
5ba3f43e A |
240 | if (kdebug_enable) { |
241 | startTime = mach_absolute_time(); | |
b0d623f7 | 242 | kdbg_dump_trace_to_file("/var/log/shutdown/shutdown.trace"); |
5ba3f43e A |
243 | halt_log_enter("shutdown.trace", 0, mach_absolute_time() - startTime); |
244 | } | |
b0d623f7 | 245 | |
a39ff7e2 A |
246 | IOSystemShutdownNotification(kIOSystemShutdownNotificationStageRootUnmount); |
247 | ||
1c79356b A |
248 | /* |
249 | * Unmount filesystems | |
250 | */ | |
490019cf A |
251 | |
252 | #if DEVELOPMENT || DEBUG | |
253 | if (!(howto & RB_PANIC) || !kdp_has_polled_corefile()) | |
254 | #endif /* DEVELOPMENT || DEBUG */ | |
255 | { | |
5ba3f43e | 256 | startTime = mach_absolute_time(); |
c3c9b80d | 257 | vfs_unmountall(TRUE); |
5ba3f43e | 258 | halt_log_enter("vfs_unmountall", 0, mach_absolute_time() - startTime); |
490019cf | 259 | } |
1c79356b | 260 | |
c3c9b80d A |
261 | IOSystemShutdownNotification(kIOSystemShutdownNotificationTerminateDEXTs); |
262 | ||
263 | startTime = mach_absolute_time(); | |
264 | proc_shutdown(FALSE); | |
265 | halt_log_enter("proc_shutdown", 0, mach_absolute_time() - startTime); | |
266 | ||
267 | #if DEVELOPMENT || DEBUG | |
268 | if (!(howto & RB_PANIC) || !kdp_has_polled_corefile()) | |
269 | #endif /* DEVELOPMENT || DEBUG */ | |
270 | { | |
271 | startTime = mach_absolute_time(); | |
272 | vfs_unmountall(FALSE); | |
273 | halt_log_enter("vfs_unmountall", 0, mach_absolute_time() - startTime); | |
274 | } | |
275 | ||
276 | ||
277 | ||
1c79356b | 278 | /* Wait for the buffer cache to clean remaining dirty buffers */ |
5ba3f43e | 279 | startTime = mach_absolute_time(); |
91447636 | 280 | for (iter = 0; iter < 100; iter++) { |
1c79356b | 281 | nbusy = count_busy_buffers(); |
0a7de745 | 282 | if (nbusy == 0) { |
1c79356b | 283 | break; |
0a7de745 | 284 | } |
1c79356b | 285 | printf("%d ", nbusy); |
2d21ac55 | 286 | delay_for_interval( 1 * nbusy, 1000 * 1000); |
1c79356b | 287 | } |
0a7de745 | 288 | if (nbusy) { |
1c79356b | 289 | printf("giving up\n"); |
0a7de745 | 290 | } else { |
1c79356b | 291 | printf("done\n"); |
0a7de745 | 292 | } |
5ba3f43e | 293 | halt_log_enter("bufferclean", 0, mach_absolute_time() - startTime); |
1c79356b | 294 | } |
2d21ac55 | 295 | #if NETWORKING |
1c79356b A |
296 | /* |
297 | * Can't just use an splnet() here to disable the network | |
298 | * because that will lock out softints which the disk | |
299 | * drivers depend on to finish DMAs. | |
300 | */ | |
5ba3f43e | 301 | startTime = mach_absolute_time(); |
1c79356b | 302 | if_down_all(); |
5ba3f43e | 303 | halt_log_enter("if_down_all", 0, mach_absolute_time() - startTime); |
2d21ac55 | 304 | #endif /* NETWORKING */ |
1c79356b | 305 | |
6d2010ae | 306 | force_reboot: |
3e170ce0 A |
307 | |
308 | if (howto & RB_PANIC) { | |
d26ffc64 | 309 | panic_kernel(howto, message); |
3e170ce0 A |
310 | } |
311 | ||
0a7de745 | 312 | if (howto & RB_HALT) { |
1c79356b | 313 | hostboot_option = HOST_REBOOT_HALT; |
0a7de745 | 314 | } |
1c79356b | 315 | |
6d2010ae A |
316 | if (howto & RB_UPSDELAY) { |
317 | hostboot_option = HOST_REBOOT_UPSDELAY; | |
318 | } | |
0c530ab8 | 319 | |
1c79356b | 320 | host_reboot(host_priv_self(), hostboot_option); |
6d2010ae A |
321 | /* |
322 | * should not be reached | |
323 | */ | |
0a7de745 | 324 | return 0; |
1c79356b A |
325 | } |
326 | ||
b0d623f7 A |
327 | static int |
328 | sd_openlog(vfs_context_t ctx) | |
329 | { | |
330 | int error = 0; | |
331 | struct timeval tv; | |
0a7de745 | 332 | |
b0d623f7 A |
333 | /* Open shutdown log */ |
334 | if ((error = vnode_open(PROC_SHUTDOWN_LOG, (O_CREAT | FWRITE | O_NOFOLLOW), 0644, 0, &sd_logvp, ctx))) { | |
335 | printf("Failed to open %s: error %d\n", PROC_SHUTDOWN_LOG, error); | |
336 | sd_logvp = NULLVP; | |
337 | return error; | |
338 | } | |
339 | ||
340 | vnode_setsize(sd_logvp, (off_t)0, 0, ctx); | |
341 | ||
342 | /* Write a little header */ | |
343 | microtime(&tv); | |
344 | sd_log(ctx, "Process shutdown log. Current time is %lu (in seconds).\n\n", tv.tv_sec); | |
345 | ||
346 | return 0; | |
347 | } | |
348 | ||
349 | static int | |
350 | sd_closelog(vfs_context_t ctx) | |
351 | { | |
352 | int error = 0; | |
353 | if (sd_logvp != NULLVP) { | |
354 | VNOP_FSYNC(sd_logvp, MNT_WAIT, ctx); | |
355 | error = vnode_close(sd_logvp, FWRITE, ctx); | |
c3c9b80d | 356 | sd_logvp = NULLVP; |
b0d623f7 A |
357 | } |
358 | ||
359 | return error; | |
360 | } | |
361 | ||
362 | static void | |
0a7de745 | 363 | sd_log(vfs_context_t ctx, const char *fmt, ...) |
b0d623f7 A |
364 | { |
365 | int resid, log_error, len; | |
366 | char logbuf[100]; | |
367 | va_list arglist; | |
368 | ||
369 | /* If the log isn't open yet, open it */ | |
370 | if (sd_logvp == NULLVP) { | |
371 | if (sd_openlog(ctx) != 0) { | |
372 | /* Couldn't open, we fail out */ | |
373 | return; | |
374 | } | |
375 | } | |
376 | ||
377 | va_start(arglist, fmt); | |
378 | len = vsnprintf(logbuf, sizeof(logbuf), fmt, arglist); | |
379 | log_error = vn_rdwr(UIO_WRITE, sd_logvp, (caddr_t)logbuf, len, sd_log_offset, | |
0a7de745 | 380 | UIO_SYSSPACE, IO_UNIT | IO_NOAUTH, vfs_context_ucred(ctx), &resid, vfs_context_proc(ctx)); |
b0d623f7 A |
381 | if (log_error == EIO || log_error == 0) { |
382 | sd_log_offset += (len - resid); | |
383 | } | |
384 | ||
385 | va_end(arglist); | |
b0d623f7 A |
386 | } |
387 | ||
c3c9b80d A |
388 | #define proc_is_driver(p) (task_is_driver((p)->task)) |
389 | ||
2d21ac55 A |
390 | static int |
391 | sd_filt1(proc_t p, void * args) | |
392 | { | |
393 | proc_t self = current_proc(); | |
394 | struct sd_filterargs * sf = (struct sd_filterargs *)args; | |
0a7de745 | 395 | int delayterm = sf->delayterm; |
2d21ac55 A |
396 | int shutdownstate = sf->shutdownstate; |
397 | ||
c3c9b80d A |
398 | if (sf->only_non_dext && proc_is_driver(p)) { |
399 | return 0; | |
400 | } | |
401 | ||
0a7de745 A |
402 | if (((p->p_flag & P_SYSTEM) != 0) || (p->p_ppid == 0) |
403 | || (p == self) || (p->p_stat == SZOMB) | |
404 | || (p->p_shutdownstate != shutdownstate) | |
405 | || ((delayterm == 0) && ((p->p_lflag & P_LDELAYTERM) == P_LDELAYTERM)) | |
406 | || ((p->p_sigcatch & sigmask(SIGTERM)) == 0)) { | |
407 | return 0; | |
408 | } else { | |
409 | return 1; | |
410 | } | |
2d21ac55 A |
411 | } |
412 | ||
413 | ||
39037602 | 414 | static int |
2d21ac55 A |
415 | sd_callback1(proc_t p, void * args) |
416 | { | |
417 | struct sd_iterargs * sd = (struct sd_iterargs *)args; | |
418 | int signo = sd->signo; | |
419 | int setsdstate = sd->setsdstate; | |
b0d623f7 | 420 | int countproc = sd->countproc; |
2d21ac55 A |
421 | |
422 | proc_lock(p); | |
f427ee49 | 423 | p->p_shutdownstate = (char)setsdstate; |
2d21ac55 A |
424 | if (p->p_stat != SZOMB) { |
425 | proc_unlock(p); | |
b0d623f7 A |
426 | if (countproc != 0) { |
427 | proc_list_lock(); | |
428 | p->p_listflag |= P_LIST_EXITCOUNT; | |
429 | proc_shutdown_exitcount++; | |
430 | proc_list_unlock(); | |
431 | } | |
c3c9b80d A |
432 | if (proc_is_driver(p)) { |
433 | printf("lingering dext %s signal(%d)\n", p->p_name, signo); | |
434 | } | |
2d21ac55 | 435 | psignal(p, signo); |
0a7de745 | 436 | if (countproc != 0) { |
b0d623f7 | 437 | sd->activecount++; |
0a7de745 | 438 | } |
39037602 | 439 | } else { |
2d21ac55 | 440 | proc_unlock(p); |
39037602 A |
441 | } |
442 | ||
443 | return PROC_RETURNED; | |
2d21ac55 A |
444 | } |
445 | ||
446 | static int | |
447 | sd_filt2(proc_t p, void * args) | |
448 | { | |
449 | proc_t self = current_proc(); | |
450 | struct sd_filterargs * sf = (struct sd_filterargs *)args; | |
0a7de745 | 451 | int delayterm = sf->delayterm; |
2d21ac55 A |
452 | int shutdownstate = sf->shutdownstate; |
453 | ||
c3c9b80d A |
454 | if (sf->only_non_dext && proc_is_driver(p)) { |
455 | return 0; | |
456 | } | |
457 | ||
0a7de745 A |
458 | if (((p->p_flag & P_SYSTEM) != 0) || (p->p_ppid == 0) |
459 | || (p == self) || (p->p_stat == SZOMB) | |
460 | || (p->p_shutdownstate == shutdownstate) | |
461 | || ((delayterm == 0) && ((p->p_lflag & P_LDELAYTERM) == P_LDELAYTERM))) { | |
462 | return 0; | |
463 | } else { | |
464 | return 1; | |
465 | } | |
2d21ac55 A |
466 | } |
467 | ||
39037602 | 468 | static int |
2d21ac55 A |
469 | sd_callback2(proc_t p, void * args) |
470 | { | |
471 | struct sd_iterargs * sd = (struct sd_iterargs *)args; | |
472 | int signo = sd->signo; | |
473 | int setsdstate = sd->setsdstate; | |
b0d623f7 | 474 | int countproc = sd->countproc; |
2d21ac55 A |
475 | |
476 | proc_lock(p); | |
f427ee49 | 477 | p->p_shutdownstate = (char)setsdstate; |
2d21ac55 A |
478 | if (p->p_stat != SZOMB) { |
479 | proc_unlock(p); | |
0a7de745 | 480 | if (countproc != 0) { |
b0d623f7 A |
481 | proc_list_lock(); |
482 | p->p_listflag |= P_LIST_EXITCOUNT; | |
483 | proc_shutdown_exitcount++; | |
484 | proc_list_unlock(); | |
485 | } | |
c3c9b80d A |
486 | if (proc_is_driver(p)) { |
487 | printf("lingering dext %s signal(%d)\n", p->p_name, signo); | |
488 | } | |
2d21ac55 | 489 | psignal(p, signo); |
0a7de745 | 490 | if (countproc != 0) { |
b0d623f7 | 491 | sd->activecount++; |
0a7de745 | 492 | } |
39037602 | 493 | } else { |
2d21ac55 | 494 | proc_unlock(p); |
39037602 | 495 | } |
2d21ac55 | 496 | |
39037602 | 497 | return PROC_RETURNED; |
2d21ac55 A |
498 | } |
499 | ||
39037602 | 500 | static int |
2d21ac55 A |
501 | sd_callback3(proc_t p, void * args) |
502 | { | |
503 | struct sd_iterargs * sd = (struct sd_iterargs *)args; | |
b0d623f7 A |
504 | vfs_context_t ctx = vfs_context_current(); |
505 | ||
2d21ac55 A |
506 | int setsdstate = sd->setsdstate; |
507 | ||
508 | proc_lock(p); | |
f427ee49 | 509 | p->p_shutdownstate = (char)setsdstate; |
2d21ac55 | 510 | if (p->p_stat != SZOMB) { |
0a7de745 A |
511 | /* |
512 | * NOTE: following code ignores sig_lock and plays | |
513 | * with exit_thread correctly. This is OK unless we | |
514 | * are a multiprocessor, in which case I do not | |
515 | * understand the sig_lock. This needs to be fixed. | |
516 | * XXX | |
517 | */ | |
518 | if (p->exit_thread) { /* someone already doing it */ | |
2d21ac55 A |
519 | proc_unlock(p); |
520 | /* give him a chance */ | |
521 | thread_block(THREAD_CONTINUE_NULL); | |
522 | } else { | |
523 | p->exit_thread = current_thread(); | |
524 | printf("."); | |
b0d623f7 A |
525 | |
526 | sd_log(ctx, "%s[%d] had to be forced closed with exit1().\n", p->p_comm, p->p_pid); | |
527 | ||
2d21ac55 | 528 | proc_unlock(p); |
b0d623f7 | 529 | KERNEL_DEBUG_CONSTANT(BSDDBG_CODE(DBG_BSD_PROC, BSD_PROC_FRCEXIT) | DBG_FUNC_NONE, |
0a7de745 | 530 | p->p_pid, 0, 1, 0, 0); |
b0d623f7 | 531 | sd->activecount++; |
2d21ac55 A |
532 | exit1(p, 1, (int *)NULL); |
533 | } | |
39037602 | 534 | } else { |
2d21ac55 | 535 | proc_unlock(p); |
39037602 | 536 | } |
2d21ac55 | 537 | |
39037602 | 538 | return PROC_RETURNED; |
2d21ac55 A |
539 | } |
540 | ||
541 | ||
1c79356b A |
542 | /* |
543 | * proc_shutdown() | |
544 | * | |
545 | * Shutdown down proc system (release references to current and root | |
546 | * dirs for each process). | |
547 | * | |
548 | * POSIX modifications: | |
549 | * | |
5ba3f43e | 550 | * For POSIX fcntl() file locking call vno_lockrelease() on |
1c79356b A |
551 | * the file to release all of its record locks, if any. |
552 | */ | |
553 | ||
554 | static void | |
c3c9b80d | 555 | proc_shutdown(int only_non_dext) |
1c79356b | 556 | { |
b0d623f7 A |
557 | vfs_context_t ctx = vfs_context_current(); |
558 | struct proc *p, *self; | |
91447636 | 559 | int delayterm = 0; |
2d21ac55 A |
560 | struct sd_filterargs sfargs; |
561 | struct sd_iterargs sdargs; | |
b0d623f7 A |
562 | int error = 0; |
563 | struct timespec ts; | |
1c79356b A |
564 | |
565 | /* | |
566 | * Kill as many procs as we can. (Except ourself...) | |
567 | */ | |
0b4e3aa0 | 568 | self = (struct proc *)current_proc(); |
5ba3f43e | 569 | |
1c79356b | 570 | /* |
91447636 | 571 | * Signal the init with SIGTERM so that he does not launch |
5ba3f43e | 572 | * new processes |
1c79356b | 573 | */ |
2d21ac55 | 574 | p = proc_find(1); |
91447636 A |
575 | if (p && p != self) { |
576 | psignal(p, SIGTERM); | |
577 | } | |
2d21ac55 | 578 | proc_rele(p); |
1c79356b | 579 | |
1c79356b A |
580 | printf("Killing all processes "); |
581 | ||
2d21ac55 | 582 | sigterm_loop: |
1c79356b A |
583 | /* |
584 | * send SIGTERM to those procs interested in catching one | |
585 | */ | |
2d21ac55 A |
586 | sfargs.delayterm = delayterm; |
587 | sfargs.shutdownstate = 0; | |
c3c9b80d | 588 | sfargs.only_non_dext = only_non_dext; |
2d21ac55 A |
589 | sdargs.signo = SIGTERM; |
590 | sdargs.setsdstate = 1; | |
b0d623f7 A |
591 | sdargs.countproc = 1; |
592 | sdargs.activecount = 0; | |
2d21ac55 | 593 | |
b0d623f7 | 594 | error = 0; |
2d21ac55 A |
595 | /* post a SIGTERM to all that catch SIGTERM and not marked for delay */ |
596 | proc_rebootscan(sd_callback1, (void *)&sdargs, sd_filt1, (void *)&sfargs); | |
91447636 | 597 | |
0a7de745 | 598 | if (sdargs.activecount != 0 && proc_shutdown_exitcount != 0) { |
2d21ac55 | 599 | proc_list_lock(); |
b0d623f7 A |
600 | if (proc_shutdown_exitcount != 0) { |
601 | /* | |
5ba3f43e A |
602 | * now wait for up to 3 seconds to allow those procs catching SIGTERM |
603 | * to digest it | |
604 | * as soon as these procs have exited, we'll continue on to the next step | |
605 | */ | |
606 | ts.tv_sec = 3; | |
b0d623f7 | 607 | ts.tv_nsec = 0; |
c3c9b80d | 608 | error = msleep(&proc_shutdown_exitcount, &proc_list_mlock, PWAIT, "shutdownwait", &ts); |
b0d623f7 A |
609 | if (error != 0) { |
610 | for (p = allproc.lh_first; p; p = p->p_list.le_next) { | |
0a7de745 | 611 | if ((p->p_listflag & P_LIST_EXITCOUNT) == P_LIST_EXITCOUNT) { |
b0d623f7 | 612 | p->p_listflag &= ~P_LIST_EXITCOUNT; |
0a7de745 | 613 | } |
b0d623f7 A |
614 | } |
615 | for (p = zombproc.lh_first; p; p = p->p_list.le_next) { | |
0a7de745 | 616 | if ((p->p_listflag & P_LIST_EXITCOUNT) == P_LIST_EXITCOUNT) { |
b0d623f7 | 617 | p->p_listflag &= ~P_LIST_EXITCOUNT; |
0a7de745 | 618 | } |
b0d623f7 | 619 | } |
91447636 | 620 | } |
1c79356b | 621 | } |
2d21ac55 | 622 | proc_list_unlock(); |
1c79356b | 623 | } |
b0d623f7 | 624 | if (error == ETIMEDOUT) { |
91447636 | 625 | /* |
55e303ae A |
626 | * log the names of the unresponsive tasks |
627 | */ | |
91447636 | 628 | |
2d21ac55 A |
629 | proc_list_lock(); |
630 | ||
b0d623f7 | 631 | for (p = allproc.lh_first; p; p = p->p_list.le_next) { |
91447636 | 632 | if (p->p_shutdownstate == 1) { |
b0d623f7 A |
633 | printf("%s[%d]: didn't act on SIGTERM\n", p->p_comm, p->p_pid); |
634 | sd_log(ctx, "%s[%d]: didn't act on SIGTERM\n", p->p_comm, p->p_pid); | |
91447636 | 635 | } |
55e303ae | 636 | } |
2d21ac55 A |
637 | |
638 | proc_list_unlock(); | |
55e303ae | 639 | } |
1c79356b A |
640 | |
641 | /* | |
642 | * send a SIGKILL to all the procs still hanging around | |
643 | */ | |
2d21ac55 A |
644 | sfargs.delayterm = delayterm; |
645 | sfargs.shutdownstate = 2; | |
646 | sdargs.signo = SIGKILL; | |
647 | sdargs.setsdstate = 2; | |
b0d623f7 A |
648 | sdargs.countproc = 1; |
649 | sdargs.activecount = 0; | |
2d21ac55 | 650 | |
b0d623f7 | 651 | /* post a SIGKILL to all that catch SIGTERM and not marked for delay */ |
2d21ac55 | 652 | proc_rebootscan(sd_callback2, (void *)&sdargs, sd_filt2, (void *)&sfargs); |
91447636 | 653 | |
5ba3f43e A |
654 | error = 0; |
655 | ||
0a7de745 | 656 | if (sdargs.activecount != 0 && proc_shutdown_exitcount != 0) { |
2d21ac55 | 657 | proc_list_lock(); |
b0d623f7 A |
658 | if (proc_shutdown_exitcount != 0) { |
659 | /* | |
0a7de745 A |
660 | * wait for up to 60 seconds to allow these procs to exit normally |
661 | * | |
662 | * History: The delay interval was changed from 100 to 200 | |
663 | * for NFS requests in particular. | |
664 | */ | |
5ba3f43e | 665 | ts.tv_sec = 10; |
b0d623f7 | 666 | ts.tv_nsec = 0; |
c3c9b80d | 667 | error = msleep(&proc_shutdown_exitcount, &proc_list_mlock, PWAIT, "shutdownwait", &ts); |
b0d623f7 A |
668 | if (error != 0) { |
669 | for (p = allproc.lh_first; p; p = p->p_list.le_next) { | |
0a7de745 | 670 | if ((p->p_listflag & P_LIST_EXITCOUNT) == P_LIST_EXITCOUNT) { |
b0d623f7 | 671 | p->p_listflag &= ~P_LIST_EXITCOUNT; |
0a7de745 | 672 | } |
b0d623f7 A |
673 | } |
674 | for (p = zombproc.lh_first; p; p = p->p_list.le_next) { | |
0a7de745 | 675 | if ((p->p_listflag & P_LIST_EXITCOUNT) == P_LIST_EXITCOUNT) { |
b0d623f7 | 676 | p->p_listflag &= ~P_LIST_EXITCOUNT; |
0a7de745 | 677 | } |
b0d623f7 A |
678 | } |
679 | } | |
1c79356b | 680 | } |
2d21ac55 | 681 | proc_list_unlock(); |
1c79356b A |
682 | } |
683 | ||
5ba3f43e A |
684 | if (error == ETIMEDOUT) { |
685 | /* | |
686 | * log the names of the unresponsive tasks | |
687 | */ | |
688 | ||
689 | proc_list_lock(); | |
690 | ||
691 | for (p = allproc.lh_first; p; p = p->p_list.le_next) { | |
692 | if (p->p_shutdownstate == 2) { | |
693 | printf("%s[%d]: didn't act on SIGKILL\n", p->p_comm, p->p_pid); | |
694 | sd_log(ctx, "%s[%d]: didn't act on SIGKILL\n", p->p_comm, p->p_pid); | |
695 | } | |
696 | } | |
697 | ||
698 | proc_list_unlock(); | |
699 | } | |
700 | ||
1c79356b A |
701 | /* |
702 | * if we still have procs that haven't exited, then brute force 'em | |
703 | */ | |
2d21ac55 A |
704 | sfargs.delayterm = delayterm; |
705 | sfargs.shutdownstate = 3; | |
706 | sdargs.signo = 0; | |
707 | sdargs.setsdstate = 3; | |
b0d623f7 A |
708 | sdargs.countproc = 0; |
709 | sdargs.activecount = 0; | |
4a249263 | 710 | |
5ba3f43e A |
711 | |
712 | ||
2d21ac55 A |
713 | /* post a SIGTERM to all that catch SIGTERM and not marked for delay */ |
714 | proc_rebootscan(sd_callback3, (void *)&sdargs, sd_filt2, (void *)&sfargs); | |
715 | printf("\n"); | |
91447636 A |
716 | |
717 | /* Now start the termination of processes that are marked for delayed termn */ | |
718 | if (delayterm == 0) { | |
719 | delayterm = 1; | |
720 | goto sigterm_loop; | |
1c79356b | 721 | } |
b0d623f7 A |
722 | |
723 | sd_closelog(ctx); | |
724 | ||
c3c9b80d A |
725 | if (only_non_dext) { |
726 | return; | |
727 | } | |
728 | ||
3e170ce0 A |
729 | /* |
730 | * Now that all other processes have been terminated, suspend init | |
731 | */ | |
732 | task_suspend_internal(initproc->task); | |
733 | ||
2d21ac55 A |
734 | /* drop the ref on initproc */ |
735 | proc_rele(initproc); | |
1c79356b A |
736 | printf("continuing\n"); |
737 | } |