diff --git a/sys/kern/kern_exit.c b/sys/kern/kern_exit.c index 53ae14ec9010..6215ecb1a5c9 100644 --- a/sys/kern/kern_exit.c +++ b/sys/kern/kern_exit.c @@ -963,9 +963,7 @@ proc_reap(struct thread *td, struct proc *p, int *status, int options) KASSERT(FIRST_THREAD_IN_PROC(p), ("proc_reap: no residual thread!")); uma_zfree(proc_zone, p); - sx_xlock(&allproc_lock); - nprocs--; - sx_xunlock(&allproc_lock); + atomic_add_int(&nprocs, -1); } static int diff --git a/sys/kern/kern_fork.c b/sys/kern/kern_fork.c index 9256f3949c3a..0e28072f010f 100644 --- a/sys/kern/kern_fork.c +++ b/sys/kern/kern_fork.c @@ -382,12 +382,6 @@ do_fork(struct thread *td, int flags, struct proc *p2, struct thread *td2, p2_held = 0; p1 = td->td_proc; - /* - * Increment the nprocs resource before blocking can occur. There - * are hard-limits as to the number of processes that can run. - */ - nprocs++; - trypid = fork_findpid(flags); sx_sunlock(&proctree_lock); @@ -771,16 +765,14 @@ int fork1(struct thread *td, int flags, int pages, struct proc **procp, int *procdescp, int pdflags, struct filecaps *fcaps) { - struct proc *p1; - struct proc *newproc; - int ok; + struct proc *p1, *newproc; struct thread *td2; struct vmspace *vm2; + struct file *fp_procdesc; vm_ooffset_t mem_charged; - int error; + int error, nprocs_new, ok; static int curfail; static struct timeval lastfail; - struct file *fp_procdesc = NULL; /* Check for the undefined or unimplemented flags. */ if ((flags & ~(RFFLAGS | RFTSIGFLAGS(RFTSIGMASK))) != 0) @@ -819,6 +811,35 @@ fork1(struct thread *td, int flags, int pages, struct proc **procp, return (fork_norfproc(td, flags)); } + fp_procdesc = NULL; + newproc = NULL; + vm2 = NULL; + + /* + * Increment the nprocs resource before allocations occur. + * Although process entries are dynamically created, we still + * keep a global limit on the maximum number we will + * create. There are hard-limits as to the number of processes + * that can run, established by the KVA and memory usage for + * the process data. + * + * Don't allow a nonprivileged user to use the last ten + * processes; don't let root exceed the limit. + */ + nprocs_new = atomic_fetchadd_int(&nprocs, 1) + 1; + if ((nprocs_new >= maxproc - 10 && priv_check_cred(td->td_ucred, + PRIV_MAXPROC, 0) != 0) || nprocs_new >= maxproc) { + error = EAGAIN; + sx_xlock(&allproc_lock); + if (ppsratecheck(&lastfail, &curfail, 1)) { + printf("maxproc limit exceeded by uid %u (pid %d); " + "see tuning(7) and login.conf(5)\n", + td->td_ucred->cr_ruid, p1->p_pid); + } + sx_xunlock(&allproc_lock); + goto fail2; + } + /* * If required, create a process descriptor in the parent first; we * will abandon it if something goes wrong. We don't finit() until @@ -831,7 +852,6 @@ fork1(struct thread *td, int flags, int pages, struct proc **procp, } mem_charged = 0; - vm2 = NULL; if (pages == 0) pages = kstack_pages; /* Allocate new proc. */ @@ -898,20 +918,7 @@ fork1(struct thread *td, int flags, int pages, struct proc **procp, /* We have to lock the process tree while we look for a pid. */ sx_slock(&proctree_lock); - - /* - * Although process entries are dynamically created, we still keep - * a global limit on the maximum number we will create. Don't allow - * a nonprivileged user to use the last ten processes; don't let root - * exceed the limit. The variable nprocs is the current number of - * processes, maxproc is the limit. - */ sx_xlock(&allproc_lock); - if ((nprocs >= maxproc - 10 && priv_check_cred(td->td_ucred, - PRIV_MAXPROC, 0) != 0) || nprocs >= maxproc) { - error = EAGAIN; - goto fail; - } /* * Increment the count of procs running with this uid. Don't allow @@ -942,11 +949,7 @@ fork1(struct thread *td, int flags, int pages, struct proc **procp, } error = EAGAIN; -fail: sx_sunlock(&proctree_lock); - if (ppsratecheck(&lastfail, &curfail, 1)) - printf("maxproc limit exceeded by uid %u (pid %d); see tuning(7) and login.conf(5)\n", - td->td_ucred->cr_ruid, p1->p_pid); sx_xunlock(&allproc_lock); #ifdef MAC mac_proc_destroy(newproc); @@ -963,6 +966,7 @@ fork1(struct thread *td, int flags, int pages, struct proc **procp, fdclose(td, fp_procdesc, *procdescp); fdrop(fp_procdesc, td); } + atomic_add_int(&nprocs, -1); pause("fork", hz / 2); return (error); }