17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5ab9a77c7Sahl * Common Development and Distribution License (the "License"). 6ab9a77c7Sahl * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 218132eb48Sraf 227c478bd9Sstevel@tonic-gate /* 23ff19e029SMenno Lageman * Copyright (c) 1988, 2010, Oracle and/or its affiliates. All rights reserved. 242dc692e0SJerry Jelinek * Copyright 2013, Joyent, Inc. All rights reserved. 257c478bd9Sstevel@tonic-gate */ 267c478bd9Sstevel@tonic-gate 277c478bd9Sstevel@tonic-gate /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 287c478bd9Sstevel@tonic-gate /* All Rights Reserved */ 297c478bd9Sstevel@tonic-gate 307c478bd9Sstevel@tonic-gate #include <sys/types.h> 317c478bd9Sstevel@tonic-gate #include <sys/param.h> 327c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 337c478bd9Sstevel@tonic-gate #include <sys/signal.h> 347c478bd9Sstevel@tonic-gate #include <sys/cred.h> 357c478bd9Sstevel@tonic-gate #include <sys/policy.h> 367c478bd9Sstevel@tonic-gate #include <sys/user.h> 377c478bd9Sstevel@tonic-gate #include <sys/systm.h> 387c478bd9Sstevel@tonic-gate #include <sys/cpuvar.h> 397c478bd9Sstevel@tonic-gate #include <sys/vfs.h> 407c478bd9Sstevel@tonic-gate #include <sys/vnode.h> 417c478bd9Sstevel@tonic-gate #include <sys/file.h> 427c478bd9Sstevel@tonic-gate #include <sys/errno.h> 437c478bd9Sstevel@tonic-gate #include <sys/time.h> 447c478bd9Sstevel@tonic-gate #include <sys/proc.h> 457c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 467c478bd9Sstevel@tonic-gate #include <sys/acct.h> 477c478bd9Sstevel@tonic-gate #include <sys/tuneable.h> 487c478bd9Sstevel@tonic-gate #include <sys/class.h> 497c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 507c478bd9Sstevel@tonic-gate #include <sys/session.h> 517c478bd9Sstevel@tonic-gate #include <sys/ucontext.h> 527c478bd9Sstevel@tonic-gate #include <sys/stack.h> 537c478bd9Sstevel@tonic-gate #include <sys/procfs.h> 547c478bd9Sstevel@tonic-gate #include <sys/prsystm.h> 557c478bd9Sstevel@tonic-gate #include <sys/vmsystm.h> 567c478bd9Sstevel@tonic-gate #include <sys/vtrace.h> 577c478bd9Sstevel@tonic-gate #include <sys/debug.h> 587c478bd9Sstevel@tonic-gate #include <sys/shm_impl.h> 597c478bd9Sstevel@tonic-gate #include <sys/door_data.h> 607c478bd9Sstevel@tonic-gate #include <vm/as.h> 617c478bd9Sstevel@tonic-gate #include <vm/rm.h> 627c478bd9Sstevel@tonic-gate #include <c2/audit.h> 637c478bd9Sstevel@tonic-gate #include <sys/var.h> 647c478bd9Sstevel@tonic-gate #include <sys/schedctl.h> 657c478bd9Sstevel@tonic-gate #include <sys/utrap.h> 667c478bd9Sstevel@tonic-gate #include <sys/task.h> 677c478bd9Sstevel@tonic-gate #include <sys/resource.h> 687c478bd9Sstevel@tonic-gate #include <sys/cyclic.h> 697c478bd9Sstevel@tonic-gate #include <sys/lgrp.h> 707c478bd9Sstevel@tonic-gate #include <sys/rctl.h> 717c478bd9Sstevel@tonic-gate #include <sys/contract_impl.h> 727c478bd9Sstevel@tonic-gate #include <sys/contract/process_impl.h> 737c478bd9Sstevel@tonic-gate #include <sys/list.h> 747c478bd9Sstevel@tonic-gate #include <sys/dtrace.h> 757c478bd9Sstevel@tonic-gate #include <sys/pool.h> 767c478bd9Sstevel@tonic-gate #include <sys/zone.h> 777c478bd9Sstevel@tonic-gate #include <sys/sdt.h> 787c478bd9Sstevel@tonic-gate #include <sys/class.h> 797c478bd9Sstevel@tonic-gate #include <sys/corectl.h> 809acbbeafSnn35248 #include <sys/brand.h> 81657b1f3dSraf #include <sys/fork.h> 827c478bd9Sstevel@tonic-gate 83657b1f3dSraf static int64_t cfork(int, int, int); 8435a5a358SJonathan Adams static int getproc(proc_t **, pid_t, uint_t); 8535a5a358SJonathan Adams #define GETPROC_USER 0x0 8635a5a358SJonathan Adams #define GETPROC_KERNEL 0x1 8735a5a358SJonathan Adams 887c478bd9Sstevel@tonic-gate static void fork_fail(proc_t *); 897c478bd9Sstevel@tonic-gate static void forklwp_fail(proc_t *); 907c478bd9Sstevel@tonic-gate 917c478bd9Sstevel@tonic-gate int fork_fail_pending; 927c478bd9Sstevel@tonic-gate 937c478bd9Sstevel@tonic-gate extern struct kmem_cache *process_cache; 947c478bd9Sstevel@tonic-gate 957c478bd9Sstevel@tonic-gate /* 968fd04b83SRoger A. Faulkner * The vfork() system call trap is no longer invoked by libc. 978fd04b83SRoger A. Faulkner * It is retained only for the benefit of applications running 988fd04b83SRoger A. Faulkner * within a solaris10 branded zone. It should be eliminated 998fd04b83SRoger A. Faulkner * when we no longer support solaris10 branded zones. 1007c478bd9Sstevel@tonic-gate */ 1017c478bd9Sstevel@tonic-gate int64_t 1027c478bd9Sstevel@tonic-gate vfork(void) 1037c478bd9Sstevel@tonic-gate { 1047c478bd9Sstevel@tonic-gate curthread->t_post_sys = 1; /* so vfwait() will be called */ 105657b1f3dSraf return (cfork(1, 1, 0)); 1067c478bd9Sstevel@tonic-gate } 1077c478bd9Sstevel@tonic-gate 1087c478bd9Sstevel@tonic-gate /* 1098fd04b83SRoger A. Faulkner * forksys system call - forkx, forkallx, vforkx. This is the 1108fd04b83SRoger A. Faulkner * interface invoked by libc for fork1(), forkall(), and vfork() 111657b1f3dSraf */ 112657b1f3dSraf int64_t 113657b1f3dSraf forksys(int subcode, int flags) 114657b1f3dSraf { 115657b1f3dSraf switch (subcode) { 116657b1f3dSraf case 0: 117657b1f3dSraf return (cfork(0, 1, flags)); /* forkx(flags) */ 118657b1f3dSraf case 1: 119657b1f3dSraf return (cfork(0, 0, flags)); /* forkallx(flags) */ 120657b1f3dSraf case 2: 121657b1f3dSraf curthread->t_post_sys = 1; /* so vfwait() will be called */ 122657b1f3dSraf return (cfork(1, 1, flags)); /* vforkx(flags) */ 123657b1f3dSraf default: 124657b1f3dSraf return ((int64_t)set_errno(EINVAL)); 125657b1f3dSraf } 1267c478bd9Sstevel@tonic-gate } 1277c478bd9Sstevel@tonic-gate 1287c478bd9Sstevel@tonic-gate /* ARGSUSED */ 1297c478bd9Sstevel@tonic-gate static int64_t 130657b1f3dSraf cfork(int isvfork, int isfork1, int flags) 1317c478bd9Sstevel@tonic-gate { 1327c478bd9Sstevel@tonic-gate proc_t *p = ttoproc(curthread); 1337c478bd9Sstevel@tonic-gate struct as *as; 1347c478bd9Sstevel@tonic-gate proc_t *cp, **orphpp; 1357c478bd9Sstevel@tonic-gate klwp_t *clone; 1367c478bd9Sstevel@tonic-gate kthread_t *t; 1377c478bd9Sstevel@tonic-gate task_t *tk; 1387c478bd9Sstevel@tonic-gate rval_t r; 1397c478bd9Sstevel@tonic-gate int error; 1407c478bd9Sstevel@tonic-gate int i; 1417c478bd9Sstevel@tonic-gate rctl_set_t *dup_set; 1427c478bd9Sstevel@tonic-gate rctl_alloc_gp_t *dup_gp; 1437c478bd9Sstevel@tonic-gate rctl_entity_p_t e; 1447c478bd9Sstevel@tonic-gate lwpdir_t *ldp; 1457c478bd9Sstevel@tonic-gate lwpent_t *lep; 1467c478bd9Sstevel@tonic-gate lwpent_t *clep; 1477c478bd9Sstevel@tonic-gate 1487c478bd9Sstevel@tonic-gate /* 149657b1f3dSraf * Allow only these two flags. 150657b1f3dSraf */ 151657b1f3dSraf if ((flags & ~(FORK_NOSIGCHLD | FORK_WAITPID)) != 0) { 152657b1f3dSraf error = EINVAL; 1532dc692e0SJerry Jelinek atomic_inc_32(&curproc->p_zone->zone_ffmisc); 154657b1f3dSraf goto forkerr; 155657b1f3dSraf } 156657b1f3dSraf 157657b1f3dSraf /* 1587c478bd9Sstevel@tonic-gate * fork is not supported for the /proc agent lwp. 1597c478bd9Sstevel@tonic-gate */ 1607c478bd9Sstevel@tonic-gate if (curthread == p->p_agenttp) { 1617c478bd9Sstevel@tonic-gate error = ENOTSUP; 1622dc692e0SJerry Jelinek atomic_inc_32(&curproc->p_zone->zone_ffmisc); 1637c478bd9Sstevel@tonic-gate goto forkerr; 1647c478bd9Sstevel@tonic-gate } 1657c478bd9Sstevel@tonic-gate 1662dc692e0SJerry Jelinek if ((error = secpolicy_basic_fork(CRED())) != 0) { 1672dc692e0SJerry Jelinek atomic_inc_32(&p->p_zone->zone_ffmisc); 1687c478bd9Sstevel@tonic-gate goto forkerr; 1692dc692e0SJerry Jelinek } 1707c478bd9Sstevel@tonic-gate 1717c478bd9Sstevel@tonic-gate /* 1727c478bd9Sstevel@tonic-gate * If the calling lwp is doing a fork1() then the 1737c478bd9Sstevel@tonic-gate * other lwps in this process are not duplicated and 1747c478bd9Sstevel@tonic-gate * don't need to be held where their kernel stacks can be 1757c478bd9Sstevel@tonic-gate * cloned. If doing forkall(), the process is held with 1767c478bd9Sstevel@tonic-gate * SHOLDFORK, so that the lwps are at a point where their 1777c478bd9Sstevel@tonic-gate * stacks can be copied which is on entry or exit from 1787c478bd9Sstevel@tonic-gate * the kernel. 1797c478bd9Sstevel@tonic-gate */ 1807c478bd9Sstevel@tonic-gate if (!holdlwps(isfork1 ? SHOLDFORK1 : SHOLDFORK)) { 1817c478bd9Sstevel@tonic-gate aston(curthread); 1827c478bd9Sstevel@tonic-gate error = EINTR; 1832dc692e0SJerry Jelinek atomic_inc_32(&p->p_zone->zone_ffmisc); 1847c478bd9Sstevel@tonic-gate goto forkerr; 1857c478bd9Sstevel@tonic-gate } 1867c478bd9Sstevel@tonic-gate 1877c478bd9Sstevel@tonic-gate #if defined(__sparc) 1887c478bd9Sstevel@tonic-gate /* 1897c478bd9Sstevel@tonic-gate * Ensure that the user stack is fully constructed 1907c478bd9Sstevel@tonic-gate * before creating the child process structure. 1917c478bd9Sstevel@tonic-gate */ 1927c478bd9Sstevel@tonic-gate (void) flush_user_windows_to_stack(NULL); 1937c478bd9Sstevel@tonic-gate #endif 1947c478bd9Sstevel@tonic-gate 195f787e422Sraf mutex_enter(&p->p_lock); 196f787e422Sraf /* 197f787e422Sraf * If this is vfork(), cancel any suspend request we might 198f787e422Sraf * have gotten from some other thread via lwp_suspend(). 199f787e422Sraf * Otherwise we could end up with a deadlock on return 200f787e422Sraf * from the vfork() in both the parent and the child. 201f787e422Sraf */ 202f787e422Sraf if (isvfork) 203f787e422Sraf curthread->t_proc_flag &= ~TP_HOLDLWP; 2047c478bd9Sstevel@tonic-gate /* 2057c478bd9Sstevel@tonic-gate * Prevent our resource set associations from being changed during fork. 2067c478bd9Sstevel@tonic-gate */ 2077c478bd9Sstevel@tonic-gate pool_barrier_enter(); 2087c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock); 2097c478bd9Sstevel@tonic-gate 2107c478bd9Sstevel@tonic-gate /* 2117c478bd9Sstevel@tonic-gate * Create a child proc struct. Place a VN_HOLD on appropriate vnodes. 2127c478bd9Sstevel@tonic-gate */ 21335a5a358SJonathan Adams if (getproc(&cp, 0, GETPROC_USER) < 0) { 2147c478bd9Sstevel@tonic-gate mutex_enter(&p->p_lock); 2157c478bd9Sstevel@tonic-gate pool_barrier_exit(); 2167c478bd9Sstevel@tonic-gate continuelwps(p); 2177c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock); 2187c478bd9Sstevel@tonic-gate error = EAGAIN; 2197c478bd9Sstevel@tonic-gate goto forkerr; 2207c478bd9Sstevel@tonic-gate } 2217c478bd9Sstevel@tonic-gate 2227c478bd9Sstevel@tonic-gate TRACE_2(TR_FAC_PROC, TR_PROC_FORK, "proc_fork:cp %p p %p", cp, p); 2237c478bd9Sstevel@tonic-gate 2247c478bd9Sstevel@tonic-gate /* 2257c478bd9Sstevel@tonic-gate * Assign an address space to child 2267c478bd9Sstevel@tonic-gate */ 2277c478bd9Sstevel@tonic-gate if (isvfork) { 2287c478bd9Sstevel@tonic-gate /* 2297c478bd9Sstevel@tonic-gate * Clear any watched areas and remember the 2307c478bd9Sstevel@tonic-gate * watched pages for restoring in vfwait(). 2317c478bd9Sstevel@tonic-gate */ 2327c478bd9Sstevel@tonic-gate as = p->p_as; 2337c478bd9Sstevel@tonic-gate if (avl_numnodes(&as->a_wpage) != 0) { 234*dc32d872SJosef 'Jeff' Sipek AS_LOCK_ENTER(as, RW_WRITER); 2357c478bd9Sstevel@tonic-gate as_clearwatch(as); 2367c478bd9Sstevel@tonic-gate p->p_wpage = as->a_wpage; 2377c478bd9Sstevel@tonic-gate avl_create(&as->a_wpage, wp_compare, 2387c478bd9Sstevel@tonic-gate sizeof (struct watched_page), 2397c478bd9Sstevel@tonic-gate offsetof(struct watched_page, wp_link)); 240*dc32d872SJosef 'Jeff' Sipek AS_LOCK_EXIT(as); 2417c478bd9Sstevel@tonic-gate } 2427c478bd9Sstevel@tonic-gate cp->p_as = as; 2437c478bd9Sstevel@tonic-gate cp->p_flag |= SVFORK; 244bb637ba7SVamsi Nagineni 245bb637ba7SVamsi Nagineni /* 246bb637ba7SVamsi Nagineni * Use the parent's shm segment list information for 247bb637ba7SVamsi Nagineni * the child as it uses its address space till it execs. 248bb637ba7SVamsi Nagineni */ 249bb637ba7SVamsi Nagineni cp->p_segacct = p->p_segacct; 2507c478bd9Sstevel@tonic-gate } else { 2517c478bd9Sstevel@tonic-gate /* 2527c478bd9Sstevel@tonic-gate * We need to hold P_PR_LOCK until the address space has 2537c478bd9Sstevel@tonic-gate * been duplicated and we've had a chance to remove from the 2547c478bd9Sstevel@tonic-gate * child any DTrace probes that were in the parent. Holding 2557c478bd9Sstevel@tonic-gate * P_PR_LOCK prevents any new probes from being added and any 2567c478bd9Sstevel@tonic-gate * extant probes from being removed. 2577c478bd9Sstevel@tonic-gate */ 2587c478bd9Sstevel@tonic-gate mutex_enter(&p->p_lock); 2597c478bd9Sstevel@tonic-gate sprlock_proc(p); 260ab9a77c7Sahl p->p_flag |= SFORKING; 2617c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock); 2627c478bd9Sstevel@tonic-gate 263bb5ca623SVamsi Nagineni error = as_dup(p->p_as, cp); 2647c478bd9Sstevel@tonic-gate if (error != 0) { 265aa47d340Sethindra mutex_enter(&p->p_lock); 266aa47d340Sethindra sprunlock(p); 2677c478bd9Sstevel@tonic-gate fork_fail(cp); 2687c478bd9Sstevel@tonic-gate mutex_enter(&pidlock); 2697c478bd9Sstevel@tonic-gate orphpp = &p->p_orphan; 2707c478bd9Sstevel@tonic-gate while (*orphpp != cp) 2717c478bd9Sstevel@tonic-gate orphpp = &(*orphpp)->p_nextorph; 2727c478bd9Sstevel@tonic-gate *orphpp = cp->p_nextorph; 2731e2e7a75Shuah if (p->p_child == cp) 2747c478bd9Sstevel@tonic-gate p->p_child = cp->p_sibling; 2751e2e7a75Shuah if (cp->p_sibling) 2761e2e7a75Shuah cp->p_sibling->p_psibling = cp->p_psibling; 2771e2e7a75Shuah if (cp->p_psibling) 2781e2e7a75Shuah cp->p_psibling->p_sibling = cp->p_sibling; 2797c478bd9Sstevel@tonic-gate mutex_enter(&cp->p_lock); 2807c478bd9Sstevel@tonic-gate tk = cp->p_task; 2817c478bd9Sstevel@tonic-gate task_detach(cp); 2827c478bd9Sstevel@tonic-gate ASSERT(cp->p_pool->pool_ref > 0); 2831a5e258fSJosef 'Jeff' Sipek atomic_dec_32(&cp->p_pool->pool_ref); 2847c478bd9Sstevel@tonic-gate mutex_exit(&cp->p_lock); 2854bcbe6e7SMenno Lageman pid_exit(cp, tk); 2867c478bd9Sstevel@tonic-gate mutex_exit(&pidlock); 2877c478bd9Sstevel@tonic-gate task_rele(tk); 2887c478bd9Sstevel@tonic-gate 2897c478bd9Sstevel@tonic-gate mutex_enter(&p->p_lock); 290ab9a77c7Sahl p->p_flag &= ~SFORKING; 2917c478bd9Sstevel@tonic-gate pool_barrier_exit(); 2927c478bd9Sstevel@tonic-gate continuelwps(p); 293aa47d340Sethindra mutex_exit(&p->p_lock); 2947c478bd9Sstevel@tonic-gate /* 2957c478bd9Sstevel@tonic-gate * Preserve ENOMEM error condition but 2967c478bd9Sstevel@tonic-gate * map all others to EAGAIN. 2977c478bd9Sstevel@tonic-gate */ 2987c478bd9Sstevel@tonic-gate error = (error == ENOMEM) ? ENOMEM : EAGAIN; 2992dc692e0SJerry Jelinek atomic_inc_32(&p->p_zone->zone_ffnomem); 3007c478bd9Sstevel@tonic-gate goto forkerr; 3017c478bd9Sstevel@tonic-gate } 302c6939658Ssl108498 303ab9a77c7Sahl /* 304ab9a77c7Sahl * Remove all DTrace tracepoints from the child process. We 305ab9a77c7Sahl * need to do this _before_ duplicating USDT providers since 306ab9a77c7Sahl * any associated probes may be immediately enabled. 307ab9a77c7Sahl */ 308ab9a77c7Sahl if (p->p_dtrace_count > 0) 309ab9a77c7Sahl dtrace_fasttrap_fork(p, cp); 310ab9a77c7Sahl 3113cd189deSEthindra Ramamurthy mutex_enter(&p->p_lock); 3123cd189deSEthindra Ramamurthy sprunlock(p); 3133cd189deSEthindra Ramamurthy 3143cd189deSEthindra Ramamurthy /* Duplicate parent's shared memory */ 3153cd189deSEthindra Ramamurthy if (p->p_segacct) 3163cd189deSEthindra Ramamurthy shmfork(p, cp); 3173cd189deSEthindra Ramamurthy 318ab9a77c7Sahl /* 319ab9a77c7Sahl * Duplicate any helper actions and providers. The SFORKING 320ab9a77c7Sahl * we set above informs the code to enable USDT probes that 321ab9a77c7Sahl * sprlock() may fail because the child is being forked. 322ab9a77c7Sahl */ 3237c478bd9Sstevel@tonic-gate if (p->p_dtrace_helpers != NULL) { 3247c478bd9Sstevel@tonic-gate ASSERT(dtrace_helpers_fork != NULL); 3257c478bd9Sstevel@tonic-gate (*dtrace_helpers_fork)(p, cp); 3263cd189deSEthindra Ramamurthy } 3277c478bd9Sstevel@tonic-gate 3287c478bd9Sstevel@tonic-gate mutex_enter(&p->p_lock); 329ab9a77c7Sahl p->p_flag &= ~SFORKING; 330dcafa303Sahl mutex_exit(&p->p_lock); 331dcafa303Sahl } 3327c478bd9Sstevel@tonic-gate 3337c478bd9Sstevel@tonic-gate /* 3347c478bd9Sstevel@tonic-gate * Duplicate parent's resource controls. 3357c478bd9Sstevel@tonic-gate */ 3367c478bd9Sstevel@tonic-gate dup_set = rctl_set_create(); 3377c478bd9Sstevel@tonic-gate for (;;) { 3387c478bd9Sstevel@tonic-gate dup_gp = rctl_set_dup_prealloc(p->p_rctls); 3397c478bd9Sstevel@tonic-gate mutex_enter(&p->p_rctls->rcs_lock); 3407c478bd9Sstevel@tonic-gate if (rctl_set_dup_ready(p->p_rctls, dup_gp)) 3417c478bd9Sstevel@tonic-gate break; 3427c478bd9Sstevel@tonic-gate mutex_exit(&p->p_rctls->rcs_lock); 3437c478bd9Sstevel@tonic-gate rctl_prealloc_destroy(dup_gp); 3447c478bd9Sstevel@tonic-gate } 3457c478bd9Sstevel@tonic-gate e.rcep_p.proc = cp; 3467c478bd9Sstevel@tonic-gate e.rcep_t = RCENTITY_PROCESS; 3477c478bd9Sstevel@tonic-gate cp->p_rctls = rctl_set_dup(p->p_rctls, p, cp, &e, dup_set, dup_gp, 3487c478bd9Sstevel@tonic-gate RCD_DUP | RCD_CALLBACK); 3497c478bd9Sstevel@tonic-gate mutex_exit(&p->p_rctls->rcs_lock); 3507c478bd9Sstevel@tonic-gate 3517c478bd9Sstevel@tonic-gate rctl_prealloc_destroy(dup_gp); 3527c478bd9Sstevel@tonic-gate 3537c478bd9Sstevel@tonic-gate /* 3547c478bd9Sstevel@tonic-gate * Allocate the child's lwp directory and lwpid hash table. 3557c478bd9Sstevel@tonic-gate */ 3567c478bd9Sstevel@tonic-gate if (isfork1) 3577c478bd9Sstevel@tonic-gate cp->p_lwpdir_sz = 2; 3587c478bd9Sstevel@tonic-gate else 3597c478bd9Sstevel@tonic-gate cp->p_lwpdir_sz = p->p_lwpdir_sz; 3607c478bd9Sstevel@tonic-gate cp->p_lwpdir = cp->p_lwpfree = ldp = 3617c478bd9Sstevel@tonic-gate kmem_zalloc(cp->p_lwpdir_sz * sizeof (lwpdir_t), KM_SLEEP); 3627c478bd9Sstevel@tonic-gate for (i = 1; i < cp->p_lwpdir_sz; i++, ldp++) 3637c478bd9Sstevel@tonic-gate ldp->ld_next = ldp + 1; 3647c478bd9Sstevel@tonic-gate cp->p_tidhash_sz = (cp->p_lwpdir_sz + 2) / 2; 3657c478bd9Sstevel@tonic-gate cp->p_tidhash = 3666eb30ec3SRoger A. Faulkner kmem_zalloc(cp->p_tidhash_sz * sizeof (tidhash_t), KM_SLEEP); 3677c478bd9Sstevel@tonic-gate 3687c478bd9Sstevel@tonic-gate /* 3697c478bd9Sstevel@tonic-gate * Duplicate parent's lwps. 3707c478bd9Sstevel@tonic-gate * Mutual exclusion is not needed because the process is 3717c478bd9Sstevel@tonic-gate * in the hold state and only the current lwp is running. 3727c478bd9Sstevel@tonic-gate */ 3737c478bd9Sstevel@tonic-gate klgrpset_clear(cp->p_lgrpset); 3747c478bd9Sstevel@tonic-gate if (isfork1) { 3757c478bd9Sstevel@tonic-gate clone = forklwp(ttolwp(curthread), cp, curthread->t_tid); 3767c478bd9Sstevel@tonic-gate if (clone == NULL) 3777c478bd9Sstevel@tonic-gate goto forklwperr; 3787c478bd9Sstevel@tonic-gate /* 3797c478bd9Sstevel@tonic-gate * Inherit only the lwp_wait()able flag, 3807c478bd9Sstevel@tonic-gate * Daemon threads should not call fork1(), but oh well... 3817c478bd9Sstevel@tonic-gate */ 3827c478bd9Sstevel@tonic-gate lwptot(clone)->t_proc_flag |= 3837c478bd9Sstevel@tonic-gate (curthread->t_proc_flag & TP_TWAIT); 3847c478bd9Sstevel@tonic-gate } else { 3857c478bd9Sstevel@tonic-gate /* this is forkall(), no one can be in lwp_wait() */ 3867c478bd9Sstevel@tonic-gate ASSERT(p->p_lwpwait == 0 && p->p_lwpdwait == 0); 3877c478bd9Sstevel@tonic-gate /* for each entry in the parent's lwp directory... */ 3887c478bd9Sstevel@tonic-gate for (i = 0, ldp = p->p_lwpdir; i < p->p_lwpdir_sz; i++, ldp++) { 3897c478bd9Sstevel@tonic-gate klwp_t *clwp; 390c4978b50Sraf kthread_t *ct; 3917c478bd9Sstevel@tonic-gate 3927c478bd9Sstevel@tonic-gate if ((lep = ldp->ld_entry) == NULL) 3937c478bd9Sstevel@tonic-gate continue; 3947c478bd9Sstevel@tonic-gate 3957c478bd9Sstevel@tonic-gate if ((t = lep->le_thread) != NULL) { 3967c478bd9Sstevel@tonic-gate clwp = forklwp(ttolwp(t), cp, t->t_tid); 3977c478bd9Sstevel@tonic-gate if (clwp == NULL) 3987c478bd9Sstevel@tonic-gate goto forklwperr; 399c4978b50Sraf ct = lwptot(clwp); 4007c478bd9Sstevel@tonic-gate /* 4017c478bd9Sstevel@tonic-gate * Inherit lwp_wait()able and daemon flags. 4027c478bd9Sstevel@tonic-gate */ 403c4978b50Sraf ct->t_proc_flag |= 4047c478bd9Sstevel@tonic-gate (t->t_proc_flag & (TP_TWAIT|TP_DAEMON)); 4057c478bd9Sstevel@tonic-gate /* 4067c478bd9Sstevel@tonic-gate * Keep track of the clone of curthread to 4077c478bd9Sstevel@tonic-gate * post return values through lwp_setrval(). 408c4978b50Sraf * Mark other threads for special treatment 409c4978b50Sraf * by lwp_rtt() / post_syscall(). 4107c478bd9Sstevel@tonic-gate */ 4117c478bd9Sstevel@tonic-gate if (t == curthread) 4127c478bd9Sstevel@tonic-gate clone = clwp; 413c4978b50Sraf else 414c4978b50Sraf ct->t_flag |= T_FORKALL; 4157c478bd9Sstevel@tonic-gate } else { 4167c478bd9Sstevel@tonic-gate /* 4177c478bd9Sstevel@tonic-gate * Replicate zombie lwps in the child. 4187c478bd9Sstevel@tonic-gate */ 4197c478bd9Sstevel@tonic-gate clep = kmem_zalloc(sizeof (*clep), KM_SLEEP); 4207c478bd9Sstevel@tonic-gate clep->le_lwpid = lep->le_lwpid; 4217c478bd9Sstevel@tonic-gate clep->le_start = lep->le_start; 4226eb30ec3SRoger A. Faulkner lwp_hash_in(cp, clep, 4236eb30ec3SRoger A. Faulkner cp->p_tidhash, cp->p_tidhash_sz, 0); 4247c478bd9Sstevel@tonic-gate } 4257c478bd9Sstevel@tonic-gate } 4267c478bd9Sstevel@tonic-gate } 4277c478bd9Sstevel@tonic-gate 4287c478bd9Sstevel@tonic-gate /* 4297c478bd9Sstevel@tonic-gate * Put new process in the parent's process contract, or put it 4307c478bd9Sstevel@tonic-gate * in a new one if there is an active process template. Send a 4317c478bd9Sstevel@tonic-gate * fork event (if requested) to whatever contract the child is 4327c478bd9Sstevel@tonic-gate * a member of. Fails if the parent has been SIGKILLed. 4337c478bd9Sstevel@tonic-gate */ 4342dc692e0SJerry Jelinek if (contract_process_fork(NULL, cp, p, B_TRUE) == NULL) { 4352dc692e0SJerry Jelinek atomic_inc_32(&p->p_zone->zone_ffmisc); 4367c478bd9Sstevel@tonic-gate goto forklwperr; 4372dc692e0SJerry Jelinek } 4387c478bd9Sstevel@tonic-gate 4397c478bd9Sstevel@tonic-gate /* 4407c478bd9Sstevel@tonic-gate * No fork failures occur beyond this point. 4417c478bd9Sstevel@tonic-gate */ 4427c478bd9Sstevel@tonic-gate 4437c478bd9Sstevel@tonic-gate cp->p_lwpid = p->p_lwpid; 4447c478bd9Sstevel@tonic-gate if (!isfork1) { 4457c478bd9Sstevel@tonic-gate cp->p_lwpdaemon = p->p_lwpdaemon; 4467c478bd9Sstevel@tonic-gate cp->p_zombcnt = p->p_zombcnt; 4477c478bd9Sstevel@tonic-gate /* 4487c478bd9Sstevel@tonic-gate * If the parent's lwp ids have wrapped around, so have the 4497c478bd9Sstevel@tonic-gate * child's. 4507c478bd9Sstevel@tonic-gate */ 4517c478bd9Sstevel@tonic-gate cp->p_flag |= p->p_flag & SLWPWRAP; 4527c478bd9Sstevel@tonic-gate } 4537c478bd9Sstevel@tonic-gate 45480283c8fSkk112340 mutex_enter(&p->p_lock); 4557c478bd9Sstevel@tonic-gate corectl_path_hold(cp->p_corefile = p->p_corefile); 4567c478bd9Sstevel@tonic-gate corectl_content_hold(cp->p_content = p->p_content); 45780283c8fSkk112340 mutex_exit(&p->p_lock); 4587c478bd9Sstevel@tonic-gate 4597c478bd9Sstevel@tonic-gate /* 4600baeff3dSrab * Duplicate process context ops, if any. 4617c478bd9Sstevel@tonic-gate */ 4620baeff3dSrab if (p->p_pctx) 4630baeff3dSrab forkpctx(p, cp); 4647c478bd9Sstevel@tonic-gate 4657c478bd9Sstevel@tonic-gate #ifdef __sparc 4667c478bd9Sstevel@tonic-gate utrap_dup(p, cp); 4677c478bd9Sstevel@tonic-gate #endif 4687c478bd9Sstevel@tonic-gate /* 4697c478bd9Sstevel@tonic-gate * If the child process has been marked to stop on exit 4707c478bd9Sstevel@tonic-gate * from this fork, arrange for all other lwps to stop in 4717c478bd9Sstevel@tonic-gate * sympathy with the active lwp. 4727c478bd9Sstevel@tonic-gate */ 4737c478bd9Sstevel@tonic-gate if (PTOU(cp)->u_systrap && 4747c478bd9Sstevel@tonic-gate prismember(&PTOU(cp)->u_exitmask, curthread->t_sysnum)) { 4757c478bd9Sstevel@tonic-gate mutex_enter(&cp->p_lock); 4767c478bd9Sstevel@tonic-gate t = cp->p_tlist; 4777c478bd9Sstevel@tonic-gate do { 4787c478bd9Sstevel@tonic-gate t->t_proc_flag |= TP_PRSTOP; 4797c478bd9Sstevel@tonic-gate aston(t); /* so TP_PRSTOP will be seen */ 4807c478bd9Sstevel@tonic-gate } while ((t = t->t_forw) != cp->p_tlist); 4817c478bd9Sstevel@tonic-gate mutex_exit(&cp->p_lock); 4827c478bd9Sstevel@tonic-gate } 4837c478bd9Sstevel@tonic-gate /* 4847c478bd9Sstevel@tonic-gate * If the parent process has been marked to stop on exit 4857c478bd9Sstevel@tonic-gate * from this fork, and its asynchronous-stop flag has not 4867c478bd9Sstevel@tonic-gate * been set, arrange for all other lwps to stop before 4877c478bd9Sstevel@tonic-gate * they return back to user level. 4887c478bd9Sstevel@tonic-gate */ 4897c478bd9Sstevel@tonic-gate if (!(p->p_proc_flag & P_PR_ASYNC) && PTOU(p)->u_systrap && 4907c478bd9Sstevel@tonic-gate prismember(&PTOU(p)->u_exitmask, curthread->t_sysnum)) { 4917c478bd9Sstevel@tonic-gate mutex_enter(&p->p_lock); 4927c478bd9Sstevel@tonic-gate t = p->p_tlist; 4937c478bd9Sstevel@tonic-gate do { 4947c478bd9Sstevel@tonic-gate t->t_proc_flag |= TP_PRSTOP; 4957c478bd9Sstevel@tonic-gate aston(t); /* so TP_PRSTOP will be seen */ 4967c478bd9Sstevel@tonic-gate } while ((t = t->t_forw) != p->p_tlist); 4977c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock); 4987c478bd9Sstevel@tonic-gate } 4997c478bd9Sstevel@tonic-gate 5009acbbeafSnn35248 if (PROC_IS_BRANDED(p)) 5019acbbeafSnn35248 BROP(p)->b_lwp_setrval(clone, p->p_pid, 1); 5029acbbeafSnn35248 else 5037c478bd9Sstevel@tonic-gate lwp_setrval(clone, p->p_pid, 1); 5047c478bd9Sstevel@tonic-gate 5057c478bd9Sstevel@tonic-gate /* set return values for parent */ 5067c478bd9Sstevel@tonic-gate r.r_val1 = (int)cp->p_pid; 5077c478bd9Sstevel@tonic-gate r.r_val2 = 0; 5087c478bd9Sstevel@tonic-gate 5097c478bd9Sstevel@tonic-gate /* 5107c478bd9Sstevel@tonic-gate * pool_barrier_exit() can now be called because the child process has: 5117c478bd9Sstevel@tonic-gate * - all identifying features cloned or set (p_pid, p_task, p_pool) 5127c478bd9Sstevel@tonic-gate * - all resource sets associated (p_tlist->*->t_cpupart, p_as->a_mset) 5137c478bd9Sstevel@tonic-gate * - any other fields set which are used in resource set binding. 5147c478bd9Sstevel@tonic-gate */ 5157c478bd9Sstevel@tonic-gate mutex_enter(&p->p_lock); 5167c478bd9Sstevel@tonic-gate pool_barrier_exit(); 5177c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock); 5187c478bd9Sstevel@tonic-gate 5197c478bd9Sstevel@tonic-gate mutex_enter(&pidlock); 5207c478bd9Sstevel@tonic-gate mutex_enter(&cp->p_lock); 5217c478bd9Sstevel@tonic-gate 5227c478bd9Sstevel@tonic-gate /* 523657b1f3dSraf * Set flags telling the child what (not) to do on exit. 524657b1f3dSraf */ 525657b1f3dSraf if (flags & FORK_NOSIGCHLD) 526657b1f3dSraf cp->p_pidflag |= CLDNOSIGCHLD; 527657b1f3dSraf if (flags & FORK_WAITPID) 528657b1f3dSraf cp->p_pidflag |= CLDWAITPID; 529657b1f3dSraf 530657b1f3dSraf /* 5317c478bd9Sstevel@tonic-gate * Now that there are lwps and threads attached, add the new 5327c478bd9Sstevel@tonic-gate * process to the process group. 5337c478bd9Sstevel@tonic-gate */ 5347c478bd9Sstevel@tonic-gate pgjoin(cp, p->p_pgidp); 5357c478bd9Sstevel@tonic-gate cp->p_stat = SRUN; 5367c478bd9Sstevel@tonic-gate /* 5377c478bd9Sstevel@tonic-gate * We are now done with all the lwps in the child process. 5387c478bd9Sstevel@tonic-gate */ 5397c478bd9Sstevel@tonic-gate t = cp->p_tlist; 5407c478bd9Sstevel@tonic-gate do { 5417c478bd9Sstevel@tonic-gate /* 5427c478bd9Sstevel@tonic-gate * Set the lwp_suspend()ed lwps running. 5437c478bd9Sstevel@tonic-gate * They will suspend properly at syscall exit. 5447c478bd9Sstevel@tonic-gate */ 5457c478bd9Sstevel@tonic-gate if (t->t_proc_flag & TP_HOLDLWP) 5467c478bd9Sstevel@tonic-gate lwp_create_done(t); 5477c478bd9Sstevel@tonic-gate else { 5487c478bd9Sstevel@tonic-gate /* set TS_CREATE to allow continuelwps() to work */ 5497c478bd9Sstevel@tonic-gate thread_lock(t); 5507c478bd9Sstevel@tonic-gate ASSERT(t->t_state == TS_STOPPED && 5517c478bd9Sstevel@tonic-gate !(t->t_schedflag & (TS_CREATE|TS_CSTART))); 5527c478bd9Sstevel@tonic-gate t->t_schedflag |= TS_CREATE; 5537c478bd9Sstevel@tonic-gate thread_unlock(t); 5547c478bd9Sstevel@tonic-gate } 5557c478bd9Sstevel@tonic-gate } while ((t = t->t_forw) != cp->p_tlist); 5567c478bd9Sstevel@tonic-gate mutex_exit(&cp->p_lock); 5577c478bd9Sstevel@tonic-gate 5587c478bd9Sstevel@tonic-gate if (isvfork) { 5597c478bd9Sstevel@tonic-gate CPU_STATS_ADDQ(CPU, sys, sysvfork, 1); 5607c478bd9Sstevel@tonic-gate mutex_enter(&p->p_lock); 5618d186f16Sraf p->p_flag |= SVFWAIT; 5628d186f16Sraf curthread->t_flag |= T_VFPARENT; 5637c478bd9Sstevel@tonic-gate DTRACE_PROC1(create, proc_t *, cp); 5647c478bd9Sstevel@tonic-gate cv_broadcast(&pr_pid_cv[p->p_slot]); /* inform /proc */ 5657c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock); 5667c478bd9Sstevel@tonic-gate /* 5677c478bd9Sstevel@tonic-gate * Grab child's p_lock before dropping pidlock to ensure 5687c478bd9Sstevel@tonic-gate * the process will not disappear before we set it running. 5697c478bd9Sstevel@tonic-gate */ 5707c478bd9Sstevel@tonic-gate mutex_enter(&cp->p_lock); 5717c478bd9Sstevel@tonic-gate mutex_exit(&pidlock); 5727c478bd9Sstevel@tonic-gate sigdefault(cp); 5737c478bd9Sstevel@tonic-gate continuelwps(cp); 5747c478bd9Sstevel@tonic-gate mutex_exit(&cp->p_lock); 5757c478bd9Sstevel@tonic-gate } else { 5767c478bd9Sstevel@tonic-gate CPU_STATS_ADDQ(CPU, sys, sysfork, 1); 5777c478bd9Sstevel@tonic-gate DTRACE_PROC1(create, proc_t *, cp); 5787c478bd9Sstevel@tonic-gate /* 5797c478bd9Sstevel@tonic-gate * It is CL_FORKRET's job to drop pidlock. 5807c478bd9Sstevel@tonic-gate * If we do it here, the process could be set running 5817c478bd9Sstevel@tonic-gate * and disappear before CL_FORKRET() is called. 5827c478bd9Sstevel@tonic-gate */ 5837c478bd9Sstevel@tonic-gate CL_FORKRET(curthread, cp->p_tlist); 584d4204c85Sraf schedctl_set_cidpri(curthread); 5857c478bd9Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(&pidlock)); 5867c478bd9Sstevel@tonic-gate } 5877c478bd9Sstevel@tonic-gate 5887c478bd9Sstevel@tonic-gate return (r.r_vals); 5897c478bd9Sstevel@tonic-gate 5907c478bd9Sstevel@tonic-gate forklwperr: 5917c478bd9Sstevel@tonic-gate if (isvfork) { 5927c478bd9Sstevel@tonic-gate if (avl_numnodes(&p->p_wpage) != 0) { 5937c478bd9Sstevel@tonic-gate /* restore watchpoints to parent */ 5947c478bd9Sstevel@tonic-gate as = p->p_as; 595*dc32d872SJosef 'Jeff' Sipek AS_LOCK_ENTER(as, RW_WRITER); 5967c478bd9Sstevel@tonic-gate as->a_wpage = p->p_wpage; 5977c478bd9Sstevel@tonic-gate avl_create(&p->p_wpage, wp_compare, 5987c478bd9Sstevel@tonic-gate sizeof (struct watched_page), 5997c478bd9Sstevel@tonic-gate offsetof(struct watched_page, wp_link)); 6007c478bd9Sstevel@tonic-gate as_setwatch(as); 601*dc32d872SJosef 'Jeff' Sipek AS_LOCK_EXIT(as); 6027c478bd9Sstevel@tonic-gate } 6037c478bd9Sstevel@tonic-gate } else { 6047c478bd9Sstevel@tonic-gate if (cp->p_segacct) 6057c478bd9Sstevel@tonic-gate shmexit(cp); 6067c478bd9Sstevel@tonic-gate as = cp->p_as; 6077c478bd9Sstevel@tonic-gate cp->p_as = &kas; 6087c478bd9Sstevel@tonic-gate as_free(as); 6097c478bd9Sstevel@tonic-gate } 6107c478bd9Sstevel@tonic-gate 6117c478bd9Sstevel@tonic-gate if (cp->p_lwpdir) { 6127c478bd9Sstevel@tonic-gate for (i = 0, ldp = cp->p_lwpdir; i < cp->p_lwpdir_sz; i++, ldp++) 6137c478bd9Sstevel@tonic-gate if ((lep = ldp->ld_entry) != NULL) 6147c478bd9Sstevel@tonic-gate kmem_free(lep, sizeof (*lep)); 6157c478bd9Sstevel@tonic-gate kmem_free(cp->p_lwpdir, 6167c478bd9Sstevel@tonic-gate cp->p_lwpdir_sz * sizeof (*cp->p_lwpdir)); 6177c478bd9Sstevel@tonic-gate } 6187c478bd9Sstevel@tonic-gate cp->p_lwpdir = NULL; 6197c478bd9Sstevel@tonic-gate cp->p_lwpfree = NULL; 6207c478bd9Sstevel@tonic-gate cp->p_lwpdir_sz = 0; 6217c478bd9Sstevel@tonic-gate 6227c478bd9Sstevel@tonic-gate if (cp->p_tidhash) 6237c478bd9Sstevel@tonic-gate kmem_free(cp->p_tidhash, 6247c478bd9Sstevel@tonic-gate cp->p_tidhash_sz * sizeof (*cp->p_tidhash)); 6257c478bd9Sstevel@tonic-gate cp->p_tidhash = NULL; 6267c478bd9Sstevel@tonic-gate cp->p_tidhash_sz = 0; 6277c478bd9Sstevel@tonic-gate 6287c478bd9Sstevel@tonic-gate forklwp_fail(cp); 6297c478bd9Sstevel@tonic-gate fork_fail(cp); 6307c478bd9Sstevel@tonic-gate rctl_set_free(cp->p_rctls); 6317c478bd9Sstevel@tonic-gate mutex_enter(&pidlock); 6327c478bd9Sstevel@tonic-gate 6337c478bd9Sstevel@tonic-gate /* 6347c478bd9Sstevel@tonic-gate * Detach failed child from task. 6357c478bd9Sstevel@tonic-gate */ 6367c478bd9Sstevel@tonic-gate mutex_enter(&cp->p_lock); 6377c478bd9Sstevel@tonic-gate tk = cp->p_task; 6387c478bd9Sstevel@tonic-gate task_detach(cp); 6397c478bd9Sstevel@tonic-gate ASSERT(cp->p_pool->pool_ref > 0); 6401a5e258fSJosef 'Jeff' Sipek atomic_dec_32(&cp->p_pool->pool_ref); 6417c478bd9Sstevel@tonic-gate mutex_exit(&cp->p_lock); 6427c478bd9Sstevel@tonic-gate 6437c478bd9Sstevel@tonic-gate orphpp = &p->p_orphan; 6447c478bd9Sstevel@tonic-gate while (*orphpp != cp) 6457c478bd9Sstevel@tonic-gate orphpp = &(*orphpp)->p_nextorph; 6467c478bd9Sstevel@tonic-gate *orphpp = cp->p_nextorph; 6471e2e7a75Shuah if (p->p_child == cp) 6487c478bd9Sstevel@tonic-gate p->p_child = cp->p_sibling; 6491e2e7a75Shuah if (cp->p_sibling) 6501e2e7a75Shuah cp->p_sibling->p_psibling = cp->p_psibling; 6511e2e7a75Shuah if (cp->p_psibling) 6521e2e7a75Shuah cp->p_psibling->p_sibling = cp->p_sibling; 6534bcbe6e7SMenno Lageman pid_exit(cp, tk); 6547c478bd9Sstevel@tonic-gate mutex_exit(&pidlock); 6557c478bd9Sstevel@tonic-gate 6567c478bd9Sstevel@tonic-gate task_rele(tk); 6577c478bd9Sstevel@tonic-gate 6587c478bd9Sstevel@tonic-gate mutex_enter(&p->p_lock); 6597c478bd9Sstevel@tonic-gate pool_barrier_exit(); 6607c478bd9Sstevel@tonic-gate continuelwps(p); 6617c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock); 6627c478bd9Sstevel@tonic-gate error = EAGAIN; 6637c478bd9Sstevel@tonic-gate forkerr: 6647c478bd9Sstevel@tonic-gate return ((int64_t)set_errno(error)); 6657c478bd9Sstevel@tonic-gate } 6667c478bd9Sstevel@tonic-gate 6677c478bd9Sstevel@tonic-gate /* 6687c478bd9Sstevel@tonic-gate * Free allocated resources from getproc() if a fork failed. 6697c478bd9Sstevel@tonic-gate */ 6707c478bd9Sstevel@tonic-gate static void 6717c478bd9Sstevel@tonic-gate fork_fail(proc_t *cp) 6727c478bd9Sstevel@tonic-gate { 6737c478bd9Sstevel@tonic-gate uf_info_t *fip = P_FINFO(cp); 6747c478bd9Sstevel@tonic-gate 6757c478bd9Sstevel@tonic-gate fcnt_add(fip, -1); 6767c478bd9Sstevel@tonic-gate sigdelq(cp, NULL, 0); 6777c478bd9Sstevel@tonic-gate 6787c478bd9Sstevel@tonic-gate mutex_enter(&pidlock); 6797c478bd9Sstevel@tonic-gate upcount_dec(crgetruid(cp->p_cred), crgetzoneid(cp->p_cred)); 6807c478bd9Sstevel@tonic-gate mutex_exit(&pidlock); 6817c478bd9Sstevel@tonic-gate 6827c478bd9Sstevel@tonic-gate /* 6837c478bd9Sstevel@tonic-gate * single threaded, so no locking needed here 6847c478bd9Sstevel@tonic-gate */ 6857c478bd9Sstevel@tonic-gate crfree(cp->p_cred); 6867c478bd9Sstevel@tonic-gate 6877c478bd9Sstevel@tonic-gate kmem_free(fip->fi_list, fip->fi_nfiles * sizeof (uf_entry_t)); 6887c478bd9Sstevel@tonic-gate 689ae115bc7Smrj VN_RELE(PTOU(curproc)->u_cdir); 690ae115bc7Smrj if (PTOU(curproc)->u_rdir) 691ae115bc7Smrj VN_RELE(PTOU(curproc)->u_rdir); 6927c478bd9Sstevel@tonic-gate if (cp->p_exec) 6937c478bd9Sstevel@tonic-gate VN_RELE(cp->p_exec); 6947c478bd9Sstevel@tonic-gate if (cp->p_execdir) 6957c478bd9Sstevel@tonic-gate VN_RELE(cp->p_execdir); 696ae115bc7Smrj if (PTOU(curproc)->u_cwd) 697ae115bc7Smrj refstr_rele(PTOU(curproc)->u_cwd); 698e9f7cbf0SVamsi Nagineni if (PROC_IS_BRANDED(cp)) { 699e9f7cbf0SVamsi Nagineni brand_clearbrand(cp, B_TRUE); 700e9f7cbf0SVamsi Nagineni } 7017c478bd9Sstevel@tonic-gate } 7027c478bd9Sstevel@tonic-gate 7037c478bd9Sstevel@tonic-gate /* 7047c478bd9Sstevel@tonic-gate * Clean up the lwps already created for this child process. 7057c478bd9Sstevel@tonic-gate * The fork failed while duplicating all the lwps of the parent 7067c478bd9Sstevel@tonic-gate * and those lwps already created must be freed. 7077c478bd9Sstevel@tonic-gate * This process is invisible to the rest of the system, 7087c478bd9Sstevel@tonic-gate * so we don't need to hold p->p_lock to protect the list. 7097c478bd9Sstevel@tonic-gate */ 7107c478bd9Sstevel@tonic-gate static void 7117c478bd9Sstevel@tonic-gate forklwp_fail(proc_t *p) 7127c478bd9Sstevel@tonic-gate { 7137c478bd9Sstevel@tonic-gate kthread_t *t; 7147c478bd9Sstevel@tonic-gate task_t *tk; 715e9f7cbf0SVamsi Nagineni int branded = 0; 716e9f7cbf0SVamsi Nagineni 717e9f7cbf0SVamsi Nagineni if (PROC_IS_BRANDED(p)) 718e9f7cbf0SVamsi Nagineni branded = 1; 7197c478bd9Sstevel@tonic-gate 7207c478bd9Sstevel@tonic-gate while ((t = p->p_tlist) != NULL) { 7217c478bd9Sstevel@tonic-gate /* 7227c478bd9Sstevel@tonic-gate * First remove the lwp from the process's p_tlist. 7237c478bd9Sstevel@tonic-gate */ 7247c478bd9Sstevel@tonic-gate if (t != t->t_forw) 7257c478bd9Sstevel@tonic-gate p->p_tlist = t->t_forw; 7267c478bd9Sstevel@tonic-gate else 7277c478bd9Sstevel@tonic-gate p->p_tlist = NULL; 7287c478bd9Sstevel@tonic-gate p->p_lwpcnt--; 7297c478bd9Sstevel@tonic-gate t->t_forw->t_back = t->t_back; 7307c478bd9Sstevel@tonic-gate t->t_back->t_forw = t->t_forw; 7317c478bd9Sstevel@tonic-gate 7327c478bd9Sstevel@tonic-gate tk = p->p_task; 7337c478bd9Sstevel@tonic-gate mutex_enter(&p->p_zone->zone_nlwps_lock); 7347c478bd9Sstevel@tonic-gate tk->tk_nlwps--; 7357c478bd9Sstevel@tonic-gate tk->tk_proj->kpj_nlwps--; 7367c478bd9Sstevel@tonic-gate p->p_zone->zone_nlwps--; 7377c478bd9Sstevel@tonic-gate mutex_exit(&p->p_zone->zone_nlwps_lock); 7387c478bd9Sstevel@tonic-gate 7397c478bd9Sstevel@tonic-gate ASSERT(t->t_schedctl == NULL); 7407c478bd9Sstevel@tonic-gate 741e9f7cbf0SVamsi Nagineni if (branded) 742e9f7cbf0SVamsi Nagineni BROP(p)->b_freelwp(ttolwp(t)); 743e9f7cbf0SVamsi Nagineni 7447c478bd9Sstevel@tonic-gate if (t->t_door != NULL) { 7457c478bd9Sstevel@tonic-gate kmem_free(t->t_door, sizeof (door_data_t)); 7467c478bd9Sstevel@tonic-gate t->t_door = NULL; 7477c478bd9Sstevel@tonic-gate } 7487c478bd9Sstevel@tonic-gate lwp_ctmpl_clear(ttolwp(t)); 7497c478bd9Sstevel@tonic-gate 7507c478bd9Sstevel@tonic-gate /* 7517c478bd9Sstevel@tonic-gate * Remove the thread from the all threads list. 7527c478bd9Sstevel@tonic-gate * We need to hold pidlock for this. 7537c478bd9Sstevel@tonic-gate */ 7547c478bd9Sstevel@tonic-gate mutex_enter(&pidlock); 7557c478bd9Sstevel@tonic-gate t->t_next->t_prev = t->t_prev; 7567c478bd9Sstevel@tonic-gate t->t_prev->t_next = t->t_next; 7577c478bd9Sstevel@tonic-gate CL_EXIT(t); /* tell the scheduler that we're exiting */ 7587c478bd9Sstevel@tonic-gate cv_broadcast(&t->t_joincv); /* tell anyone in thread_join */ 7597c478bd9Sstevel@tonic-gate mutex_exit(&pidlock); 7607c478bd9Sstevel@tonic-gate 7617c478bd9Sstevel@tonic-gate /* 7627c478bd9Sstevel@tonic-gate * Let the lgroup load averages know that this thread isn't 7637c478bd9Sstevel@tonic-gate * going to show up (i.e. un-do what was done on behalf of 7647c478bd9Sstevel@tonic-gate * this thread by the earlier lgrp_move_thread()). 7657c478bd9Sstevel@tonic-gate */ 7667c478bd9Sstevel@tonic-gate kpreempt_disable(); 7677c478bd9Sstevel@tonic-gate lgrp_move_thread(t, NULL, 1); 7687c478bd9Sstevel@tonic-gate kpreempt_enable(); 7697c478bd9Sstevel@tonic-gate 7707c478bd9Sstevel@tonic-gate /* 7717c478bd9Sstevel@tonic-gate * The thread was created TS_STOPPED. 7727c478bd9Sstevel@tonic-gate * We change it to TS_FREE to avoid an 7737c478bd9Sstevel@tonic-gate * ASSERT() panic in thread_free(). 7747c478bd9Sstevel@tonic-gate */ 7757c478bd9Sstevel@tonic-gate t->t_state = TS_FREE; 7767c478bd9Sstevel@tonic-gate thread_rele(t); 7777c478bd9Sstevel@tonic-gate thread_free(t); 7787c478bd9Sstevel@tonic-gate } 7797c478bd9Sstevel@tonic-gate } 7807c478bd9Sstevel@tonic-gate 7817c478bd9Sstevel@tonic-gate extern struct as kas; 7827c478bd9Sstevel@tonic-gate 7837c478bd9Sstevel@tonic-gate /* 7847c478bd9Sstevel@tonic-gate * fork a kernel process. 7857c478bd9Sstevel@tonic-gate */ 7867c478bd9Sstevel@tonic-gate int 78735a5a358SJonathan Adams newproc(void (*pc)(), caddr_t arg, id_t cid, int pri, struct contract **ct, 78835a5a358SJonathan Adams pid_t pid) 7897c478bd9Sstevel@tonic-gate { 7907c478bd9Sstevel@tonic-gate proc_t *p; 7917c478bd9Sstevel@tonic-gate struct user *up; 79235a5a358SJonathan Adams kthread_t *t; 7937c478bd9Sstevel@tonic-gate cont_process_t *ctp = NULL; 7947c478bd9Sstevel@tonic-gate rctl_entity_p_t e; 7957c478bd9Sstevel@tonic-gate 79635a5a358SJonathan Adams ASSERT(cid != sysdccid); 79735a5a358SJonathan Adams ASSERT(cid != syscid || ct == NULL); 79835a5a358SJonathan Adams if (CLASS_KERNEL(cid)) { 7997c478bd9Sstevel@tonic-gate rctl_alloc_gp_t *init_gp; 8007c478bd9Sstevel@tonic-gate rctl_set_t *init_set; 8017c478bd9Sstevel@tonic-gate 80235a5a358SJonathan Adams ASSERT(pid != 1); 80335a5a358SJonathan Adams 80435a5a358SJonathan Adams if (getproc(&p, pid, GETPROC_KERNEL) < 0) 8057c478bd9Sstevel@tonic-gate return (EAGAIN); 8067c478bd9Sstevel@tonic-gate 807cdf26504SPramod Batni /* 808cdf26504SPramod Batni * Release the hold on the p_exec and p_execdir, these 809cdf26504SPramod Batni * were acquired in getproc() 810cdf26504SPramod Batni */ 811cdf26504SPramod Batni if (p->p_execdir != NULL) 812cdf26504SPramod Batni VN_RELE(p->p_execdir); 813cdf26504SPramod Batni if (p->p_exec != NULL) 814cdf26504SPramod Batni VN_RELE(p->p_exec); 8157c478bd9Sstevel@tonic-gate p->p_flag |= SNOWAIT; 8167c478bd9Sstevel@tonic-gate p->p_exec = NULL; 8177c478bd9Sstevel@tonic-gate p->p_execdir = NULL; 8187c478bd9Sstevel@tonic-gate 8197c478bd9Sstevel@tonic-gate init_set = rctl_set_create(); 8207c478bd9Sstevel@tonic-gate init_gp = rctl_set_init_prealloc(RCENTITY_PROCESS); 8217c478bd9Sstevel@tonic-gate 8227c478bd9Sstevel@tonic-gate /* 8237c478bd9Sstevel@tonic-gate * kernel processes do not inherit /proc tracing flags. 8247c478bd9Sstevel@tonic-gate */ 8257c478bd9Sstevel@tonic-gate sigemptyset(&p->p_sigmask); 8267c478bd9Sstevel@tonic-gate premptyset(&p->p_fltmask); 8277c478bd9Sstevel@tonic-gate up = PTOU(p); 8287c478bd9Sstevel@tonic-gate up->u_systrap = 0; 8297c478bd9Sstevel@tonic-gate premptyset(&(up->u_entrymask)); 8307c478bd9Sstevel@tonic-gate premptyset(&(up->u_exitmask)); 8317c478bd9Sstevel@tonic-gate mutex_enter(&p->p_lock); 8327c478bd9Sstevel@tonic-gate e.rcep_p.proc = p; 8337c478bd9Sstevel@tonic-gate e.rcep_t = RCENTITY_PROCESS; 8347c478bd9Sstevel@tonic-gate p->p_rctls = rctl_set_init(RCENTITY_PROCESS, p, &e, init_set, 8357c478bd9Sstevel@tonic-gate init_gp); 8367c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock); 8377c478bd9Sstevel@tonic-gate 8387c478bd9Sstevel@tonic-gate rctl_prealloc_destroy(init_gp); 83935a5a358SJonathan Adams 84035a5a358SJonathan Adams t = lwp_kernel_create(p, pc, arg, TS_STOPPED, pri); 8417c478bd9Sstevel@tonic-gate } else { 8427c478bd9Sstevel@tonic-gate rctl_alloc_gp_t *init_gp, *default_gp; 8437c478bd9Sstevel@tonic-gate rctl_set_t *init_set; 8447c478bd9Sstevel@tonic-gate task_t *tk, *tk_old; 84535a5a358SJonathan Adams klwp_t *lwp; 8467c478bd9Sstevel@tonic-gate 84735a5a358SJonathan Adams if (getproc(&p, pid, GETPROC_USER) < 0) 8487c478bd9Sstevel@tonic-gate return (EAGAIN); 8497c478bd9Sstevel@tonic-gate /* 8507c478bd9Sstevel@tonic-gate * init creates a new task, distinct from the task 8517c478bd9Sstevel@tonic-gate * containing kernel "processes". 8527c478bd9Sstevel@tonic-gate */ 8537c478bd9Sstevel@tonic-gate tk = task_create(0, p->p_zone); 8547c478bd9Sstevel@tonic-gate mutex_enter(&tk->tk_zone->zone_nlwps_lock); 8557c478bd9Sstevel@tonic-gate tk->tk_proj->kpj_ntasks++; 856ff19e029SMenno Lageman tk->tk_nprocs++; 8577c478bd9Sstevel@tonic-gate mutex_exit(&tk->tk_zone->zone_nlwps_lock); 8587c478bd9Sstevel@tonic-gate 8597c478bd9Sstevel@tonic-gate default_gp = rctl_rlimit_set_prealloc(RLIM_NLIMITS); 8607c478bd9Sstevel@tonic-gate init_gp = rctl_set_init_prealloc(RCENTITY_PROCESS); 8617c478bd9Sstevel@tonic-gate init_set = rctl_set_create(); 8627c478bd9Sstevel@tonic-gate 8637c478bd9Sstevel@tonic-gate mutex_enter(&pidlock); 8647c478bd9Sstevel@tonic-gate mutex_enter(&p->p_lock); 8657c478bd9Sstevel@tonic-gate tk_old = p->p_task; /* switch to new task */ 8667c478bd9Sstevel@tonic-gate 8677c478bd9Sstevel@tonic-gate task_detach(p); 8687c478bd9Sstevel@tonic-gate task_begin(tk, p); 8697c478bd9Sstevel@tonic-gate mutex_exit(&pidlock); 8707c478bd9Sstevel@tonic-gate 871ff19e029SMenno Lageman mutex_enter(&tk_old->tk_zone->zone_nlwps_lock); 872ff19e029SMenno Lageman tk_old->tk_nprocs--; 873ff19e029SMenno Lageman mutex_exit(&tk_old->tk_zone->zone_nlwps_lock); 874ff19e029SMenno Lageman 8757c478bd9Sstevel@tonic-gate e.rcep_p.proc = p; 8767c478bd9Sstevel@tonic-gate e.rcep_t = RCENTITY_PROCESS; 8777c478bd9Sstevel@tonic-gate p->p_rctls = rctl_set_init(RCENTITY_PROCESS, p, &e, init_set, 8787c478bd9Sstevel@tonic-gate init_gp); 8797c478bd9Sstevel@tonic-gate rctlproc_default_init(p, default_gp); 8807c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock); 8817c478bd9Sstevel@tonic-gate 8827c478bd9Sstevel@tonic-gate task_rele(tk_old); 8837c478bd9Sstevel@tonic-gate rctl_prealloc_destroy(default_gp); 8847c478bd9Sstevel@tonic-gate rctl_prealloc_destroy(init_gp); 8857c478bd9Sstevel@tonic-gate 8867c478bd9Sstevel@tonic-gate if ((lwp = lwp_create(pc, arg, 0, p, TS_STOPPED, pri, 8877c478bd9Sstevel@tonic-gate &curthread->t_hold, cid, 1)) == NULL) { 8887c478bd9Sstevel@tonic-gate task_t *tk; 8897c478bd9Sstevel@tonic-gate fork_fail(p); 8907c478bd9Sstevel@tonic-gate mutex_enter(&pidlock); 8917c478bd9Sstevel@tonic-gate mutex_enter(&p->p_lock); 8927c478bd9Sstevel@tonic-gate tk = p->p_task; 8937c478bd9Sstevel@tonic-gate task_detach(p); 8947c478bd9Sstevel@tonic-gate ASSERT(p->p_pool->pool_ref > 0); 8957c478bd9Sstevel@tonic-gate atomic_add_32(&p->p_pool->pool_ref, -1); 8967c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock); 8974bcbe6e7SMenno Lageman pid_exit(p, tk); 8987c478bd9Sstevel@tonic-gate mutex_exit(&pidlock); 8997c478bd9Sstevel@tonic-gate task_rele(tk); 9007c478bd9Sstevel@tonic-gate 9017c478bd9Sstevel@tonic-gate return (EAGAIN); 9027c478bd9Sstevel@tonic-gate } 90335a5a358SJonathan Adams t = lwptot(lwp); 9047c478bd9Sstevel@tonic-gate 9057c478bd9Sstevel@tonic-gate ctp = contract_process_fork(sys_process_tmpl, p, curproc, 9067c478bd9Sstevel@tonic-gate B_FALSE); 9077c478bd9Sstevel@tonic-gate ASSERT(ctp != NULL); 9087c478bd9Sstevel@tonic-gate if (ct != NULL) 9097c478bd9Sstevel@tonic-gate *ct = &ctp->conp_contract; 9107c478bd9Sstevel@tonic-gate } 9117c478bd9Sstevel@tonic-gate 91235a5a358SJonathan Adams ASSERT3U(t->t_tid, ==, 1); 9137c478bd9Sstevel@tonic-gate p->p_lwpid = 1; 9147c478bd9Sstevel@tonic-gate mutex_enter(&pidlock); 91535a5a358SJonathan Adams pgjoin(p, p->p_parent->p_pgidp); 9167c478bd9Sstevel@tonic-gate p->p_stat = SRUN; 9177c478bd9Sstevel@tonic-gate mutex_enter(&p->p_lock); 91835a5a358SJonathan Adams t->t_proc_flag &= ~TP_HOLDLWP; 91935a5a358SJonathan Adams lwp_create_done(t); 9207c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock); 9217c478bd9Sstevel@tonic-gate mutex_exit(&pidlock); 9227c478bd9Sstevel@tonic-gate return (0); 9237c478bd9Sstevel@tonic-gate } 9247c478bd9Sstevel@tonic-gate 9257c478bd9Sstevel@tonic-gate /* 9267c478bd9Sstevel@tonic-gate * create a child proc struct. 9277c478bd9Sstevel@tonic-gate */ 9287c478bd9Sstevel@tonic-gate static int 92935a5a358SJonathan Adams getproc(proc_t **cpp, pid_t pid, uint_t flags) 9307c478bd9Sstevel@tonic-gate { 9317c478bd9Sstevel@tonic-gate proc_t *pp, *cp; 9327c478bd9Sstevel@tonic-gate pid_t newpid; 9337c478bd9Sstevel@tonic-gate struct user *uarea; 9347c478bd9Sstevel@tonic-gate extern uint_t nproc; 9357c478bd9Sstevel@tonic-gate struct cred *cr; 9367c478bd9Sstevel@tonic-gate uid_t ruid; 9377c478bd9Sstevel@tonic-gate zoneid_t zoneid; 938ff19e029SMenno Lageman task_t *task; 939ff19e029SMenno Lageman kproject_t *proj; 940ff19e029SMenno Lageman zone_t *zone; 941ff19e029SMenno Lageman int rctlfail = 0; 9427c478bd9Sstevel@tonic-gate 9437c478bd9Sstevel@tonic-gate if (zone_status_get(curproc->p_zone) >= ZONE_IS_SHUTTING_DOWN) 9447c478bd9Sstevel@tonic-gate return (-1); /* no point in starting new processes */ 9457c478bd9Sstevel@tonic-gate 94635a5a358SJonathan Adams pp = (flags & GETPROC_KERNEL) ? &p0 : curproc; 947ff19e029SMenno Lageman task = pp->p_task; 948ff19e029SMenno Lageman proj = task->tk_proj; 949ff19e029SMenno Lageman zone = pp->p_zone; 950ff19e029SMenno Lageman 951ff19e029SMenno Lageman mutex_enter(&pp->p_lock); 952ff19e029SMenno Lageman mutex_enter(&zone->zone_nlwps_lock); 953ff19e029SMenno Lageman if (proj != proj0p) { 954ff19e029SMenno Lageman if (task->tk_nprocs >= task->tk_nprocs_ctl) 955ff19e029SMenno Lageman if (rctl_test(rc_task_nprocs, task->tk_rctls, 956ff19e029SMenno Lageman pp, 1, 0) & RCT_DENY) 957ff19e029SMenno Lageman rctlfail = 1; 958ff19e029SMenno Lageman 959ff19e029SMenno Lageman if (proj->kpj_nprocs >= proj->kpj_nprocs_ctl) 960ff19e029SMenno Lageman if (rctl_test(rc_project_nprocs, proj->kpj_rctls, 961ff19e029SMenno Lageman pp, 1, 0) & RCT_DENY) 962ff19e029SMenno Lageman rctlfail = 1; 963ff19e029SMenno Lageman 964ff19e029SMenno Lageman if (zone->zone_nprocs >= zone->zone_nprocs_ctl) 965ff19e029SMenno Lageman if (rctl_test(rc_zone_nprocs, zone->zone_rctls, 966ff19e029SMenno Lageman pp, 1, 0) & RCT_DENY) 967ff19e029SMenno Lageman rctlfail = 1; 968ff19e029SMenno Lageman 969ff19e029SMenno Lageman if (rctlfail) { 970ff19e029SMenno Lageman mutex_exit(&zone->zone_nlwps_lock); 971ff19e029SMenno Lageman mutex_exit(&pp->p_lock); 9722dc692e0SJerry Jelinek atomic_inc_32(&zone->zone_ffcap); 973ff19e029SMenno Lageman goto punish; 974ff19e029SMenno Lageman } 975ff19e029SMenno Lageman } 976ff19e029SMenno Lageman task->tk_nprocs++; 977ff19e029SMenno Lageman proj->kpj_nprocs++; 978ff19e029SMenno Lageman zone->zone_nprocs++; 979ff19e029SMenno Lageman mutex_exit(&zone->zone_nlwps_lock); 980ff19e029SMenno Lageman mutex_exit(&pp->p_lock); 981ff19e029SMenno Lageman 9827c478bd9Sstevel@tonic-gate cp = kmem_cache_alloc(process_cache, KM_SLEEP); 9837c478bd9Sstevel@tonic-gate bzero(cp, sizeof (proc_t)); 9847c478bd9Sstevel@tonic-gate 9857c478bd9Sstevel@tonic-gate /* 9867c478bd9Sstevel@tonic-gate * Make proc entry for child process 9877c478bd9Sstevel@tonic-gate */ 9889acbbeafSnn35248 mutex_init(&cp->p_splock, NULL, MUTEX_DEFAULT, NULL); 9897c478bd9Sstevel@tonic-gate mutex_init(&cp->p_crlock, NULL, MUTEX_DEFAULT, NULL); 9907c478bd9Sstevel@tonic-gate mutex_init(&cp->p_pflock, NULL, MUTEX_DEFAULT, NULL); 9917c478bd9Sstevel@tonic-gate #if defined(__x86) 9927c478bd9Sstevel@tonic-gate mutex_init(&cp->p_ldtlock, NULL, MUTEX_DEFAULT, NULL); 9937c478bd9Sstevel@tonic-gate #endif 9947c478bd9Sstevel@tonic-gate mutex_init(&cp->p_maplock, NULL, MUTEX_DEFAULT, NULL); 9957c478bd9Sstevel@tonic-gate cp->p_stat = SIDL; 9967c478bd9Sstevel@tonic-gate cp->p_mstart = gethrtime(); 99735a5a358SJonathan Adams cp->p_as = &kas; 998ae5aeae1Sgjelinek /* 999ae5aeae1Sgjelinek * p_zone must be set before we call pid_allocate since the process 1000ae5aeae1Sgjelinek * will be visible after that and code such as prfind_zone will 1001ae5aeae1Sgjelinek * look at the p_zone field. 1002ae5aeae1Sgjelinek */ 1003ae5aeae1Sgjelinek cp->p_zone = pp->p_zone; 10042cb27123Saguzovsk cp->p_t1_lgrpid = LGRP_NONE; 10052cb27123Saguzovsk cp->p_tr_lgrpid = LGRP_NONE; 10067c478bd9Sstevel@tonic-gate 100735a5a358SJonathan Adams if ((newpid = pid_allocate(cp, pid, PID_ALLOC_PROC)) == -1) { 10087c478bd9Sstevel@tonic-gate if (nproc == v.v_proc) { 10097c478bd9Sstevel@tonic-gate CPU_STATS_ADDQ(CPU, sys, procovf, 1); 10107c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "out of processes"); 10117c478bd9Sstevel@tonic-gate } 10127c478bd9Sstevel@tonic-gate goto bad; 10137c478bd9Sstevel@tonic-gate } 10147c478bd9Sstevel@tonic-gate 1015a4aeef46SDonghai Qiao mutex_enter(&pp->p_lock); 1016a4aeef46SDonghai Qiao cp->p_exec = pp->p_exec; 1017a4aeef46SDonghai Qiao cp->p_execdir = pp->p_execdir; 1018a4aeef46SDonghai Qiao mutex_exit(&pp->p_lock); 1019a4aeef46SDonghai Qiao 1020a4aeef46SDonghai Qiao if (cp->p_exec) { 1021a4aeef46SDonghai Qiao VN_HOLD(cp->p_exec); 1022a4aeef46SDonghai Qiao /* 1023a4aeef46SDonghai Qiao * Each VOP_OPEN() must be paired with a corresponding 1024a4aeef46SDonghai Qiao * VOP_CLOSE(). In this case, the executable will be 1025a4aeef46SDonghai Qiao * closed for the child in either proc_exit() or gexec(). 1026a4aeef46SDonghai Qiao */ 1027a4aeef46SDonghai Qiao if (VOP_OPEN(&cp->p_exec, FREAD, CRED(), NULL) != 0) { 1028a4aeef46SDonghai Qiao VN_RELE(cp->p_exec); 1029a4aeef46SDonghai Qiao cp->p_exec = NULLVP; 1030a4aeef46SDonghai Qiao cp->p_execdir = NULLVP; 1031a4aeef46SDonghai Qiao goto bad; 1032a4aeef46SDonghai Qiao } 1033a4aeef46SDonghai Qiao } 1034a4aeef46SDonghai Qiao if (cp->p_execdir) 1035a4aeef46SDonghai Qiao VN_HOLD(cp->p_execdir); 1036a4aeef46SDonghai Qiao 10377c478bd9Sstevel@tonic-gate /* 10387c478bd9Sstevel@tonic-gate * If not privileged make sure that this user hasn't exceeded 10397c478bd9Sstevel@tonic-gate * v.v_maxup processes, and that users collectively haven't 10407c478bd9Sstevel@tonic-gate * exceeded v.v_maxupttl processes. 10417c478bd9Sstevel@tonic-gate */ 10427c478bd9Sstevel@tonic-gate mutex_enter(&pidlock); 10437c478bd9Sstevel@tonic-gate ASSERT(nproc < v.v_proc); /* otherwise how'd we get our pid? */ 10447c478bd9Sstevel@tonic-gate cr = CRED(); 10457c478bd9Sstevel@tonic-gate ruid = crgetruid(cr); 10467c478bd9Sstevel@tonic-gate zoneid = crgetzoneid(cr); 10477c478bd9Sstevel@tonic-gate if (nproc >= v.v_maxup && /* short-circuit; usually false */ 10487c478bd9Sstevel@tonic-gate (nproc >= v.v_maxupttl || 10497c478bd9Sstevel@tonic-gate upcount_get(ruid, zoneid) >= v.v_maxup) && 10507c478bd9Sstevel@tonic-gate secpolicy_newproc(cr) != 0) { 10517c478bd9Sstevel@tonic-gate mutex_exit(&pidlock); 10527c478bd9Sstevel@tonic-gate zcmn_err(zoneid, CE_NOTE, 10537c478bd9Sstevel@tonic-gate "out of per-user processes for uid %d", ruid); 10547c478bd9Sstevel@tonic-gate goto bad; 10557c478bd9Sstevel@tonic-gate } 10567c478bd9Sstevel@tonic-gate 10577c478bd9Sstevel@tonic-gate /* 10587c478bd9Sstevel@tonic-gate * Everything is cool, put the new proc on the active process list. 10597c478bd9Sstevel@tonic-gate * It is already on the pid list and in /proc. 10607c478bd9Sstevel@tonic-gate * Increment the per uid process count (upcount). 10617c478bd9Sstevel@tonic-gate */ 10627c478bd9Sstevel@tonic-gate nproc++; 10637c478bd9Sstevel@tonic-gate upcount_inc(ruid, zoneid); 10647c478bd9Sstevel@tonic-gate 10657c478bd9Sstevel@tonic-gate cp->p_next = practive; 10667c478bd9Sstevel@tonic-gate practive->p_prev = cp; 10677c478bd9Sstevel@tonic-gate practive = cp; 10687c478bd9Sstevel@tonic-gate 10697c478bd9Sstevel@tonic-gate cp->p_ignore = pp->p_ignore; 10707c478bd9Sstevel@tonic-gate cp->p_siginfo = pp->p_siginfo; 10717c478bd9Sstevel@tonic-gate cp->p_flag = pp->p_flag & (SJCTL|SNOWAIT|SNOCD); 10727c478bd9Sstevel@tonic-gate cp->p_sessp = pp->p_sessp; 10739acbbeafSnn35248 sess_hold(pp); 10749acbbeafSnn35248 cp->p_brand = pp->p_brand; 10759acbbeafSnn35248 if (PROC_IS_BRANDED(pp)) 10769acbbeafSnn35248 BROP(pp)->b_copy_procdata(cp, pp); 10777c478bd9Sstevel@tonic-gate cp->p_bssbase = pp->p_bssbase; 10787c478bd9Sstevel@tonic-gate cp->p_brkbase = pp->p_brkbase; 10797c478bd9Sstevel@tonic-gate cp->p_brksize = pp->p_brksize; 10807c478bd9Sstevel@tonic-gate cp->p_brkpageszc = pp->p_brkpageszc; 10817c478bd9Sstevel@tonic-gate cp->p_stksize = pp->p_stksize; 10827c478bd9Sstevel@tonic-gate cp->p_stkpageszc = pp->p_stkpageszc; 10837c478bd9Sstevel@tonic-gate cp->p_stkprot = pp->p_stkprot; 10847c478bd9Sstevel@tonic-gate cp->p_datprot = pp->p_datprot; 10857c478bd9Sstevel@tonic-gate cp->p_usrstack = pp->p_usrstack; 10867c478bd9Sstevel@tonic-gate cp->p_model = pp->p_model; 10877c478bd9Sstevel@tonic-gate cp->p_ppid = pp->p_pid; 10887c478bd9Sstevel@tonic-gate cp->p_ancpid = pp->p_pid; 10897c478bd9Sstevel@tonic-gate cp->p_portcnt = pp->p_portcnt; 10907c478bd9Sstevel@tonic-gate 10917c478bd9Sstevel@tonic-gate /* 10927c478bd9Sstevel@tonic-gate * Initialize watchpoint structures 10937c478bd9Sstevel@tonic-gate */ 10947c478bd9Sstevel@tonic-gate avl_create(&cp->p_warea, wa_compare, sizeof (struct watched_area), 10957c478bd9Sstevel@tonic-gate offsetof(struct watched_area, wa_link)); 10967c478bd9Sstevel@tonic-gate 10977c478bd9Sstevel@tonic-gate /* 10987c478bd9Sstevel@tonic-gate * Initialize immediate resource control values. 10997c478bd9Sstevel@tonic-gate */ 11007c478bd9Sstevel@tonic-gate cp->p_stk_ctl = pp->p_stk_ctl; 11017c478bd9Sstevel@tonic-gate cp->p_fsz_ctl = pp->p_fsz_ctl; 11027c478bd9Sstevel@tonic-gate cp->p_vmem_ctl = pp->p_vmem_ctl; 11037c478bd9Sstevel@tonic-gate cp->p_fno_ctl = pp->p_fno_ctl; 11047c478bd9Sstevel@tonic-gate 11057c478bd9Sstevel@tonic-gate /* 11067c478bd9Sstevel@tonic-gate * Link up to parent-child-sibling chain. No need to lock 11077c478bd9Sstevel@tonic-gate * in general since only a call to freeproc() (done by the 11087c478bd9Sstevel@tonic-gate * same parent as newproc()) diddles with the child chain. 11097c478bd9Sstevel@tonic-gate */ 11107c478bd9Sstevel@tonic-gate cp->p_sibling = pp->p_child; 11117c478bd9Sstevel@tonic-gate if (pp->p_child) 11127c478bd9Sstevel@tonic-gate pp->p_child->p_psibling = cp; 11137c478bd9Sstevel@tonic-gate 11147c478bd9Sstevel@tonic-gate cp->p_parent = pp; 11157c478bd9Sstevel@tonic-gate pp->p_child = cp; 11167c478bd9Sstevel@tonic-gate 11177c478bd9Sstevel@tonic-gate cp->p_child_ns = NULL; 11187c478bd9Sstevel@tonic-gate cp->p_sibling_ns = NULL; 11197c478bd9Sstevel@tonic-gate 11207c478bd9Sstevel@tonic-gate cp->p_nextorph = pp->p_orphan; 11217c478bd9Sstevel@tonic-gate cp->p_nextofkin = pp; 11227c478bd9Sstevel@tonic-gate pp->p_orphan = cp; 11237c478bd9Sstevel@tonic-gate 11247c478bd9Sstevel@tonic-gate /* 11257c478bd9Sstevel@tonic-gate * Inherit profiling state; do not inherit REALPROF profiling state. 11267c478bd9Sstevel@tonic-gate */ 11277c478bd9Sstevel@tonic-gate cp->p_prof = pp->p_prof; 11287c478bd9Sstevel@tonic-gate cp->p_rprof_cyclic = CYCLIC_NONE; 11297c478bd9Sstevel@tonic-gate 11307c478bd9Sstevel@tonic-gate /* 11317c478bd9Sstevel@tonic-gate * Inherit pool pointer from the parent. Kernel processes are 11327c478bd9Sstevel@tonic-gate * always bound to the default pool. 11337c478bd9Sstevel@tonic-gate */ 11347c478bd9Sstevel@tonic-gate mutex_enter(&pp->p_lock); 113535a5a358SJonathan Adams if (flags & GETPROC_KERNEL) { 11367c478bd9Sstevel@tonic-gate cp->p_pool = pool_default; 11377c478bd9Sstevel@tonic-gate cp->p_flag |= SSYS; 11387c478bd9Sstevel@tonic-gate } else { 11397c478bd9Sstevel@tonic-gate cp->p_pool = pp->p_pool; 11407c478bd9Sstevel@tonic-gate } 11411a5e258fSJosef 'Jeff' Sipek atomic_inc_32(&cp->p_pool->pool_ref); 11427c478bd9Sstevel@tonic-gate mutex_exit(&pp->p_lock); 11437c478bd9Sstevel@tonic-gate 11447c478bd9Sstevel@tonic-gate /* 11457c478bd9Sstevel@tonic-gate * Add the child process to the current task. Kernel processes 11467c478bd9Sstevel@tonic-gate * are always attached to task0. 11477c478bd9Sstevel@tonic-gate */ 11487c478bd9Sstevel@tonic-gate mutex_enter(&cp->p_lock); 114935a5a358SJonathan Adams if (flags & GETPROC_KERNEL) 11507c478bd9Sstevel@tonic-gate task_attach(task0p, cp); 11517c478bd9Sstevel@tonic-gate else 11527c478bd9Sstevel@tonic-gate task_attach(pp->p_task, cp); 11537c478bd9Sstevel@tonic-gate mutex_exit(&cp->p_lock); 11547c478bd9Sstevel@tonic-gate mutex_exit(&pidlock); 11557c478bd9Sstevel@tonic-gate 11567c478bd9Sstevel@tonic-gate avl_create(&cp->p_ct_held, contract_compar, sizeof (contract_t), 11577c478bd9Sstevel@tonic-gate offsetof(contract_t, ct_ctlist)); 11587c478bd9Sstevel@tonic-gate 11597c478bd9Sstevel@tonic-gate /* 11607c478bd9Sstevel@tonic-gate * Duplicate any audit information kept in the process table 11617c478bd9Sstevel@tonic-gate */ 11627c478bd9Sstevel@tonic-gate if (audit_active) /* copy audit data to cp */ 11637c478bd9Sstevel@tonic-gate audit_newproc(cp); 11647c478bd9Sstevel@tonic-gate 11657c478bd9Sstevel@tonic-gate crhold(cp->p_cred = cr); 11667c478bd9Sstevel@tonic-gate 11677c478bd9Sstevel@tonic-gate /* 11687c478bd9Sstevel@tonic-gate * Bump up the counts on the file structures pointed at by the 11697c478bd9Sstevel@tonic-gate * parent's file table since the child will point at them too. 11707c478bd9Sstevel@tonic-gate */ 11717c478bd9Sstevel@tonic-gate fcnt_add(P_FINFO(pp), 1); 11727c478bd9Sstevel@tonic-gate 117335a5a358SJonathan Adams if (PTOU(pp)->u_cdir) { 1174ae115bc7Smrj VN_HOLD(PTOU(pp)->u_cdir); 117535a5a358SJonathan Adams } else { 117635a5a358SJonathan Adams ASSERT(pp == &p0); 117735a5a358SJonathan Adams /* 117835a5a358SJonathan Adams * We must be at or before vfs_mountroot(); it will take care of 117935a5a358SJonathan Adams * assigning our current directory. 118035a5a358SJonathan Adams */ 118135a5a358SJonathan Adams } 1182ae115bc7Smrj if (PTOU(pp)->u_rdir) 1183ae115bc7Smrj VN_HOLD(PTOU(pp)->u_rdir); 1184ae115bc7Smrj if (PTOU(pp)->u_cwd) 1185ae115bc7Smrj refstr_hold(PTOU(pp)->u_cwd); 11867c478bd9Sstevel@tonic-gate 11877c478bd9Sstevel@tonic-gate /* 11887c478bd9Sstevel@tonic-gate * copy the parent's uarea. 11897c478bd9Sstevel@tonic-gate */ 11907c478bd9Sstevel@tonic-gate uarea = PTOU(cp); 1191ae115bc7Smrj bcopy(PTOU(pp), uarea, sizeof (*uarea)); 11927c478bd9Sstevel@tonic-gate flist_fork(P_FINFO(pp), P_FINFO(cp)); 11937c478bd9Sstevel@tonic-gate 11947c478bd9Sstevel@tonic-gate gethrestime(&uarea->u_start); 1195d3d50737SRafael Vanoni uarea->u_ticks = ddi_get_lbolt(); 11967c478bd9Sstevel@tonic-gate uarea->u_mem = rm_asrss(pp->p_as); 11977c478bd9Sstevel@tonic-gate uarea->u_acflag = AFORK; 11987c478bd9Sstevel@tonic-gate 11997c478bd9Sstevel@tonic-gate /* 12007c478bd9Sstevel@tonic-gate * If inherit-on-fork, copy /proc tracing flags to child. 12017c478bd9Sstevel@tonic-gate */ 12027c478bd9Sstevel@tonic-gate if ((pp->p_proc_flag & P_PR_FORK) != 0) { 12037c478bd9Sstevel@tonic-gate cp->p_proc_flag |= pp->p_proc_flag & (P_PR_TRACE|P_PR_FORK); 12047c478bd9Sstevel@tonic-gate cp->p_sigmask = pp->p_sigmask; 12057c478bd9Sstevel@tonic-gate cp->p_fltmask = pp->p_fltmask; 12067c478bd9Sstevel@tonic-gate } else { 12077c478bd9Sstevel@tonic-gate sigemptyset(&cp->p_sigmask); 12087c478bd9Sstevel@tonic-gate premptyset(&cp->p_fltmask); 12097c478bd9Sstevel@tonic-gate uarea->u_systrap = 0; 12107c478bd9Sstevel@tonic-gate premptyset(&uarea->u_entrymask); 12117c478bd9Sstevel@tonic-gate premptyset(&uarea->u_exitmask); 12127c478bd9Sstevel@tonic-gate } 12137c478bd9Sstevel@tonic-gate /* 12147c478bd9Sstevel@tonic-gate * If microstate accounting is being inherited, mark child 12157c478bd9Sstevel@tonic-gate */ 12167c478bd9Sstevel@tonic-gate if ((pp->p_flag & SMSFORK) != 0) 12177c478bd9Sstevel@tonic-gate cp->p_flag |= pp->p_flag & (SMSFORK|SMSACCT); 12187c478bd9Sstevel@tonic-gate 12197c478bd9Sstevel@tonic-gate /* 12207c478bd9Sstevel@tonic-gate * Inherit fixalignment flag from the parent 12217c478bd9Sstevel@tonic-gate */ 12227c478bd9Sstevel@tonic-gate cp->p_fixalignment = pp->p_fixalignment; 12237c478bd9Sstevel@tonic-gate 12247c478bd9Sstevel@tonic-gate *cpp = cp; 12257c478bd9Sstevel@tonic-gate return (0); 12267c478bd9Sstevel@tonic-gate 12277c478bd9Sstevel@tonic-gate bad: 12287c478bd9Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(&pidlock)); 12297c478bd9Sstevel@tonic-gate 12307c478bd9Sstevel@tonic-gate mutex_destroy(&cp->p_crlock); 12317c478bd9Sstevel@tonic-gate mutex_destroy(&cp->p_pflock); 12327c478bd9Sstevel@tonic-gate #if defined(__x86) 12337c478bd9Sstevel@tonic-gate mutex_destroy(&cp->p_ldtlock); 12347c478bd9Sstevel@tonic-gate #endif 12357c478bd9Sstevel@tonic-gate if (newpid != -1) { 12367c478bd9Sstevel@tonic-gate proc_entry_free(cp->p_pidp); 12377c478bd9Sstevel@tonic-gate (void) pid_rele(cp->p_pidp); 12387c478bd9Sstevel@tonic-gate } 12397c478bd9Sstevel@tonic-gate kmem_cache_free(process_cache, cp); 12407c478bd9Sstevel@tonic-gate 1241ff19e029SMenno Lageman mutex_enter(&zone->zone_nlwps_lock); 1242ff19e029SMenno Lageman task->tk_nprocs--; 1243ff19e029SMenno Lageman proj->kpj_nprocs--; 1244ff19e029SMenno Lageman zone->zone_nprocs--; 1245ff19e029SMenno Lageman mutex_exit(&zone->zone_nlwps_lock); 12462dc692e0SJerry Jelinek atomic_inc_32(&zone->zone_ffnoproc); 1247ff19e029SMenno Lageman 1248ff19e029SMenno Lageman punish: 12497c478bd9Sstevel@tonic-gate /* 12507c478bd9Sstevel@tonic-gate * We most likely got into this situation because some process is 12517c478bd9Sstevel@tonic-gate * forking out of control. As punishment, put it to sleep for a 12527c478bd9Sstevel@tonic-gate * bit so it can't eat the machine alive. Sleep interval is chosen 12537c478bd9Sstevel@tonic-gate * to allow no more than one fork failure per cpu per clock tick 12547c478bd9Sstevel@tonic-gate * on average (yes, I just made this up). This has two desirable 12557c478bd9Sstevel@tonic-gate * properties: (1) it sets a constant limit on the fork failure 12567c478bd9Sstevel@tonic-gate * rate, and (2) the busier the system is, the harsher the penalty 12577c478bd9Sstevel@tonic-gate * for abusing it becomes. 12587c478bd9Sstevel@tonic-gate */ 12597c478bd9Sstevel@tonic-gate INCR_COUNT(&fork_fail_pending, &pidlock); 12607c478bd9Sstevel@tonic-gate delay(fork_fail_pending / ncpus + 1); 12617c478bd9Sstevel@tonic-gate DECR_COUNT(&fork_fail_pending, &pidlock); 12627c478bd9Sstevel@tonic-gate 12637c478bd9Sstevel@tonic-gate return (-1); /* out of memory or proc slots */ 12647c478bd9Sstevel@tonic-gate } 12657c478bd9Sstevel@tonic-gate 12667c478bd9Sstevel@tonic-gate /* 12677c478bd9Sstevel@tonic-gate * Release virtual memory. 12687c478bd9Sstevel@tonic-gate * In the case of vfork(), the child was given exclusive access to its 12697c478bd9Sstevel@tonic-gate * parent's address space. The parent is waiting in vfwait() for the 12707c478bd9Sstevel@tonic-gate * child to release its exclusive claim via relvm(). 12717c478bd9Sstevel@tonic-gate */ 12727c478bd9Sstevel@tonic-gate void 12737c478bd9Sstevel@tonic-gate relvm() 12747c478bd9Sstevel@tonic-gate { 12757c478bd9Sstevel@tonic-gate proc_t *p = curproc; 12767c478bd9Sstevel@tonic-gate 12777c478bd9Sstevel@tonic-gate ASSERT((unsigned)p->p_lwpcnt <= 1); 12787c478bd9Sstevel@tonic-gate 12797c478bd9Sstevel@tonic-gate prrelvm(); /* inform /proc */ 12807c478bd9Sstevel@tonic-gate 12817c478bd9Sstevel@tonic-gate if (p->p_flag & SVFORK) { 12827c478bd9Sstevel@tonic-gate proc_t *pp = p->p_parent; 12837c478bd9Sstevel@tonic-gate /* 12847c478bd9Sstevel@tonic-gate * The child process is either exec'ing or exit'ing. 12857c478bd9Sstevel@tonic-gate * The child is now separated from the parent's address 12867c478bd9Sstevel@tonic-gate * space. The parent process is made dispatchable. 12877c478bd9Sstevel@tonic-gate * 12887c478bd9Sstevel@tonic-gate * This is a delicate locking maneuver, involving 12897c478bd9Sstevel@tonic-gate * both the parent's p_lock and the child's p_lock. 12907c478bd9Sstevel@tonic-gate * As soon as the SVFORK flag is turned off, the 12917c478bd9Sstevel@tonic-gate * parent is free to run, but it must not run until 12927c478bd9Sstevel@tonic-gate * we wake it up using its p_cv because it might 12937c478bd9Sstevel@tonic-gate * exit and we would be referencing invalid memory. 12947c478bd9Sstevel@tonic-gate * Therefore, we hold the parent with its p_lock 12957c478bd9Sstevel@tonic-gate * while protecting our p_flags with our own p_lock. 12967c478bd9Sstevel@tonic-gate */ 12977c478bd9Sstevel@tonic-gate try_again: 12987c478bd9Sstevel@tonic-gate mutex_enter(&p->p_lock); /* grab child's lock first */ 12997c478bd9Sstevel@tonic-gate prbarrier(p); /* make sure /proc is blocked out */ 13007c478bd9Sstevel@tonic-gate mutex_enter(&pp->p_lock); 13017c478bd9Sstevel@tonic-gate 13027c478bd9Sstevel@tonic-gate /* 13037c478bd9Sstevel@tonic-gate * Check if parent is locked by /proc. 13047c478bd9Sstevel@tonic-gate */ 13057c478bd9Sstevel@tonic-gate if (pp->p_proc_flag & P_PR_LOCK) { 13067c478bd9Sstevel@tonic-gate /* 13077c478bd9Sstevel@tonic-gate * Delay until /proc is done with the parent. 13087c478bd9Sstevel@tonic-gate * We must drop our (the child's) p->p_lock, wait 13097c478bd9Sstevel@tonic-gate * via prbarrier() on the parent, then start over. 13107c478bd9Sstevel@tonic-gate */ 13117c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock); 13127c478bd9Sstevel@tonic-gate prbarrier(pp); 13137c478bd9Sstevel@tonic-gate mutex_exit(&pp->p_lock); 13147c478bd9Sstevel@tonic-gate goto try_again; 13157c478bd9Sstevel@tonic-gate } 13167c478bd9Sstevel@tonic-gate p->p_flag &= ~SVFORK; 13177c478bd9Sstevel@tonic-gate kpreempt_disable(); 13187c478bd9Sstevel@tonic-gate p->p_as = &kas; 13197c478bd9Sstevel@tonic-gate 13207c478bd9Sstevel@tonic-gate /* 13217c478bd9Sstevel@tonic-gate * notify hat of change in thread's address space 13227c478bd9Sstevel@tonic-gate */ 13237c478bd9Sstevel@tonic-gate hat_thread_exit(curthread); 13247c478bd9Sstevel@tonic-gate kpreempt_enable(); 13257c478bd9Sstevel@tonic-gate 13267c478bd9Sstevel@tonic-gate /* 13277c478bd9Sstevel@tonic-gate * child sizes are copied back to parent because 13287c478bd9Sstevel@tonic-gate * child may have grown. 13297c478bd9Sstevel@tonic-gate */ 13307c478bd9Sstevel@tonic-gate pp->p_brkbase = p->p_brkbase; 13317c478bd9Sstevel@tonic-gate pp->p_brksize = p->p_brksize; 13327c478bd9Sstevel@tonic-gate pp->p_stksize = p->p_stksize; 1333bb637ba7SVamsi Nagineni 1334bb637ba7SVamsi Nagineni /* 1335bb637ba7SVamsi Nagineni * Copy back the shm accounting information 1336bb637ba7SVamsi Nagineni * to the parent process. 1337bb637ba7SVamsi Nagineni */ 1338bb637ba7SVamsi Nagineni pp->p_segacct = p->p_segacct; 1339bb637ba7SVamsi Nagineni p->p_segacct = NULL; 1340bb637ba7SVamsi Nagineni 13417c478bd9Sstevel@tonic-gate /* 13427c478bd9Sstevel@tonic-gate * The parent is no longer waiting for the vfork()d child. 13437c478bd9Sstevel@tonic-gate * Restore the parent's watched pages, if any. This is 13447c478bd9Sstevel@tonic-gate * safe because we know the parent is not locked by /proc 13457c478bd9Sstevel@tonic-gate */ 13467c478bd9Sstevel@tonic-gate pp->p_flag &= ~SVFWAIT; 13477c478bd9Sstevel@tonic-gate if (avl_numnodes(&pp->p_wpage) != 0) { 13487c478bd9Sstevel@tonic-gate pp->p_as->a_wpage = pp->p_wpage; 13497c478bd9Sstevel@tonic-gate avl_create(&pp->p_wpage, wp_compare, 13507c478bd9Sstevel@tonic-gate sizeof (struct watched_page), 13517c478bd9Sstevel@tonic-gate offsetof(struct watched_page, wp_link)); 13527c478bd9Sstevel@tonic-gate } 13537c478bd9Sstevel@tonic-gate cv_signal(&pp->p_cv); 13547c478bd9Sstevel@tonic-gate mutex_exit(&pp->p_lock); 13557c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock); 13567c478bd9Sstevel@tonic-gate } else { 13577c478bd9Sstevel@tonic-gate if (p->p_as != &kas) { 13587c478bd9Sstevel@tonic-gate struct as *as; 13597c478bd9Sstevel@tonic-gate 13607c478bd9Sstevel@tonic-gate if (p->p_segacct) 13617c478bd9Sstevel@tonic-gate shmexit(p); 13629acbbeafSnn35248 13637c478bd9Sstevel@tonic-gate /* 13647c478bd9Sstevel@tonic-gate * We grab p_lock for the benefit of /proc 13657c478bd9Sstevel@tonic-gate */ 13667c478bd9Sstevel@tonic-gate kpreempt_disable(); 13677c478bd9Sstevel@tonic-gate mutex_enter(&p->p_lock); 13687c478bd9Sstevel@tonic-gate prbarrier(p); /* make sure /proc is blocked out */ 13697c478bd9Sstevel@tonic-gate as = p->p_as; 13707c478bd9Sstevel@tonic-gate p->p_as = &kas; 13717c478bd9Sstevel@tonic-gate mutex_exit(&p->p_lock); 13727c478bd9Sstevel@tonic-gate 13737c478bd9Sstevel@tonic-gate /* 13747c478bd9Sstevel@tonic-gate * notify hat of change in thread's address space 13757c478bd9Sstevel@tonic-gate */ 13767c478bd9Sstevel@tonic-gate hat_thread_exit(curthread); 13777c478bd9Sstevel@tonic-gate kpreempt_enable(); 13787c478bd9Sstevel@tonic-gate 13797c478bd9Sstevel@tonic-gate as_free(as); 13802cb27123Saguzovsk p->p_tr_lgrpid = LGRP_NONE; 13817c478bd9Sstevel@tonic-gate } 13827c478bd9Sstevel@tonic-gate } 13837c478bd9Sstevel@tonic-gate } 13847c478bd9Sstevel@tonic-gate 13857c478bd9Sstevel@tonic-gate /* 13867c478bd9Sstevel@tonic-gate * Wait for child to exec or exit. 13877c478bd9Sstevel@tonic-gate * Called by parent of vfork'ed process. 13887c478bd9Sstevel@tonic-gate * See important comments in relvm(), above. 13897c478bd9Sstevel@tonic-gate */ 13907c478bd9Sstevel@tonic-gate void 13917c478bd9Sstevel@tonic-gate vfwait(pid_t pid) 13927c478bd9Sstevel@tonic-gate { 13937c478bd9Sstevel@tonic-gate int signalled = 0; 13947c478bd9Sstevel@tonic-gate proc_t *pp = ttoproc(curthread); 13957c478bd9Sstevel@tonic-gate proc_t *cp; 13967c478bd9Sstevel@tonic-gate 13977c478bd9Sstevel@tonic-gate /* 13987c478bd9Sstevel@tonic-gate * Wait for child to exec or exit. 13997c478bd9Sstevel@tonic-gate */ 14007c478bd9Sstevel@tonic-gate for (;;) { 14017c478bd9Sstevel@tonic-gate mutex_enter(&pidlock); 14027c478bd9Sstevel@tonic-gate cp = prfind(pid); 14037c478bd9Sstevel@tonic-gate if (cp == NULL || cp->p_parent != pp) { 14047c478bd9Sstevel@tonic-gate /* 14057c478bd9Sstevel@tonic-gate * Child has exit()ed. 14067c478bd9Sstevel@tonic-gate */ 14077c478bd9Sstevel@tonic-gate mutex_exit(&pidlock); 14087c478bd9Sstevel@tonic-gate break; 14097c478bd9Sstevel@tonic-gate } 14107c478bd9Sstevel@tonic-gate /* 14117c478bd9Sstevel@tonic-gate * Grab the child's p_lock before releasing pidlock. 14127c478bd9Sstevel@tonic-gate * Otherwise, the child could exit and we would be 14137c478bd9Sstevel@tonic-gate * referencing invalid memory. 14147c478bd9Sstevel@tonic-gate */ 14157c478bd9Sstevel@tonic-gate mutex_enter(&cp->p_lock); 14167c478bd9Sstevel@tonic-gate mutex_exit(&pidlock); 14177c478bd9Sstevel@tonic-gate if (!(cp->p_flag & SVFORK)) { 14187c478bd9Sstevel@tonic-gate /* 14197c478bd9Sstevel@tonic-gate * Child has exec()ed or is exit()ing. 14207c478bd9Sstevel@tonic-gate */ 14217c478bd9Sstevel@tonic-gate mutex_exit(&cp->p_lock); 14227c478bd9Sstevel@tonic-gate break; 14237c478bd9Sstevel@tonic-gate } 14247c478bd9Sstevel@tonic-gate mutex_enter(&pp->p_lock); 14257c478bd9Sstevel@tonic-gate mutex_exit(&cp->p_lock); 14267c478bd9Sstevel@tonic-gate /* 14277c478bd9Sstevel@tonic-gate * We might be waked up spuriously from the cv_wait(). 14287c478bd9Sstevel@tonic-gate * We have to do the whole operation over again to be 14297c478bd9Sstevel@tonic-gate * sure the child's SVFORK flag really is turned off. 14307c478bd9Sstevel@tonic-gate * We cannot make reference to the child because it can 14317c478bd9Sstevel@tonic-gate * exit before we return and we would be referencing 14327c478bd9Sstevel@tonic-gate * invalid memory. 14337c478bd9Sstevel@tonic-gate * 14347c478bd9Sstevel@tonic-gate * Because this is potentially a very long-term wait, 14357c478bd9Sstevel@tonic-gate * we call cv_wait_sig() (for its jobcontrol and /proc 14367c478bd9Sstevel@tonic-gate * side-effects) unless there is a current signal, in 14377c478bd9Sstevel@tonic-gate * which case we use cv_wait() because we cannot return 14387c478bd9Sstevel@tonic-gate * from this function until the child has released the 14397c478bd9Sstevel@tonic-gate * address space. Calling cv_wait_sig() with a current 14407c478bd9Sstevel@tonic-gate * signal would lead to an indefinite loop here because 14417c478bd9Sstevel@tonic-gate * cv_wait_sig() returns immediately in this case. 14427c478bd9Sstevel@tonic-gate */ 14437c478bd9Sstevel@tonic-gate if (signalled) 14447c478bd9Sstevel@tonic-gate cv_wait(&pp->p_cv, &pp->p_lock); 14457c478bd9Sstevel@tonic-gate else 14467c478bd9Sstevel@tonic-gate signalled = !cv_wait_sig(&pp->p_cv, &pp->p_lock); 14477c478bd9Sstevel@tonic-gate mutex_exit(&pp->p_lock); 14487c478bd9Sstevel@tonic-gate } 14497c478bd9Sstevel@tonic-gate 14507c478bd9Sstevel@tonic-gate /* restore watchpoints to parent */ 14517c478bd9Sstevel@tonic-gate if (pr_watch_active(pp)) { 14527c478bd9Sstevel@tonic-gate struct as *as = pp->p_as; 1453*dc32d872SJosef 'Jeff' Sipek AS_LOCK_ENTER(as, RW_WRITER); 14547c478bd9Sstevel@tonic-gate as_setwatch(as); 1455*dc32d872SJosef 'Jeff' Sipek AS_LOCK_EXIT(as); 14567c478bd9Sstevel@tonic-gate } 14577c478bd9Sstevel@tonic-gate 14587c478bd9Sstevel@tonic-gate mutex_enter(&pp->p_lock); 14597c478bd9Sstevel@tonic-gate prbarrier(pp); /* barrier against /proc locking */ 14607c478bd9Sstevel@tonic-gate continuelwps(pp); 14617c478bd9Sstevel@tonic-gate mutex_exit(&pp->p_lock); 14627c478bd9Sstevel@tonic-gate } 1463