1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24*0Sstevel@tonic-gate * Use is subject to license terms. 25*0Sstevel@tonic-gate */ 26*0Sstevel@tonic-gate 27*0Sstevel@tonic-gate /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 28*0Sstevel@tonic-gate /* All Rights Reserved */ 29*0Sstevel@tonic-gate 30*0Sstevel@tonic-gate 31*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 32*0Sstevel@tonic-gate 33*0Sstevel@tonic-gate #include <sys/types.h> 34*0Sstevel@tonic-gate #include <sys/param.h> 35*0Sstevel@tonic-gate #include <sys/sysmacros.h> 36*0Sstevel@tonic-gate #include <sys/proc.h> 37*0Sstevel@tonic-gate #include <sys/kmem.h> 38*0Sstevel@tonic-gate #include <sys/tuneable.h> 39*0Sstevel@tonic-gate #include <sys/var.h> 40*0Sstevel@tonic-gate #include <sys/cred.h> 41*0Sstevel@tonic-gate #include <sys/systm.h> 42*0Sstevel@tonic-gate #include <sys/prsystm.h> 43*0Sstevel@tonic-gate #include <sys/vnode.h> 44*0Sstevel@tonic-gate #include <sys/session.h> 45*0Sstevel@tonic-gate #include <sys/cpuvar.h> 46*0Sstevel@tonic-gate #include <sys/cmn_err.h> 47*0Sstevel@tonic-gate #include <sys/bitmap.h> 48*0Sstevel@tonic-gate #include <sys/debug.h> 49*0Sstevel@tonic-gate #include <c2/audit.h> 50*0Sstevel@tonic-gate #include <sys/zone.h> 51*0Sstevel@tonic-gate 52*0Sstevel@tonic-gate /* directory entries for /proc */ 53*0Sstevel@tonic-gate union procent { 54*0Sstevel@tonic-gate proc_t *pe_proc; 55*0Sstevel@tonic-gate union procent *pe_next; 56*0Sstevel@tonic-gate }; 57*0Sstevel@tonic-gate 58*0Sstevel@tonic-gate struct pid pid0 = { 59*0Sstevel@tonic-gate 0, /* pid_prinactive */ 60*0Sstevel@tonic-gate 1, /* pid_pgorphaned */ 61*0Sstevel@tonic-gate 0, /* pid_padding */ 62*0Sstevel@tonic-gate 0, /* pid_prslot */ 63*0Sstevel@tonic-gate 0, /* pid_id */ 64*0Sstevel@tonic-gate NULL, /* pid_pglink */ 65*0Sstevel@tonic-gate NULL, /* pid_link */ 66*0Sstevel@tonic-gate 3 /* pid_ref */ 67*0Sstevel@tonic-gate }; 68*0Sstevel@tonic-gate 69*0Sstevel@tonic-gate static int pid_hashlen = 4; /* desired average hash chain length */ 70*0Sstevel@tonic-gate static int pid_hashsz; /* number of buckets in the hash table */ 71*0Sstevel@tonic-gate 72*0Sstevel@tonic-gate #define HASHPID(pid) (pidhash[((pid)&(pid_hashsz-1))]) 73*0Sstevel@tonic-gate 74*0Sstevel@tonic-gate extern uint_t nproc; 75*0Sstevel@tonic-gate extern struct kmem_cache *process_cache; 76*0Sstevel@tonic-gate static void upcount_init(void); 77*0Sstevel@tonic-gate 78*0Sstevel@tonic-gate kmutex_t pidlock; /* global process lock */ 79*0Sstevel@tonic-gate kmutex_t pr_pidlock; /* /proc global process lock */ 80*0Sstevel@tonic-gate kcondvar_t *pr_pid_cv; /* for /proc, one per process slot */ 81*0Sstevel@tonic-gate struct plock *proc_lock; /* persistent array of p_lock's */ 82*0Sstevel@tonic-gate 83*0Sstevel@tonic-gate /* 84*0Sstevel@tonic-gate * See the comment above pid_getlockslot() for a detailed explanation of this 85*0Sstevel@tonic-gate * constant. Note that a PLOCK_SHIFT of 3 implies 64-byte coherence 86*0Sstevel@tonic-gate * granularity; if the coherence granularity is ever changed, this constant 87*0Sstevel@tonic-gate * should be modified to reflect the change to minimize proc_lock false 88*0Sstevel@tonic-gate * sharing (correctness, however, is guaranteed regardless of the coherence 89*0Sstevel@tonic-gate * granularity). 90*0Sstevel@tonic-gate */ 91*0Sstevel@tonic-gate #define PLOCK_SHIFT 3 92*0Sstevel@tonic-gate 93*0Sstevel@tonic-gate static kmutex_t pidlinklock; 94*0Sstevel@tonic-gate static struct pid **pidhash; 95*0Sstevel@tonic-gate static pid_t minpid; 96*0Sstevel@tonic-gate static pid_t mpid; 97*0Sstevel@tonic-gate static union procent *procdir; 98*0Sstevel@tonic-gate static union procent *procentfree; 99*0Sstevel@tonic-gate 100*0Sstevel@tonic-gate static struct pid * 101*0Sstevel@tonic-gate pid_lookup(pid_t pid) 102*0Sstevel@tonic-gate { 103*0Sstevel@tonic-gate struct pid *pidp; 104*0Sstevel@tonic-gate 105*0Sstevel@tonic-gate ASSERT(MUTEX_HELD(&pidlinklock)); 106*0Sstevel@tonic-gate 107*0Sstevel@tonic-gate for (pidp = HASHPID(pid); pidp; pidp = pidp->pid_link) { 108*0Sstevel@tonic-gate if (pidp->pid_id == pid) { 109*0Sstevel@tonic-gate ASSERT(pidp->pid_ref > 0); 110*0Sstevel@tonic-gate break; 111*0Sstevel@tonic-gate } 112*0Sstevel@tonic-gate } 113*0Sstevel@tonic-gate return (pidp); 114*0Sstevel@tonic-gate } 115*0Sstevel@tonic-gate 116*0Sstevel@tonic-gate void 117*0Sstevel@tonic-gate pid_setmin(void) 118*0Sstevel@tonic-gate { 119*0Sstevel@tonic-gate if (jump_pid && jump_pid > mpid) 120*0Sstevel@tonic-gate minpid = mpid = jump_pid; 121*0Sstevel@tonic-gate else 122*0Sstevel@tonic-gate minpid = mpid + 1; 123*0Sstevel@tonic-gate } 124*0Sstevel@tonic-gate 125*0Sstevel@tonic-gate /* 126*0Sstevel@tonic-gate * When prslots are simply used as an index to determine a process' p_lock, 127*0Sstevel@tonic-gate * adjacent prslots share adjacent p_locks. On machines where the size 128*0Sstevel@tonic-gate * of a mutex is smaller than that of a cache line (which, as of this writing, 129*0Sstevel@tonic-gate * is true for all machines on which Solaris runs), this can potentially 130*0Sstevel@tonic-gate * induce false sharing. The standard solution for false sharing is to pad 131*0Sstevel@tonic-gate * out one's data structures (in this case, struct plock). However, 132*0Sstevel@tonic-gate * given the size and (generally) sparse use of the proc_lock array, this 133*0Sstevel@tonic-gate * is suboptimal. We therefore stride through the proc_lock array with 134*0Sstevel@tonic-gate * a stride of PLOCK_SHIFT. PLOCK_SHIFT should be defined as: 135*0Sstevel@tonic-gate * 136*0Sstevel@tonic-gate * log_2 (coherence_granularity / sizeof (kmutex_t)) 137*0Sstevel@tonic-gate * 138*0Sstevel@tonic-gate * Under this scheme, false sharing is still possible -- but only when 139*0Sstevel@tonic-gate * the number of active processes is very large. Note that the one-to-one 140*0Sstevel@tonic-gate * mapping between prslots and lockslots is maintained. 141*0Sstevel@tonic-gate */ 142*0Sstevel@tonic-gate static int 143*0Sstevel@tonic-gate pid_getlockslot(int prslot) 144*0Sstevel@tonic-gate { 145*0Sstevel@tonic-gate int even = (v.v_proc >> PLOCK_SHIFT) << PLOCK_SHIFT; 146*0Sstevel@tonic-gate int perlap = even >> PLOCK_SHIFT; 147*0Sstevel@tonic-gate 148*0Sstevel@tonic-gate if (prslot >= even) 149*0Sstevel@tonic-gate return (prslot); 150*0Sstevel@tonic-gate 151*0Sstevel@tonic-gate return (((prslot % perlap) << PLOCK_SHIFT) + (prslot / perlap)); 152*0Sstevel@tonic-gate } 153*0Sstevel@tonic-gate 154*0Sstevel@tonic-gate /* 155*0Sstevel@tonic-gate * This function assigns a pid for use in a fork request. It allocates 156*0Sstevel@tonic-gate * a pid structure, tries to find an empty slot in the proc table, 157*0Sstevel@tonic-gate * and selects the process id. 158*0Sstevel@tonic-gate * 159*0Sstevel@tonic-gate * pid_assign() returns the new pid on success, -1 on failure. 160*0Sstevel@tonic-gate */ 161*0Sstevel@tonic-gate pid_t 162*0Sstevel@tonic-gate pid_assign(proc_t *prp) 163*0Sstevel@tonic-gate { 164*0Sstevel@tonic-gate struct pid *pidp; 165*0Sstevel@tonic-gate union procent *pep; 166*0Sstevel@tonic-gate pid_t newpid, startpid; 167*0Sstevel@tonic-gate 168*0Sstevel@tonic-gate pidp = kmem_zalloc(sizeof (struct pid), KM_SLEEP); 169*0Sstevel@tonic-gate 170*0Sstevel@tonic-gate mutex_enter(&pidlinklock); 171*0Sstevel@tonic-gate if ((pep = procentfree) == NULL) { 172*0Sstevel@tonic-gate /* 173*0Sstevel@tonic-gate * ran out of /proc directory entries 174*0Sstevel@tonic-gate */ 175*0Sstevel@tonic-gate goto failed; 176*0Sstevel@tonic-gate } 177*0Sstevel@tonic-gate 178*0Sstevel@tonic-gate /* 179*0Sstevel@tonic-gate * Allocate a pid 180*0Sstevel@tonic-gate */ 181*0Sstevel@tonic-gate startpid = mpid; 182*0Sstevel@tonic-gate do { 183*0Sstevel@tonic-gate newpid = (++mpid == maxpid ? mpid = minpid : mpid); 184*0Sstevel@tonic-gate } while (pid_lookup(newpid) && newpid != startpid); 185*0Sstevel@tonic-gate 186*0Sstevel@tonic-gate if (newpid == startpid && pid_lookup(newpid)) { 187*0Sstevel@tonic-gate /* couldn't find a free pid */ 188*0Sstevel@tonic-gate goto failed; 189*0Sstevel@tonic-gate } 190*0Sstevel@tonic-gate 191*0Sstevel@tonic-gate procentfree = pep->pe_next; 192*0Sstevel@tonic-gate pep->pe_proc = prp; 193*0Sstevel@tonic-gate prp->p_pidp = pidp; 194*0Sstevel@tonic-gate 195*0Sstevel@tonic-gate /* 196*0Sstevel@tonic-gate * Put pid into the pid hash table. 197*0Sstevel@tonic-gate */ 198*0Sstevel@tonic-gate pidp->pid_link = HASHPID(newpid); 199*0Sstevel@tonic-gate HASHPID(newpid) = pidp; 200*0Sstevel@tonic-gate pidp->pid_ref = 1; 201*0Sstevel@tonic-gate pidp->pid_id = newpid; 202*0Sstevel@tonic-gate pidp->pid_prslot = pep - procdir; 203*0Sstevel@tonic-gate prp->p_lockp = &proc_lock[pid_getlockslot(pidp->pid_prslot)]; 204*0Sstevel@tonic-gate mutex_exit(&pidlinklock); 205*0Sstevel@tonic-gate 206*0Sstevel@tonic-gate return (newpid); 207*0Sstevel@tonic-gate 208*0Sstevel@tonic-gate failed: 209*0Sstevel@tonic-gate mutex_exit(&pidlinklock); 210*0Sstevel@tonic-gate kmem_free(pidp, sizeof (struct pid)); 211*0Sstevel@tonic-gate return (-1); 212*0Sstevel@tonic-gate } 213*0Sstevel@tonic-gate 214*0Sstevel@tonic-gate /* 215*0Sstevel@tonic-gate * decrement the reference count for pid 216*0Sstevel@tonic-gate */ 217*0Sstevel@tonic-gate int 218*0Sstevel@tonic-gate pid_rele(struct pid *pidp) 219*0Sstevel@tonic-gate { 220*0Sstevel@tonic-gate struct pid **pidpp; 221*0Sstevel@tonic-gate 222*0Sstevel@tonic-gate mutex_enter(&pidlinklock); 223*0Sstevel@tonic-gate ASSERT(pidp != &pid0); 224*0Sstevel@tonic-gate 225*0Sstevel@tonic-gate pidpp = &HASHPID(pidp->pid_id); 226*0Sstevel@tonic-gate for (;;) { 227*0Sstevel@tonic-gate ASSERT(*pidpp != NULL); 228*0Sstevel@tonic-gate if (*pidpp == pidp) 229*0Sstevel@tonic-gate break; 230*0Sstevel@tonic-gate pidpp = &(*pidpp)->pid_link; 231*0Sstevel@tonic-gate } 232*0Sstevel@tonic-gate 233*0Sstevel@tonic-gate *pidpp = pidp->pid_link; 234*0Sstevel@tonic-gate mutex_exit(&pidlinklock); 235*0Sstevel@tonic-gate 236*0Sstevel@tonic-gate kmem_free(pidp, sizeof (*pidp)); 237*0Sstevel@tonic-gate return (0); 238*0Sstevel@tonic-gate } 239*0Sstevel@tonic-gate 240*0Sstevel@tonic-gate void 241*0Sstevel@tonic-gate proc_entry_free(struct pid *pidp) 242*0Sstevel@tonic-gate { 243*0Sstevel@tonic-gate mutex_enter(&pidlinklock); 244*0Sstevel@tonic-gate pidp->pid_prinactive = 1; 245*0Sstevel@tonic-gate procdir[pidp->pid_prslot].pe_next = procentfree; 246*0Sstevel@tonic-gate procentfree = &procdir[pidp->pid_prslot]; 247*0Sstevel@tonic-gate mutex_exit(&pidlinklock); 248*0Sstevel@tonic-gate } 249*0Sstevel@tonic-gate 250*0Sstevel@tonic-gate void 251*0Sstevel@tonic-gate pid_exit(proc_t *prp) 252*0Sstevel@tonic-gate { 253*0Sstevel@tonic-gate struct pid *pidp; 254*0Sstevel@tonic-gate 255*0Sstevel@tonic-gate ASSERT(MUTEX_HELD(&pidlock)); 256*0Sstevel@tonic-gate 257*0Sstevel@tonic-gate /* 258*0Sstevel@tonic-gate * Exit process group. If it is NULL, it's because fork failed 259*0Sstevel@tonic-gate * before calling pgjoin(). 260*0Sstevel@tonic-gate */ 261*0Sstevel@tonic-gate ASSERT(prp->p_pgidp != NULL || prp->p_stat == SIDL); 262*0Sstevel@tonic-gate if (prp->p_pgidp != NULL) 263*0Sstevel@tonic-gate pgexit(prp); 264*0Sstevel@tonic-gate 265*0Sstevel@tonic-gate SESS_RELE(prp->p_sessp); 266*0Sstevel@tonic-gate 267*0Sstevel@tonic-gate pidp = prp->p_pidp; 268*0Sstevel@tonic-gate 269*0Sstevel@tonic-gate proc_entry_free(pidp); 270*0Sstevel@tonic-gate 271*0Sstevel@tonic-gate #ifdef C2_AUDIT 272*0Sstevel@tonic-gate if (audit_active) 273*0Sstevel@tonic-gate audit_pfree(prp); 274*0Sstevel@tonic-gate #endif 275*0Sstevel@tonic-gate 276*0Sstevel@tonic-gate if (practive == prp) { 277*0Sstevel@tonic-gate practive = prp->p_next; 278*0Sstevel@tonic-gate } 279*0Sstevel@tonic-gate 280*0Sstevel@tonic-gate if (prp->p_next) { 281*0Sstevel@tonic-gate prp->p_next->p_prev = prp->p_prev; 282*0Sstevel@tonic-gate } 283*0Sstevel@tonic-gate if (prp->p_prev) { 284*0Sstevel@tonic-gate prp->p_prev->p_next = prp->p_next; 285*0Sstevel@tonic-gate } 286*0Sstevel@tonic-gate 287*0Sstevel@tonic-gate PID_RELE(pidp); 288*0Sstevel@tonic-gate 289*0Sstevel@tonic-gate mutex_destroy(&prp->p_crlock); 290*0Sstevel@tonic-gate kmem_cache_free(process_cache, prp); 291*0Sstevel@tonic-gate nproc--; 292*0Sstevel@tonic-gate } 293*0Sstevel@tonic-gate 294*0Sstevel@tonic-gate /* 295*0Sstevel@tonic-gate * Find a process visible from the specified zone given its process ID. 296*0Sstevel@tonic-gate */ 297*0Sstevel@tonic-gate proc_t * 298*0Sstevel@tonic-gate prfind_zone(pid_t pid, zoneid_t zoneid) 299*0Sstevel@tonic-gate { 300*0Sstevel@tonic-gate struct pid *pidp; 301*0Sstevel@tonic-gate proc_t *p; 302*0Sstevel@tonic-gate 303*0Sstevel@tonic-gate ASSERT(MUTEX_HELD(&pidlock)); 304*0Sstevel@tonic-gate 305*0Sstevel@tonic-gate mutex_enter(&pidlinklock); 306*0Sstevel@tonic-gate pidp = pid_lookup(pid); 307*0Sstevel@tonic-gate mutex_exit(&pidlinklock); 308*0Sstevel@tonic-gate if (pidp != NULL && pidp->pid_prinactive == 0) { 309*0Sstevel@tonic-gate p = procdir[pidp->pid_prslot].pe_proc; 310*0Sstevel@tonic-gate if (zoneid == ALL_ZONES || p->p_zone->zone_id == zoneid) 311*0Sstevel@tonic-gate return (p); 312*0Sstevel@tonic-gate } 313*0Sstevel@tonic-gate return (NULL); 314*0Sstevel@tonic-gate } 315*0Sstevel@tonic-gate 316*0Sstevel@tonic-gate /* 317*0Sstevel@tonic-gate * Find a process given its process ID. This obeys zone restrictions, 318*0Sstevel@tonic-gate * so if the caller is in a non-global zone it won't find processes 319*0Sstevel@tonic-gate * associated with other zones. Use prfind_zone(pid, ALL_ZONES) to 320*0Sstevel@tonic-gate * bypass this restriction. 321*0Sstevel@tonic-gate */ 322*0Sstevel@tonic-gate proc_t * 323*0Sstevel@tonic-gate prfind(pid_t pid) 324*0Sstevel@tonic-gate { 325*0Sstevel@tonic-gate zoneid_t zoneid; 326*0Sstevel@tonic-gate 327*0Sstevel@tonic-gate if (INGLOBALZONE(curproc)) 328*0Sstevel@tonic-gate zoneid = ALL_ZONES; 329*0Sstevel@tonic-gate else 330*0Sstevel@tonic-gate zoneid = getzoneid(); 331*0Sstevel@tonic-gate return (prfind_zone(pid, zoneid)); 332*0Sstevel@tonic-gate } 333*0Sstevel@tonic-gate 334*0Sstevel@tonic-gate proc_t * 335*0Sstevel@tonic-gate pgfind_zone(pid_t pgid, zoneid_t zoneid) 336*0Sstevel@tonic-gate { 337*0Sstevel@tonic-gate struct pid *pidp; 338*0Sstevel@tonic-gate 339*0Sstevel@tonic-gate ASSERT(MUTEX_HELD(&pidlock)); 340*0Sstevel@tonic-gate 341*0Sstevel@tonic-gate mutex_enter(&pidlinklock); 342*0Sstevel@tonic-gate pidp = pid_lookup(pgid); 343*0Sstevel@tonic-gate mutex_exit(&pidlinklock); 344*0Sstevel@tonic-gate if (pidp != NULL) { 345*0Sstevel@tonic-gate proc_t *p = pidp->pid_pglink; 346*0Sstevel@tonic-gate 347*0Sstevel@tonic-gate if (zoneid == ALL_ZONES || pgid == 0 || p == NULL || 348*0Sstevel@tonic-gate p->p_zone->zone_id == zoneid) 349*0Sstevel@tonic-gate return (p); 350*0Sstevel@tonic-gate } 351*0Sstevel@tonic-gate return (NULL); 352*0Sstevel@tonic-gate } 353*0Sstevel@tonic-gate 354*0Sstevel@tonic-gate /* 355*0Sstevel@tonic-gate * return the head of the list of processes whose process group ID is 'pgid', 356*0Sstevel@tonic-gate * or NULL, if no such process group 357*0Sstevel@tonic-gate */ 358*0Sstevel@tonic-gate proc_t * 359*0Sstevel@tonic-gate pgfind(pid_t pgid) 360*0Sstevel@tonic-gate { 361*0Sstevel@tonic-gate zoneid_t zoneid; 362*0Sstevel@tonic-gate 363*0Sstevel@tonic-gate if (INGLOBALZONE(curproc)) 364*0Sstevel@tonic-gate zoneid = ALL_ZONES; 365*0Sstevel@tonic-gate else 366*0Sstevel@tonic-gate zoneid = getzoneid(); 367*0Sstevel@tonic-gate return (pgfind_zone(pgid, zoneid)); 368*0Sstevel@tonic-gate } 369*0Sstevel@tonic-gate 370*0Sstevel@tonic-gate /* 371*0Sstevel@tonic-gate * If pid exists, find its proc, acquire its p_lock and mark it P_PR_LOCK. 372*0Sstevel@tonic-gate * Returns the proc pointer on success, NULL on failure. sprlock() is 373*0Sstevel@tonic-gate * really just a stripped-down version of pr_p_lock() to allow practive 374*0Sstevel@tonic-gate * walkers like dofusers() and dumpsys() to synchronize with /proc. 375*0Sstevel@tonic-gate */ 376*0Sstevel@tonic-gate proc_t * 377*0Sstevel@tonic-gate sprlock_zone(pid_t pid, zoneid_t zoneid) 378*0Sstevel@tonic-gate { 379*0Sstevel@tonic-gate proc_t *p; 380*0Sstevel@tonic-gate kmutex_t *mp; 381*0Sstevel@tonic-gate 382*0Sstevel@tonic-gate for (;;) { 383*0Sstevel@tonic-gate mutex_enter(&pidlock); 384*0Sstevel@tonic-gate if ((p = prfind_zone(pid, zoneid)) == NULL) { 385*0Sstevel@tonic-gate mutex_exit(&pidlock); 386*0Sstevel@tonic-gate return (NULL); 387*0Sstevel@tonic-gate } 388*0Sstevel@tonic-gate /* 389*0Sstevel@tonic-gate * p_lock is persistent, but p itself is not -- it could 390*0Sstevel@tonic-gate * vanish during cv_wait(). Load p->p_lock now so we can 391*0Sstevel@tonic-gate * drop it after cv_wait() without referencing p. 392*0Sstevel@tonic-gate */ 393*0Sstevel@tonic-gate mp = &p->p_lock; 394*0Sstevel@tonic-gate mutex_enter(mp); 395*0Sstevel@tonic-gate mutex_exit(&pidlock); 396*0Sstevel@tonic-gate /* 397*0Sstevel@tonic-gate * If the process is in some half-baked state, fail. 398*0Sstevel@tonic-gate */ 399*0Sstevel@tonic-gate if (p->p_stat == SZOMB || p->p_stat == SIDL || 400*0Sstevel@tonic-gate p->p_tlist == NULL || (p->p_flag & SEXITLWPS)) { 401*0Sstevel@tonic-gate mutex_exit(mp); 402*0Sstevel@tonic-gate return (NULL); 403*0Sstevel@tonic-gate } 404*0Sstevel@tonic-gate if (panicstr) 405*0Sstevel@tonic-gate return (p); 406*0Sstevel@tonic-gate if (!(p->p_proc_flag & P_PR_LOCK)) 407*0Sstevel@tonic-gate break; 408*0Sstevel@tonic-gate cv_wait(&pr_pid_cv[p->p_slot], mp); 409*0Sstevel@tonic-gate mutex_exit(mp); 410*0Sstevel@tonic-gate } 411*0Sstevel@tonic-gate p->p_proc_flag |= P_PR_LOCK; 412*0Sstevel@tonic-gate THREAD_KPRI_REQUEST(); 413*0Sstevel@tonic-gate return (p); 414*0Sstevel@tonic-gate } 415*0Sstevel@tonic-gate 416*0Sstevel@tonic-gate proc_t * 417*0Sstevel@tonic-gate sprlock(pid_t pid) 418*0Sstevel@tonic-gate { 419*0Sstevel@tonic-gate zoneid_t zoneid; 420*0Sstevel@tonic-gate 421*0Sstevel@tonic-gate if (INGLOBALZONE(curproc)) 422*0Sstevel@tonic-gate zoneid = ALL_ZONES; 423*0Sstevel@tonic-gate else 424*0Sstevel@tonic-gate zoneid = getzoneid(); 425*0Sstevel@tonic-gate return (sprlock_zone(pid, zoneid)); 426*0Sstevel@tonic-gate } 427*0Sstevel@tonic-gate 428*0Sstevel@tonic-gate void 429*0Sstevel@tonic-gate sprlock_proc(proc_t *p) 430*0Sstevel@tonic-gate { 431*0Sstevel@tonic-gate ASSERT(MUTEX_HELD(&p->p_lock)); 432*0Sstevel@tonic-gate 433*0Sstevel@tonic-gate while (p->p_proc_flag & P_PR_LOCK) { 434*0Sstevel@tonic-gate cv_wait(&pr_pid_cv[p->p_slot], &p->p_lock); 435*0Sstevel@tonic-gate } 436*0Sstevel@tonic-gate 437*0Sstevel@tonic-gate p->p_proc_flag |= P_PR_LOCK; 438*0Sstevel@tonic-gate THREAD_KPRI_REQUEST(); 439*0Sstevel@tonic-gate } 440*0Sstevel@tonic-gate 441*0Sstevel@tonic-gate void 442*0Sstevel@tonic-gate sprunlock(proc_t *p) 443*0Sstevel@tonic-gate { 444*0Sstevel@tonic-gate if (panicstr) { 445*0Sstevel@tonic-gate mutex_exit(&p->p_lock); 446*0Sstevel@tonic-gate return; 447*0Sstevel@tonic-gate } 448*0Sstevel@tonic-gate 449*0Sstevel@tonic-gate ASSERT(p->p_proc_flag & P_PR_LOCK); 450*0Sstevel@tonic-gate ASSERT(MUTEX_HELD(&p->p_lock)); 451*0Sstevel@tonic-gate 452*0Sstevel@tonic-gate cv_signal(&pr_pid_cv[p->p_slot]); 453*0Sstevel@tonic-gate p->p_proc_flag &= ~P_PR_LOCK; 454*0Sstevel@tonic-gate mutex_exit(&p->p_lock); 455*0Sstevel@tonic-gate THREAD_KPRI_RELEASE(); 456*0Sstevel@tonic-gate } 457*0Sstevel@tonic-gate 458*0Sstevel@tonic-gate void 459*0Sstevel@tonic-gate pid_init(void) 460*0Sstevel@tonic-gate { 461*0Sstevel@tonic-gate int i; 462*0Sstevel@tonic-gate 463*0Sstevel@tonic-gate pid_hashsz = 1 << highbit(v.v_proc / pid_hashlen); 464*0Sstevel@tonic-gate 465*0Sstevel@tonic-gate pidhash = kmem_zalloc(sizeof (struct pid *) * pid_hashsz, KM_SLEEP); 466*0Sstevel@tonic-gate procdir = kmem_alloc(sizeof (union procent) * v.v_proc, KM_SLEEP); 467*0Sstevel@tonic-gate pr_pid_cv = kmem_zalloc(sizeof (kcondvar_t) * v.v_proc, KM_SLEEP); 468*0Sstevel@tonic-gate proc_lock = kmem_zalloc(sizeof (struct plock) * v.v_proc, KM_SLEEP); 469*0Sstevel@tonic-gate 470*0Sstevel@tonic-gate nproc = 1; 471*0Sstevel@tonic-gate practive = proc_sched; 472*0Sstevel@tonic-gate proc_sched->p_next = NULL; 473*0Sstevel@tonic-gate procdir[0].pe_proc = proc_sched; 474*0Sstevel@tonic-gate 475*0Sstevel@tonic-gate procentfree = &procdir[1]; 476*0Sstevel@tonic-gate for (i = 1; i < v.v_proc - 1; i++) 477*0Sstevel@tonic-gate procdir[i].pe_next = &procdir[i+1]; 478*0Sstevel@tonic-gate procdir[i].pe_next = NULL; 479*0Sstevel@tonic-gate 480*0Sstevel@tonic-gate HASHPID(0) = &pid0; 481*0Sstevel@tonic-gate 482*0Sstevel@tonic-gate upcount_init(); 483*0Sstevel@tonic-gate } 484*0Sstevel@tonic-gate 485*0Sstevel@tonic-gate proc_t * 486*0Sstevel@tonic-gate pid_entry(int slot) 487*0Sstevel@tonic-gate { 488*0Sstevel@tonic-gate union procent *pep; 489*0Sstevel@tonic-gate proc_t *prp; 490*0Sstevel@tonic-gate 491*0Sstevel@tonic-gate ASSERT(MUTEX_HELD(&pidlock)); 492*0Sstevel@tonic-gate ASSERT(slot >= 0 && slot < v.v_proc); 493*0Sstevel@tonic-gate 494*0Sstevel@tonic-gate pep = procdir[slot].pe_next; 495*0Sstevel@tonic-gate if (pep >= procdir && pep < &procdir[v.v_proc]) 496*0Sstevel@tonic-gate return (NULL); 497*0Sstevel@tonic-gate prp = procdir[slot].pe_proc; 498*0Sstevel@tonic-gate if (prp != 0 && prp->p_stat == SIDL) 499*0Sstevel@tonic-gate return (NULL); 500*0Sstevel@tonic-gate return (prp); 501*0Sstevel@tonic-gate } 502*0Sstevel@tonic-gate 503*0Sstevel@tonic-gate /* 504*0Sstevel@tonic-gate * Send the specified signal to all processes whose process group ID is 505*0Sstevel@tonic-gate * equal to 'pgid' 506*0Sstevel@tonic-gate */ 507*0Sstevel@tonic-gate 508*0Sstevel@tonic-gate void 509*0Sstevel@tonic-gate signal(pid_t pgid, int sig) 510*0Sstevel@tonic-gate { 511*0Sstevel@tonic-gate struct pid *pidp; 512*0Sstevel@tonic-gate proc_t *prp; 513*0Sstevel@tonic-gate 514*0Sstevel@tonic-gate mutex_enter(&pidlock); 515*0Sstevel@tonic-gate mutex_enter(&pidlinklock); 516*0Sstevel@tonic-gate if (pgid == 0 || (pidp = pid_lookup(pgid)) == NULL) { 517*0Sstevel@tonic-gate mutex_exit(&pidlinklock); 518*0Sstevel@tonic-gate mutex_exit(&pidlock); 519*0Sstevel@tonic-gate return; 520*0Sstevel@tonic-gate } 521*0Sstevel@tonic-gate mutex_exit(&pidlinklock); 522*0Sstevel@tonic-gate for (prp = pidp->pid_pglink; prp; prp = prp->p_pglink) { 523*0Sstevel@tonic-gate mutex_enter(&prp->p_lock); 524*0Sstevel@tonic-gate sigtoproc(prp, NULL, sig); 525*0Sstevel@tonic-gate mutex_exit(&prp->p_lock); 526*0Sstevel@tonic-gate } 527*0Sstevel@tonic-gate mutex_exit(&pidlock); 528*0Sstevel@tonic-gate } 529*0Sstevel@tonic-gate 530*0Sstevel@tonic-gate /* 531*0Sstevel@tonic-gate * Send the specified signal to the specified process 532*0Sstevel@tonic-gate */ 533*0Sstevel@tonic-gate 534*0Sstevel@tonic-gate void 535*0Sstevel@tonic-gate prsignal(struct pid *pidp, int sig) 536*0Sstevel@tonic-gate { 537*0Sstevel@tonic-gate if (!(pidp->pid_prinactive)) 538*0Sstevel@tonic-gate psignal(procdir[pidp->pid_prslot].pe_proc, sig); 539*0Sstevel@tonic-gate } 540*0Sstevel@tonic-gate 541*0Sstevel@tonic-gate #include <sys/sunddi.h> 542*0Sstevel@tonic-gate 543*0Sstevel@tonic-gate /* 544*0Sstevel@tonic-gate * DDI/DKI interfaces for drivers to send signals to processes 545*0Sstevel@tonic-gate */ 546*0Sstevel@tonic-gate 547*0Sstevel@tonic-gate /* 548*0Sstevel@tonic-gate * obtain an opaque reference to a process for signaling 549*0Sstevel@tonic-gate */ 550*0Sstevel@tonic-gate void * 551*0Sstevel@tonic-gate proc_ref(void) 552*0Sstevel@tonic-gate { 553*0Sstevel@tonic-gate struct pid *pidp; 554*0Sstevel@tonic-gate 555*0Sstevel@tonic-gate mutex_enter(&pidlock); 556*0Sstevel@tonic-gate pidp = curproc->p_pidp; 557*0Sstevel@tonic-gate PID_HOLD(pidp); 558*0Sstevel@tonic-gate mutex_exit(&pidlock); 559*0Sstevel@tonic-gate 560*0Sstevel@tonic-gate return (pidp); 561*0Sstevel@tonic-gate } 562*0Sstevel@tonic-gate 563*0Sstevel@tonic-gate /* 564*0Sstevel@tonic-gate * release a reference to a process 565*0Sstevel@tonic-gate * - a process can exit even if a driver has a reference to it 566*0Sstevel@tonic-gate * - one proc_unref for every proc_ref 567*0Sstevel@tonic-gate */ 568*0Sstevel@tonic-gate void 569*0Sstevel@tonic-gate proc_unref(void *pref) 570*0Sstevel@tonic-gate { 571*0Sstevel@tonic-gate mutex_enter(&pidlock); 572*0Sstevel@tonic-gate PID_RELE((struct pid *)pref); 573*0Sstevel@tonic-gate mutex_exit(&pidlock); 574*0Sstevel@tonic-gate } 575*0Sstevel@tonic-gate 576*0Sstevel@tonic-gate /* 577*0Sstevel@tonic-gate * send a signal to a process 578*0Sstevel@tonic-gate * 579*0Sstevel@tonic-gate * - send the process the signal 580*0Sstevel@tonic-gate * - if the process went away, return a -1 581*0Sstevel@tonic-gate * - if the process is still there return 0 582*0Sstevel@tonic-gate */ 583*0Sstevel@tonic-gate int 584*0Sstevel@tonic-gate proc_signal(void *pref, int sig) 585*0Sstevel@tonic-gate { 586*0Sstevel@tonic-gate struct pid *pidp = pref; 587*0Sstevel@tonic-gate 588*0Sstevel@tonic-gate prsignal(pidp, sig); 589*0Sstevel@tonic-gate return (pidp->pid_prinactive ? -1 : 0); 590*0Sstevel@tonic-gate } 591*0Sstevel@tonic-gate 592*0Sstevel@tonic-gate 593*0Sstevel@tonic-gate static struct upcount **upc_hash; /* a boot time allocated array */ 594*0Sstevel@tonic-gate static ulong_t upc_hashmask; 595*0Sstevel@tonic-gate #define UPC_HASH(x, y) ((ulong_t)(x ^ y) & upc_hashmask) 596*0Sstevel@tonic-gate 597*0Sstevel@tonic-gate /* 598*0Sstevel@tonic-gate * Get us off the ground. Called once at boot. 599*0Sstevel@tonic-gate */ 600*0Sstevel@tonic-gate void 601*0Sstevel@tonic-gate upcount_init(void) 602*0Sstevel@tonic-gate { 603*0Sstevel@tonic-gate ulong_t upc_hashsize; 604*0Sstevel@tonic-gate 605*0Sstevel@tonic-gate /* 606*0Sstevel@tonic-gate * An entry per MB of memory is our current guess 607*0Sstevel@tonic-gate */ 608*0Sstevel@tonic-gate /* 609*0Sstevel@tonic-gate * 2^20 is a meg, so shifting right by 20 - PAGESHIFT 610*0Sstevel@tonic-gate * converts pages to megs (without overflowing a u_int 611*0Sstevel@tonic-gate * if you have more than 4G of memory, like ptob(physmem)/1M 612*0Sstevel@tonic-gate * would). 613*0Sstevel@tonic-gate */ 614*0Sstevel@tonic-gate upc_hashsize = (1 << highbit(physmem >> (20 - PAGESHIFT))); 615*0Sstevel@tonic-gate upc_hashmask = upc_hashsize - 1; 616*0Sstevel@tonic-gate upc_hash = kmem_zalloc(upc_hashsize * sizeof (struct upcount *), 617*0Sstevel@tonic-gate KM_SLEEP); 618*0Sstevel@tonic-gate } 619*0Sstevel@tonic-gate 620*0Sstevel@tonic-gate /* 621*0Sstevel@tonic-gate * Increment the number of processes associated with a given uid and zoneid. 622*0Sstevel@tonic-gate */ 623*0Sstevel@tonic-gate void 624*0Sstevel@tonic-gate upcount_inc(uid_t uid, zoneid_t zoneid) 625*0Sstevel@tonic-gate { 626*0Sstevel@tonic-gate struct upcount **upc, **hupc; 627*0Sstevel@tonic-gate struct upcount *new; 628*0Sstevel@tonic-gate 629*0Sstevel@tonic-gate ASSERT(MUTEX_HELD(&pidlock)); 630*0Sstevel@tonic-gate new = NULL; 631*0Sstevel@tonic-gate hupc = &upc_hash[UPC_HASH(uid, zoneid)]; 632*0Sstevel@tonic-gate top: 633*0Sstevel@tonic-gate upc = hupc; 634*0Sstevel@tonic-gate while ((*upc) != NULL) { 635*0Sstevel@tonic-gate if ((*upc)->up_uid == uid && (*upc)->up_zoneid == zoneid) { 636*0Sstevel@tonic-gate (*upc)->up_count++; 637*0Sstevel@tonic-gate if (new) { 638*0Sstevel@tonic-gate /* 639*0Sstevel@tonic-gate * did not need `new' afterall. 640*0Sstevel@tonic-gate */ 641*0Sstevel@tonic-gate kmem_free(new, sizeof (*new)); 642*0Sstevel@tonic-gate } 643*0Sstevel@tonic-gate return; 644*0Sstevel@tonic-gate } 645*0Sstevel@tonic-gate upc = &(*upc)->up_next; 646*0Sstevel@tonic-gate } 647*0Sstevel@tonic-gate 648*0Sstevel@tonic-gate /* 649*0Sstevel@tonic-gate * There is no entry for this <uid,zoneid> pair. 650*0Sstevel@tonic-gate * Allocate one. If we have to drop pidlock, check 651*0Sstevel@tonic-gate * again. 652*0Sstevel@tonic-gate */ 653*0Sstevel@tonic-gate if (new == NULL) { 654*0Sstevel@tonic-gate new = (struct upcount *)kmem_alloc(sizeof (*new), KM_NOSLEEP); 655*0Sstevel@tonic-gate if (new == NULL) { 656*0Sstevel@tonic-gate mutex_exit(&pidlock); 657*0Sstevel@tonic-gate new = (struct upcount *)kmem_alloc(sizeof (*new), 658*0Sstevel@tonic-gate KM_SLEEP); 659*0Sstevel@tonic-gate mutex_enter(&pidlock); 660*0Sstevel@tonic-gate goto top; 661*0Sstevel@tonic-gate } 662*0Sstevel@tonic-gate } 663*0Sstevel@tonic-gate 664*0Sstevel@tonic-gate 665*0Sstevel@tonic-gate /* 666*0Sstevel@tonic-gate * On the assumption that a new user is going to do some 667*0Sstevel@tonic-gate * more forks, put the new upcount structure on the front. 668*0Sstevel@tonic-gate */ 669*0Sstevel@tonic-gate upc = hupc; 670*0Sstevel@tonic-gate 671*0Sstevel@tonic-gate new->up_uid = uid; 672*0Sstevel@tonic-gate new->up_zoneid = zoneid; 673*0Sstevel@tonic-gate new->up_count = 1; 674*0Sstevel@tonic-gate new->up_next = *upc; 675*0Sstevel@tonic-gate 676*0Sstevel@tonic-gate *upc = new; 677*0Sstevel@tonic-gate } 678*0Sstevel@tonic-gate 679*0Sstevel@tonic-gate /* 680*0Sstevel@tonic-gate * Decrement the number of processes a given uid and zoneid has. 681*0Sstevel@tonic-gate */ 682*0Sstevel@tonic-gate void 683*0Sstevel@tonic-gate upcount_dec(uid_t uid, zoneid_t zoneid) 684*0Sstevel@tonic-gate { 685*0Sstevel@tonic-gate struct upcount **upc; 686*0Sstevel@tonic-gate struct upcount *done; 687*0Sstevel@tonic-gate 688*0Sstevel@tonic-gate ASSERT(MUTEX_HELD(&pidlock)); 689*0Sstevel@tonic-gate 690*0Sstevel@tonic-gate upc = &upc_hash[UPC_HASH(uid, zoneid)]; 691*0Sstevel@tonic-gate while ((*upc) != NULL) { 692*0Sstevel@tonic-gate if ((*upc)->up_uid == uid && (*upc)->up_zoneid == zoneid) { 693*0Sstevel@tonic-gate (*upc)->up_count--; 694*0Sstevel@tonic-gate if ((*upc)->up_count == 0) { 695*0Sstevel@tonic-gate done = *upc; 696*0Sstevel@tonic-gate *upc = (*upc)->up_next; 697*0Sstevel@tonic-gate kmem_free(done, sizeof (*done)); 698*0Sstevel@tonic-gate } 699*0Sstevel@tonic-gate return; 700*0Sstevel@tonic-gate } 701*0Sstevel@tonic-gate upc = &(*upc)->up_next; 702*0Sstevel@tonic-gate } 703*0Sstevel@tonic-gate cmn_err(CE_PANIC, "decr_upcount-off the end"); 704*0Sstevel@tonic-gate } 705*0Sstevel@tonic-gate 706*0Sstevel@tonic-gate /* 707*0Sstevel@tonic-gate * Returns the number of processes a uid has. 708*0Sstevel@tonic-gate * Non-existent uid's are assumed to have no processes. 709*0Sstevel@tonic-gate */ 710*0Sstevel@tonic-gate int 711*0Sstevel@tonic-gate upcount_get(uid_t uid, zoneid_t zoneid) 712*0Sstevel@tonic-gate { 713*0Sstevel@tonic-gate struct upcount *upc; 714*0Sstevel@tonic-gate 715*0Sstevel@tonic-gate ASSERT(MUTEX_HELD(&pidlock)); 716*0Sstevel@tonic-gate 717*0Sstevel@tonic-gate upc = upc_hash[UPC_HASH(uid, zoneid)]; 718*0Sstevel@tonic-gate while (upc != NULL) { 719*0Sstevel@tonic-gate if (upc->up_uid == uid && upc->up_zoneid == zoneid) { 720*0Sstevel@tonic-gate return (upc->up_count); 721*0Sstevel@tonic-gate } 722*0Sstevel@tonic-gate upc = upc->up_next; 723*0Sstevel@tonic-gate } 724*0Sstevel@tonic-gate return (0); 725*0Sstevel@tonic-gate } 726