uadmin.c revision 753a6d457b330b1b29b2d3eefcd0831116ce950d
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin/*
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * CDDL HEADER START
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin *
3e14f97f673e8a630f076077de35afdd43dc1587Roger A. Faulkner * The contents of this file are subject to the terms of the
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * Common Development and Distribution License (the "License").
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * You may not use this file except in compliance with the License.
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * or http://www.opensolaris.org/os/licensing.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * See the License for the specific language governing permissions
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * and limitations under the License.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * When distributing Covered Code, include this CDDL HEADER in each
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * If applicable, add the following below this CDDL HEADER, with the
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * fields enclosed by brackets "[]" replaced with your own identifying
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * information: Portions Copyright [yyyy] [name of copyright owner]
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * CDDL HEADER END
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin/*
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * Use is subject to license terms.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#include <sys/param.h>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#include <sys/types.h>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#include <sys/sysmacros.h>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#include <sys/systm.h>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#include <sys/errno.h>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#include <sys/vfs.h>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#include <sys/vnode.h>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#include <sys/swap.h>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#include <sys/file.h>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#include <sys/proc.h>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#include <sys/var.h>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#include <sys/uadmin.h>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#include <sys/signal.h>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#include <sys/time.h>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#include <vm/seg_kmem.h>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#include <sys/modctl.h>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#include <sys/callb.h>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#include <sys/dumphdr.h>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#include <sys/debug.h>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#include <sys/ftrace.h>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#include <sys/cmn_err.h>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#include <sys/panic.h>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#include <sys/ddi.h>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#include <sys/sunddi.h>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#include <sys/policy.h>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#include <sys/zone.h>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#include <sys/condvar.h>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#include <sys/thread.h>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin#include <sys/sdt.h>
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin/*
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * Administrivia system call. We provide this in two flavors: one for calling
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * from the system call path (uadmin), and the other for calling from elsewhere
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * within the kernel (kadmin). Callers must beware that certain uadmin cmd
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * values (specifically A_SWAPCTL) are only supported by uadmin and not kadmin.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinextern ksema_t fsflush_sema;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinkmutex_t ualock;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinkcondvar_t uacond;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinkthread_t *ua_shutdown_thread = NULL;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinint sys_shutdown = 0;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinvolatile int fastreboot_dryrun = 0;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin/*
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * Kill all user processes in said zone. A special argument of ALL_ZONES is
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * passed in when the system as a whole is shutting down. The lack of per-zone
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * process lists is likely to make the following a performance bottleneck on a
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * system with many zones.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinvoid
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinkillall(zoneid_t zoneid)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin{
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin proc_t *p;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin ASSERT(zoneid != GLOBAL_ZONEID);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /*
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * Kill all processes except kernel daemons and ourself.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * Make a first pass to stop all processes so they won't
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * be trying to restart children as we kill them.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin mutex_enter(&pidlock);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin for (p = practive; p != NULL; p = p->p_next) {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if ((zoneid == ALL_ZONES || p->p_zone->zone_id == zoneid) &&
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin p->p_exec != NULLVP && /* kernel daemons */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin p->p_as != &kas &&
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin p->p_stat != SZOMB) {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin mutex_enter(&p->p_lock);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin p->p_flag |= SNOWAIT;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin sigtoproc(p, NULL, SIGSTOP);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin mutex_exit(&p->p_lock);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin p = practive;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin while (p != NULL) {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if ((zoneid == ALL_ZONES || p->p_zone->zone_id == zoneid) &&
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin p->p_exec != NULLVP && /* kernel daemons */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin p->p_as != &kas &&
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin p->p_stat != SIDL &&
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin p->p_stat != SZOMB) {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin mutex_enter(&p->p_lock);
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin if (sigismember(&p->p_sig, SIGKILL)) {
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin mutex_exit(&p->p_lock);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin p = p->p_next;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin } else {
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin sigtoproc(p, NULL, SIGKILL);
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin mutex_exit(&p->p_lock);
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin (void) cv_timedwait(&p->p_srwchan_cv, &pidlock,
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin lbolt + hz);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin p = practive;
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin }
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin } else {
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin p = p->p_next;
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin mutex_exit(&pidlock);
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin}
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinint
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chinkadmin(int cmd, int fcn, void *mdep, cred_t *credp)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin{
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin int error = 0;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin char *buf;
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin size_t buflen = 0;
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin boolean_t invoke_cb = B_FALSE;
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin
7c2fbfb345896881c631598ee3852ce9ce33fb07April Chin /*
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * We might be called directly by the kernel's fault-handling code, so
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * we can't assert that the caller is in the global zone.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /*
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * Make sure that cmd is one of the valid <sys/uadmin.h> command codes
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * and that we have appropriate privileges for this action.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin switch (cmd) {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin case A_FTRACE:
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin case A_SHUTDOWN:
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin case A_REBOOT:
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin case A_REMOUNT:
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin case A_FREEZE:
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin case A_DUMP:
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin case A_SDTTEST:
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin case A_CONFIG:
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (secpolicy_sys_config(credp, B_FALSE) != 0)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return (EPERM);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin break;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin default:
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return (EINVAL);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /*
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * Serialize these operations on ualock. If it is held, the
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * system should shutdown, reboot, or remount shortly, unless there is
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * an error. We need a cv rather than just a mutex because proper
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * functioning of A_REBOOT relies on being able to interrupt blocked
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * userland callers.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin *
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * We only clear ua_shutdown_thread after A_REMOUNT or A_CONFIG.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * Other commands should never return.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (cmd == A_SHUTDOWN || cmd == A_REBOOT || cmd == A_REMOUNT ||
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin cmd == A_CONFIG) {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin mutex_enter(&ualock);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin while (ua_shutdown_thread != NULL) {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (cv_wait_sig(&uacond, &ualock) == 0) {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /*
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * If we were interrupted, leave, and handle
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * the signal (or exit, depending on what
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * happened)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin mutex_exit(&ualock);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return (EINTR);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin ua_shutdown_thread = curthread;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin mutex_exit(&ualock);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin switch (cmd) {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin case A_SHUTDOWN:
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin proc_t *p = ttoproc(curthread);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /*
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * Release (almost) all of our own resources if we are called
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * from a user context, however if we are calling kadmin() from
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * a kernel context then we do not release these resources.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (p != &p0) {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin proc_is_exiting(p);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if ((error = exitlwps(0)) != 0) {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /*
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * Another thread in this process also called
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * exitlwps().
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin mutex_enter(&ualock);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin ua_shutdown_thread = NULL;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin cv_signal(&uacond);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin mutex_exit(&ualock);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin return (error);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin mutex_enter(&p->p_lock);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin p->p_flag |= SNOWAIT;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin sigfillset(&p->p_ignore);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin curthread->t_lwp->lwp_cursig = 0;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin curthread->t_lwp->lwp_extsig = 0;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (p->p_exec) {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin vnode_t *exec_vp = p->p_exec;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin p->p_exec = NULLVP;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin mutex_exit(&p->p_lock);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin VN_RELE(exec_vp);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin } else {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin mutex_exit(&p->p_lock);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin pollcleanup();
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin closeall(P_FINFO(curproc));
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin relvm();
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin } else {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /*
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * Reset t_cred if not set because much of the
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * filesystem code depends on CRED() being valid.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (curthread->t_cred == NULL)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin curthread->t_cred = kcred;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /* indicate shutdown in progress */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin sys_shutdown = 1;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /*
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * Communcate that init shouldn't be restarted.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin zone_shutdown_global();
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin killall(ALL_ZONES);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /*
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * If we are calling kadmin() from a kernel context then we
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * do not release these resources.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (ttoproc(curthread) != &p0) {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin VN_RELE(PTOU(curproc)->u_cdir);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (PTOU(curproc)->u_rdir)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin VN_RELE(PTOU(curproc)->u_rdir);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if (PTOU(curproc)->u_cwd)
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin refstr_rele(PTOU(curproc)->u_cwd);
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin PTOU(curproc)->u_cdir = rootdir;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin PTOU(curproc)->u_rdir = NULL;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin PTOU(curproc)->u_cwd = NULL;
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin }
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin /*
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * Allow the reboot/halt/poweroff code a chance to do
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * anything it needs to whilst we still have filesystems
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * mounted, like loading any modules necessary for later
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin * performing the actual poweroff.
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin */
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin if ((mdep != NULL) && (*(char *)mdep == '/')) {
da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968chin buf = i_convert_boot_device_name(mdep, NULL, &buflen);
mdpreboot(cmd, fcn, buf);
} else
mdpreboot(cmd, fcn, mdep);
/*
* Allow fsflush to finish running and then prevent it
* from ever running again so that vfs_unmountall() and
* vfs_syncall() can acquire the vfs locks they need.
*/
sema_p(&fsflush_sema);
(void) callb_execute_class(CB_CL_UADMIN_PRE_VFS, NULL);
vfs_unmountall();
(void) VFS_MOUNTROOT(rootvfs, ROOT_UNMOUNT);
vfs_syncall();
dump_ereports();
dump_messages();
invoke_cb = B_TRUE;
/* FALLTHROUGH */
}
case A_REBOOT:
if ((mdep != NULL) && (*(char *)mdep == '/')) {
buf = i_convert_boot_device_name(mdep, NULL, &buflen);
mdboot(cmd, fcn, buf, invoke_cb);
} else
mdboot(cmd, fcn, mdep, invoke_cb);
/* no return expected */
break;
case A_CONFIG:
switch (fcn) {
case AD_UPDATE_BOOT_CONFIG:
#ifndef __sparc
{
extern int fastreboot_capable;
extern void fastboot_update_config(const char *);
if (fastreboot_capable)
fastboot_update_config(mdep);
}
#endif
break;
}
/* Let other threads enter the shutdown path now */
mutex_enter(&ualock);
ua_shutdown_thread = NULL;
cv_signal(&uacond);
mutex_exit(&ualock);
break;
case A_REMOUNT:
(void) VFS_MOUNTROOT(rootvfs, ROOT_REMOUNT);
/* Let other threads enter the shutdown path now */
mutex_enter(&ualock);
ua_shutdown_thread = NULL;
cv_signal(&uacond);
mutex_exit(&ualock);
break;
case A_FREEZE:
{
/*
* This is the entrypoint for all suspend/resume actions.
*/
extern int cpr(int, void *);
if (modload("misc", "cpr") == -1)
return (ENOTSUP);
/* Let the CPR module decide what to do with mdep */
error = cpr(fcn, mdep);
break;
}
case A_FTRACE:
{
switch (fcn) {
case AD_FTRACE_START:
(void) FTRACE_START();
break;
case AD_FTRACE_STOP:
(void) FTRACE_STOP();
break;
default:
error = EINVAL;
}
break;
}
case A_DUMP:
{
if (fcn == AD_NOSYNC) {
in_sync = 1;
break;
}
panic_bootfcn = fcn;
panic_forced = 1;
if ((mdep != NULL) && (*(char *)mdep == '/')) {
panic_bootstr = i_convert_boot_device_name(mdep,
NULL, &buflen);
} else
panic_bootstr = mdep;
#ifndef __sparc
extern int fastreboot_onpanic;
if (fcn != AD_FASTREBOOT) {
extern void fastboot_update_config(const char *);
/*
* If user has explicitly requested reboot to prom,
* or uadmin(1M) was invoked with other functions,
* don't try to fast reboot after dumping.
*/
fastreboot_onpanic = 0;
fastboot_update_config((char *)&fastreboot_onpanic);
}
if (fastreboot_onpanic) {
extern void fastboot_load_kernel(char *);
fastboot_load_kernel(mdep);
}
#endif
panic("forced crash dump initiated at user request");
/*NOTREACHED*/
}
case A_SDTTEST:
{
DTRACE_PROBE7(test, int, 1, int, 2, int, 3, int, 4, int, 5,
int, 6, int, 7);
break;
}
default:
error = EINVAL;
}
return (error);
}
int
uadmin(int cmd, int fcn, uintptr_t mdep)
{
int error = 0, rv = 0;
size_t nbytes = 0;
cred_t *credp = CRED();
char *bootargs = NULL;
int reset_status = 0;
if (cmd == A_SHUTDOWN && fcn == AD_FASTREBOOT_DRYRUN) {
ddi_walk_devs(ddi_root_node(), check_driver_quiesce,
&reset_status);
if (reset_status != 0)
return (EIO);
else
return (0);
}
/*
* The swapctl system call doesn't have its own entry point: it uses
* uadmin as a wrapper so we just call it directly from here.
*/
if (cmd == A_SWAPCTL) {
if (get_udatamodel() == DATAMODEL_NATIVE)
error = swapctl(fcn, (void *)mdep, &rv);
#if defined(_SYSCALL32_IMPL)
else
error = swapctl32(fcn, (void *)mdep, &rv);
#endif /* _SYSCALL32_IMPL */
return (error ? set_errno(error) : rv);
}
/*
* Certain subcommands intepret a non-NULL mdep value as a pointer to
* a boot string. We pull that in as bootargs, if applicable.
*/
if (mdep != NULL &&
(cmd == A_SHUTDOWN || cmd == A_REBOOT || cmd == A_DUMP ||
cmd == A_FREEZE || cmd == A_CONFIG)) {
bootargs = kmem_zalloc(BOOTARGS_MAX, KM_SLEEP);
if ((error = copyinstr((const char *)mdep, bootargs,
BOOTARGS_MAX, &nbytes)) != 0) {
kmem_free(bootargs, BOOTARGS_MAX);
return (set_errno(error));
}
}
/*
* Invoke the appropriate kadmin() routine.
*/
if (getzoneid() != GLOBAL_ZONEID)
error = zone_kadmin(cmd, fcn, bootargs, credp);
else
error = kadmin(cmd, fcn, bootargs, credp);
if (bootargs != NULL)
kmem_free(bootargs, BOOTARGS_MAX);
return (error ? set_errno(error) : 0);
}