Module Name:    src
Committed By:   ad
Date:           Tue Apr 21 21:42:47 UTC 2020

Modified Files:
        src/sys/compat/netbsd32: netbsd32_fs.c
        src/sys/kern: kern_exec.c kern_proc.c uipc_usrreq.c vfs_cwd.c
            vfs_getcwd.c vfs_lookup.c vfs_mount.c vfs_subr.c vfs_syscalls.c
        src/sys/miscfs/procfs: procfs_vnops.c
        src/sys/sys: filedesc.h

Log Message:
Revert the changes made in February to make cwdinfo use mostly lockless,
which relied on taking extra vnode refs.

Having benchmarked various experimental changes over the past few months it
seems that it's better to avoid vnode refs as much as possible.  cwdi_lock
as a RW lock already did that to some extent for getcwd() and will permit
the same for namei() too.


To generate a diff of this commit:
cvs rdiff -u -r1.87 -r1.88 src/sys/compat/netbsd32/netbsd32_fs.c
cvs rdiff -u -r1.497 -r1.498 src/sys/kern/kern_exec.c
cvs rdiff -u -r1.245 -r1.246 src/sys/kern/kern_proc.c
cvs rdiff -u -r1.197 -r1.198 src/sys/kern/uipc_usrreq.c
cvs rdiff -u -r1.5 -r1.6 src/sys/kern/vfs_cwd.c
cvs rdiff -u -r1.58 -r1.59 src/sys/kern/vfs_getcwd.c
cvs rdiff -u -r1.217 -r1.218 src/sys/kern/vfs_lookup.c
cvs rdiff -u -r1.80 -r1.81 src/sys/kern/vfs_mount.c
cvs rdiff -u -r1.485 -r1.486 src/sys/kern/vfs_subr.c
cvs rdiff -u -r1.546 -r1.547 src/sys/kern/vfs_syscalls.c
cvs rdiff -u -r1.210 -r1.211 src/sys/miscfs/procfs/procfs_vnops.c
cvs rdiff -u -r1.66 -r1.67 src/sys/sys/filedesc.h

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/compat/netbsd32/netbsd32_fs.c
diff -u src/sys/compat/netbsd32/netbsd32_fs.c:1.87 src/sys/compat/netbsd32/netbsd32_fs.c:1.88
--- src/sys/compat/netbsd32/netbsd32_fs.c:1.87	Sun Feb 23 22:14:03 2020
+++ src/sys/compat/netbsd32/netbsd32_fs.c	Tue Apr 21 21:42:47 2020
@@ -1,4 +1,4 @@
-/*	$NetBSD: netbsd32_fs.c,v 1.87 2020/02/23 22:14:03 ad Exp $	*/
+/*	$NetBSD: netbsd32_fs.c,v 1.88 2020/04/21 21:42:47 ad Exp $	*/
 
 /*
  * Copyright (c) 1998, 2001 Matthew R. Green
@@ -27,7 +27,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: netbsd32_fs.c,v 1.87 2020/02/23 22:14:03 ad Exp $");
+__KERNEL_RCSID(0, "$NetBSD: netbsd32_fs.c,v 1.88 2020/04/21 21:42:47 ad Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -740,12 +740,13 @@ netbsd32___getcwd(struct lwp *l, const s
 		syscallarg(char *) bufp;
 		syscallarg(size_t) length;
 	} */
+	struct proc *p = l->l_proc;
 	int     error;
 	char   *path;
 	char   *bp, *bend;
 	int     len = (int)SCARG(uap, length);
 	int	lenused;
-	struct	vnode *dvp;
+	struct	cwdinfo *cwdi;
 
 	if (len > MAXPATHLEN*4)
 		len = MAXPATHLEN*4;
@@ -763,10 +764,11 @@ netbsd32___getcwd(struct lwp *l, const s
 	 * limit it to N/2 vnodes for an N byte buffer.
 	 */
 #define GETCWD_CHECK_ACCESS 0x0001
-	dvp = cwdcdir();
-	error = getcwd_common (dvp, NULL, &bp, path, len/2,
+	cwdi = p->p_cwdi;
+	rw_enter(&cwdi->cwdi_lock, RW_READER);
+	error = getcwd_common (cwdi->cwdi_cdir, NULL, &bp, path, len/2,
 			       GETCWD_CHECK_ACCESS, l);
-	vrele(dvp);
+	rw_exit(&cwdi->cwdi_lock);
 
 	if (error)
 		goto out;

Index: src/sys/kern/kern_exec.c
diff -u src/sys/kern/kern_exec.c:1.497 src/sys/kern/kern_exec.c:1.498
--- src/sys/kern/kern_exec.c:1.497	Sun Apr 19 20:31:59 2020
+++ src/sys/kern/kern_exec.c	Tue Apr 21 21:42:47 2020
@@ -1,4 +1,4 @@
-/*	$NetBSD: kern_exec.c,v 1.497 2020/04/19 20:31:59 thorpej Exp $	*/
+/*	$NetBSD: kern_exec.c,v 1.498 2020/04/21 21:42:47 ad Exp $	*/
 
 /*-
  * Copyright (c) 2008, 2019, 2020 The NetBSD Foundation, Inc.
@@ -62,7 +62,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: kern_exec.c,v 1.497 2020/04/19 20:31:59 thorpej Exp $");
+__KERNEL_RCSID(0, "$NetBSD: kern_exec.c,v 1.498 2020/04/21 21:42:47 ad Exp $");
 
 #include "opt_exec.h"
 #include "opt_execfmt.h"
@@ -672,7 +672,7 @@ exec_makepathbuf(struct lwp *l, const ch
 	char *path, *bp;
 	size_t len, tlen;
 	int error;
-	struct vnode *dvp;
+	struct cwdinfo *cwdi;
 
 	path = PNBUF_GET();
 	if (seg == UIO_SYSSPACE) {
@@ -698,10 +698,11 @@ exec_makepathbuf(struct lwp *l, const ch
 	memmove(bp, path, len);
 	*(--bp) = '/';
 
-	dvp = cwdcdir();
-	error = getcwd_common(dvp, NULL, &bp, path, MAXPATHLEN / 2,
+	cwdi = l->l_proc->p_cwdi;
+	rw_enter(&cwdi->cwdi_lock, RW_READER);
+	error = getcwd_common(cwdi->cwdi_cdir, NULL, &bp, path, MAXPATHLEN / 2,
 	    GETCWD_CHECK_ACCESS, l);
-	vrele(dvp);
+	rw_exit(&cwdi->cwdi_lock);
 
 	if (error)
 		goto err;
@@ -1118,7 +1119,6 @@ static void
 emulexec(struct lwp *l, struct exec_package *epp)
 {
 	struct proc		*p = l->l_proc;
-	struct cwdinfo		*cwdi;
 
 	/* The emulation root will usually have been found when we looked
 	 * for the elf interpreter (or similar), if not look now. */
@@ -1127,10 +1127,9 @@ emulexec(struct lwp *l, struct exec_pack
 		emul_find_root(l, epp);
 
 	/* Any old emulation root got removed by fdcloseexec */
-	KASSERT(p == curproc);
-	cwdi = cwdenter(RW_WRITER);
-	cwdi->cwdi_edir = epp->ep_emul_root;
-	cwdexit(cwdi);
+	rw_enter(&p->p_cwdi->cwdi_lock, RW_WRITER);
+	p->p_cwdi->cwdi_edir = epp->ep_emul_root;
+	rw_exit(&p->p_cwdi->cwdi_lock);
 	epp->ep_emul_root = NULL;
 	if (epp->ep_interp != NULL)
 		vrele(epp->ep_interp);

Index: src/sys/kern/kern_proc.c
diff -u src/sys/kern/kern_proc.c:1.245 src/sys/kern/kern_proc.c:1.246
--- src/sys/kern/kern_proc.c:1.245	Mon Apr 20 16:32:03 2020
+++ src/sys/kern/kern_proc.c	Tue Apr 21 21:42:47 2020
@@ -1,4 +1,4 @@
-/*	$NetBSD: kern_proc.c,v 1.245 2020/04/20 16:32:03 maxv Exp $	*/
+/*	$NetBSD: kern_proc.c,v 1.246 2020/04/21 21:42:47 ad Exp $	*/
 
 /*-
  * Copyright (c) 1999, 2006, 2007, 2008, 2020 The NetBSD Foundation, Inc.
@@ -62,7 +62,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: kern_proc.c,v 1.245 2020/04/20 16:32:03 maxv Exp $");
+__KERNEL_RCSID(0, "$NetBSD: kern_proc.c,v 1.246 2020/04/21 21:42:47 ad Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_kstack.h"
@@ -106,7 +106,6 @@ __KERNEL_RCSID(0, "$NetBSD: kern_proc.c,
 #include <sys/exec.h>
 #include <sys/cpu.h>
 #include <sys/compat_stub.h>
-#include <sys/vnode.h>
 
 #include <uvm/uvm_extern.h>
 #include <uvm/uvm.h>
@@ -477,7 +476,7 @@ proc0_init(void)
 	p->p_cred = cred0;
 
 	/* Create the CWD info. */
-	mutex_init(&cwdi0.cwdi_lock, MUTEX_DEFAULT, IPL_NONE);
+	rw_init(&cwdi0.cwdi_lock);
 
 	/* Create the limits structures. */
 	mutex_init(&limit0.pl_lock, MUTEX_DEFAULT, IPL_NONE);
@@ -2601,7 +2600,7 @@ fill_cwd(struct lwp *l, pid_t pid, void 
 	struct proc *p;
 	char *path;
 	char *bp, *bend;
-	const struct cwdinfo *cwdi;
+	struct cwdinfo *cwdi;
 	struct vnode *vp;
 	size_t len, lenused;
 
@@ -2616,12 +2615,11 @@ fill_cwd(struct lwp *l, pid_t pid, void 
 	bend = bp;
 	*(--bp) = '\0';
 
-	cwdi = cwdlock(p);
+	cwdi = p->p_cwdi;
+	rw_enter(&cwdi->cwdi_lock, RW_READER);
 	vp = cwdi->cwdi_cdir;
-	vref(vp);
-	cwdunlock(p);
 	error = getcwd_common(vp, NULL, &bp, path, len/2, 0, l);
-	vrele(vp);
+	rw_exit(&cwdi->cwdi_lock);
 
 	if (error)
 		goto out;

Index: src/sys/kern/uipc_usrreq.c
diff -u src/sys/kern/uipc_usrreq.c:1.197 src/sys/kern/uipc_usrreq.c:1.198
--- src/sys/kern/uipc_usrreq.c:1.197	Sun Feb 23 22:14:03 2020
+++ src/sys/kern/uipc_usrreq.c	Tue Apr 21 21:42:47 2020
@@ -1,4 +1,4 @@
-/*	$NetBSD: uipc_usrreq.c,v 1.197 2020/02/23 22:14:03 ad Exp $	*/
+/*	$NetBSD: uipc_usrreq.c,v 1.198 2020/04/21 21:42:47 ad Exp $	*/
 
 /*-
  * Copyright (c) 1998, 2000, 2004, 2008, 2009, 2020 The NetBSD Foundation, Inc.
@@ -96,7 +96,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: uipc_usrreq.c,v 1.197 2020/02/23 22:14:03 ad Exp $");
+__KERNEL_RCSID(0, "$NetBSD: uipc_usrreq.c,v 1.198 2020/04/21 21:42:47 ad Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_compat_netbsd.h"
@@ -1395,7 +1395,6 @@ unp_externalize(struct mbuf *rights, str
 {
 	struct cmsghdr * const cm = mtod(rights, struct cmsghdr *);
 	struct proc * const p = l->l_proc;
-	struct vnode *rvp = NULL;
 	file_t **rp;
 	int error = 0;
 
@@ -1405,11 +1404,9 @@ unp_externalize(struct mbuf *rights, str
 		goto noop;
 
 	int * const fdp = kmem_alloc(nfds * sizeof(int), KM_SLEEP);
-
-	KASSERT(l == curlwp);
+	rw_enter(&p->p_cwdi->cwdi_lock, RW_READER);
 
 	/* Make sure the recipient should be able to see the files.. */
-	rvp = cwdrdir();
 	rp = (file_t **)CMSG_DATA(cm);
 	for (size_t i = 0; i < nfds; i++) {
 		file_t * const fp = *rp++;
@@ -1423,15 +1420,16 @@ unp_externalize(struct mbuf *rights, str
 		 * sure it's inside the subtree we're allowed
 		 * to access.
 		 */
-		if (rvp != NULL && fp->f_type == DTYPE_VNODE) {
+		if (p->p_cwdi->cwdi_rdir != NULL && fp->f_type == DTYPE_VNODE) {
 			vnode_t *vp = fp->f_vnode;
-			if ((vp->v_type == VDIR) && !vn_isunder(vp, rvp, l)) {
+			if ((vp->v_type == VDIR) &&
+			    !vn_isunder(vp, p->p_cwdi->cwdi_rdir, l)) {
 				error = EPERM;
 				goto out;
 			}
 		}
 	}
-	
+
  restart:
 	/*
 	 * First loop -- allocate file descriptor table slots for the
@@ -1508,6 +1506,7 @@ unp_externalize(struct mbuf *rights, str
 		cm->cmsg_len = CMSG_LEN(0);
 		rights->m_len = CMSG_SPACE(0);
 	}
+	rw_exit(&p->p_cwdi->cwdi_lock);
 	kmem_free(fdp, nfds * sizeof(int));
 
  noop:
@@ -1517,10 +1516,6 @@ unp_externalize(struct mbuf *rights, str
 	KASSERT(cm->cmsg_len <= rights->m_len);
 	memset(&mtod(rights, char *)[cm->cmsg_len], 0, rights->m_len -
 	    cm->cmsg_len);
-
-	/* Async release since in the networking code. */
-	if (rvp != NULL)
-		vrele_async(rvp);
 	return error;
 }
 

Index: src/sys/kern/vfs_cwd.c
diff -u src/sys/kern/vfs_cwd.c:1.5 src/sys/kern/vfs_cwd.c:1.6
--- src/sys/kern/vfs_cwd.c:1.5	Sun Feb 23 22:14:03 2020
+++ src/sys/kern/vfs_cwd.c	Tue Apr 21 21:42:47 2020
@@ -1,4 +1,4 @@
-/*	$NetBSD: vfs_cwd.c,v 1.5 2020/02/23 22:14:03 ad Exp $	*/
+/*	$NetBSD: vfs_cwd.c,v 1.6 2020/04/21 21:42:47 ad Exp $	*/
 
 /*-
  * Copyright (c) 2008, 2020 The NetBSD Foundation, Inc.
@@ -31,14 +31,13 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: vfs_cwd.c,v 1.5 2020/02/23 22:14:03 ad Exp $");
+__KERNEL_RCSID(0, "$NetBSD: vfs_cwd.c,v 1.6 2020/04/21 21:42:47 ad Exp $");
 
 #include <sys/param.h>
 #include <sys/atomic.h>
 #include <sys/filedesc.h>
 #include <sys/proc.h>
 #include <sys/vnode.h>
-#include <sys/xcall.h>
 
 static int	cwdi_ctor(void *, void *, int);
 static void	cwdi_dtor(void *, void *);
@@ -65,8 +64,9 @@ cwdinit(void)
 	struct cwdinfo *copy;
 
 	cwdi = pool_cache_get(cwdi_cache, PR_WAITOK);
+	copy = curproc->p_cwdi;
 
-	copy = cwdenter(RW_READER);
+	rw_enter(&copy->cwdi_lock, RW_READER);
 	cwdi->cwdi_cdir = copy->cwdi_cdir;
 	if (cwdi->cwdi_cdir)
 		vref(cwdi->cwdi_cdir);
@@ -78,7 +78,7 @@ cwdinit(void)
 		vref(cwdi->cwdi_edir);
 	cwdi->cwdi_cmask = copy->cwdi_cmask;
 	cwdi->cwdi_refcnt = 1;
-	cwdexit(copy);
+	rw_exit(&copy->cwdi_lock);
 
 	return (cwdi);
 }
@@ -88,7 +88,7 @@ cwdi_ctor(void *arg, void *obj, int flag
 {
 	struct cwdinfo *cwdi = obj;
 
-	mutex_init(&cwdi->cwdi_lock, MUTEX_DEFAULT, IPL_NONE);
+	rw_init(&cwdi->cwdi_lock);
 
 	return 0;
 }
@@ -98,7 +98,7 @@ cwdi_dtor(void *arg, void *obj)
 {
 	struct cwdinfo *cwdi = obj;
 
-	mutex_destroy(&cwdi->cwdi_lock);
+	rw_destroy(&cwdi->cwdi_lock);
 }
 
 /*
@@ -159,120 +159,3 @@ cwdexec(struct proc *p)
 		vrele(p->p_cwdi->cwdi_edir);
 	}
 }
-
-/*
- * Used when curlwp wants to use or update its cwdinfo, and needs to prevent
- * concurrent changes.
- *
- * "op" is either RW_READER or RW_WRITER indicating the kind of lock
- * required.  If a read lock on the cwdinfo is requested, then curlwp must
- * not block while holding the lock, or the cwdinfo could become stale. 
- * It's okay to block while holding a write lock.
- */
-struct cwdinfo *
-cwdenter(krw_t op)
-{
-	struct cwdinfo *cwdi = curproc->p_cwdi;
-
-	if (__predict_true(op == RW_READER)) {
-		/*
-		 * Disable preemption to hold off the writer side's xcall,
-		 * then observe the lock.  If it's already taken, we need to
-		 * join in the melee.  Otherwise we're good to go; keeping
-		 * the xcall at bay with kpreempt_disable() will prevent any
-		 * changes while the caller is pondering the cwdinfo.
-		 */
-		kpreempt_disable();
-		if (__predict_true(mutex_owner(&cwdi->cwdi_lock) == NULL)) {
-			membar_consumer();
-			return cwdi;
-		}
-		kpreempt_enable();
-		mutex_enter(&cwdi->cwdi_lock);
-	} else {
-		/*
-		 * About to make changes.  If there's more than one
-		 * reference on the cwdinfo, or curproc has more than one
-		 * LWP, then LWPs other than curlwp can also see the
-		 * cwdinfo.  Run a cross call to get all LWPs out of the
-		 * read section.
-		 */
-		mutex_enter(&cwdi->cwdi_lock);
-		if (cwdi->cwdi_refcnt + curproc->p_nlwps > 2)
-			xc_barrier(0);
-	}
-	return cwdi;
-}
-
-/*
- * Release a lock previously taken with cwdenter().
- */
-void
-cwdexit(struct cwdinfo *cwdi)
-{
-	struct lwp *l = curlwp;
-
-	KASSERT(cwdi == l->l_proc->p_cwdi);
-
-	if (__predict_true(mutex_owner(&cwdi->cwdi_lock) != l))
-		kpreempt_enable();
-	else
-		mutex_exit(&cwdi->cwdi_lock);
-}
-
-/*
- * Called when there is a need to inspect some other process' cwdinfo.  Used
- * by procfs and sysctl.  This gets you a read lock; the cwdinfo must NOT be
- * changed.
- */
-const struct cwdinfo *
-cwdlock(struct proc *p)
-{
-	struct cwdinfo *cwdi = p->p_cwdi;
-
-	mutex_enter(&cwdi->cwdi_lock);
-	return cwdi;
-}
-
-/*
- * Release a lock acquired with cwdlock().
- */
-void
-cwdunlock(struct proc *p)
-{
-	struct cwdinfo *cwdi = p->p_cwdi;
-
-	mutex_exit(&cwdi->cwdi_lock);
-}
-
-/*
- * Get a reference to the current working directory and return it.
- */
-struct vnode *
-cwdcdir(void)
-{
-	struct cwdinfo *cwdi;
-	struct vnode *vp;
-
-	cwdi = cwdenter(RW_READER);
-	if ((vp = cwdi->cwdi_cdir) != NULL)
-		vref(vp);
-	cwdexit(cwdi);
-	return vp;
-}
-
-/*
- * Get a reference to the root directory and return it.
- */
-struct vnode *
-cwdrdir(void)
-{
-	struct cwdinfo *cwdi;
-	struct vnode *vp;
-
-	cwdi = cwdenter(RW_READER);
-	if ((vp = cwdi->cwdi_rdir) != NULL)
-		vref(vp);
-	cwdexit(cwdi);
-	return vp;
-}

Index: src/sys/kern/vfs_getcwd.c
diff -u src/sys/kern/vfs_getcwd.c:1.58 src/sys/kern/vfs_getcwd.c:1.59
--- src/sys/kern/vfs_getcwd.c:1.58	Mon Apr 13 19:23:18 2020
+++ src/sys/kern/vfs_getcwd.c	Tue Apr 21 21:42:47 2020
@@ -1,4 +1,4 @@
-/* $NetBSD: vfs_getcwd.c,v 1.58 2020/04/13 19:23:18 ad Exp $ */
+/* $NetBSD: vfs_getcwd.c,v 1.59 2020/04/21 21:42:47 ad Exp $ */
 
 /*-
  * Copyright (c) 1999, 2020 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: vfs_getcwd.c,v 1.58 2020/04/13 19:23:18 ad Exp $");
+__KERNEL_RCSID(0, "$NetBSD: vfs_getcwd.c,v 1.59 2020/04/21 21:42:47 ad Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -479,7 +479,7 @@ sys___getcwd(struct lwp *l, const struct
 	char   *bp, *bend;
 	int     len = SCARG(uap, length);
 	int	lenused;
-	struct	vnode *dvp;
+	struct	cwdinfo *cwdi;
 
 	if (len > MAXPATHLEN * 4)
 		len = MAXPATHLEN * 4;
@@ -496,10 +496,11 @@ sys___getcwd(struct lwp *l, const struct
 	 * Since each entry takes up at least 2 bytes in the output buffer,
 	 * limit it to N/2 vnodes for an N byte buffer.
 	 */
-	dvp = cwdcdir();
-	error = getcwd_common(dvp, NULL, &bp, path, 
+	cwdi = l->l_proc->p_cwdi;
+	rw_enter(&cwdi->cwdi_lock, RW_READER);
+	error = getcwd_common(cwdi->cwdi_cdir, NULL, &bp, path, 
 	    len/2, GETCWD_CHECK_ACCESS, l);
-	vrele(dvp);
+	rw_exit(&cwdi->cwdi_lock);
 
 	if (error)
 		goto out;

Index: src/sys/kern/vfs_lookup.c
diff -u src/sys/kern/vfs_lookup.c:1.217 src/sys/kern/vfs_lookup.c:1.218
--- src/sys/kern/vfs_lookup.c:1.217	Tue Apr  7 19:17:50 2020
+++ src/sys/kern/vfs_lookup.c	Tue Apr 21 21:42:47 2020
@@ -1,4 +1,4 @@
-/*	$NetBSD: vfs_lookup.c,v 1.217 2020/04/07 19:17:50 ad Exp $	*/
+/*	$NetBSD: vfs_lookup.c,v 1.218 2020/04/21 21:42:47 ad Exp $	*/
 
 /*
  * Copyright (c) 1982, 1986, 1989, 1993
@@ -37,7 +37,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: vfs_lookup.c,v 1.217 2020/04/07 19:17:50 ad Exp $");
+__KERNEL_RCSID(0, "$NetBSD: vfs_lookup.c,v 1.218 2020/04/21 21:42:47 ad Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_magiclinks.h"
@@ -536,6 +536,7 @@ namei_getstartdir(struct namei_state *st
 	struct nameidata *ndp = state->ndp;
 	struct componentname *cnp = state->cnp;
 	struct cwdinfo *cwdi;		/* pointer to cwd state */
+	struct lwp *self = curlwp;	/* thread doing namei() */
 	struct vnode *rootdir, *erootdir, *curdir, *startdir;
 
 	if (state->root_referenced) {
@@ -546,8 +547,8 @@ namei_getstartdir(struct namei_state *st
 		state->root_referenced = 0;
 	}
 
-	/* NB: must not block while inspecting the cwdinfo. */
-	cwdi = cwdenter(RW_READER);
+	cwdi = self->l_proc->p_cwdi;
+	rw_enter(&cwdi->cwdi_lock, RW_READER);
 
 	/* root dir */
 	if (cwdi->cwdi_rdir == NULL || (cnp->cn_flags & NOCHROOT)) {
@@ -605,7 +606,7 @@ namei_getstartdir(struct namei_state *st
 		vref(state->ndp->ni_erootdir);
 	state->root_referenced = 1;
 
-	cwdexit(cwdi);
+	rw_exit(&cwdi->cwdi_lock);
 	return startdir;
 }
 

Index: src/sys/kern/vfs_mount.c
diff -u src/sys/kern/vfs_mount.c:1.80 src/sys/kern/vfs_mount.c:1.81
--- src/sys/kern/vfs_mount.c:1.80	Mon Apr 20 21:39:05 2020
+++ src/sys/kern/vfs_mount.c	Tue Apr 21 21:42:47 2020
@@ -1,4 +1,4 @@
-/*	$NetBSD: vfs_mount.c,v 1.80 2020/04/20 21:39:05 ad Exp $	*/
+/*	$NetBSD: vfs_mount.c,v 1.81 2020/04/21 21:42:47 ad Exp $	*/
 
 /*-
  * Copyright (c) 1997-2020 The NetBSD Foundation, Inc.
@@ -67,7 +67,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: vfs_mount.c,v 1.80 2020/04/20 21:39:05 ad Exp $");
+__KERNEL_RCSID(0, "$NetBSD: vfs_mount.c,v 1.81 2020/04/21 21:42:47 ad Exp $");
 
 #include <sys/param.h>
 #include <sys/kernel.h>
@@ -90,7 +90,6 @@ __KERNEL_RCSID(0, "$NetBSD: vfs_mount.c,
 #include <sys/systm.h>
 #include <sys/vfs_syscalls.h>
 #include <sys/vnode_impl.h>
-#include <sys/xcall.h>
 
 #include <miscfs/genfs/genfs.h>
 #include <miscfs/specfs/specdev.h>
@@ -678,23 +677,18 @@ mount_checkdirs(vnode_t *olddp)
 			rele2 = NULL;
 			atomic_inc_uint(&cwdi->cwdi_refcnt);
 			mutex_exit(proc_lock);
-			mutex_enter(&cwdi->cwdi_lock);
-			if (cwdi->cwdi_cdir == olddp ||
-			    cwdi->cwdi_rdir == olddp) {
-			    	/* XXX belongs in vfs_cwd.c, but rump. */
-			    	xc_barrier(0);
-			    	if (cwdi->cwdi_cdir == olddp) {
-					rele1 = cwdi->cwdi_cdir;
-					vref(newdp);
-					cwdi->cwdi_cdir = newdp;
-				}
-				if (cwdi->cwdi_rdir == olddp) {
-					rele2 = cwdi->cwdi_rdir;
-					vref(newdp);
-					cwdi->cwdi_rdir = newdp;
-				}
+			rw_enter(&cwdi->cwdi_lock, RW_WRITER);
+			if (cwdi->cwdi_cdir == olddp) {
+				rele1 = cwdi->cwdi_cdir;
+				vref(newdp);
+				cwdi->cwdi_cdir = newdp;
+			}
+			if (cwdi->cwdi_rdir == olddp) {
+				rele2 = cwdi->cwdi_rdir;
+				vref(newdp);
+				cwdi->cwdi_rdir = newdp;
 			}
-			mutex_exit(&cwdi->cwdi_lock);
+			rw_exit(&cwdi->cwdi_lock);
 			cwdfree(cwdi);
 			if (rele1 != NULL)
 				vrele(rele1);

Index: src/sys/kern/vfs_subr.c
diff -u src/sys/kern/vfs_subr.c:1.485 src/sys/kern/vfs_subr.c:1.486
--- src/sys/kern/vfs_subr.c:1.485	Mon Apr 13 19:23:18 2020
+++ src/sys/kern/vfs_subr.c	Tue Apr 21 21:42:47 2020
@@ -1,4 +1,4 @@
-/*	$NetBSD: vfs_subr.c,v 1.485 2020/04/13 19:23:18 ad Exp $	*/
+/*	$NetBSD: vfs_subr.c,v 1.486 2020/04/21 21:42:47 ad Exp $	*/
 
 /*-
  * Copyright (c) 1997, 1998, 2004, 2005, 2007, 2008, 2019, 2020
@@ -69,7 +69,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: vfs_subr.c,v 1.485 2020/04/13 19:23:18 ad Exp $");
+__KERNEL_RCSID(0, "$NetBSD: vfs_subr.c,v 1.486 2020/04/21 21:42:47 ad Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_ddb.h"
@@ -1211,25 +1211,24 @@ set_statvfs_info(const char *onp, int uk
 	size_t size;
 	struct statvfs *sfs = &mp->mnt_stat;
 	int (*fun)(const void *, void *, size_t, size_t *);
-	struct vnode *rvp;
 
 	(void)strlcpy(mp->mnt_stat.f_fstypename, vfsname,
 	    sizeof(mp->mnt_stat.f_fstypename));
 
 	if (onp) {
+		struct cwdinfo *cwdi = l->l_proc->p_cwdi;
 		fun = (ukon == UIO_SYSSPACE) ? copystr : copyinstr;
-		KASSERT(l == curlwp);
-		rvp = cwdrdir();
-		if (rvp != NULL) {
+		if (cwdi->cwdi_rdir != NULL) {
 			size_t len;
 			char *bp;
 			char *path = PNBUF_GET();
 
 			bp = path + MAXPATHLEN;
 			*--bp = '\0';
-			error = getcwd_common(rvp, rootvnode, &bp,
+			rw_enter(&cwdi->cwdi_lock, RW_READER);
+			error = getcwd_common(cwdi->cwdi_rdir, rootvnode, &bp,
 			    path, MAXPATHLEN / 2, 0, l);
-			vrele(rvp);
+			rw_exit(&cwdi->cwdi_lock);
 			if (error) {
 				PNBUF_PUT(path);
 				return error;

Index: src/sys/kern/vfs_syscalls.c
diff -u src/sys/kern/vfs_syscalls.c:1.546 src/sys/kern/vfs_syscalls.c:1.547
--- src/sys/kern/vfs_syscalls.c:1.546	Mon Apr 20 21:39:05 2020
+++ src/sys/kern/vfs_syscalls.c	Tue Apr 21 21:42:47 2020
@@ -1,4 +1,4 @@
-/*	$NetBSD: vfs_syscalls.c,v 1.546 2020/04/20 21:39:05 ad Exp $	*/
+/*	$NetBSD: vfs_syscalls.c,v 1.547 2020/04/21 21:42:47 ad Exp $	*/
 
 /*-
  * Copyright (c) 2008, 2009, 2019, 2020 The NetBSD Foundation, Inc.
@@ -70,7 +70,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: vfs_syscalls.c,v 1.546 2020/04/20 21:39:05 ad Exp $");
+__KERNEL_RCSID(0, "$NetBSD: vfs_syscalls.c,v 1.547 2020/04/21 21:42:47 ad Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_fileassoc.h"
@@ -1166,32 +1166,37 @@ int
 dostatvfs(struct mount *mp, struct statvfs *sp, struct lwp *l, int flags,
     int root)
 {
-	struct vnode *rvp;
+	struct cwdinfo *cwdi = l->l_proc->p_cwdi;
+	bool chrooted;
 	int error = 0;
 
+	KASSERT(l == curlwp);
+
+	/*
+	 * This is safe unlocked.  cwdi_rdir never goes non-NULL -> NULL,
+	 * since it would imply chroots can be escaped.  Just make sure this
+	 * routine is self-consistent.
+	 */
+	chrooted = (atomic_load_relaxed(&cwdi->cwdi_rdir) != NULL);
+
 	/*
 	 * If MNT_NOWAIT or MNT_LAZY is specified, do not
 	 * refresh the fsstat cache. MNT_WAIT or MNT_LAZY
 	 * overrides MNT_NOWAIT.
 	 */
-	KASSERT(l == curlwp);
-	rvp = cwdrdir();
 	if (flags == MNT_NOWAIT	|| flags == MNT_LAZY ||
 	    (flags != MNT_WAIT && flags != 0)) {
 		memcpy(sp, &mp->mnt_stat, sizeof(*sp));
 	} else {
 		/* Get the filesystem stats now */
 		memset(sp, 0, sizeof(*sp));
-		if ((error = VFS_STATVFS(mp, sp)) != 0) {
-			if (rvp)
-				vrele(rvp);
+		if ((error = VFS_STATVFS(mp, sp)) != 0)
 			return error;
-		}
-		if (rvp == NULL)
+		if (!chrooted)
 			(void)memcpy(&mp->mnt_stat, sp, sizeof(mp->mnt_stat));
 	}
 
-	if (rvp != NULL) {
+	if (chrooted) {
 		size_t len;
 		char *bp;
 		char c;
@@ -1199,11 +1204,12 @@ dostatvfs(struct mount *mp, struct statv
 
 		bp = path + MAXPATHLEN;
 		*--bp = '\0';
-		error = getcwd_common(rvp, rootvnode, &bp, path,
+		rw_enter(&cwdi->cwdi_lock, RW_READER);
+		error = getcwd_common(cwdi->cwdi_rdir, rootvnode, &bp, path,
 		    MAXPATHLEN / 2, 0, l);
+		rw_exit(&cwdi->cwdi_lock);
 		if (error) {
 			PNBUF_PUT(path);
-			vrele(rvp);
 			return error;
 		}
 		len = strlen(bp);
@@ -1228,7 +1234,6 @@ dostatvfs(struct mount *mp, struct statv
 			}
 		}
 		PNBUF_PUT(path);
-		vrele(rvp);
 	}
 	sp->f_flag = mp->mnt_flag & MNT_VISFLAGMASK;
 	return error;
@@ -1398,6 +1403,7 @@ sys_fchdir(struct lwp *l, const struct s
 	/* {
 		syscallarg(int) fd;
 	} */
+	struct proc *p = l->l_proc;
 	struct cwdinfo *cwdi;
 	struct vnode *vp, *tdp;
 	struct mount *mp;
@@ -1437,7 +1443,8 @@ sys_fchdir(struct lwp *l, const struct s
 	 * Disallow changing to a directory not under the process's
 	 * current root directory (if there is one).
 	 */
-	cwdi = cwdenter(RW_WRITER);
+	cwdi = p->p_cwdi;
+	rw_enter(&cwdi->cwdi_lock, RW_WRITER);
 	if (cwdi->cwdi_rdir && !vn_isunder(vp, NULL, l)) {
 		vrele(vp);
 		error = EPERM;	/* operation not permitted */
@@ -1445,7 +1452,7 @@ sys_fchdir(struct lwp *l, const struct s
 		vrele(cwdi->cwdi_cdir);
 		cwdi->cwdi_cdir = vp;
 	}
-	cwdexit(cwdi);
+	rw_exit(&cwdi->cwdi_lock);
 
  out:
 	fd_putfile(fd);
@@ -1496,19 +1503,19 @@ sys_chdir(struct lwp *l, const struct sy
 	/* {
 		syscallarg(const char *) path;
 	} */
+	struct proc *p = l->l_proc;
 	struct cwdinfo *cwdi;
 	int error;
-	struct vnode *vp, *ovp;
+	struct vnode *vp;
 
-	error = chdir_lookup(SCARG(uap, path), UIO_USERSPACE, &vp, l);
-	if (error != 0)
+	if ((error = chdir_lookup(SCARG(uap, path), UIO_USERSPACE,
+				  &vp, l)) != 0)
 		return (error);
-
-	cwdi = cwdenter(RW_WRITER);
-	ovp = cwdi->cwdi_cdir;
+	cwdi = p->p_cwdi;
+	rw_enter(&cwdi->cwdi_lock, RW_WRITER);
+	vrele(cwdi->cwdi_cdir);
 	cwdi->cwdi_cdir = vp;
-	cwdexit(cwdi);
-	vrele(ovp);
+	rw_exit(&cwdi->cwdi_lock);
 	return (0);
 }
 
@@ -1542,14 +1549,14 @@ sys_chroot(struct lwp *l, const struct s
 void
 change_root(struct vnode *vp)
 {
-	struct cwdinfo *cwdi;
 	kauth_cred_t ncred;
 	struct lwp *l = curlwp;
 	struct proc *p = l->l_proc;
+	struct cwdinfo *cwdi = p->p_cwdi;
 
 	ncred = kauth_cred_alloc();
 
-	cwdi = cwdenter(RW_WRITER);
+	rw_enter(&cwdi->cwdi_lock, RW_WRITER);
 	if (cwdi->cwdi_rdir != NULL)
 		vrele(cwdi->cwdi_rdir);
 	cwdi->cwdi_rdir = vp;
@@ -1568,7 +1575,7 @@ change_root(struct vnode *vp)
 		vref(vp);
 		cwdi->cwdi_cdir = vp;
 	}
-	cwdexit(cwdi);
+	rw_exit(&cwdi->cwdi_lock);
 
 	/* Get a write lock on the process credential. */
 	proc_crmod_enter();

Index: src/sys/miscfs/procfs/procfs_vnops.c
diff -u src/sys/miscfs/procfs/procfs_vnops.c:1.210 src/sys/miscfs/procfs/procfs_vnops.c:1.211
--- src/sys/miscfs/procfs/procfs_vnops.c:1.210	Mon Feb 24 20:47:41 2020
+++ src/sys/miscfs/procfs/procfs_vnops.c	Tue Apr 21 21:42:47 2020
@@ -1,4 +1,4 @@
-/*	$NetBSD: procfs_vnops.c,v 1.210 2020/02/24 20:47:41 ad Exp $	*/
+/*	$NetBSD: procfs_vnops.c,v 1.211 2020/04/21 21:42:47 ad Exp $	*/
 
 /*-
  * Copyright (c) 2006, 2007, 2008, 2020 The NetBSD Foundation, Inc.
@@ -105,7 +105,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: procfs_vnops.c,v 1.210 2020/02/24 20:47:41 ad Exp $");
+__KERNEL_RCSID(0, "$NetBSD: procfs_vnops.c,v 1.211 2020/04/21 21:42:47 ad Exp $");
 
 #include <sys/param.h>
 #include <sys/atomic.h>
@@ -558,7 +558,7 @@ static void
 procfs_dir(pfstype t, struct lwp *caller, struct proc *target, char **bpp,
     char *path, size_t len)
 {
-	const struct cwdinfo *cwdi;
+	struct cwdinfo *cwdi;
 	struct vnode *vp, *rvp;
 	char *bp;
 
@@ -567,25 +567,26 @@ procfs_dir(pfstype t, struct lwp *caller
 	 * we are interested in to prevent it from disappearing
 	 * before getcwd_common() below.
 	 */
-	cwdi = cwdlock(target);
+	rw_enter(&target->p_cwdi->cwdi_lock, RW_READER);
 	switch (t) {
 	case PFScwd:
-		vp = cwdi->cwdi_cdir;
+		vp = target->p_cwdi->cwdi_cdir;
 		break;
 	case PFSchroot:
-		vp = cwdi->cwdi_rdir;
+		vp = target->p_cwdi->cwdi_rdir;
 		break;
 	default:
-		cwdunlock(target);
+		rw_exit(&target->p_cwdi->cwdi_lock);
 		return;
 	}
 	if (vp != NULL)
 		vref(vp);
-	cwdunlock(target);
+	rw_exit(&target->p_cwdi->cwdi_lock);
 
-	KASSERT(caller == curlwp);
+	cwdi = caller->l_proc->p_cwdi;
+	rw_enter(&cwdi->cwdi_lock, RW_READER);
 
-	rvp = cwdrdir();
+	rvp = cwdi->cwdi_rdir;
 	bp = bpp ? *bpp : NULL;
 
 	/*
@@ -598,15 +599,12 @@ procfs_dir(pfstype t, struct lwp *caller
 			*bpp = bp;
 		}
 		vrele(vp);
-		if (rvp != NULL)
-			vrele(rvp);
+		rw_exit(&cwdi->cwdi_lock);
 		return;
 	}
 
-	if (rvp == NULL) {
+	if (rvp == NULL)
 		rvp = rootvnode;
-		vref(rvp);
-	}
 	if (vp == NULL || getcwd_common(vp, rvp, bp ? &bp : NULL, path,
 	    len / 2, 0, caller) != 0) {
 		if (bpp) {
@@ -620,8 +618,7 @@ procfs_dir(pfstype t, struct lwp *caller
 
 	if (vp != NULL)
 		vrele(vp);
-	if (rvp != NULL)
-		vrele(rvp);
+	rw_exit(&cwdi->cwdi_lock);
 }
 
 /*
@@ -1650,7 +1647,7 @@ procfs_readlink(void *v)
 		len = strlen(bp);
 	} else {
 		file_t *fp;
-		struct vnode *vxp, *rvp;
+		struct vnode *vxp, *vp;
 
 		if ((error = procfs_proc_lock(pfs->pfs_pid, &pown, ESRCH)) != 0)
 			return error;
@@ -1683,13 +1680,14 @@ procfs_readlink(void *v)
 			if (vxp->v_tag == VT_PROCFS) {
 				*--bp = '/';
 			} else {
-				if ((rvp = cwdrdir()) == NULL) {
-					rvp = rootvnode;
-					vref(rvp);
-				}
-				error = getcwd_common(vxp, rvp, &bp, path,
+				rw_enter(&curproc->p_cwdi->cwdi_lock,
+				    RW_READER);
+				vp = curproc->p_cwdi->cwdi_rdir;
+				if (vp == NULL)
+					vp = rootvnode;
+				error = getcwd_common(vxp, vp, &bp, path,
 				    MAXPATHLEN / 2, 0, curlwp);
-				vrele(rvp);
+				rw_exit(&curproc->p_cwdi->cwdi_lock);
 			}
 			if (error)
 				break;

Index: src/sys/sys/filedesc.h
diff -u src/sys/sys/filedesc.h:1.66 src/sys/sys/filedesc.h:1.67
--- src/sys/sys/filedesc.h:1.66	Sun Feb 23 22:14:04 2020
+++ src/sys/sys/filedesc.h	Tue Apr 21 21:42:47 2020
@@ -1,4 +1,4 @@
-/*	$NetBSD: filedesc.h,v 1.66 2020/02/23 22:14:04 ad Exp $	*/
+/*	$NetBSD: filedesc.h,v 1.67 2020/04/21 21:42:47 ad Exp $	*/
 
 /*-
  * Copyright (c) 2008 The NetBSD Foundation, Inc.
@@ -168,7 +168,7 @@ typedef struct cwdinfo {
 	struct vnode	*cwdi_cdir;	/* current directory */
 	struct vnode	*cwdi_rdir;	/* root directory */
 	struct vnode	*cwdi_edir;	/* emulation root (if known) */
-	kmutex_t	cwdi_lock;	/* lock on entire struct */
+	krwlock_t	cwdi_lock;	/* lock on entire struct */
 	u_int		cwdi_cmask;	/* mask for file creation */
 	u_int		cwdi_refcnt;	/* reference count */
 } cwdinfo_t;
@@ -215,17 +215,11 @@ int	pipe1(struct lwp *, int *, int);
 int	dodup(struct lwp *, int, int, int, register_t *);
 
 void	cwd_sys_init(void);
-struct	cwdinfo *cwdinit(void);
+struct cwdinfo *cwdinit(void);
 void	cwdshare(proc_t *);
 void	cwdunshare(proc_t *);
 void	cwdfree(struct cwdinfo *);
 void	cwdexec(struct proc *);
-struct	cwdinfo *cwdenter(krw_t);
-void	cwdexit(struct cwdinfo *);
-const	struct cwdinfo *cwdlock(struct proc *);
-void	cwdunlock(struct proc *);
-struct	vnode *cwdcdir(void);
-struct	vnode *cwdrdir(void);
 
 #define GETCWD_CHECK_ACCESS 0x0001
 int	getcwd_common(struct vnode *, struct vnode *, char **, char *, int,

Reply via email to