Changeset View
Changeset View
Standalone View
Standalone View
sys/kern/init_main.c
Show First 20 Lines • Show All 50 Lines • ▼ Show 20 Lines | |||||
#include "opt_verbose_sysinit.h" | #include "opt_verbose_sysinit.h" | ||||
#include <sys/param.h> | #include <sys/param.h> | ||||
#include <sys/kernel.h> | #include <sys/kernel.h> | ||||
#include <sys/exec.h> | #include <sys/exec.h> | ||||
#include <sys/file.h> | #include <sys/file.h> | ||||
#include <sys/filedesc.h> | #include <sys/filedesc.h> | ||||
#include <sys/jail.h> | #include <sys/jail.h> | ||||
#include <sys/kthread.h> | |||||
#include <sys/ktr.h> | #include <sys/ktr.h> | ||||
#include <sys/lock.h> | #include <sys/lock.h> | ||||
#include <sys/loginclass.h> | #include <sys/loginclass.h> | ||||
#include <sys/mount.h> | #include <sys/mount.h> | ||||
#include <sys/mutex.h> | #include <sys/mutex.h> | ||||
#include <sys/syscallsubr.h> | #include <sys/syscallsubr.h> | ||||
#include <sys/sysctl.h> | #include <sys/sysctl.h> | ||||
#include <sys/proc.h> | #include <sys/proc.h> | ||||
#include <sys/racct.h> | #include <sys/racct.h> | ||||
#include <sys/resourcevar.h> | #include <sys/resourcevar.h> | ||||
#include <sys/systm.h> | #include <sys/systm.h> | ||||
#include <sys/signalvar.h> | #include <sys/signalvar.h> | ||||
#include <sys/vnode.h> | #include <sys/vnode.h> | ||||
#include <sys/sysent.h> | #include <sys/sysent.h> | ||||
#include <sys/reboot.h> | #include <sys/reboot.h> | ||||
#include <sys/sched.h> | #include <sys/sched.h> | ||||
#include <sys/sx.h> | #include <sys/sx.h> | ||||
#include <sys/sysproto.h> | #include <sys/sysproto.h> | ||||
#include <sys/vmmeter.h> | #include <sys/vmmeter.h> | ||||
#include <sys/unistd.h> | #include <sys/unistd.h> | ||||
#include <sys/malloc.h> | #include <sys/malloc.h> | ||||
#include <sys/conf.h> | #include <sys/conf.h> | ||||
#include <sys/cpuset.h> | #include <sys/cpuset.h> | ||||
#include <sys/vps.h> | |||||
#include <machine/cpu.h> | #include <machine/cpu.h> | ||||
#include <security/audit/audit.h> | #include <security/audit/audit.h> | ||||
#include <security/mac/mac_framework.h> | #include <security/mac/mac_framework.h> | ||||
#include <vm/vm.h> | #include <vm/vm.h> | ||||
#include <vm/vm_param.h> | #include <vm/vm_param.h> | ||||
#include <vm/vm_extern.h> | #include <vm/vm_extern.h> | ||||
#include <vm/pmap.h> | #include <vm/pmap.h> | ||||
#include <vm/vm_map.h> | #include <vm/vm_map.h> | ||||
#include <sys/copyright.h> | #include <sys/copyright.h> | ||||
#include <ddb/ddb.h> | #include <ddb/ddb.h> | ||||
#include <ddb/db_sym.h> | #include <ddb/db_sym.h> | ||||
void mi_startup(void); /* Should be elsewhere */ | void mi_startup(void); /* Should be elsewhere */ | ||||
/* Components of the first process -- never freed. */ | /* Components of the first process -- never freed. */ | ||||
static struct session session0; | static struct session session0; | ||||
static struct pgrp pgrp0; | static struct pgrp pgrp0; | ||||
struct proc proc0; | struct proc proc0; | ||||
struct thread0_storage thread0_st __aligned(32); | struct thread0_storage thread0_st __aligned(32); | ||||
struct vmspace vmspace0; | struct vmspace vmspace0; | ||||
struct proc *initproc; | VPS_DEFINE(struct proc *, initproc); | ||||
VPS_DEFINE(struct proc *, vproc0); | |||||
#ifdef VIMAGE | |||||
/* | |||||
* Initialize to -2; after kproc_create() our thread will still be | |||||
* forked from thread0 and in the wrong vps. Once that is fixed it will | |||||
* see the local copy and not the DEFAULT_VPS one. Make sure we have | |||||
* a value that we can spin on until this happens. | |||||
*/ | |||||
VPS_DEFINE(int, vpsdying) = -2; | |||||
#endif | |||||
#ifndef BOOTHOWTO | #ifndef BOOTHOWTO | ||||
#define BOOTHOWTO 0 | #define BOOTHOWTO 0 | ||||
#endif | #endif | ||||
int boothowto = BOOTHOWTO; /* initialized so that it can be patched */ | int boothowto = BOOTHOWTO; /* initialized so that it can be patched */ | ||||
SYSCTL_INT(_debug, OID_AUTO, boothowto, CTLFLAG_RD, &boothowto, 0, | SYSCTL_INT(_debug, OID_AUTO, boothowto, CTLFLAG_RD, &boothowto, 0, | ||||
"Boot control flags, passed from loader"); | "Boot control flags, passed from loader"); | ||||
#ifndef BOOTVERBOSE | #ifndef BOOTVERBOSE | ||||
▲ Show 20 Lines • Show All 340 Lines • ▼ Show 20 Lines | proc0_init(void *dummy __unused) | ||||
/* | /* | ||||
* Initialize magic number and osrel. | * Initialize magic number and osrel. | ||||
*/ | */ | ||||
p->p_magic = P_MAGIC; | p->p_magic = P_MAGIC; | ||||
p->p_osrel = osreldate; | p->p_osrel = osreldate; | ||||
/* | /* | ||||
* Initialize thread and process structures. | * Initialize thread structures. | ||||
*/ | */ | ||||
procinit(); /* set up proc zone */ | |||||
threadinit(); /* set up UMA zones */ | threadinit(); /* set up UMA zones */ | ||||
/* | /* | ||||
* Initialise scheduler resources. | * Initialise scheduler resources. | ||||
* Add scheduler specific parts to proc, thread as needed. | * Add scheduler specific parts to proc, thread as needed. | ||||
*/ | */ | ||||
schedinit(); /* scheduler gets its house in order */ | schedinit(); /* scheduler gets its house in order */ | ||||
/* | /* | ||||
* Create process 0 (the swapper). | * Create process 0 (the swapper). | ||||
*/ | */ | ||||
LIST_INSERT_HEAD(&allproc, p, p_list); | V_vproc0 = p; | ||||
LIST_INSERT_HEAD(&V_allproc, p, p_list); | |||||
LIST_INSERT_HEAD(PIDHASH(0), p, p_hash); | LIST_INSERT_HEAD(PIDHASH(0), p, p_hash); | ||||
mtx_init(&pgrp0.pg_mtx, "process group", NULL, MTX_DEF | MTX_DUPOK); | mtx_init(&pgrp0.pg_mtx, "process group", NULL, MTX_DEF | MTX_DUPOK); | ||||
p->p_pgrp = &pgrp0; | p->p_pgrp = &pgrp0; | ||||
LIST_INSERT_HEAD(PGRPHASH(0), &pgrp0, pg_hash); | LIST_INSERT_HEAD(PGRPHASH(0), &pgrp0, pg_hash); | ||||
LIST_INIT(&pgrp0.pg_members); | LIST_INIT(&pgrp0.pg_members); | ||||
LIST_INSERT_HEAD(&pgrp0.pg_members, p, p_pglist); | LIST_INSERT_HEAD(&pgrp0.pg_members, p, p_pglist); | ||||
pgrp0.pg_session = &session0; | pgrp0.pg_session = &session0; | ||||
Show All 19 Lines | proc0_init(void *dummy __unused) | ||||
td->td_priority = PVM; | td->td_priority = PVM; | ||||
td->td_base_pri = PVM; | td->td_base_pri = PVM; | ||||
td->td_oncpu = curcpu; | td->td_oncpu = curcpu; | ||||
td->td_flags = TDF_INMEM; | td->td_flags = TDF_INMEM; | ||||
td->td_pflags = TDP_KTHREAD; | td->td_pflags = TDP_KTHREAD; | ||||
td->td_cpuset = cpuset_thread0(); | td->td_cpuset = cpuset_thread0(); | ||||
td->td_domain.dr_policy = td->td_cpuset->cs_domain; | td->td_domain.dr_policy = td->td_cpuset->cs_domain; | ||||
prison0_init(); | prison0_init(); | ||||
#ifdef VIMAGE | |||||
td->td_vps = vps0; | |||||
#endif | |||||
p->p_peers = 0; | p->p_peers = 0; | ||||
p->p_leader = p; | p->p_leader = p; | ||||
p->p_reaper = p; | p->p_reaper = p; | ||||
p->p_treeflag |= P_TREE_REAPER; | p->p_treeflag |= P_TREE_REAPER; | ||||
LIST_INIT(&p->p_reaplist); | LIST_INIT(&p->p_reaplist); | ||||
strncpy(p->p_comm, "kernel", sizeof (p->p_comm)); | strncpy(p->p_comm, "kernel", sizeof (p->p_comm)); | ||||
strncpy(td->td_name, "swapper", sizeof (td->td_name)); | strncpy(td->td_name, "swapper", sizeof (td->td_name)); | ||||
Show All 22 Lines | |||||
#endif | #endif | ||||
#ifdef MAC | #ifdef MAC | ||||
mac_cred_create_swapper(newcred); | mac_cred_create_swapper(newcred); | ||||
#endif | #endif | ||||
/* Create sigacts. */ | /* Create sigacts. */ | ||||
p->p_sigacts = sigacts_alloc(); | p->p_sigacts = sigacts_alloc(); | ||||
/* Initialize signal state for process 0. */ | /* Initialize signal state for process 0. */ | ||||
siginit(&proc0); | siginit(V_vproc0); | ||||
/* Create the file descriptor table. */ | /* Create the file descriptor table. */ | ||||
p->p_fd = fdinit(NULL, false); | p->p_fd = fdinit(NULL, false); | ||||
p->p_fdtol = NULL; | p->p_fdtol = NULL; | ||||
/* Create the limits structures. */ | /* Create the limits structures. */ | ||||
p->p_limit = lim_alloc(); | p->p_limit = lim_alloc(); | ||||
for (i = 0; i < RLIM_NLIMITS; i++) | for (i = 0; i < RLIM_NLIMITS; i++) | ||||
▲ Show 20 Lines • Show All 48 Lines • ▼ Show 20 Lines | #endif | ||||
/* | /* | ||||
* Charge root for one process. | * Charge root for one process. | ||||
*/ | */ | ||||
(void)chgproccnt(p->p_ucred->cr_ruidinfo, 1, 0); | (void)chgproccnt(p->p_ucred->cr_ruidinfo, 1, 0); | ||||
PROC_LOCK(p); | PROC_LOCK(p); | ||||
racct_add_force(p, RACCT_NPROC, 1); | racct_add_force(p, RACCT_NPROC, 1); | ||||
PROC_UNLOCK(p); | PROC_UNLOCK(p); | ||||
} | } | ||||
SYSINIT(p0init, SI_SUB_INTRINSIC, SI_ORDER_FIRST, proc0_init, NULL); | SYSINIT(p0init, SI_SUB_INTRINSIC, SI_ORDER_THIRD, proc0_init, NULL); | ||||
#ifdef VIMAGE | |||||
static void | |||||
vps_swapper(void *dummy __unused) | |||||
{ | |||||
/* | |||||
* Make sure the surgical changes to V_vproc0 are done before | |||||
* entering the long-lasting loop. Otherwise we may start | |||||
* acquiring locks and accessing variables based on the wrong | |||||
* credential leading to, e.g., panics when trying to unlock a | |||||
* lock from a different context which may not be locked. | |||||
* When entering the function our credentials might still point | |||||
* to the DEFAULT_VPS; see comment for V_vpsdying declaration above. | |||||
*/ | |||||
while (V_vpsdying < 0) | |||||
pause("wswvps", hz/2); | |||||
/* | |||||
* Now hand over this thread to swapper. | |||||
*/ | |||||
swapper(); | |||||
if (V_vpsdying < 1) | |||||
panic("%s: swapper curtd %p ended but V_vpsdying %d\n", | |||||
__func__, curthread, V_vpsdying); | |||||
kproc_exit(0); | |||||
} | |||||
static void | |||||
proc0_init_vps(void *dummy __unused) | |||||
{ | |||||
struct ucred *newcred, *savecred; | |||||
struct thread *td; | |||||
struct prison *pr; | |||||
struct uidinfo tmpuinfo; | |||||
struct loginclass tmplc = { | |||||
.lc_name = "", | |||||
}; | |||||
int error; | |||||
/* vps0 is handled normally in p0init. */ | |||||
if (IS_DEFAULT_VPS(curvps)) | |||||
return; | |||||
KASSERT((curvps->vps_pr != NULL && curvps != vps0), | |||||
("%s: curvps %p has vps_pr %p or is vps0 %p\n", | |||||
__func__, curvps, curvps->vps_pr, vps0)); | |||||
KASSERT((curvps == curvps->vps_pr->pr_vps), | |||||
("%s: curvps %p != curvps->vps_pr %p ->pr_vps %p\n", | |||||
__func__, curvps, curvps->vps_pr, curvps->vps_pr->pr_vps)); | |||||
/* | |||||
* Initialized the non-default VPS version to < 0 so vps_swapper() | |||||
* will spin once the credential is changed before all other surgery | |||||
* has happened. | |||||
*/ | |||||
V_vpsdying = -1; | |||||
/* | |||||
* Default is nprocs = 1 for vps0; need to set it to 0 here as our | |||||
* "proc0" and with that initproc are forked and not manually constructed. | |||||
*/ | |||||
V_nprocs = 0; | |||||
/* | |||||
* Set lastpid to -1 so that our swapper gets 0. | |||||
*/ | |||||
V_lastpid = -1; | |||||
error = kproc_create(vps_swapper, NULL, &V_vproc0, 0, 0, "vps%u", | |||||
curvps->vps_pr->pr_id); | |||||
if (error) | |||||
panic("%s: cannot create vps %p swapper: %d\n", | |||||
jamie: Panicking seems harsh when kproc_create can fail simply because the process limit has been hit. | |||||
Not Done Inline ActionsYes. There's a few such situations; we would need to add a flag to the vps structure, check in between every sysinit invokation; in case of error, undo the exact bits we already allocated/initialised, and the return an error to jail creation. We never did for vnets; maybe it's time; but the cleanup can be "complex" to get fully symmetric. For the moment having well-defined errors (panic) seems better while developing. bz: Yes. There's a few such situations; we would need to add a flag to the vps structure, check… | |||||
__func__, curvps, error); | |||||
/* Create credentials. Copied from proc0. Just using vps_pr. */ | |||||
newcred = crget(); | |||||
newcred->cr_ngroups = 1; /* group 0 */ | |||||
/* A hack to prevent uifind from tripping over NULL pointers. */ | |||||
savecred = curthread->td_ucred; | |||||
curthread->td_ucred = newcred; | |||||
tmpuinfo.ui_uid = 1; | |||||
newcred->cr_uidinfo = newcred->cr_ruidinfo = &tmpuinfo; | |||||
newcred->cr_uidinfo = uifind(0); | |||||
newcred->cr_ruidinfo = uifind(0); | |||||
newcred->cr_loginclass = &tmplc; | |||||
newcred->cr_loginclass = loginclass_find("default"); | |||||
/* End hack. creds get properly set later with thread_cow_get_proc */ | |||||
curthread->td_ucred = savecred; | |||||
PROC_LOCK(V_vproc0); | |||||
newcred->cr_prison = curvps->vps_pr; | |||||
prison_hold(newcred->cr_prison); | |||||
/* The kernel process was accounted to thread0's prison. */ | |||||
prison_proc_hold(newcred->cr_prison); | |||||
prison_proc_free(savecred->cr_prison); | |||||
V_vproc0->p_treeflag |= P_TREE_REAPER; | |||||
savecred = proc_set_cred(V_vproc0, newcred); | |||||
PROC_UNLOCK(V_vproc0); | |||||
#ifdef AUDIT | |||||
audit_cred_kproc0(newcred); | |||||
#endif | |||||
#ifdef MAC | |||||
mac_cred_create_swapper(newcred); | |||||
#endif | |||||
crfree(savecred); | |||||
PROC_LOCK(V_vproc0); | |||||
td = FIRST_THREAD_IN_PROC(V_vproc0); | |||||
thread_cow_get_proc(td, V_vproc0); | |||||
PROC_UNLOCK(V_vproc0); | |||||
KASSERT(curvps->vps_pr == | |||||
FIRST_THREAD_IN_PROC(V_vproc0)->td_ucred->cr_prison, | |||||
("%s:%d: curvps %p vps_pr %p != FTIP(V_vproc0 %p)->td_ucred %p " | |||||
"cr_prison %p\n", __func__, __LINE__, | |||||
curvps, curvps->vps_pr, V_vproc0, | |||||
FIRST_THREAD_IN_PROC(V_vproc0)->td_ucred, | |||||
FIRST_THREAD_IN_PROC(V_vproc0)->td_ucred->cr_prison)); | |||||
KASSERT(curvps == TD_TO_VPS(FIRST_THREAD_IN_PROC(V_vproc0)), | |||||
("%s:%d: curvps %p != TD_TO_VPS(..(V_vproc0 %p)) %p\n", | |||||
__func__, __LINE__, | |||||
curvps, V_vproc0, TD_TO_VPS(FIRST_THREAD_IN_PROC(V_vproc0)))); | |||||
/* Chroot it. */ | |||||
td = FIRST_THREAD_IN_PROC(V_vproc0); | |||||
pr = curvps->vps_pr; | |||||
vn_lock(pr->pr_root, LK_EXCLUSIVE | LK_RETRY); | |||||
if ((error = change_dir(pr->pr_root, td)) != 0) { | |||||
printf("%s: td %p change_dir %p failed: %d\n", | |||||
__func__, td, pr->pr_root, error); | |||||
goto err; | |||||
} | |||||
#ifdef MAC | |||||
if ((error = mac_vnode_check_chroot(td->td_ucred, pr->pr_root))) { | |||||
printf("%s: td %p mac_vnode_check_chroot %p failed: %d\n", | |||||
__func__, td, pr->pr_root, error); | |||||
goto err; | |||||
} | |||||
#endif | |||||
VOP_UNLOCK(pr->pr_root, 0); | |||||
if ((error = pwd_chroot(td, pr->pr_root))) { | |||||
printf("%s: td %p pwd_chroot %p failed: %d\n", | |||||
__func__, td, pr->pr_root, error); | |||||
goto err; | |||||
} | |||||
V_vpsdying = 0; | |||||
return; | |||||
err: | |||||
/* XXX could panic or singal the jail to abort; cannot really stop. */ | |||||
return; | |||||
} | |||||
VPS_SYSINIT(p0init_vps, SI_SUB_INTRINSIC, SI_ORDER_THIRD, proc0_init_vps, NULL); | |||||
static void | |||||
proc0_uninit_vps(void *dummy __unused) | |||||
{ | |||||
if (IS_DEFAULT_VPS(curvps)) | |||||
return; | |||||
/* | |||||
* XXX ideally we want to get that state from elsewhere; | |||||
* neither prison, not vps state, .. lends itself though. | |||||
*/ | |||||
V_vpsdying = 1; | |||||
wakeup(V_vproc0); | |||||
/* Operate on current vps instance only. */ | |||||
while (V_vproc0 != NULL || | |||||
!LIST_EMPTY(&V_zombproc) || !LIST_EMPTY(&V_allproc)) | |||||
pause("p0uvps", hz/2); | |||||
} | |||||
VPS_SYSUNINIT(p0uninit_vps, SI_SUB_INTRINSIC, SI_ORDER_THIRD, proc0_uninit_vps, NULL); | |||||
#endif | |||||
/* ARGSUSED*/ | /* ARGSUSED*/ | ||||
static void | static void | ||||
proc0_post(void *dummy __unused) | proc0_post(void *dummy __unused) | ||||
{ | { | ||||
struct timespec ts; | struct timespec ts; | ||||
struct proc *p; | struct proc *p; | ||||
struct rusage ru; | struct rusage ru; | ||||
struct thread *td; | struct thread *td; | ||||
/* | /* | ||||
* Now we can look at the time, having had a chance to verify the | * Now we can look at the time, having had a chance to verify the | ||||
* time from the filesystem. Pretend that proc0 started now. | * time from the filesystem. Pretend that proc0 started now. | ||||
* Operate on vps0 instance only. | |||||
*/ | */ | ||||
sx_slock(&allproc_lock); | sx_slock(&V_allproc_lock); | ||||
FOREACH_PROC_IN_SYSTEM(p) { | FOREACH_PROC_IN_SYSTEM(p) { | ||||
PROC_LOCK(p); | PROC_LOCK(p); | ||||
if (p->p_state == PRS_NEW) { | if (p->p_state == PRS_NEW) { | ||||
PROC_UNLOCK(p); | PROC_UNLOCK(p); | ||||
continue; | continue; | ||||
} | } | ||||
microuptime(&p->p_stats->p_start); | microuptime(&p->p_stats->p_start); | ||||
PROC_STATLOCK(p); | PROC_STATLOCK(p); | ||||
rufetch(p, &ru); /* Clears thread stats */ | rufetch(p, &ru); /* Clears thread stats */ | ||||
p->p_rux.rux_runtime = 0; | p->p_rux.rux_runtime = 0; | ||||
p->p_rux.rux_uticks = 0; | p->p_rux.rux_uticks = 0; | ||||
p->p_rux.rux_sticks = 0; | p->p_rux.rux_sticks = 0; | ||||
p->p_rux.rux_iticks = 0; | p->p_rux.rux_iticks = 0; | ||||
PROC_STATUNLOCK(p); | PROC_STATUNLOCK(p); | ||||
FOREACH_THREAD_IN_PROC(p, td) { | FOREACH_THREAD_IN_PROC(p, td) { | ||||
td->td_runtime = 0; | td->td_runtime = 0; | ||||
} | } | ||||
PROC_UNLOCK(p); | PROC_UNLOCK(p); | ||||
} | } | ||||
sx_sunlock(&allproc_lock); | sx_sunlock(&V_allproc_lock); | ||||
PCPU_SET(switchtime, cpu_ticks()); | PCPU_SET(switchtime, cpu_ticks()); | ||||
PCPU_SET(switchticks, ticks); | PCPU_SET(switchticks, ticks); | ||||
/* | /* | ||||
* Give the ``random'' number generator a thump. | * Give the ``random'' number generator a thump. | ||||
*/ | */ | ||||
nanotime(&ts); | nanotime(&ts); | ||||
srandom(ts.tv_sec ^ ts.tv_nsec); | srandom(ts.tv_sec ^ ts.tv_nsec); | ||||
▲ Show 20 Lines • Show All 63 Lines • ▼ Show 20 Lines | start_init(void *dummy) | ||||
struct thread *td; | struct thread *td; | ||||
struct proc *p; | struct proc *p; | ||||
TSENTER(); /* Here so we don't overlap with mi_startup. */ | TSENTER(); /* Here so we don't overlap with mi_startup. */ | ||||
td = curthread; | td = curthread; | ||||
p = td->td_proc; | p = td->td_proc; | ||||
if (IS_DEFAULT_VPS(curvps)) | |||||
vfs_mountroot(); | vfs_mountroot(); | ||||
/* Wipe GELI passphrase from the environment. */ | /* Wipe GELI passphrase from the environment. */ | ||||
kern_unsetenv("kern.geom.eli.passphrase"); | kern_unsetenv("kern.geom.eli.passphrase"); | ||||
/* | /* | ||||
* Need just enough stack to hold the faked-up "execve()" arguments. | * Need just enough stack to hold the faked-up "execve()" arguments. | ||||
*/ | */ | ||||
addr = p->p_sysent->sv_usrstack - PAGE_SIZE; | addr = p->p_sysent->sv_usrstack - PAGE_SIZE; | ||||
if (vm_map_find(&p->p_vmspace->vm_map, NULL, 0, &addr, PAGE_SIZE, 0, | if (vm_map_find(&p->p_vmspace->vm_map, NULL, 0, &addr, PAGE_SIZE, 0, | ||||
VMFS_NO_SPACE, VM_PROT_ALL, VM_PROT_ALL, 0) != 0) | VMFS_NO_SPACE, VM_PROT_ALL, VM_PROT_ALL, 0) != 0) | ||||
panic("init: couldn't allocate argument space"); | panic("init: couldn't allocate argument space"); | ||||
p->p_vmspace->vm_maxsaddr = (caddr_t)addr; | p->p_vmspace->vm_maxsaddr = (caddr_t)addr; | ||||
p->p_vmspace->vm_ssize = 1; | p->p_vmspace->vm_ssize = 1; | ||||
if ((var = kern_getenv("init_path")) != NULL) { | if ((var = kern_getenv("init_path")) != NULL) { | ||||
strlcpy(init_path, var, sizeof(init_path)); | strlcpy(init_path, var, sizeof(init_path)); | ||||
freeenv(var); | freeenv(var); | ||||
} | } | ||||
free_init_path = tmp_init_path = strdup(init_path, M_TEMP); | free_init_path = tmp_init_path = strdup(init_path, M_TEMP); | ||||
while ((path = strsep(&tmp_init_path, ":")) != NULL) { | while ((path = strsep(&tmp_init_path, ":")) != NULL) { | ||||
pathlen = strlen(path) + 1; | pathlen = strlen(path) + 1; | ||||
if (bootverbose) | if (bootverbose) | ||||
printf("start_init: trying %s\n", path); | printf("%s: trying %s\n", __func__, path); | ||||
/* | /* | ||||
* Move out the boot flag argument. | * Move out the boot flag argument. | ||||
*/ | */ | ||||
options = 0; | options = 0; | ||||
ucp = (char *)p->p_sysent->sv_usrstack; | ucp = (char *)p->p_sysent->sv_usrstack; | ||||
(void)subyte(--ucp, 0); /* trailing zero */ | (void)subyte(--ucp, 0); /* trailing zero */ | ||||
if (boothowto & RB_SINGLE) { | if (boothowto & RB_SINGLE) { | ||||
(void)subyte(--ucp, 's'); | (void)subyte(--ucp, 's'); | ||||
▲ Show 20 Lines • Show All 68 Lines • ▼ Show 20 Lines | |||||
static void | static void | ||||
create_init(const void *udata __unused) | create_init(const void *udata __unused) | ||||
{ | { | ||||
struct fork_req fr; | struct fork_req fr; | ||||
struct ucred *newcred, *oldcred; | struct ucred *newcred, *oldcred; | ||||
struct thread *td; | struct thread *td; | ||||
int error; | int error; | ||||
KASSERT(curvps == FIRST_THREAD_IN_PROC(V_vproc0)->td_vps, | |||||
("%s: curvps %p != V_vproc0 %p first td %p td_vps %p\n", | |||||
__func__, curvps, V_vproc0, FIRST_THREAD_IN_PROC(V_vproc0), | |||||
FIRST_THREAD_IN_PROC(V_vproc0)->td_vps)); | |||||
KASSERT(curvps == TD_TO_VPS(FIRST_THREAD_IN_PROC(V_vproc0)), | |||||
("%s: curvps %p != TD_TO_VPS(..(V_vproc0 %p)) %p\n", | |||||
__func__, curvps, V_vproc0, | |||||
TD_TO_VPS(FIRST_THREAD_IN_PROC(V_vproc0)))); | |||||
bzero(&fr, sizeof(fr)); | bzero(&fr, sizeof(fr)); | ||||
fr.fr_flags = RFFDG | RFPROC | RFSTOPPED; | fr.fr_flags = RFFDG | RFPROC | RFSTOPPED; | ||||
fr.fr_procp = &initproc; | fr.fr_procp = &V_initproc; | ||||
error = fork1(&thread0, &fr); | td = FIRST_THREAD_IN_PROC(V_vproc0); | ||||
error = fork1(td, &fr); | |||||
if (error) | if (error) | ||||
panic("cannot fork init: %d\n", error); | panic("cannot fork init: %d\n", error); | ||||
KASSERT(initproc->p_pid == 1, ("create_init: initproc->p_pid != 1")); | KASSERT(V_initproc->p_pid == 1, ("%s: initproc->p_pid(%d) != 1", | ||||
__func__, V_initproc->p_pid)); | |||||
KASSERT(curvps == FIRST_THREAD_IN_PROC(V_initproc)->td_vps, | |||||
("%s: curvps %p != V_initproc %p first td %p td_vps %p\n", | |||||
__func__, curvps, V_initproc, FIRST_THREAD_IN_PROC(V_initproc), | |||||
FIRST_THREAD_IN_PROC(V_initproc)->td_vps)); | |||||
/* divorce init's credentials from the kernel's */ | /* divorce init's credentials from the kernel's */ | ||||
newcred = crget(); | newcred = crget(); | ||||
sx_xlock(&proctree_lock); | sx_xlock(&V_proctree_lock); | ||||
PROC_LOCK(initproc); | PROC_LOCK(V_initproc); | ||||
initproc->p_flag |= P_SYSTEM | P_INMEM; | V_initproc->p_flag |= P_SYSTEM | P_INMEM; | ||||
initproc->p_treeflag |= P_TREE_REAPER; | V_initproc->p_treeflag |= P_TREE_REAPER; | ||||
oldcred = initproc->p_ucred; | oldcred = V_initproc->p_ucred; | ||||
crcopy(newcred, oldcred); | crcopy(newcred, oldcred); | ||||
#ifdef VIMAGE | |||||
/* Swap to the correct prison. */ | |||||
/* XXX is this really needed or was this related to a V_vproc0 bug? */ | |||||
prison_free(newcred->cr_prison); | |||||
newcred->cr_prison = curvps->vps_pr; | |||||
prison_hold(newcred->cr_prison); | |||||
#endif | |||||
#ifdef MAC | #ifdef MAC | ||||
mac_cred_create_init(newcred); | mac_cred_create_init(newcred); | ||||
#endif | #endif | ||||
#ifdef AUDIT | #ifdef AUDIT | ||||
audit_cred_proc1(newcred); | audit_cred_proc1(newcred); | ||||
#endif | #endif | ||||
proc_set_cred(initproc, newcred); | /* This will also update cowgen. */ | ||||
td = FIRST_THREAD_IN_PROC(initproc); | proc_set_cred(V_initproc, newcred); | ||||
crfree(td->td_ucred); | PROC_UNLOCK(V_initproc); | ||||
td->td_ucred = crhold(initproc->p_ucred); | sx_xunlock(&V_proctree_lock); | ||||
PROC_UNLOCK(initproc); | |||||
sx_xunlock(&proctree_lock); | |||||
crfree(oldcred); | crfree(oldcred); | ||||
cpu_fork_kthread_handler(FIRST_THREAD_IN_PROC(initproc), | |||||
cpu_fork_kthread_handler(FIRST_THREAD_IN_PROC(V_initproc), | |||||
start_init, NULL); | start_init, NULL); | ||||
} | } | ||||
SYSINIT(init, SI_SUB_CREATE_INIT, SI_ORDER_FIRST, create_init, NULL); | VPS_SYSINIT(init, SI_SUB_CREATE_INIT, SI_ORDER_FIRST, create_init, NULL); | ||||
/* | /* | ||||
* Make it runnable now. | * Make it runnable now. | ||||
*/ | */ | ||||
static void | static void | ||||
kick_init(const void *udata __unused) | kick_init(const void *udata __unused) | ||||
{ | { | ||||
struct thread *td; | struct thread *td; | ||||
td = FIRST_THREAD_IN_PROC(initproc); | td = FIRST_THREAD_IN_PROC(V_initproc); | ||||
thread_lock(td); | thread_lock(td); | ||||
TD_SET_CAN_RUN(td); | TD_SET_CAN_RUN(td); | ||||
sched_add(td, SRQ_BORING); | sched_add(td, SRQ_BORING); | ||||
thread_unlock(td); | thread_unlock(td); | ||||
} | } | ||||
SYSINIT(kickinit, SI_SUB_KTHREAD_INIT, SI_ORDER_MIDDLE, kick_init, NULL); | VPS_SYSINIT(kickinit, SI_SUB_KTHREAD_INIT, SI_ORDER_MIDDLE, kick_init, NULL); | ||||
#ifdef VIMAGE | |||||
static void | |||||
reapinit(void *ident __unused) | |||||
{ | |||||
struct proc *p, *p2; | |||||
while (V_nprocs > 2) { | |||||
sx_slock(&V_allproc_lock); | |||||
FOREACH_PROC_IN_SYSTEM(p) { | |||||
if (p->p_pid <= 1) | |||||
continue; | |||||
PROC_LOCK(p); | |||||
kern_psignal(p, SIGKILL); | |||||
PROC_UNLOCK(p); | |||||
} | |||||
sx_sunlock(&V_allproc_lock); | |||||
pause("reapin1t", hz/2); | |||||
} | |||||
/* Operate on current vps instance only. */ | |||||
sx_xlock(&V_proctree_lock); | |||||
LIST_FOREACH_SAFE(p, &V_zombproc, p_list, p2) { | |||||
PROC_LOCK(p); | |||||
proc_reap(FIRST_THREAD_IN_PROC(V_vproc0), p, NULL, 0); | |||||
sx_xlock(&V_proctree_lock); | |||||
} | |||||
sx_xunlock(&V_proctree_lock); | |||||
while (V_nprocs > 1) | |||||
pause("reapinit", hz/2); | |||||
/* Only our "swapper" left. */ | |||||
KASSERT(V_nprocs == 1, ("%s: vps %p V_nprocs %d != 1", | |||||
__func__, curvps, V_nprocs)); | |||||
} | |||||
/* Run very first. */ | |||||
VPS_SYSUNINIT(reapinit, SI_SUB_VIMAGE_DONE, SI_ORDER_ANY, reapinit, NULL); | |||||
#endif |
Panicking seems harsh when kproc_create can fail simply because the process limit has been hit. Is there a way to just fail the jail creation, or if not that to destroy the jail? Perhaps with a warning - a sort of VPS panic.