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