uadmin.c revision a288e5a9793fdffe5e842d7e61ab45263e75eaca
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
* Copyright 2013 Joyent, Inc. All rights reserved.
*/
#include <sys/sysmacros.h>
#include <vm/seg_kmem.h>
#include <sys/ddi_periodic.h>
/*
* Administrivia system call. We provide this in two flavors: one for calling
* from the system call path (uadmin), and the other for calling from elsewhere
* within the kernel (kadmin). Callers must beware that certain uadmin cmd
* values (specifically A_SWAPCTL) are only supported by uadmin and not kadmin.
*/
extern ksema_t fsflush_sema;
int sys_shutdown = 0;
volatile int fastreboot_dryrun = 0;
/*
* Kill all user processes in said zone. A special argument of ALL_ZONES is
* passed in when the system as a whole is shutting down. The lack of per-zone
* process lists is likely to make the following a performance bottleneck on a
* system with many zones.
*/
void
{
proc_t *p;
/*
* Kill all processes except kernel daemons and ourself.
* Make a first pass to stop all processes so they won't
* be trying to restart children as we kill them.
*/
mutex_enter(&p->p_lock);
mutex_exit(&p->p_lock);
}
}
p = practive;
while (p != NULL) {
mutex_enter(&p->p_lock);
mutex_exit(&p->p_lock);
p = p->p_next;
} else {
mutex_exit(&p->p_lock);
(void) cv_reltimedwait(&p->p_srwchan_cv,
p = practive;
}
} else {
p = p->p_next;
}
}
}
int
{
int error = 0;
char *buf;
/*
* We might be called directly by the kernel's fault-handling code, so
* we can't assert that the caller is in the global zone.
*/
/*
* and that we have appropriate privileges for this action.
*/
switch (cmd) {
case A_FTRACE:
case A_SHUTDOWN:
case A_REBOOT:
case A_REMOUNT:
case A_FREEZE:
case A_DUMP:
case A_SDTTEST:
case A_CONFIG:
return (EPERM);
break;
default:
return (EINVAL);
}
/*
* Serialize these operations on ualock. If it is held, the
* system should shutdown, reboot, or remount shortly, unless there is
* an error. We need a cv rather than just a mutex because proper
* functioning of A_REBOOT relies on being able to interrupt blocked
* userland callers.
*
* We only clear ua_shutdown_thread after A_REMOUNT or A_CONFIG.
* Other commands should never return.
*/
while (ua_shutdown_thread != NULL) {
/*
* If we were interrupted, leave, and handle
* the signal (or exit, depending on what
* happened)
*/
mutex_exit(&ualock);
return (EINTR);
}
}
mutex_exit(&ualock);
}
switch (cmd) {
case A_SHUTDOWN:
{
/*
* Release (almost) all of our own resources if we are called
* from a user context, however if we are calling kadmin() from
* a kernel context then we do not release these resources.
*/
if (p != &p0) {
proc_is_exiting(p);
/*
* Another thread in this process also called
* exitlwps().
*/
mutex_exit(&ualock);
return (error);
}
mutex_enter(&p->p_lock);
sigfillset(&p->p_ignore);
if (p->p_exec) {
mutex_exit(&p->p_lock);
} else {
mutex_exit(&p->p_lock);
}
pollcleanup();
relvm();
} else {
/*
* Reset t_cred if not set because much of the
* filesystem code depends on CRED() being valid.
*/
}
/* indicate shutdown in progress */
sys_shutdown = 1;
/*
* Communcate that init shouldn't be restarted.
*/
/*
* If we are calling kadmin() from a kernel context then we
* do not release these resources.
*/
}
/*
* anything it needs to whilst we still have filesystems
* mounted, like loading any modules necessary for later
* performing the actual poweroff.
*/
} else
/*
* 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.
*/
vfs_syncall();
/*
* Check for (and unregister) any DDI periodic handlers that
* still exist, as they most likely constitute resource leaks:
*/
/* FALLTHROUGH */
}
case A_REBOOT:
} else
/* no return expected */
break;
case A_CONFIG:
switch (fcn) {
case AD_UPDATE_BOOT_CONFIG:
#ifndef __sparc
{
extern void fastboot_update_config(const char *);
}
#endif
break;
}
/* Let other threads enter the shutdown path now */
mutex_exit(&ualock);
break;
case A_REMOUNT:
/* Let other threads enter the shutdown path now */
mutex_exit(&ualock);
break;
case A_FREEZE:
{
/*
*/
extern int cpr(int, void *);
return (ENOTSUP);
/* Let the CPR module decide what to do with mdep */
break;
}
case A_FTRACE:
{
switch (fcn) {
case AD_FTRACE_START:
(void) FTRACE_START();
break;
case AD_FTRACE_STOP:
(void) FTRACE_STOP();
break;
default:
}
break;
}
case A_DUMP:
{
in_sync = 1;
break;
}
panic_bootfcn = fcn;
panic_forced = 1;
} else
#ifndef __sparc
extern void fastboot_update_and_load(int, char *);
#endif
panic("forced crash dump initiated at user request");
/*NOTREACHED*/
}
case A_SDTTEST:
{
int, 6, int, 7);
break;
}
default:
}
return (error);
}
int
{
int reset_status = 0;
&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 (get_udatamodel() == DATAMODEL_NATIVE)
#if defined(_SYSCALL32_IMPL)
else
#endif /* _SYSCALL32_IMPL */
}
/*
* Certain subcommands intepret a non-NULL mdep value as a pointer to
* a boot string. We pull that in as bootargs, if applicable.
*/
BOOTARGS_MAX, &nbytes)) != 0) {
}
}
/*
* Invoke the appropriate kadmin() routine.
*/
if (getzoneid() != GLOBAL_ZONEID)
else
}