Print this page
OS-2366 ddi_periodic_add(9F) is entirely rubbish (MORE)
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/common/syscall/uadmin.c
+++ new/usr/src/uts/common/syscall/uadmin.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
↓ open down ↓ |
14 lines elided |
↑ open up ↑ |
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21
22 22 /*
23 23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 24 * Use is subject to license terms.
25 - * Copyright 2011 Joyent, Inc. All rights reserved.
25 + * Copyright 2013 Joyent, Inc. All rights reserved.
26 26 */
27 27
28 28 #include <sys/param.h>
29 29 #include <sys/types.h>
30 30 #include <sys/sysmacros.h>
31 31 #include <sys/systm.h>
32 32 #include <sys/errno.h>
33 33 #include <sys/vfs.h>
34 34 #include <sys/vnode.h>
35 35 #include <sys/swap.h>
36 36 #include <sys/file.h>
37 37 #include <sys/proc.h>
38 38 #include <sys/var.h>
39 39 #include <sys/uadmin.h>
40 40 #include <sys/signal.h>
↓ open down ↓ |
5 lines elided |
↑ open up ↑ |
41 41 #include <sys/time.h>
42 42 #include <vm/seg_kmem.h>
43 43 #include <sys/modctl.h>
44 44 #include <sys/callb.h>
45 45 #include <sys/dumphdr.h>
46 46 #include <sys/debug.h>
47 47 #include <sys/ftrace.h>
48 48 #include <sys/cmn_err.h>
49 49 #include <sys/panic.h>
50 50 #include <sys/ddi.h>
51 +#include <sys/ddi_periodic.h>
51 52 #include <sys/sunddi.h>
52 53 #include <sys/policy.h>
53 54 #include <sys/zone.h>
54 55 #include <sys/condvar.h>
55 56 #include <sys/thread.h>
56 57 #include <sys/sdt.h>
57 58
58 59 /*
59 60 * Administrivia system call. We provide this in two flavors: one for calling
60 61 * from the system call path (uadmin), and the other for calling from elsewhere
61 62 * within the kernel (kadmin). Callers must beware that certain uadmin cmd
62 63 * values (specifically A_SWAPCTL) are only supported by uadmin and not kadmin.
63 64 */
64 65
65 66 extern ksema_t fsflush_sema;
66 67 kmutex_t ualock;
67 68 kcondvar_t uacond;
68 69 kthread_t *ua_shutdown_thread = NULL;
69 70
70 71 int sys_shutdown = 0;
71 72 volatile int fastreboot_dryrun = 0;
72 73
73 74 /*
74 75 * Kill all user processes in said zone. A special argument of ALL_ZONES is
75 76 * passed in when the system as a whole is shutting down. The lack of per-zone
76 77 * process lists is likely to make the following a performance bottleneck on a
77 78 * system with many zones.
78 79 */
79 80 void
80 81 killall(zoneid_t zoneid, boolean_t force)
81 82 {
82 83 proc_t *p;
83 84
84 85 ASSERT(zoneid != GLOBAL_ZONEID);
85 86 /*
86 87 * Kill all processes except kernel daemons and ourself.
87 88 * Make a first pass to stop all processes so they won't
88 89 * be trying to restart children as we kill them.
89 90 */
90 91 mutex_enter(&pidlock);
91 92 for (p = practive; p != NULL; p = p->p_next) {
92 93 if ((zoneid == ALL_ZONES || p->p_zone->zone_id == zoneid) &&
93 94 p->p_exec != NULLVP && /* kernel daemons */
94 95 p->p_as != &kas &&
95 96 p->p_stat != SZOMB) {
96 97 mutex_enter(&p->p_lock);
97 98 p->p_flag |= SNOWAIT;
98 99 sigtoproc(p, NULL, SIGSTOP);
99 100 mutex_exit(&p->p_lock);
100 101 }
101 102 }
102 103 p = practive;
103 104 while (p != NULL) {
104 105 if ((zoneid == ALL_ZONES || p->p_zone->zone_id == zoneid) &&
105 106 p->p_exec != NULLVP && /* kernel daemons */
106 107 p->p_as != &kas &&
107 108 p->p_stat != SIDL &&
108 109 p->p_stat != SZOMB) {
109 110 mutex_enter(&p->p_lock);
110 111 if (!force && sigismember(&p->p_sig, SIGKILL)) {
111 112 mutex_exit(&p->p_lock);
112 113 p = p->p_next;
113 114 } else {
114 115 sigtoproc(p, NULL, SIGKILL);
115 116 mutex_exit(&p->p_lock);
116 117 (void) cv_reltimedwait(&p->p_srwchan_cv,
117 118 &pidlock, hz, TR_CLOCK_TICK);
118 119 p = practive;
119 120 }
120 121 } else {
121 122 p = p->p_next;
122 123 }
123 124 }
124 125 mutex_exit(&pidlock);
125 126 }
126 127
127 128 int
128 129 kadmin(int cmd, int fcn, void *mdep, cred_t *credp)
129 130 {
130 131 int error = 0;
131 132 char *buf;
132 133 size_t buflen = 0;
133 134 boolean_t invoke_cb = B_FALSE;
134 135
135 136 /*
136 137 * We might be called directly by the kernel's fault-handling code, so
137 138 * we can't assert that the caller is in the global zone.
138 139 */
139 140
140 141 /*
141 142 * Make sure that cmd is one of the valid <sys/uadmin.h> command codes
142 143 * and that we have appropriate privileges for this action.
143 144 */
144 145 switch (cmd) {
145 146 case A_FTRACE:
146 147 case A_SHUTDOWN:
147 148 case A_REBOOT:
148 149 case A_REMOUNT:
149 150 case A_FREEZE:
150 151 case A_DUMP:
151 152 case A_SDTTEST:
152 153 case A_CONFIG:
153 154 if (secpolicy_sys_config(credp, B_FALSE) != 0)
154 155 return (EPERM);
155 156 break;
156 157
157 158 default:
158 159 return (EINVAL);
159 160 }
160 161
161 162 /*
162 163 * Serialize these operations on ualock. If it is held, the
163 164 * system should shutdown, reboot, or remount shortly, unless there is
164 165 * an error. We need a cv rather than just a mutex because proper
165 166 * functioning of A_REBOOT relies on being able to interrupt blocked
166 167 * userland callers.
167 168 *
168 169 * We only clear ua_shutdown_thread after A_REMOUNT or A_CONFIG.
169 170 * Other commands should never return.
170 171 */
171 172 if (cmd == A_SHUTDOWN || cmd == A_REBOOT || cmd == A_REMOUNT ||
172 173 cmd == A_CONFIG) {
173 174 mutex_enter(&ualock);
174 175 while (ua_shutdown_thread != NULL) {
175 176 if (cv_wait_sig(&uacond, &ualock) == 0) {
176 177 /*
177 178 * If we were interrupted, leave, and handle
178 179 * the signal (or exit, depending on what
179 180 * happened)
180 181 */
181 182 mutex_exit(&ualock);
182 183 return (EINTR);
183 184 }
184 185 }
185 186 ua_shutdown_thread = curthread;
186 187 mutex_exit(&ualock);
187 188 }
188 189
189 190 switch (cmd) {
190 191 case A_SHUTDOWN:
191 192 {
192 193 proc_t *p = ttoproc(curthread);
193 194
194 195 /*
195 196 * Release (almost) all of our own resources if we are called
196 197 * from a user context, however if we are calling kadmin() from
197 198 * a kernel context then we do not release these resources.
198 199 */
199 200 if (p != &p0) {
200 201 proc_is_exiting(p);
201 202 if ((error = exitlwps(0)) != 0) {
202 203 /*
203 204 * Another thread in this process also called
204 205 * exitlwps().
205 206 */
206 207 mutex_enter(&ualock);
207 208 ua_shutdown_thread = NULL;
208 209 cv_signal(&uacond);
209 210 mutex_exit(&ualock);
210 211 return (error);
211 212 }
212 213 mutex_enter(&p->p_lock);
213 214 p->p_flag |= SNOWAIT;
214 215 sigfillset(&p->p_ignore);
215 216 curthread->t_lwp->lwp_cursig = 0;
216 217 curthread->t_lwp->lwp_extsig = 0;
217 218 if (p->p_exec) {
218 219 vnode_t *exec_vp = p->p_exec;
219 220 p->p_exec = NULLVP;
220 221 mutex_exit(&p->p_lock);
221 222 VN_RELE(exec_vp);
222 223 } else {
223 224 mutex_exit(&p->p_lock);
224 225 }
225 226
226 227 pollcleanup();
227 228 closeall(P_FINFO(curproc));
228 229 relvm();
229 230
230 231 } else {
231 232 /*
232 233 * Reset t_cred if not set because much of the
233 234 * filesystem code depends on CRED() being valid.
234 235 */
235 236 if (curthread->t_cred == NULL)
236 237 curthread->t_cred = kcred;
237 238 }
238 239
239 240 /* indicate shutdown in progress */
240 241 sys_shutdown = 1;
241 242
242 243 /*
243 244 * Communcate that init shouldn't be restarted.
244 245 */
245 246 zone_shutdown_global();
246 247
247 248 killall(ALL_ZONES, B_FALSE);
248 249 /*
249 250 * If we are calling kadmin() from a kernel context then we
250 251 * do not release these resources.
251 252 */
252 253 if (ttoproc(curthread) != &p0) {
253 254 VN_RELE(PTOU(curproc)->u_cdir);
254 255 if (PTOU(curproc)->u_rdir)
255 256 VN_RELE(PTOU(curproc)->u_rdir);
256 257 if (PTOU(curproc)->u_cwd)
257 258 refstr_rele(PTOU(curproc)->u_cwd);
258 259
259 260 PTOU(curproc)->u_cdir = rootdir;
260 261 PTOU(curproc)->u_rdir = NULL;
261 262 PTOU(curproc)->u_cwd = NULL;
262 263 }
263 264
264 265 /*
265 266 * Allow the reboot/halt/poweroff code a chance to do
266 267 * anything it needs to whilst we still have filesystems
267 268 * mounted, like loading any modules necessary for later
268 269 * performing the actual poweroff.
269 270 */
270 271 if ((mdep != NULL) && (*(char *)mdep == '/')) {
271 272 buf = i_convert_boot_device_name(mdep, NULL, &buflen);
272 273 mdpreboot(cmd, fcn, buf);
273 274 } else
274 275 mdpreboot(cmd, fcn, mdep);
275 276
276 277 /*
277 278 * Allow fsflush to finish running and then prevent it
↓ open down ↓ |
217 lines elided |
↑ open up ↑ |
278 279 * from ever running again so that vfs_unmountall() and
279 280 * vfs_syncall() can acquire the vfs locks they need.
280 281 */
281 282 sema_p(&fsflush_sema);
282 283 (void) callb_execute_class(CB_CL_UADMIN_PRE_VFS, NULL);
283 284
284 285 vfs_unmountall();
285 286 (void) VFS_MOUNTROOT(rootvfs, ROOT_UNMOUNT);
286 287 vfs_syncall();
287 288
289 + /*
290 + * Check for (and unregister) any DDI periodic handlers that
291 + * still exist, as they most likely constitute resource leaks:
292 + */
293 + ddi_periodic_fini();
294 +
288 295 dump_ereports();
289 296 dump_messages();
290 297
291 298 invoke_cb = B_TRUE;
292 299
293 300 /* FALLTHROUGH */
294 301 }
295 302
296 303 case A_REBOOT:
297 304 if ((mdep != NULL) && (*(char *)mdep == '/')) {
298 305 buf = i_convert_boot_device_name(mdep, NULL, &buflen);
299 306 mdboot(cmd, fcn, buf, invoke_cb);
300 307 } else
301 308 mdboot(cmd, fcn, mdep, invoke_cb);
302 309 /* no return expected */
303 310 break;
304 311
305 312 case A_CONFIG:
306 313 switch (fcn) {
307 314 case AD_UPDATE_BOOT_CONFIG:
308 315 #ifndef __sparc
309 316 {
310 317 extern void fastboot_update_config(const char *);
311 318
312 319 fastboot_update_config(mdep);
313 320 }
314 321 #endif
315 322
316 323 break;
317 324 }
318 325 /* Let other threads enter the shutdown path now */
319 326 mutex_enter(&ualock);
320 327 ua_shutdown_thread = NULL;
321 328 cv_signal(&uacond);
322 329 mutex_exit(&ualock);
323 330 break;
324 331
325 332 case A_REMOUNT:
326 333 (void) VFS_MOUNTROOT(rootvfs, ROOT_REMOUNT);
327 334 /* Let other threads enter the shutdown path now */
328 335 mutex_enter(&ualock);
329 336 ua_shutdown_thread = NULL;
330 337 cv_signal(&uacond);
331 338 mutex_exit(&ualock);
332 339 break;
333 340
334 341 case A_FREEZE:
335 342 {
336 343 /*
337 344 * This is the entrypoint for all suspend/resume actions.
338 345 */
339 346 extern int cpr(int, void *);
340 347
341 348 if (modload("misc", "cpr") == -1)
342 349 return (ENOTSUP);
343 350 /* Let the CPR module decide what to do with mdep */
344 351 error = cpr(fcn, mdep);
345 352 break;
346 353 }
347 354
348 355 case A_FTRACE:
349 356 {
350 357 switch (fcn) {
351 358 case AD_FTRACE_START:
352 359 (void) FTRACE_START();
353 360 break;
354 361 case AD_FTRACE_STOP:
355 362 (void) FTRACE_STOP();
356 363 break;
357 364 default:
358 365 error = EINVAL;
359 366 }
360 367 break;
361 368 }
362 369
363 370 case A_DUMP:
364 371 {
365 372 if (fcn == AD_NOSYNC) {
366 373 in_sync = 1;
367 374 break;
368 375 }
369 376
370 377 panic_bootfcn = fcn;
371 378 panic_forced = 1;
372 379
373 380 if ((mdep != NULL) && (*(char *)mdep == '/')) {
374 381 panic_bootstr = i_convert_boot_device_name(mdep,
375 382 NULL, &buflen);
376 383 } else
377 384 panic_bootstr = mdep;
378 385
379 386 #ifndef __sparc
380 387 extern void fastboot_update_and_load(int, char *);
381 388
382 389 fastboot_update_and_load(fcn, mdep);
383 390 #endif
384 391
385 392 panic("forced crash dump initiated at user request");
386 393 /*NOTREACHED*/
387 394 }
388 395
389 396 case A_SDTTEST:
390 397 {
391 398 DTRACE_PROBE7(test, int, 1, int, 2, int, 3, int, 4, int, 5,
392 399 int, 6, int, 7);
393 400 break;
394 401 }
395 402
396 403 default:
397 404 error = EINVAL;
398 405 }
399 406
400 407 return (error);
401 408 }
402 409
403 410 int
404 411 uadmin(int cmd, int fcn, uintptr_t mdep)
405 412 {
406 413 int error = 0, rv = 0;
407 414 size_t nbytes = 0;
408 415 cred_t *credp = CRED();
409 416 char *bootargs = NULL;
410 417 int reset_status = 0;
411 418
412 419 if (cmd == A_SHUTDOWN && fcn == AD_FASTREBOOT_DRYRUN) {
413 420 ddi_walk_devs(ddi_root_node(), check_driver_quiesce,
414 421 &reset_status);
415 422 if (reset_status != 0)
416 423 return (EIO);
417 424 else
418 425 return (0);
419 426 }
420 427
421 428 /*
422 429 * The swapctl system call doesn't have its own entry point: it uses
423 430 * uadmin as a wrapper so we just call it directly from here.
424 431 */
425 432 if (cmd == A_SWAPCTL) {
426 433 if (get_udatamodel() == DATAMODEL_NATIVE)
427 434 error = swapctl(fcn, (void *)mdep, &rv);
428 435 #if defined(_SYSCALL32_IMPL)
429 436 else
430 437 error = swapctl32(fcn, (void *)mdep, &rv);
431 438 #endif /* _SYSCALL32_IMPL */
432 439 return (error ? set_errno(error) : rv);
433 440 }
434 441
435 442 /*
436 443 * Certain subcommands intepret a non-NULL mdep value as a pointer to
437 444 * a boot string. We pull that in as bootargs, if applicable.
438 445 */
439 446 if (mdep != NULL &&
440 447 (cmd == A_SHUTDOWN || cmd == A_REBOOT || cmd == A_DUMP ||
441 448 cmd == A_FREEZE || cmd == A_CONFIG)) {
442 449 bootargs = kmem_zalloc(BOOTARGS_MAX, KM_SLEEP);
443 450 if ((error = copyinstr((const char *)mdep, bootargs,
444 451 BOOTARGS_MAX, &nbytes)) != 0) {
445 452 kmem_free(bootargs, BOOTARGS_MAX);
446 453 return (set_errno(error));
447 454 }
448 455 }
449 456
450 457 /*
451 458 * Invoke the appropriate kadmin() routine.
452 459 */
453 460 if (getzoneid() != GLOBAL_ZONEID)
454 461 error = zone_kadmin(cmd, fcn, bootargs, credp);
455 462 else
456 463 error = kadmin(cmd, fcn, bootargs, credp);
457 464
458 465 if (bootargs != NULL)
459 466 kmem_free(bootargs, BOOTARGS_MAX);
460 467 return (error ? set_errno(error) : 0);
461 468 }
↓ open down ↓ |
164 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX