svn commit: r351175 - head/sys/kern

Mateusz Guzik mjg at FreeBSD.org
Sat Aug 17 18:19:50 UTC 2019


Author: mjg
Date: Sat Aug 17 18:19:49 2019
New Revision: 351175
URL: https://svnweb.freebsd.org/changeset/base/351175

Log:
  fork: rework locking around do_fork
  
  - move allproc lock into the func, it is of no use prior to it
  - the code would lock p1 and p2 while holding allproc to partially
  construct it after it gets added to the list. instead we can do the
  work prior to adding anything.
  - protect lastpid with procid_lock
  
  As a side effect we do less work with allproc held.
  
  Sponsored by:	The FreeBSD Foundation

Modified:
  head/sys/kern/kern_fork.c

Modified: head/sys/kern/kern_fork.c
==============================================================================
--- head/sys/kern/kern_fork.c	Sat Aug 17 17:56:43 2019	(r351174)
+++ head/sys/kern/kern_fork.c	Sat Aug 17 18:19:49 2019	(r351175)
@@ -246,17 +246,24 @@ static int
 fork_findpid(int flags)
 {
 	pid_t result;
-	int trypid;
+	int trypid, random;
 
+	/*
+	 * Avoid calling arc4random with procid_lock held.
+	 */
+	random = 0;
+	if (__predict_false(randompid))
+		random = arc4random() % randompid;
+
+	mtx_lock(&procid_lock);
+
 	trypid = lastpid + 1;
 	if (flags & RFHIGHPID) {
 		if (trypid < 10)
 			trypid = 10;
 	} else {
-		if (randompid)
-			trypid += arc4random() % randompid;
+		trypid += random;
 	}
-	mtx_lock(&procid_lock);
 retry:
 	if (trypid >= pid_max)
 		trypid = 2;
@@ -341,33 +348,16 @@ do_fork(struct thread *td, struct fork_req *fr, struct
     struct vmspace *vm2, struct file *fp_procdesc)
 {
 	struct proc *p1, *pptr;
-	int trypid;
 	struct filedesc *fd;
 	struct filedesc_to_leader *fdtol;
 	struct sigacts *newsigacts;
 
-	sx_assert(&allproc_lock, SX_XLOCKED);
-
 	p1 = td->td_proc;
 
-	trypid = fork_findpid(fr->fr_flags);
-	p2->p_state = PRS_NEW;		/* protect against others */
-	p2->p_pid = trypid;
-	AUDIT_ARG_PID(p2->p_pid);
-	LIST_INSERT_HEAD(&allproc, p2, p_list);
-	allproc_gen++;
-	sx_xlock(PIDHASHLOCK(p2->p_pid));
-	LIST_INSERT_HEAD(PIDHASH(p2->p_pid), p2, p_hash);
-	sx_xunlock(PIDHASHLOCK(p2->p_pid));
-	PROC_LOCK(p2);
 	PROC_LOCK(p1);
-
-	sx_xunlock(&allproc_lock);
-
 	bcopy(&p1->p_startcopy, &p2->p_startcopy,
 	    __rangeof(struct proc, p_startcopy, p_endcopy));
 	pargs_hold(p2->p_args);
-
 	PROC_UNLOCK(p1);
 
 	bzero(&p2->p_startzero,
@@ -376,8 +366,19 @@ do_fork(struct thread *td, struct fork_req *fr, struct
 	/* Tell the prison that we exist. */
 	prison_proc_hold(p2->p_ucred->cr_prison);
 
-	PROC_UNLOCK(p2);
+	p2->p_state = PRS_NEW;		/* protect against others */
+	p2->p_pid = fork_findpid(fr->fr_flags);
+	AUDIT_ARG_PID(p2->p_pid);
 
+	sx_xlock(&allproc_lock);
+	LIST_INSERT_HEAD(&allproc, p2, p_list);
+	allproc_gen++;
+	sx_xunlock(&allproc_lock);
+
+	sx_xlock(PIDHASHLOCK(p2->p_pid));
+	LIST_INSERT_HEAD(PIDHASH(p2->p_pid), p2, p_hash);
+	sx_xunlock(PIDHASHLOCK(p2->p_pid));
+
 	tidhash_add(td2);
 
 	/*
@@ -969,8 +970,6 @@ fork1(struct thread *td, struct fork_req *fr)
 	newproc->p_klist = knlist_alloc(&newproc->p_mtx);
 	STAILQ_INIT(&newproc->p_ktr);
 
-	sx_xlock(&allproc_lock);
-
 	/*
 	 * Increment the count of procs running with this uid. Don't allow
 	 * a nonprivileged user to exceed their current limit.
@@ -986,7 +985,6 @@ fork1(struct thread *td, struct fork_req *fr)
 	return (0);
 fail0:
 	error = EAGAIN;
-	sx_xunlock(&allproc_lock);
 #ifdef MAC
 	mac_proc_destroy(newproc);
 #endif


More information about the svn-src-all mailing list