diff --git a/sys/amd64/amd64/machdep.c b/sys/amd64/amd64/machdep.c index 82e6e56..9e9e1bd 100644 --- a/sys/amd64/amd64/machdep.c +++ b/sys/amd64/amd64/machdep.c @@ -1137,7 +1137,7 @@ hammer_time(u_int64_t modulep, u_int64_t physfree) * This may be done better later if it gets more high level * components in it. If so just link td->td_proc here. */ - proc_linkup(&proc0, &thread0); + proc_linkup0(&proc0, &thread0); preload_metadata = (caddr_t)(uintptr_t)(modulep + KERNBASE); preload_bootstrap_relocate(KERNBASE); diff --git a/sys/amd64/amd64/pmap.c b/sys/amd64/amd64/pmap.c index 894e880..32ed747 100644 --- a/sys/amd64/amd64/pmap.c +++ b/sys/amd64/amd64/pmap.c @@ -1186,7 +1186,7 @@ pmap_pinit0(pmap_t pmap) * Initialize a preallocated and zeroed pmap structure, * such as one in a vmspace structure. */ -void +int pmap_pinit(pmap_t pmap) { vm_page_t pml4pg; @@ -1216,6 +1216,8 @@ pmap_pinit(pmap_t pmap) pmap->pm_active = 0; TAILQ_INIT(&pmap->pm_pvchunk); bzero(&pmap->pm_stats, sizeof pmap->pm_stats); + + return (1); } /* diff --git a/sys/arm/arm/pmap.c b/sys/arm/arm/pmap.c index e831cc5..a536639 100644 --- a/sys/arm/arm/pmap.c +++ b/sys/arm/arm/pmap.c @@ -3814,7 +3814,7 @@ pmap_extract_and_hold(pmap_t pmap, vm_offset_t va, vm_prot_t prot) * such as one in a vmspace structure. */ -void +int pmap_pinit(pmap_t pmap) { PDEBUG(1, printf("pmap_pinit: pmap = %08x\n", (uint32_t) pmap)); @@ -3833,6 +3833,7 @@ pmap_pinit(pmap_t pmap) pmap_enter(pmap, vector_page, PHYS_TO_VM_PAGE(systempage.pv_pa), VM_PROT_READ, 1); } + return (1); } diff --git a/sys/arm/at91/kb920x_machdep.c b/sys/arm/at91/kb920x_machdep.c index 61fe4dc..4efd0ed 100644 --- a/sys/arm/at91/kb920x_machdep.c +++ b/sys/arm/at91/kb920x_machdep.c @@ -449,7 +449,7 @@ initarm(void *arg, void *arg2) undefined_handler_address = (u_int)undefinedinstruction_bounce; undefined_init(); - proc_linkup(&proc0, &thread0); + proc_linkup0(&proc0, &thread0); thread0.td_kstack = kernelstack.pv_va; thread0.td_pcb = (struct pcb *) (thread0.td_kstack + KSTACK_PAGES * PAGE_SIZE) - 1; diff --git a/sys/arm/sa11x0/assabet_machdep.c b/sys/arm/sa11x0/assabet_machdep.c index 22b15f4..da2fd37 100644 --- a/sys/arm/sa11x0/assabet_machdep.c +++ b/sys/arm/sa11x0/assabet_machdep.c @@ -422,7 +422,7 @@ initarm(void *arg, void *arg2) /* Set stack for exception handlers */ - proc_linkup(&proc0, &thread0); + proc_linkup0(&proc0, &thread0); thread0.td_kstack = kernelstack.pv_va; thread0.td_pcb = (struct pcb *) (thread0.td_kstack + KSTACK_PAGES * PAGE_SIZE) - 1; diff --git a/sys/arm/xscale/i80321/ep80219_machdep.c b/sys/arm/xscale/i80321/ep80219_machdep.c index 6961ffa..432f23f 100644 --- a/sys/arm/xscale/i80321/ep80219_machdep.c +++ b/sys/arm/xscale/i80321/ep80219_machdep.c @@ -426,7 +426,7 @@ initarm(void *arg, void *arg2) undefined_handler_address = (u_int)undefinedinstruction_bounce; undefined_init(); - proc_linkup(&proc0, &thread0); + proc_linkup0(&proc0, &thread0); thread0.td_kstack = kernelstack.pv_va; thread0.td_pcb = (struct pcb *) (thread0.td_kstack + KSTACK_PAGES * PAGE_SIZE) - 1; diff --git a/sys/arm/xscale/i80321/iq31244_machdep.c b/sys/arm/xscale/i80321/iq31244_machdep.c index 589e778..42c0cf8 100644 --- a/sys/arm/xscale/i80321/iq31244_machdep.c +++ b/sys/arm/xscale/i80321/iq31244_machdep.c @@ -424,7 +424,7 @@ initarm(void *arg, void *arg2) undefined_handler_address = (u_int)undefinedinstruction_bounce; undefined_init(); - proc_linkup(&proc0, &thread0); + proc_linkup0(&proc0, &thread0); thread0.td_kstack = kernelstack.pv_va; thread0.td_pcb = (struct pcb *) (thread0.td_kstack + KSTACK_PAGES * PAGE_SIZE) - 1; diff --git a/sys/arm/xscale/i8134x/crb_machdep.c b/sys/arm/xscale/i8134x/crb_machdep.c index a448628..f7b85d5 100644 --- a/sys/arm/xscale/i8134x/crb_machdep.c +++ b/sys/arm/xscale/i8134x/crb_machdep.c @@ -402,7 +402,7 @@ initarm(void *arg, void *arg2) #ifdef KSE proc_linkup(&proc0, &ksegrp0, &thread0); #else - proc_linkup(&proc0, &thread0); + proc_linkup0(&proc0, &thread0); #endif thread0.td_kstack = kernelstack.pv_va; thread0.td_pcb = (struct pcb *) diff --git a/sys/arm/xscale/ixp425/avila_machdep.c b/sys/arm/xscale/ixp425/avila_machdep.c index 8aa4352..cb135e2 100644 --- a/sys/arm/xscale/ixp425/avila_machdep.c +++ b/sys/arm/xscale/ixp425/avila_machdep.c @@ -490,7 +490,7 @@ initarm(void *arg, void *arg2) undefined_handler_address = (u_int)undefinedinstruction_bounce; undefined_init(); - proc_linkup(&proc0, &thread0); + proc_linkup0(&proc0, &thread0); thread0.td_kstack = kernelstack.pv_va; thread0.td_pcb = (struct pcb *) (thread0.td_kstack + KSTACK_PAGES * PAGE_SIZE) - 1; diff --git a/sys/compat/pecoff/imgact_pecoff.c b/sys/compat/pecoff/imgact_pecoff.c index be0359e..be376c6 100644 --- a/sys/compat/pecoff/imgact_pecoff.c +++ b/sys/compat/pecoff/imgact_pecoff.c @@ -416,7 +416,11 @@ exec_pecoff_coff_prep_zmagic(struct image_params * imgp, wp = (void *) ((char *) ap + sizeof(struct coff_aouthdr)); error = pecoff_read_from(FIRST_THREAD_IN_PROC(imgp->proc), imgp->vp, peofs + PECOFF_HDR_SIZE, (caddr_t) sh, scnsiz); + if (error) + return (error); exec_new_vmspace(imgp, &pecoff_sysvec); + if (error) + return (error); vmspace = imgp->proc->p_vmspace; for (i = 0; i < fp->f_nscns; i++) { prot = VM_PROT_WRITE; /* XXX for relocation? */ diff --git a/sys/compat/svr4/imgact_svr4.c b/sys/compat/svr4/imgact_svr4.c index a082ca3..f89afba 100644 --- a/sys/compat/svr4/imgact_svr4.c +++ b/sys/compat/svr4/imgact_svr4.c @@ -120,7 +120,9 @@ exec_svr4_imgact(imgp) /* * Destroy old process VM and create a new one (with a new stack) */ - exec_new_vmspace(imgp, &svr4_sysvec); + error = exec_new_vmspace(imgp, &svr4_sysvec); + if (error) + goto fail; vmspace = imgp->proc->p_vmspace; /* diff --git a/sys/i386/i386/machdep.c b/sys/i386/i386/machdep.c index 14b33f4..5d7a9b5 100644 --- a/sys/i386/i386/machdep.c +++ b/sys/i386/i386/machdep.c @@ -2088,7 +2088,7 @@ init386(first) * This may be done better later if it gets more high level * components in it. If so just link td->td_proc here. */ - proc_linkup(&proc0, &thread0); + proc_linkup0(&proc0, &thread0); metadata_missing = 0; if (bootinfo.bi_modulep) { diff --git a/sys/i386/i386/pmap.c b/sys/i386/i386/pmap.c index f05d7d4..2492d85 100644 --- a/sys/i386/i386/pmap.c +++ b/sys/i386/i386/pmap.c @@ -1223,11 +1223,15 @@ pmap_pinit0(pmap_t pmap) mtx_unlock_spin(&allpmaps_lock); } +static int i386_pmap_pdir_pages; +SYSCTL_INT(_vm, OID_AUTO, i386_pmap_pdir_pages, + CTLFLAG_RW, &i386_pmap_pdir_pages, 0, "Pages reserved for pmap page dirs"); + /* * Initialize a preallocated and zeroed pmap structure, * such as one in a vmspace structure. */ -void +int pmap_pinit(pmap_t pmap) { vm_page_t m, ptdpg[NPGPTD]; @@ -1244,6 +1248,12 @@ pmap_pinit(pmap_t pmap) if (pmap->pm_pdir == NULL) { pmap->pm_pdir = (pd_entry_t *)kmem_alloc_nofault(kernel_map, NBPTD); + i386_pmap_pdir_pages += NBPTD / PAGE_SIZE; + + if (pmap->pm_pdir == NULL) { + PMAP_LOCK_DESTROY(pmap); + return (0); + } #ifdef PAE pmap->pm_pdpt = uma_zalloc(pdptzone, M_WAITOK | M_ZERO); KASSERT(((vm_offset_t)pmap->pm_pdpt & @@ -1297,6 +1307,8 @@ pmap_pinit(pmap_t pmap) pmap->pm_active = 0; TAILQ_INIT(&pmap->pm_pvchunk); bzero(&pmap->pm_stats, sizeof pmap->pm_stats); + + return (1); } /* diff --git a/sys/i386/ibcs2/imgact_coff.c b/sys/i386/ibcs2/imgact_coff.c index 8a418f4..3f2feda 100644 --- a/sys/i386/ibcs2/imgact_coff.c +++ b/sys/i386/ibcs2/imgact_coff.c @@ -337,7 +337,9 @@ exec_coff_imgact(imgp) VOP_UNLOCK(imgp->vp, 0, td); - exec_new_vmspace(imgp, &ibcs2_svr3_sysvec); + error = exec_new_vmspace(imgp, &ibcs2_svr3_sysvec); + if (error) + goto fail; vmspace = imgp->proc->p_vmspace; for (i = 0; i < nscns; i++) { diff --git a/sys/i386/linux/imgact_linux.c b/sys/i386/linux/imgact_linux.c index 7d5d9df..066fa38 100644 --- a/sys/i386/linux/imgact_linux.c +++ b/sys/i386/linux/imgact_linux.c @@ -119,7 +119,9 @@ exec_linux_imgact(struct image_params *imgp) /* * Destroy old process VM and create a new one (with a new stack) */ - exec_new_vmspace(imgp, &linux_sysvec); + error = exec_new_vmspace(imgp, &linux_sysvec); + if (error) + goto fail; vmspace = imgp->proc->p_vmspace; /* diff --git a/sys/ia64/ia64/machdep.c b/sys/ia64/ia64/machdep.c index 6d79775..2ba9500 100644 --- a/sys/ia64/ia64/machdep.c +++ b/sys/ia64/ia64/machdep.c @@ -789,7 +789,7 @@ ia64_init(void) msgbufp = (struct msgbuf *)pmap_steal_memory(MSGBUF_SIZE); msgbufinit(msgbufp, MSGBUF_SIZE); - proc_linkup(&proc0, &thread0); + proc_linkup0(&proc0, &thread0); /* * Init mapping for kernel stack for proc 0 */ diff --git a/sys/ia64/ia64/pmap.c b/sys/ia64/ia64/pmap.c index 39ef9b7..7b89b16 100644 --- a/sys/ia64/ia64/pmap.c +++ b/sys/ia64/ia64/pmap.c @@ -721,6 +721,7 @@ pmap_pinit(struct pmap *pmap) pmap->pm_active = 0; TAILQ_INIT(&pmap->pm_pvlist); bzero(&pmap->pm_stats, sizeof pmap->pm_stats); + return (1); } /*************************************************** diff --git a/sys/kern/imgact_aout.c b/sys/kern/imgact_aout.c index dfd5dad..b0e9b1a 100644 --- a/sys/kern/imgact_aout.c +++ b/sys/kern/imgact_aout.c @@ -198,9 +198,11 @@ exec_aout_imgact(imgp) /* * Destroy old process VM and create a new one (with a new stack) */ - exec_new_vmspace(imgp, &aout_sysvec); + error = exec_new_vmspace(imgp, &aout_sysvec); vn_lock(imgp->vp, LK_EXCLUSIVE | LK_RETRY, td); + if (error) + return (error); /* * The vm space can be changed by exec_new_vmspace diff --git a/sys/kern/imgact_elf.c b/sys/kern/imgact_elf.c index 4ae4596..aeecd02 100644 --- a/sys/kern/imgact_elf.c +++ b/sys/kern/imgact_elf.c @@ -666,10 +666,12 @@ __CONCAT(exec_, __elfN(imgact))(struct image_params *imgp) */ VOP_UNLOCK(imgp->vp, 0, td); - exec_new_vmspace(imgp, sv); + error = exec_new_vmspace(imgp, sv); imgp->proc->p_sysent = sv; vn_lock(imgp->vp, LK_EXCLUSIVE | LK_RETRY, td); + if (error) + return (error); vmspace = imgp->proc->p_vmspace; diff --git a/sys/kern/imgact_gzip.c b/sys/kern/imgact_gzip.c index d4fb7e9..cec6169 100644 --- a/sys/kern/imgact_gzip.c +++ b/sys/kern/imgact_gzip.c @@ -239,9 +239,13 @@ do_aout_hdr(struct imgact_gzip * gz) /* * Destroy old process VM and create a new one (with a new stack) */ - exec_new_vmspace(gz->ip, &aout_sysvec); + error = exec_new_vmspace(gz->ip, &aout_sysvec); vn_lock(gz->ip->vp, LK_EXCLUSIVE | LK_RETRY, td); + if (error) { + gz->where = __LINE__; + return (error); + } vmspace = gz->ip->proc->p_vmspace; diff --git a/sys/kern/kern_exec.c b/sys/kern/kern_exec.c index 348effe..20e668e 100644 --- a/sys/kern/kern_exec.c +++ b/sys/kern/kern_exec.c @@ -914,7 +914,9 @@ exec_new_vmspace(imgp, sv) pmap_remove_pages(vmspace_pmap(vmspace)); vm_map_remove(map, vm_map_min(map), vm_map_max(map)); } else { - vmspace_exec(p, sv->sv_minuser, sv->sv_maxuser); + error = vmspace_exec(p, sv->sv_minuser, sv->sv_maxuser); + if (error) + return (error); vmspace = p->p_vmspace; map = &vmspace->vm_map; } diff --git a/sys/kern/kern_fork.c b/sys/kern/kern_fork.c index 8d0eb49..f25f3c6 100644 --- a/sys/kern/kern_fork.c +++ b/sys/kern/kern_fork.c @@ -195,6 +195,7 @@ fork1(td, flags, pages, procp) struct filedesc_to_leader *fdtol; struct thread *td2; struct sigacts *newsigacts; + struct vmspace *vm2; int error; /* Can't copy and clear. */ @@ -218,7 +219,9 @@ fork1(td, flags, pages, procp) PROC_UNLOCK(p1); } - vm_forkproc(td, NULL, NULL, flags); + error = vm_forkproc(td, NULL, NULL, NULL, flags); + if (error) + goto norfproc_fail; /* * Close all file descriptors. @@ -236,6 +239,7 @@ fork1(td, flags, pages, procp) if (flags & RFFDG) fdunshare(p1, td); +norfproc_fail: if ((p1->p_flag & P_HADTHREADS) && (flags & (RFCFDG | RFFDG))) { PROC_LOCK(p1); @@ -243,7 +247,7 @@ fork1(td, flags, pages, procp) PROC_UNLOCK(p1); } *procp = NULL; - return (0); + return (error); } /* @@ -276,6 +280,31 @@ fork1(td, flags, pages, procp) /* Allocate new proc. */ newproc = uma_zalloc(proc_zone, M_WAITOK); + if (TAILQ_EMPTY(&newproc->p_threads)) { + td2 = thread_alloc(); + if (td2 == NULL) { + error = ENOMEM; + goto fail1; + } + proc_linkup(newproc, td2); + sched_newproc(newproc, td2); + } else + td2 = FIRST_THREAD_IN_PROC(newproc); + /* Allocate and switch to an alternate kstack if specified. */ + if (pages != 0) { + if (!vm_thread_new_altkstack(td2, pages)) { + error = ENOMEM; + goto fail1; + } + } + if ((flags & RFMEM) == 0) { + vm2 = vmspace_fork(p1->p_vmspace); + if (vm2 == NULL) { + error = ENOMEM; + goto fail1; + } + } else + vm2 = NULL; #ifdef MAC mac_init_proc(newproc); #endif @@ -402,7 +431,6 @@ again: lastpid = trypid; p2 = newproc; - td2 = FIRST_THREAD_IN_PROC(newproc); p2->p_state = PRS_NEW; /* protect against others */ p2->p_pid = trypid; /* @@ -478,9 +506,6 @@ again: * Start by zeroing the section of proc that is zero-initialized, * then copy the section that is copied directly from the parent. */ - /* Allocate and switch to an alternate kstack if specified. */ - if (pages != 0) - vm_thread_new_altkstack(td2, pages); PROC_LOCK(p2); PROC_LOCK(p1); @@ -653,7 +678,7 @@ again: * Finish creating the child process. It will return via a different * execution path later. (ie: directly into user mode) */ - vm_forkproc(td, p2, td2, flags); + vm_forkproc(td, p2, td2, vm2, flags); if (flags == (RFFDG | RFPROC)) { PCPU_INC(cnt.v_forks); @@ -745,6 +770,7 @@ fail: #ifdef MAC mac_destroy_proc(newproc); #endif +fail1: uma_zfree(proc_zone, newproc); if (p1->p_flag & P_HADTHREADS) { PROC_LOCK(p1); diff --git a/sys/kern/kern_kse.c b/sys/kern/kern_kse.c index 63514c2..fa3bd7f 100644 --- a/sys/kern/kern_kse.c +++ b/sys/kern/kern_kse.c @@ -43,6 +43,7 @@ __FBSDID("$FreeBSD: src/sys/kern/kern_kse.c,v 1.234 2007/07/27 09:21:17 attilio #include #include #include +#include #include #include #include @@ -64,7 +65,7 @@ TAILQ_HEAD(, kse_upcall) zombie_upcalls = TAILQ_HEAD_INITIALIZER(zombie_upcalls); static int thread_update_usr_ticks(struct thread *td); -static void thread_alloc_spare(struct thread *td); +static int thread_alloc_spare(struct thread *td); static struct thread *thread_schedule_upcall(struct thread *td, struct kse_upcall *ku); static struct kse_upcall *upcall_alloc(void); @@ -648,6 +649,15 @@ kse_create(struct thread *td, struct kse_create_args *uap) PROC_UNLOCK(p); } + /* + * For the first call this may not have been set. + * Of course nor may it actually be needed. + * thread_schedule_upcall() will look for it. + */ + if (td->td_standin == NULL) { + if (!thread_alloc_spare(td)) + return (ENOMEM); + } /* * Even bound LWPs get a mailbox and an upcall to hold it. * XXX This should change. @@ -657,13 +667,6 @@ kse_create(struct thread *td, struct kse_create_args *uap) newku->ku_func = mbx.km_func; bcopy(&mbx.km_stack, &newku->ku_stack, sizeof(stack_t)); - /* - * For the first call this may not have been set. - * Of course nor may it actually be needed. - * thread_schedule_upcall() will look for it. - */ - if (td->td_standin == NULL) - thread_alloc_spare(td); PROC_LOCK(p); PROC_SLOCK(p); /* @@ -989,19 +992,22 @@ error: * XXX BUG.. we need to get the cr ref after the thread has * checked and chenged its own, not 6 months before... */ -void +int thread_alloc_spare(struct thread *td) { struct thread *spare; if (td->td_standin) - return; + return (1); spare = thread_alloc(); + if (spare == NULL) + return (0); td->td_standin = spare; bzero(&spare->td_startzero, __rangeof(struct thread, td_startzero, td_endzero)); spare->td_proc = td->td_proc; spare->td_ucred = crhold(td->td_ucred); + return (1); } /* @@ -1170,8 +1176,18 @@ thread_user_enter(struct thread *td) KASSERT(ku->ku_owner == td, ("wrong owner")); KASSERT(!TD_CAN_UNBIND(td), ("can unbind")); - if (td->td_standin == NULL) - thread_alloc_spare(td); + if (td->td_standin == NULL) { + if (!thread_alloc_spare(td)) { + PROC_LOCK(p); + if (kern_logsigexit) + log(LOG_INFO, + "pid %d (%s), uid %d: thread_alloc_spare failed\n", + p->p_pid, p->p_comm, + td->td_ucred ? td->td_ucred->cr_uid : -1); + sigexit(td, SIGSEGV); /* XXX ? */ + /* panic("thread_user_enter: thread_alloc_spare failed"); */ + } + } ku->ku_mflags = fuword32((void *)&ku->ku_mailbox->km_flags); tmbx = (void *)fuword((void *)&ku->ku_mailbox->km_curthread); if ((tmbx == NULL) || (tmbx == (void *)-1L) || @@ -1385,7 +1401,7 @@ out: * for when we re-enter the kernel. */ if (td->td_standin == NULL) - thread_alloc_spare(td); + thread_alloc_spare(td); /* XXX care of failure ? */ } ku->ku_mflags = 0; diff --git a/sys/kern/kern_proc.c b/sys/kern/kern_proc.c index 10f5662..cd5ec8e 100644 --- a/sys/kern/kern_proc.c +++ b/sys/kern/kern_proc.c @@ -145,20 +145,21 @@ proc_dtor(void *mem, int size, void *arg) /* INVARIANTS checks go here */ p = (struct proc *)mem; td = FIRST_THREAD_IN_PROC(p); + if (td != NULL) { #ifdef INVARIANTS - KASSERT((p->p_numthreads == 1), - ("bad number of threads in exiting process")); - KASSERT((td != NULL), ("proc_dtor: bad thread pointer")); - KASSERT(STAILQ_EMPTY(&p->p_ktr), ("proc_dtor: non-empty p_ktr")); + KASSERT((p->p_numthreads == 1), + ("bad number of threads in exiting process")); + KASSERT(STAILQ_EMPTY(&p->p_ktr), ("proc_dtor: non-empty p_ktr")); #endif - /* Dispose of an alternate kstack, if it exists. - * XXX What if there are more than one thread in the proc? - * The first thread in the proc is special and not - * freed, so you gotta do this here. - */ - if (((p->p_flag & P_KTHREAD) != 0) && (td->td_altkstack != 0)) - vm_thread_dispose_altkstack(td); + /* Dispose of an alternate kstack, if it exists. + * XXX What if there are more than one thread in the proc? + * The first thread in the proc is special and not + * freed, so you gotta do this here. + */ + if (((p->p_flag & P_KTHREAD) != 0) && (td->td_altkstack != 0)) + vm_thread_dispose_altkstack(td); + } if (p->p_ksi != NULL) KASSERT(! KSI_ONQ(p->p_ksi), ("SIGCHLD queue")); } @@ -170,17 +171,14 @@ static int proc_init(void *mem, int size, int flags) { struct proc *p; - struct thread *td; p = (struct proc *)mem; p->p_sched = (struct p_sched *)&p[1]; - td = thread_alloc(); bzero(&p->p_mtx, sizeof(struct mtx)); mtx_init(&p->p_mtx, "process lock", NULL, MTX_DEF | MTX_DUPOK); mtx_init(&p->p_slock, "process slock", NULL, MTX_SPIN | MTX_RECURSE); + TAILQ_INIT(&p->p_threads); /* all threads in proc */ p->p_stats = pstats_alloc(); - proc_linkup(p, td); - sched_newproc(p, td); return (0); } diff --git a/sys/kern/kern_sig.c b/sys/kern/kern_sig.c index 2f196cb..5adef33 100644 --- a/sys/kern/kern_sig.c +++ b/sys/kern/kern_sig.c @@ -102,7 +102,7 @@ static uma_zone_t ksiginfo_zone = NULL; struct filterops sig_filtops = { 0, filt_sigattach, filt_sigdetach, filt_signal }; -static int kern_logsigexit = 1; +int kern_logsigexit = 1; SYSCTL_INT(_kern, KERN_LOGSIGEXIT, logsigexit, CTLFLAG_RW, &kern_logsigexit, 0, "Log processes quitting on abnormal signals to syslog(3)"); diff --git a/sys/kern/kern_thr.c b/sys/kern/kern_thr.c index 07602cd..bdd90c6 100644 --- a/sys/kern/kern_thr.c +++ b/sys/kern/kern_thr.c @@ -175,6 +175,8 @@ create_thread(struct thread *td, mcontext_t *ctx, /* Initialize our td */ newtd = thread_alloc(); + if (newtd == NULL) + return (ENOMEM); /* * Try the copyout as soon as we allocate the td so we don't diff --git a/sys/kern/kern_thread.c b/sys/kern/kern_thread.c index 348db77..3d8ddab 100644 --- a/sys/kern/kern_thread.c +++ b/sys/kern/kern_thread.c @@ -114,23 +114,6 @@ thread_ctor(void *mem, int size, void *arg, int flags) struct thread *td; td = (struct thread *)mem; - td->td_state = TDS_INACTIVE; - td->td_oncpu = NOCPU; - - td->td_tid = alloc_unr(tid_unrhdr); - td->td_syscalls = 0; - - /* - * Note that td_critnest begins life as 1 because the thread is not - * running and is thereby implicitly waiting to be on the receiving - * end of a context switch. - */ - td->td_critnest = 1; - -#ifdef AUDIT - audit_thread_alloc(td); -#endif - umtx_thread_alloc(td); return (0); } @@ -140,35 +123,6 @@ thread_ctor(void *mem, int size, void *arg, int flags) static void thread_dtor(void *mem, int size, void *arg) { - struct thread *td; - - td = (struct thread *)mem; - -#ifdef INVARIANTS - /* Verify that this thread is in a safe state to free. */ - switch (td->td_state) { - case TDS_INHIBITED: - case TDS_RUNNING: - case TDS_CAN_RUN: - case TDS_RUNQ: - /* - * We must never unlink a thread that is in one of - * these states, because it is currently active. - */ - panic("bad state for thread unlinking"); - /* NOTREACHED */ - case TDS_INACTIVE: - break; - default: - panic("bad thread state"); - /* NOTREACHED */ - } -#endif -#ifdef AUDIT - audit_thread_free(td); -#endif - free_unr(tid_unrhdr, td->td_tid); - sched_newthread(td); } /* @@ -180,14 +134,7 @@ thread_init(void *mem, int size, int flags) struct thread *td; td = (struct thread *)mem; - - vm_thread_new(td, 0); - cpu_thread_setup(td); - td->td_sleepqueue = sleepq_alloc(); - td->td_turnstile = turnstile_alloc(); - td->td_sched = (struct td_sched *)&td[1]; - sched_newthread(td); - umtx_thread_init(td); + td->td_kstack = 0; return (0); } @@ -200,10 +147,15 @@ thread_fini(void *mem, int size) struct thread *td; td = (struct thread *)mem; - turnstile_free(td->td_turnstile); - sleepq_free(td->td_sleepqueue); - umtx_thread_fini(td); - vm_thread_dispose(td); + if (td->td_altkstack != 0) { + vm_thread_dispose_altkstack(td); + } + if (td->td_kstack != 0) { + turnstile_free(td->td_turnstile); + sleepq_free(td->td_sleepqueue); + umtx_thread_fini(td); + vm_thread_dispose(td); + } } /* @@ -215,10 +167,16 @@ thread_fini(void *mem, int size) * proc_init() */ void +proc_linkup0(struct proc *p, struct thread *td) +{ + TAILQ_INIT(&p->p_threads); /* all threads in proc */ + proc_linkup(p, td); +} + +void proc_linkup(struct proc *p, struct thread *td) { - TAILQ_INIT(&p->p_threads); /* all threads in proc */ #ifdef KSE TAILQ_INIT(&p->p_upcalls); /* upcall list */ #endif @@ -246,6 +204,7 @@ threadinit(void) thread_zone = uma_zcreate("THREAD", sched_sizeof_thread(), thread_ctor, thread_dtor, thread_init, thread_fini, 16 - 1, 0); +/* uma_zone_set_max(thread_zone, XXX); */ #ifdef KSE kseinit(); /* set up kse specific stuff e.g. upcall zone*/ #endif @@ -310,9 +269,45 @@ thread_reap(void) struct thread * thread_alloc(void) { + struct thread *td; thread_reap(); /* check if any zombies to get */ - return (uma_zalloc(thread_zone, M_WAITOK)); + + td = (struct thread *)uma_zalloc(thread_zone, M_WAITOK); + if (td == NULL) + return (NULL); + if (td->td_kstack == 0) { + if (!vm_thread_new(td, 0)) { + uma_zfree(thread_zone, td); + return (NULL); + } + cpu_thread_setup(td); + td->td_sleepqueue = sleepq_alloc(); + td->td_turnstile = turnstile_alloc(); + td->td_sched = (struct td_sched *)&td[1]; + sched_newthread(td); + umtx_thread_init(td); + } + + td->td_state = TDS_INACTIVE; + td->td_oncpu = NOCPU; + + td->td_tid = alloc_unr(tid_unrhdr); + td->td_syscalls = 0; + + /* + * Note that td_critnest begins life as 1 because the thread is not + * running and is thereby implicitly waiting to be on the receiving + * end of a context switch. + */ + td->td_critnest = 1; + +#ifdef AUDIT + audit_thread_alloc(td); +#endif + umtx_thread_alloc(td); + + return (td); } @@ -324,6 +319,31 @@ thread_free(struct thread *td) { cpu_thread_clean(td); +#ifdef INVARIANTS + /* Verify that this thread is in a safe state to free. */ + switch (td->td_state) { + case TDS_INHIBITED: + case TDS_RUNNING: + case TDS_CAN_RUN: + case TDS_RUNQ: + /* + * We must never unlink a thread that is in one of + * these states, because it is currently active. + */ + panic("bad state for thread unlinking"); + /* NOTREACHED */ + case TDS_INACTIVE: + break; + default: + panic("bad thread state"); + /* NOTREACHED */ + } +#endif +#ifdef AUDIT + audit_thread_free(td); +#endif + free_unr(tid_unrhdr, td->td_tid); + sched_newthread(td); uma_zfree(thread_zone, td); } diff --git a/sys/pc98/pc98/machdep.c b/sys/pc98/pc98/machdep.c index 1cf2cfa..9a8f7de 100644 --- a/sys/pc98/pc98/machdep.c +++ b/sys/pc98/pc98/machdep.c @@ -1917,7 +1917,7 @@ init386(first) * This may be done better later if it gets more high level * components in it. If so just link td->td_proc here. */ - proc_linkup(&proc0, &thread0); + proc_linkup0(&proc0, &thread0); /* * Initialize DMAC diff --git a/sys/powerpc/powerpc/machdep.c b/sys/powerpc/powerpc/machdep.c index 515539f..fcf4231 100644 --- a/sys/powerpc/powerpc/machdep.c +++ b/sys/powerpc/powerpc/machdep.c @@ -287,7 +287,7 @@ powerpc_init(u_int startkernel, u_int endkernel, u_int basekernel, void *mdp) /* * Start initializing proc0 and thread0. */ - proc_linkup(&proc0, &thread0); + proc_linkup0(&proc0, &thread0); thread0.td_frame = &frame0; /* diff --git a/sys/powerpc/powerpc/pmap_dispatch.c b/sys/powerpc/powerpc/pmap_dispatch.c index 37bff4a..a668e07 100644 --- a/sys/powerpc/powerpc/pmap_dispatch.c +++ b/sys/powerpc/powerpc/pmap_dispatch.c @@ -197,6 +197,7 @@ void pmap_pinit(pmap_t pmap) { MMU_PINIT(mmu_obj, pmap); + return (1); } void diff --git a/sys/sparc64/sparc64/machdep.c b/sys/sparc64/sparc64/machdep.c index 16bedb2..0e12ea5 100644 --- a/sys/sparc64/sparc64/machdep.c +++ b/sys/sparc64/sparc64/machdep.c @@ -399,7 +399,7 @@ sparc64_init(caddr_t mdp, u_long o1, u_long o2, u_long o3, ofw_vec_t *vec) /* * Initialize proc0 stuff (p_contested needs to be done early). */ - proc_linkup(&proc0, &thread0); + proc_linkup0(&proc0, &thread0); proc0.p_md.md_sigtramp = NULL; proc0.p_md.md_utrap = NULL; thread0.td_kstack = kstack0; diff --git a/sys/sparc64/sparc64/pmap.c b/sys/sparc64/sparc64/pmap.c index 6f27e3d..0cb16fb 100644 --- a/sys/sparc64/sparc64/pmap.c +++ b/sys/sparc64/sparc64/pmap.c @@ -1021,6 +1021,10 @@ pmap_pinit(pmap_t pm) if (pm->pm_tsb == NULL) { pm->pm_tsb = (struct tte *)kmem_alloc_nofault(kernel_map, TSB_BSIZE); + if (pm->pm_tsb == NULL) { + PMAP_LOCK_DESTROY(pm); + return (0); + } } /* @@ -1044,6 +1048,7 @@ pmap_pinit(pmap_t pm) pm->pm_context[i] = -1; pm->pm_active = 0; bzero(&pm->pm_stats, sizeof(pm->pm_stats)); + return (1); } /* diff --git a/sys/sun4v/sun4v/machdep.c b/sys/sun4v/sun4v/machdep.c index e184f2c..93b15c8 100644 --- a/sys/sun4v/sun4v/machdep.c +++ b/sys/sun4v/sun4v/machdep.c @@ -364,7 +364,7 @@ sparc64_init(caddr_t mdp, u_long o1, u_long o2, u_long o3, ofw_vec_t *vec) * Initialize proc0 stuff (p_contested needs to be done early). */ - proc_linkup(&proc0, &thread0); + proc_linkup0(&proc0, &thread0); proc0.p_md.md_sigtramp = NULL; proc0.p_md.md_utrap = NULL; frame0.tf_tstate = TSTATE_IE | TSTATE_PEF | TSTATE_PRIV; diff --git a/sys/sun4v/sun4v/pmap.c b/sys/sun4v/sun4v/pmap.c index 60f88c3..553c11b 100644 --- a/sys/sun4v/sun4v/pmap.c +++ b/sys/sun4v/sun4v/pmap.c @@ -1723,6 +1723,7 @@ pmap_pinit(pmap_t pmap) TAILQ_INIT(&pmap->pm_pvlist); PMAP_LOCK_INIT(pmap); bzero(&pmap->pm_stats, sizeof pmap->pm_stats); + return (1); } /* diff --git a/sys/sys/proc.h b/sys/sys/proc.h index 138e43e..0d5d589 100644 --- a/sys/sys/proc.h +++ b/sys/sys/proc.h @@ -841,6 +841,7 @@ void pargs_drop(struct pargs *pa); void pargs_free(struct pargs *pa); void pargs_hold(struct pargs *pa); void procinit(void); +void proc_linkup0(struct proc *p, struct thread *td); void proc_linkup(struct proc *p, struct thread *td); void proc_reparent(struct proc *child, struct proc *newparent); struct pstats *pstats_alloc(void); diff --git a/sys/sys/signalvar.h b/sys/sys/signalvar.h index f955dc7..5a81b56 100644 --- a/sys/sys/signalvar.h +++ b/sys/sys/signalvar.h @@ -299,6 +299,7 @@ struct mtx; extern int sugid_coredump; /* Sysctl variable kern.sugid_coredump */ extern struct mtx sigio_lock; +extern int kern_logsigexit; /* Sysctl variable kern.logsigexit */ /* * Lock the pointers for a sigio object in the underlying objects of diff --git a/sys/vm/pmap.h b/sys/vm/pmap.h index d05e85e..3a53726 100644 --- a/sys/vm/pmap.h +++ b/sys/vm/pmap.h @@ -114,7 +114,7 @@ void pmap_object_init_pt(pmap_t pmap, vm_offset_t addr, vm_object_t object, vm_pindex_t pindex, vm_size_t size); boolean_t pmap_page_exists_quick(pmap_t pmap, vm_page_t m); void pmap_page_init(vm_page_t m); -void pmap_pinit(pmap_t); +int pmap_pinit(pmap_t); void pmap_pinit0(pmap_t); void pmap_protect(pmap_t, vm_offset_t, vm_offset_t, vm_prot_t); void pmap_qenter(vm_offset_t, vm_page_t *, int); diff --git a/sys/vm/vm_extern.h b/sys/vm/vm_extern.h index 6c310bd..380101a 100644 --- a/sys/vm/vm_extern.h +++ b/sys/vm/vm_extern.h @@ -70,14 +70,14 @@ int vm_fault(vm_map_t, vm_offset_t, vm_prot_t, int); void vm_fault_copy_entry(vm_map_t, vm_map_t, vm_map_entry_t, vm_map_entry_t); void vm_fault_unwire(vm_map_t, vm_offset_t, vm_offset_t, boolean_t); int vm_fault_wire(vm_map_t, vm_offset_t, vm_offset_t, boolean_t, boolean_t); -void vm_forkproc(struct thread *, struct proc *, struct thread *, int); +int vm_forkproc(struct thread *, struct proc *, struct thread *, struct vmspace *, int); void vm_waitproc(struct proc *); int vm_mmap(vm_map_t, vm_offset_t *, vm_size_t, vm_prot_t, vm_prot_t, int, objtype_t, void *, vm_ooffset_t); void vm_set_page_size(void); struct vmspace *vmspace_alloc(vm_offset_t, vm_offset_t); struct vmspace *vmspace_fork(struct vmspace *); -void vmspace_exec(struct proc *, vm_offset_t, vm_offset_t); -void vmspace_unshare(struct proc *); +int vmspace_exec(struct proc *, vm_offset_t, vm_offset_t); +int vmspace_unshare(struct proc *); void vmspace_exit(struct thread *); struct vmspace *vmspace_acquire_ref(struct proc *); void vmspace_free(struct vmspace *); @@ -92,8 +92,8 @@ struct sf_buf *vm_imgact_map_page(vm_object_t object, vm_ooffset_t offset); void vm_imgact_unmap_page(struct sf_buf *sf); void vm_thread_dispose(struct thread *td); void vm_thread_dispose_altkstack(struct thread *td); -void vm_thread_new(struct thread *td, int pages); -void vm_thread_new_altkstack(struct thread *td, int pages); +int vm_thread_new(struct thread *td, int pages); +int vm_thread_new_altkstack(struct thread *td, int pages); void vm_thread_swapin(struct thread *td); void vm_thread_swapout(struct thread *td); #endif /* _KERNEL */ diff --git a/sys/vm/vm_glue.c b/sys/vm/vm_glue.c index ee0a019..7f84931 100644 --- a/sys/vm/vm_glue.c +++ b/sys/vm/vm_glue.c @@ -315,12 +315,16 @@ vm_imgact_unmap_page(struct sf_buf *sf) #define KSTACK_MAX_PAGES 32 #endif +static int thread_kstack_pages; +SYSCTL_INT(_vm, OID_AUTO, thread_kstack_pages, + CTLFLAG_RW, &thread_kstack_pages, 0, "Pages reserved for thread kernel stacks"); + /* * Create the kernel stack (including pcb for i386) for a new thread. * This routine directly affects the fork perf for a process and * create performance for a thread. */ -void +int vm_thread_new(struct thread *td, int pages) { vm_object_t ksobj; @@ -337,18 +341,23 @@ vm_thread_new(struct thread *td, int pages) * Allocate an object for the kstack. */ ksobj = vm_object_allocate(OBJT_DEFAULT, pages); - td->td_kstack_obj = ksobj; /* * Get a kernel virtual address for this thread's kstack. */ ks = kmem_alloc_nofault(kernel_map, (pages + KSTACK_GUARD_PAGES) * PAGE_SIZE); - if (ks == 0) - panic("vm_thread_new: kstack allocation failed"); + if (ks == 0) { + printf("vm_thread_new: kstack allocation failed\n"); + vm_object_deallocate(ksobj); + return (0); + } + thread_kstack_pages += pages + KSTACK_GUARD_PAGES; + if (KSTACK_GUARD_PAGES != 0) { pmap_qremove(ks, KSTACK_GUARD_PAGES); ks += KSTACK_GUARD_PAGES * PAGE_SIZE; } + td->td_kstack_obj = ksobj; td->td_kstack = ks; /* * Knowing the number of pages allocated is useful when you @@ -371,6 +380,7 @@ vm_thread_new(struct thread *td, int pages) } VM_OBJECT_UNLOCK(ksobj); pmap_qenter(ks, ma, pages); + return (1); } /* @@ -402,6 +412,8 @@ vm_thread_dispose(struct thread *td) vm_object_deallocate(ksobj); kmem_free(kernel_map, ks - (KSTACK_GUARD_PAGES * PAGE_SIZE), (pages + KSTACK_GUARD_PAGES) * PAGE_SIZE); + thread_kstack_pages -= pages + KSTACK_GUARD_PAGES; + td->td_kstack = 0; } /* @@ -467,7 +479,7 @@ vm_thread_swapin(struct thread *td) /* * Set up a variable-sized alternate kstack. */ -void +int vm_thread_new_altkstack(struct thread *td, int pages) { @@ -475,7 +487,7 @@ vm_thread_new_altkstack(struct thread *td, int pages) td->td_altkstack_obj = td->td_kstack_obj; td->td_altkstack_pages = td->td_kstack_pages; - vm_thread_new(td, pages); + return (vm_thread_new(td, pages)); } /* @@ -503,14 +515,16 @@ vm_thread_dispose_altkstack(struct thread *td) * ready to run. The new process is set up so that it returns directly * to user mode to avoid stack copying and relocation problems. */ -void -vm_forkproc(td, p2, td2, flags) +int +vm_forkproc(td, p2, td2, vm2, flags) struct thread *td; struct proc *p2; struct thread *td2; + struct vmspace *vm2; int flags; { struct proc *p1 = td->td_proc; + int error; if ((flags & RFPROC) == 0) { /* @@ -520,11 +534,13 @@ vm_forkproc(td, p2, td2, flags) */ if ((flags & RFMEM) == 0) { if (p1->p_vmspace->vm_refcnt > 1) { - vmspace_unshare(p1); + error = vmspace_unshare(p1); + if (error) + return (error); } } cpu_fork(td, p2, td2, flags); - return; + return (0); } if (flags & RFMEM) { @@ -537,7 +553,7 @@ vm_forkproc(td, p2, td2, flags) } if ((flags & RFMEM) == 0) { - p2->p_vmspace = vmspace_fork(p1->p_vmspace); + p2->p_vmspace = vm2; if (p1->p_vmspace->vm_shm) shmfork(p1, p2); } @@ -547,6 +563,7 @@ vm_forkproc(td, p2, td2, flags) * and make the child ready to run. */ cpu_fork(td, p2, td2, flags); + return (0); } /* diff --git a/sys/vm/vm_map.c b/sys/vm/vm_map.c index fdff905..9c1dab4 100644 --- a/sys/vm/vm_map.c +++ b/sys/vm/vm_map.c @@ -197,7 +197,6 @@ vmspace_zfini(void *mem, int size) struct vmspace *vm; vm = (struct vmspace *)mem; - pmap_release(vmspace_pmap(vm)); vm_map_zfini(&vm->vm_map, sizeof(vm->vm_map)); } @@ -209,7 +208,6 @@ vmspace_zinit(void *mem, int size, int flags) vm = (struct vmspace *)mem; (void)vm_map_zinit(&vm->vm_map, sizeof(vm->vm_map), flags); - pmap_pinit(vmspace_pmap(vm)); return (0); } @@ -272,6 +270,10 @@ vmspace_alloc(min, max) struct vmspace *vm; vm = uma_zalloc(vmspace_zone, M_WAITOK); + if (!pmap_pinit(vmspace_pmap(vm))) { + uma_zfree(vmspace_zone, vm); + return (NULL); + } CTR1(KTR_VM, "vmspace_alloc: %p", vm); _vm_map_init(&vm->vm_map, min, max); vm->vm_map.pmap = vmspace_pmap(vm); /* XXX */ @@ -321,6 +323,7 @@ vmspace_dofree(struct vmspace *vm) (void)vm_map_remove(&vm->vm_map, vm->vm_map.min_offset, vm->vm_map.max_offset); + pmap_release(vmspace_pmap(vm)); uma_zfree(vmspace_zone, vm); } @@ -2586,6 +2589,8 @@ vmspace_fork(struct vmspace *vm1) vm_map_lock(old_map); vm2 = vmspace_alloc(old_map->min_offset, old_map->max_offset); + if (vm2 == NULL) + goto unlock_and_return; vm2->vm_taddr = vm1->vm_taddr; vm2->vm_daddr = vm1->vm_daddr; vm2->vm_maxsaddr = vm1->vm_maxsaddr; @@ -2677,7 +2682,7 @@ vmspace_fork(struct vmspace *vm1) } old_entry = old_entry->next; } - +unlock_and_return: vm_map_unlock(old_map); return (vm2); @@ -3005,13 +3010,15 @@ Retry: * Unshare the specified VM space for exec. If other processes are * mapped to it, then create a new one. The new vmspace is null. */ -void +int vmspace_exec(struct proc *p, vm_offset_t minuser, vm_offset_t maxuser) { struct vmspace *oldvmspace = p->p_vmspace; struct vmspace *newvmspace; newvmspace = vmspace_alloc(minuser, maxuser); + if (newvmspace == NULL) + return (ENOMEM); newvmspace->vm_swrss = oldvmspace->vm_swrss; /* * This code is written like this for prototype purposes. The @@ -3026,27 +3033,31 @@ vmspace_exec(struct proc *p, vm_offset_t minuser, vm_offset_t maxuser) if (p == curthread->td_proc) /* XXXKSE ? */ pmap_activate(curthread); vmspace_free(oldvmspace); + return (0); } /* * Unshare the specified VM space for forcing COW. This * is called by rfork, for the (RFMEM|RFPROC) == 0 case. */ -void +int vmspace_unshare(struct proc *p) { struct vmspace *oldvmspace = p->p_vmspace; struct vmspace *newvmspace; if (oldvmspace->vm_refcnt == 1) - return; + return (0); newvmspace = vmspace_fork(oldvmspace); + if (newvmspace == NULL) + return (ENOMEM); PROC_VMSPACE_LOCK(p); p->p_vmspace = newvmspace; PROC_VMSPACE_UNLOCK(p); if (p == curthread->td_proc) /* XXXKSE ? */ pmap_activate(curthread); vmspace_free(oldvmspace); + return (0); } /*