xref: /onnv-gate/usr/src/uts/common/syscall/uadmin.c (revision 11066:cebb50cbe4f9)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
52267Sdp  * Common Development and Distribution License (the "License").
62267Sdp  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
21390Sraf 
220Sstevel@tonic-gate /*
239160SSherry.Moore@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
270Sstevel@tonic-gate #include <sys/param.h>
280Sstevel@tonic-gate #include <sys/types.h>
290Sstevel@tonic-gate #include <sys/sysmacros.h>
300Sstevel@tonic-gate #include <sys/systm.h>
310Sstevel@tonic-gate #include <sys/errno.h>
320Sstevel@tonic-gate #include <sys/vfs.h>
330Sstevel@tonic-gate #include <sys/vnode.h>
340Sstevel@tonic-gate #include <sys/swap.h>
350Sstevel@tonic-gate #include <sys/file.h>
360Sstevel@tonic-gate #include <sys/proc.h>
370Sstevel@tonic-gate #include <sys/var.h>
380Sstevel@tonic-gate #include <sys/uadmin.h>
390Sstevel@tonic-gate #include <sys/signal.h>
400Sstevel@tonic-gate #include <sys/time.h>
410Sstevel@tonic-gate #include <vm/seg_kmem.h>
420Sstevel@tonic-gate #include <sys/modctl.h>
430Sstevel@tonic-gate #include <sys/callb.h>
440Sstevel@tonic-gate #include <sys/dumphdr.h>
450Sstevel@tonic-gate #include <sys/debug.h>
460Sstevel@tonic-gate #include <sys/ftrace.h>
470Sstevel@tonic-gate #include <sys/cmn_err.h>
480Sstevel@tonic-gate #include <sys/panic.h>
490Sstevel@tonic-gate #include <sys/ddi.h>
500Sstevel@tonic-gate #include <sys/sunddi.h>
510Sstevel@tonic-gate #include <sys/policy.h>
520Sstevel@tonic-gate #include <sys/zone.h>
534579Scg209009 #include <sys/condvar.h>
544579Scg209009 #include <sys/thread.h>
556878Sbrendan #include <sys/sdt.h>
560Sstevel@tonic-gate 
570Sstevel@tonic-gate /*
580Sstevel@tonic-gate  * Administrivia system call.  We provide this in two flavors: one for calling
590Sstevel@tonic-gate  * from the system call path (uadmin), and the other for calling from elsewhere
600Sstevel@tonic-gate  * within the kernel (kadmin).  Callers must beware that certain uadmin cmd
610Sstevel@tonic-gate  * values (specifically A_SWAPCTL) are only supported by uadmin and not kadmin.
620Sstevel@tonic-gate  */
630Sstevel@tonic-gate 
640Sstevel@tonic-gate extern ksema_t fsflush_sema;
650Sstevel@tonic-gate kmutex_t ualock;
664579Scg209009 kcondvar_t uacond;
674579Scg209009 kthread_t *ua_shutdown_thread = NULL;
680Sstevel@tonic-gate 
692621Sllai1 int sys_shutdown = 0;
707656SSherry.Moore@Sun.COM volatile int fastreboot_dryrun = 0;
710Sstevel@tonic-gate 
720Sstevel@tonic-gate /*
730Sstevel@tonic-gate  * Kill all user processes in said zone.  A special argument of ALL_ZONES is
740Sstevel@tonic-gate  * passed in when the system as a whole is shutting down.  The lack of per-zone
750Sstevel@tonic-gate  * process lists is likely to make the following a performance bottleneck on a
760Sstevel@tonic-gate  * system with many zones.
770Sstevel@tonic-gate  */
780Sstevel@tonic-gate void
killall(zoneid_t zoneid)790Sstevel@tonic-gate killall(zoneid_t zoneid)
800Sstevel@tonic-gate {
810Sstevel@tonic-gate 	proc_t *p;
820Sstevel@tonic-gate 
830Sstevel@tonic-gate 	ASSERT(zoneid != GLOBAL_ZONEID);
840Sstevel@tonic-gate 	/*
850Sstevel@tonic-gate 	 * Kill all processes except kernel daemons and ourself.
860Sstevel@tonic-gate 	 * Make a first pass to stop all processes so they won't
870Sstevel@tonic-gate 	 * be trying to restart children as we kill them.
880Sstevel@tonic-gate 	 */
890Sstevel@tonic-gate 	mutex_enter(&pidlock);
900Sstevel@tonic-gate 	for (p = practive; p != NULL; p = p->p_next) {
910Sstevel@tonic-gate 		if ((zoneid == ALL_ZONES || p->p_zone->zone_id == zoneid) &&
920Sstevel@tonic-gate 		    p->p_exec != NULLVP &&	/* kernel daemons */
930Sstevel@tonic-gate 		    p->p_as != &kas &&
940Sstevel@tonic-gate 		    p->p_stat != SZOMB) {
950Sstevel@tonic-gate 			mutex_enter(&p->p_lock);
960Sstevel@tonic-gate 			p->p_flag |= SNOWAIT;
970Sstevel@tonic-gate 			sigtoproc(p, NULL, SIGSTOP);
980Sstevel@tonic-gate 			mutex_exit(&p->p_lock);
990Sstevel@tonic-gate 		}
1000Sstevel@tonic-gate 	}
1010Sstevel@tonic-gate 	p = practive;
1020Sstevel@tonic-gate 	while (p != NULL) {
1030Sstevel@tonic-gate 		if ((zoneid == ALL_ZONES || p->p_zone->zone_id == zoneid) &&
1040Sstevel@tonic-gate 		    p->p_exec != NULLVP &&	/* kernel daemons */
1050Sstevel@tonic-gate 		    p->p_as != &kas &&
1060Sstevel@tonic-gate 		    p->p_stat != SIDL &&
1070Sstevel@tonic-gate 		    p->p_stat != SZOMB) {
1080Sstevel@tonic-gate 			mutex_enter(&p->p_lock);
1090Sstevel@tonic-gate 			if (sigismember(&p->p_sig, SIGKILL)) {
1100Sstevel@tonic-gate 				mutex_exit(&p->p_lock);
1110Sstevel@tonic-gate 				p = p->p_next;
1120Sstevel@tonic-gate 			} else {
1130Sstevel@tonic-gate 				sigtoproc(p, NULL, SIGKILL);
1140Sstevel@tonic-gate 				mutex_exit(&p->p_lock);
115*11066Srafael.vanoni@sun.com 				(void) cv_reltimedwait(&p->p_srwchan_cv,
116*11066Srafael.vanoni@sun.com 				    &pidlock, hz, TR_CLOCK_TICK);
1170Sstevel@tonic-gate 				p = practive;
1180Sstevel@tonic-gate 			}
1190Sstevel@tonic-gate 		} else {
1200Sstevel@tonic-gate 			p = p->p_next;
1210Sstevel@tonic-gate 		}
1220Sstevel@tonic-gate 	}
1230Sstevel@tonic-gate 	mutex_exit(&pidlock);
1240Sstevel@tonic-gate }
1250Sstevel@tonic-gate 
1260Sstevel@tonic-gate int
kadmin(int cmd,int fcn,void * mdep,cred_t * credp)1270Sstevel@tonic-gate kadmin(int cmd, int fcn, void *mdep, cred_t *credp)
1280Sstevel@tonic-gate {
1290Sstevel@tonic-gate 	int error = 0;
1300Sstevel@tonic-gate 	char *buf;
1310Sstevel@tonic-gate 	size_t buflen = 0;
132136Sachartre 	boolean_t invoke_cb = B_FALSE;
1330Sstevel@tonic-gate 
1340Sstevel@tonic-gate 	/*
1350Sstevel@tonic-gate 	 * We might be called directly by the kernel's fault-handling code, so
1360Sstevel@tonic-gate 	 * we can't assert that the caller is in the global zone.
1370Sstevel@tonic-gate 	 */
1380Sstevel@tonic-gate 
1390Sstevel@tonic-gate 	/*
1400Sstevel@tonic-gate 	 * Make sure that cmd is one of the valid <sys/uadmin.h> command codes
1410Sstevel@tonic-gate 	 * and that we have appropriate privileges for this action.
1420Sstevel@tonic-gate 	 */
1430Sstevel@tonic-gate 	switch (cmd) {
1440Sstevel@tonic-gate 	case A_FTRACE:
1450Sstevel@tonic-gate 	case A_SHUTDOWN:
1460Sstevel@tonic-gate 	case A_REBOOT:
1470Sstevel@tonic-gate 	case A_REMOUNT:
1480Sstevel@tonic-gate 	case A_FREEZE:
1490Sstevel@tonic-gate 	case A_DUMP:
1506878Sbrendan 	case A_SDTTEST:
1519160SSherry.Moore@Sun.COM 	case A_CONFIG:
1520Sstevel@tonic-gate 		if (secpolicy_sys_config(credp, B_FALSE) != 0)
1530Sstevel@tonic-gate 			return (EPERM);
1540Sstevel@tonic-gate 		break;
1550Sstevel@tonic-gate 
1560Sstevel@tonic-gate 	default:
1570Sstevel@tonic-gate 		return (EINVAL);
1580Sstevel@tonic-gate 	}
1590Sstevel@tonic-gate 
1600Sstevel@tonic-gate 	/*
1614579Scg209009 	 * Serialize these operations on ualock.  If it is held, the
1624579Scg209009 	 * system should shutdown, reboot, or remount shortly, unless there is
1634579Scg209009 	 * an error.  We need a cv rather than just a mutex because proper
1644579Scg209009 	 * functioning of A_REBOOT relies on being able to interrupt blocked
1654579Scg209009 	 * userland callers.
1664579Scg209009 	 *
1679160SSherry.Moore@Sun.COM 	 * We only clear ua_shutdown_thread after A_REMOUNT or A_CONFIG.
1689160SSherry.Moore@Sun.COM 	 * Other commands should never return.
1690Sstevel@tonic-gate 	 */
1709160SSherry.Moore@Sun.COM 	if (cmd == A_SHUTDOWN || cmd == A_REBOOT || cmd == A_REMOUNT ||
1719160SSherry.Moore@Sun.COM 	    cmd == A_CONFIG) {
1724579Scg209009 		mutex_enter(&ualock);
1734579Scg209009 		while (ua_shutdown_thread != NULL) {
1744579Scg209009 			if (cv_wait_sig(&uacond, &ualock) == 0) {
1754579Scg209009 				/*
1764579Scg209009 				 * If we were interrupted, leave, and handle
1774579Scg209009 				 * the signal (or exit, depending on what
1784579Scg209009 				 * happened)
1794579Scg209009 				 */
1804579Scg209009 				mutex_exit(&ualock);
1814579Scg209009 				return (EINTR);
1824579Scg209009 			}
1834579Scg209009 		}
1844579Scg209009 		ua_shutdown_thread = curthread;
1854579Scg209009 		mutex_exit(&ualock);
1860Sstevel@tonic-gate 	}
1870Sstevel@tonic-gate 
1880Sstevel@tonic-gate 	switch (cmd) {
1890Sstevel@tonic-gate 	case A_SHUTDOWN:
1900Sstevel@tonic-gate 	{
1910Sstevel@tonic-gate 		proc_t *p = ttoproc(curthread);
1920Sstevel@tonic-gate 
1930Sstevel@tonic-gate 		/*
1940Sstevel@tonic-gate 		 * Release (almost) all of our own resources if we are called
1950Sstevel@tonic-gate 		 * from a user context, however if we are calling kadmin() from
1960Sstevel@tonic-gate 		 * a kernel context then we do not release these resources.
1970Sstevel@tonic-gate 		 */
198390Sraf 		if (p != &p0) {
199390Sraf 			proc_is_exiting(p);
2004434Scg209009 			if ((error = exitlwps(0)) != 0) {
2014579Scg209009 				/*
2024579Scg209009 				 * Another thread in this process also called
2034579Scg209009 				 * exitlwps().
2044579Scg209009 				 */
2054579Scg209009 				mutex_enter(&ualock);
2064579Scg209009 				ua_shutdown_thread = NULL;
2074579Scg209009 				cv_signal(&uacond);
2084434Scg209009 				mutex_exit(&ualock);
2090Sstevel@tonic-gate 				return (error);
2104434Scg209009 			}
2110Sstevel@tonic-gate 			mutex_enter(&p->p_lock);
2120Sstevel@tonic-gate 			p->p_flag |= SNOWAIT;
2130Sstevel@tonic-gate 			sigfillset(&p->p_ignore);
2140Sstevel@tonic-gate 			curthread->t_lwp->lwp_cursig = 0;
2150Sstevel@tonic-gate 			curthread->t_lwp->lwp_extsig = 0;
2160Sstevel@tonic-gate 			if (p->p_exec) {
2170Sstevel@tonic-gate 				vnode_t *exec_vp = p->p_exec;
2180Sstevel@tonic-gate 				p->p_exec = NULLVP;
2190Sstevel@tonic-gate 				mutex_exit(&p->p_lock);
2200Sstevel@tonic-gate 				VN_RELE(exec_vp);
2210Sstevel@tonic-gate 			} else {
2220Sstevel@tonic-gate 				mutex_exit(&p->p_lock);
2230Sstevel@tonic-gate 			}
2240Sstevel@tonic-gate 
2250Sstevel@tonic-gate 			pollcleanup();
2260Sstevel@tonic-gate 			closeall(P_FINFO(curproc));
2270Sstevel@tonic-gate 			relvm();
2280Sstevel@tonic-gate 
2290Sstevel@tonic-gate 		} else {
2300Sstevel@tonic-gate 			/*
2310Sstevel@tonic-gate 			 * Reset t_cred if not set because much of the
2320Sstevel@tonic-gate 			 * filesystem code depends on CRED() being valid.
2330Sstevel@tonic-gate 			 */
2340Sstevel@tonic-gate 			if (curthread->t_cred == NULL)
2350Sstevel@tonic-gate 				curthread->t_cred = kcred;
2360Sstevel@tonic-gate 		}
2370Sstevel@tonic-gate 
2382621Sllai1 		/* indicate shutdown in progress */
2392621Sllai1 		sys_shutdown = 1;
2402621Sllai1 
2410Sstevel@tonic-gate 		/*
2420Sstevel@tonic-gate 		 * Communcate that init shouldn't be restarted.
2430Sstevel@tonic-gate 		 */
2440Sstevel@tonic-gate 		zone_shutdown_global();
2450Sstevel@tonic-gate 
2460Sstevel@tonic-gate 		killall(ALL_ZONES);
2470Sstevel@tonic-gate 		/*
2480Sstevel@tonic-gate 		 * If we are calling kadmin() from a kernel context then we
2490Sstevel@tonic-gate 		 * do not release these resources.
2500Sstevel@tonic-gate 		 */
2510Sstevel@tonic-gate 		if (ttoproc(curthread) != &p0) {
2523446Smrj 			VN_RELE(PTOU(curproc)->u_cdir);
2533446Smrj 			if (PTOU(curproc)->u_rdir)
2543446Smrj 				VN_RELE(PTOU(curproc)->u_rdir);
2553446Smrj 			if (PTOU(curproc)->u_cwd)
2563446Smrj 				refstr_rele(PTOU(curproc)->u_cwd);
2570Sstevel@tonic-gate 
2583446Smrj 			PTOU(curproc)->u_cdir = rootdir;
2593446Smrj 			PTOU(curproc)->u_rdir = NULL;
2603446Smrj 			PTOU(curproc)->u_cwd = NULL;
2610Sstevel@tonic-gate 		}
2620Sstevel@tonic-gate 
2630Sstevel@tonic-gate 		/*
2640Sstevel@tonic-gate 		 * Allow the reboot/halt/poweroff code a chance to do
2650Sstevel@tonic-gate 		 * anything it needs to whilst we still have filesystems
2660Sstevel@tonic-gate 		 * mounted, like loading any modules necessary for later
2670Sstevel@tonic-gate 		 * performing the actual poweroff.
2680Sstevel@tonic-gate 		 */
2690Sstevel@tonic-gate 		if ((mdep != NULL) && (*(char *)mdep == '/')) {
2700Sstevel@tonic-gate 			buf = i_convert_boot_device_name(mdep, NULL, &buflen);
2710Sstevel@tonic-gate 			mdpreboot(cmd, fcn, buf);
2720Sstevel@tonic-gate 		} else
2730Sstevel@tonic-gate 			mdpreboot(cmd, fcn, mdep);
2740Sstevel@tonic-gate 
2750Sstevel@tonic-gate 		/*
2760Sstevel@tonic-gate 		 * Allow fsflush to finish running and then prevent it
2770Sstevel@tonic-gate 		 * from ever running again so that vfs_unmountall() and
2780Sstevel@tonic-gate 		 * vfs_syncall() can acquire the vfs locks they need.
2790Sstevel@tonic-gate 		 */
2800Sstevel@tonic-gate 		sema_p(&fsflush_sema);
2810Sstevel@tonic-gate 		(void) callb_execute_class(CB_CL_UADMIN_PRE_VFS, NULL);
2820Sstevel@tonic-gate 
2830Sstevel@tonic-gate 		vfs_unmountall();
2840Sstevel@tonic-gate 		(void) VFS_MOUNTROOT(rootvfs, ROOT_UNMOUNT);
2850Sstevel@tonic-gate 		vfs_syncall();
2860Sstevel@tonic-gate 
2870Sstevel@tonic-gate 		dump_ereports();
2880Sstevel@tonic-gate 		dump_messages();
2890Sstevel@tonic-gate 
290136Sachartre 		invoke_cb = B_TRUE;
291136Sachartre 
2920Sstevel@tonic-gate 		/* FALLTHROUGH */
2930Sstevel@tonic-gate 	}
2940Sstevel@tonic-gate 
2950Sstevel@tonic-gate 	case A_REBOOT:
2960Sstevel@tonic-gate 		if ((mdep != NULL) && (*(char *)mdep == '/')) {
2970Sstevel@tonic-gate 			buf = i_convert_boot_device_name(mdep, NULL, &buflen);
298136Sachartre 			mdboot(cmd, fcn, buf, invoke_cb);
2990Sstevel@tonic-gate 		} else
300136Sachartre 			mdboot(cmd, fcn, mdep, invoke_cb);
3010Sstevel@tonic-gate 		/* no return expected */
3020Sstevel@tonic-gate 		break;
3030Sstevel@tonic-gate 
3049160SSherry.Moore@Sun.COM 	case A_CONFIG:
3059160SSherry.Moore@Sun.COM 		switch (fcn) {
3069160SSherry.Moore@Sun.COM 		case AD_UPDATE_BOOT_CONFIG:
3079160SSherry.Moore@Sun.COM #ifndef	__sparc
3089160SSherry.Moore@Sun.COM 		{
3099160SSherry.Moore@Sun.COM 			extern void fastboot_update_config(const char *);
3109160SSherry.Moore@Sun.COM 
31110559SSherry.Moore@Sun.COM 			fastboot_update_config(mdep);
3129160SSherry.Moore@Sun.COM 		}
3139160SSherry.Moore@Sun.COM #endif
3149160SSherry.Moore@Sun.COM 
3159160SSherry.Moore@Sun.COM 			break;
3169160SSherry.Moore@Sun.COM 		}
3179160SSherry.Moore@Sun.COM 		/* Let other threads enter the shutdown path now */
3189160SSherry.Moore@Sun.COM 		mutex_enter(&ualock);
3199160SSherry.Moore@Sun.COM 		ua_shutdown_thread = NULL;
3209160SSherry.Moore@Sun.COM 		cv_signal(&uacond);
3219160SSherry.Moore@Sun.COM 		mutex_exit(&ualock);
3229160SSherry.Moore@Sun.COM 		break;
3239160SSherry.Moore@Sun.COM 
3240Sstevel@tonic-gate 	case A_REMOUNT:
3250Sstevel@tonic-gate 		(void) VFS_MOUNTROOT(rootvfs, ROOT_REMOUNT);
3264579Scg209009 		/* Let other threads enter the shutdown path now */
3274579Scg209009 		mutex_enter(&ualock);
3284579Scg209009 		ua_shutdown_thread = NULL;
3294579Scg209009 		cv_signal(&uacond);
3304579Scg209009 		mutex_exit(&ualock);
3310Sstevel@tonic-gate 		break;
3320Sstevel@tonic-gate 
3330Sstevel@tonic-gate 	case A_FREEZE:
3340Sstevel@tonic-gate 	{
3355295Srandyf 		/*
3365295Srandyf 		 * This is the entrypoint for all suspend/resume actions.
3375295Srandyf 		 */
3385295Srandyf 		extern int cpr(int, void *);
3390Sstevel@tonic-gate 
3400Sstevel@tonic-gate 		if (modload("misc", "cpr") == -1)
3410Sstevel@tonic-gate 			return (ENOTSUP);
3425295Srandyf 		/* Let the CPR module decide what to do with mdep */
3435295Srandyf 		error = cpr(fcn, mdep);
3440Sstevel@tonic-gate 		break;
3450Sstevel@tonic-gate 	}
3460Sstevel@tonic-gate 
3470Sstevel@tonic-gate 	case A_FTRACE:
3480Sstevel@tonic-gate 	{
3490Sstevel@tonic-gate 		switch (fcn) {
3500Sstevel@tonic-gate 		case AD_FTRACE_START:
3510Sstevel@tonic-gate 			(void) FTRACE_START();
3520Sstevel@tonic-gate 			break;
3530Sstevel@tonic-gate 		case AD_FTRACE_STOP:
3540Sstevel@tonic-gate 			(void) FTRACE_STOP();
3550Sstevel@tonic-gate 			break;
3560Sstevel@tonic-gate 		default:
3570Sstevel@tonic-gate 			error = EINVAL;
3580Sstevel@tonic-gate 		}
3590Sstevel@tonic-gate 		break;
3600Sstevel@tonic-gate 	}
3610Sstevel@tonic-gate 
3620Sstevel@tonic-gate 	case A_DUMP:
3630Sstevel@tonic-gate 	{
3640Sstevel@tonic-gate 		if (fcn == AD_NOSYNC) {
3650Sstevel@tonic-gate 			in_sync = 1;
3660Sstevel@tonic-gate 			break;
3670Sstevel@tonic-gate 		}
3680Sstevel@tonic-gate 
3690Sstevel@tonic-gate 		panic_bootfcn = fcn;
3700Sstevel@tonic-gate 		panic_forced = 1;
3710Sstevel@tonic-gate 
3720Sstevel@tonic-gate 		if ((mdep != NULL) && (*(char *)mdep == '/')) {
3730Sstevel@tonic-gate 			panic_bootstr = i_convert_boot_device_name(mdep,
3742267Sdp 			    NULL, &buflen);
3750Sstevel@tonic-gate 		} else
3760Sstevel@tonic-gate 			panic_bootstr = mdep;
3770Sstevel@tonic-gate 
3789160SSherry.Moore@Sun.COM #ifndef	__sparc
37910559SSherry.Moore@Sun.COM 		extern void fastboot_update_and_load(int, char *);
3809160SSherry.Moore@Sun.COM 
38110559SSherry.Moore@Sun.COM 		fastboot_update_and_load(fcn, mdep);
3829160SSherry.Moore@Sun.COM #endif
3839160SSherry.Moore@Sun.COM 
3840Sstevel@tonic-gate 		panic("forced crash dump initiated at user request");
3850Sstevel@tonic-gate 		/*NOTREACHED*/
3860Sstevel@tonic-gate 	}
3870Sstevel@tonic-gate 
3886878Sbrendan 	case A_SDTTEST:
3896878Sbrendan 	{
3906878Sbrendan 		DTRACE_PROBE7(test, int, 1, int, 2, int, 3, int, 4, int, 5,
3916878Sbrendan 		    int, 6, int, 7);
3926878Sbrendan 		break;
3936878Sbrendan 	}
3946878Sbrendan 
3950Sstevel@tonic-gate 	default:
3960Sstevel@tonic-gate 		error = EINVAL;
3970Sstevel@tonic-gate 	}
3980Sstevel@tonic-gate 
3990Sstevel@tonic-gate 	return (error);
4000Sstevel@tonic-gate }
4010Sstevel@tonic-gate 
4020Sstevel@tonic-gate int
uadmin(int cmd,int fcn,uintptr_t mdep)4030Sstevel@tonic-gate uadmin(int cmd, int fcn, uintptr_t mdep)
4040Sstevel@tonic-gate {
4050Sstevel@tonic-gate 	int error = 0, rv = 0;
4060Sstevel@tonic-gate 	size_t nbytes = 0;
4070Sstevel@tonic-gate 	cred_t *credp = CRED();
4082267Sdp 	char *bootargs = NULL;
4097656SSherry.Moore@Sun.COM 	int reset_status = 0;
4107656SSherry.Moore@Sun.COM 
4117656SSherry.Moore@Sun.COM 	if (cmd == A_SHUTDOWN && fcn == AD_FASTREBOOT_DRYRUN) {
4127656SSherry.Moore@Sun.COM 		ddi_walk_devs(ddi_root_node(), check_driver_quiesce,
4137656SSherry.Moore@Sun.COM 		    &reset_status);
4147656SSherry.Moore@Sun.COM 		if (reset_status != 0)
4157656SSherry.Moore@Sun.COM 			return (EIO);
4167656SSherry.Moore@Sun.COM 		else
4177656SSherry.Moore@Sun.COM 			return (0);
4187656SSherry.Moore@Sun.COM 	}
4190Sstevel@tonic-gate 
4200Sstevel@tonic-gate 	/*
4210Sstevel@tonic-gate 	 * The swapctl system call doesn't have its own entry point: it uses
4220Sstevel@tonic-gate 	 * uadmin as a wrapper so we just call it directly from here.
4230Sstevel@tonic-gate 	 */
4240Sstevel@tonic-gate 	if (cmd == A_SWAPCTL) {
4250Sstevel@tonic-gate 		if (get_udatamodel() == DATAMODEL_NATIVE)
4260Sstevel@tonic-gate 			error = swapctl(fcn, (void *)mdep, &rv);
4270Sstevel@tonic-gate #if defined(_SYSCALL32_IMPL)
4280Sstevel@tonic-gate 		else
4290Sstevel@tonic-gate 			error = swapctl32(fcn, (void *)mdep, &rv);
4300Sstevel@tonic-gate #endif /* _SYSCALL32_IMPL */
4310Sstevel@tonic-gate 		return (error ? set_errno(error) : rv);
4320Sstevel@tonic-gate 	}
4330Sstevel@tonic-gate 
4340Sstevel@tonic-gate 	/*
4352267Sdp 	 * Certain subcommands intepret a non-NULL mdep value as a pointer to
4362267Sdp 	 * a boot string.  We pull that in as bootargs, if applicable.
4370Sstevel@tonic-gate 	 */
4382267Sdp 	if (mdep != NULL &&
4395295Srandyf 	    (cmd == A_SHUTDOWN || cmd == A_REBOOT || cmd == A_DUMP ||
4409160SSherry.Moore@Sun.COM 	    cmd == A_FREEZE || cmd == A_CONFIG)) {
4412267Sdp 		bootargs = kmem_zalloc(BOOTARGS_MAX, KM_SLEEP);
4422267Sdp 		if ((error = copyinstr((const char *)mdep, bootargs,
4432267Sdp 		    BOOTARGS_MAX, &nbytes)) != 0) {
4442267Sdp 			kmem_free(bootargs, BOOTARGS_MAX);
4452267Sdp 			return (set_errno(error));
4462267Sdp 		}
4470Sstevel@tonic-gate 	}
4480Sstevel@tonic-gate 
4490Sstevel@tonic-gate 	/*
4502267Sdp 	 * Invoke the appropriate kadmin() routine.
4510Sstevel@tonic-gate 	 */
4522267Sdp 	if (getzoneid() != GLOBAL_ZONEID)
4532267Sdp 		error = zone_kadmin(cmd, fcn, bootargs, credp);
4542267Sdp 	else
4552267Sdp 		error = kadmin(cmd, fcn, bootargs, credp);
4560Sstevel@tonic-gate 
4572267Sdp 	if (bootargs != NULL)
4582267Sdp 		kmem_free(bootargs, BOOTARGS_MAX);
4592267Sdp 	return (error ? set_errno(error) : 0);
4600Sstevel@tonic-gate }
461