Module Name:    src
Committed By:   ad
Date:           Sat Jan 25 15:54:04 UTC 2020

Modified Files:
        src/sys/compat/netbsd32 [ad-namecache]: netbsd32_fs.c
        src/sys/kern [ad-namecache]: 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 vfs_vnode.c
        src/sys/miscfs/procfs [ad-namecache]: procfs_vnops.c
        src/sys/sys [ad-namecache]: filedesc.h vfs_syscalls.h

Log Message:
Make cwdinfo use mostly lockless, and largely hide the details in vfs_cwd.c.


To generate a diff of this commit:
cvs rdiff -u -r1.85 -r1.85.2.1 src/sys/compat/netbsd32/netbsd32_fs.c
cvs rdiff -u -r1.485.2.1 -r1.485.2.2 src/sys/kern/kern_exec.c
cvs rdiff -u -r1.239 -r1.239.2.1 src/sys/kern/kern_proc.c
cvs rdiff -u -r1.194 -r1.194.4.1 src/sys/kern/uipc_usrreq.c
cvs rdiff -u -r1.4 -r1.4.62.1 src/sys/kern/vfs_cwd.c
cvs rdiff -u -r1.53.2.3 -r1.53.2.4 src/sys/kern/vfs_getcwd.c
cvs rdiff -u -r1.212.4.8 -r1.212.4.9 src/sys/kern/vfs_lookup.c
cvs rdiff -u -r1.73.2.1 -r1.73.2.2 src/sys/kern/vfs_mount.c
cvs rdiff -u -r1.478.2.2 -r1.478.2.3 src/sys/kern/vfs_subr.c
cvs rdiff -u -r1.539.2.2 -r1.539.2.3 src/sys/kern/vfs_syscalls.c
cvs rdiff -u -r1.105.2.5 -r1.105.2.6 src/sys/kern/vfs_vnode.c
cvs rdiff -u -r1.207 -r1.207.2.1 src/sys/miscfs/procfs/procfs_vnops.c
cvs rdiff -u -r1.65 -r1.65.2.1 src/sys/sys/filedesc.h
cvs rdiff -u -r1.26 -r1.26.2.1 src/sys/sys/vfs_syscalls.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.85 src/sys/compat/netbsd32/netbsd32_fs.c:1.85.2.1
--- src/sys/compat/netbsd32/netbsd32_fs.c:1.85	Thu Sep 26 01:32:09 2019
+++ src/sys/compat/netbsd32/netbsd32_fs.c	Sat Jan 25 15:54:03 2020
@@ -1,4 +1,4 @@
-/*	$NetBSD: netbsd32_fs.c,v 1.85 2019/09/26 01:32:09 christos Exp $	*/
+/*	$NetBSD: netbsd32_fs.c,v 1.85.2.1 2020/01/25 15:54:03 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.85 2019/09/26 01:32:09 christos Exp $");
+__KERNEL_RCSID(0, "$NetBSD: netbsd32_fs.c,v 1.85.2.1 2020/01/25 15:54:03 ad Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -740,13 +740,12 @@ 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	cwdinfo *cwdi;
+	struct	vnode *dvp;
 
 	if (len > MAXPATHLEN*4)
 		len = MAXPATHLEN*4;
@@ -764,11 +763,10 @@ netbsd32___getcwd(struct lwp *l, const s
 	 * limit it to N/2 vnodes for an N byte buffer.
 	 */
 #define GETCWD_CHECK_ACCESS 0x0001
-	cwdi = p->p_cwdi;
-	rw_enter(&cwdi->cwdi_lock, RW_READER);
-	error = getcwd_common (cwdi->cwdi_cdir, NULL, &bp, path, len/2,
+	dvp = cwdcdir();
+	error = getcwd_common (dvp, NULL, &bp, path, len/2,
 			       GETCWD_CHECK_ACCESS, l);
-	rw_exit(&cwdi->cwdi_lock);
+	vrele(dvp);
 
 	if (error)
 		goto out;

Index: src/sys/kern/kern_exec.c
diff -u src/sys/kern/kern_exec.c:1.485.2.1 src/sys/kern/kern_exec.c:1.485.2.2
--- src/sys/kern/kern_exec.c:1.485.2.1	Fri Jan 17 21:47:35 2020
+++ src/sys/kern/kern_exec.c	Sat Jan 25 15:54:03 2020
@@ -1,7 +1,7 @@
-/*	$NetBSD: kern_exec.c,v 1.485.2.1 2020/01/17 21:47:35 ad Exp $	*/
+/*	$NetBSD: kern_exec.c,v 1.485.2.2 2020/01/25 15:54:03 ad Exp $	*/
 
 /*-
- * Copyright (c) 2008, 2019 The NetBSD Foundation, Inc.
+ * Copyright (c) 2008, 2019, 2020 The NetBSD Foundation, Inc.
  * All rights reserved.
  *
  * This code is derived from software contributed to The NetBSD Foundation
@@ -62,7 +62,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: kern_exec.c,v 1.485.2.1 2020/01/17 21:47:35 ad Exp $");
+__KERNEL_RCSID(0, "$NetBSD: kern_exec.c,v 1.485.2.2 2020/01/25 15:54:03 ad Exp $");
 
 #include "opt_exec.h"
 #include "opt_execfmt.h"
@@ -664,7 +664,7 @@ exec_makepathbuf(struct lwp *l, const ch
 	char *path, *bp;
 	size_t len, tlen;
 	int error;
-	struct cwdinfo *cwdi;
+	struct vnode *dvp;
 
 	path = PNBUF_GET();
 	if (seg == UIO_SYSSPACE) {
@@ -690,11 +690,10 @@ exec_makepathbuf(struct lwp *l, const ch
 	memmove(bp, path, len);
 	*(--bp) = '/';
 
-	cwdi = l->l_proc->p_cwdi;
-	rw_enter(&cwdi->cwdi_lock, RW_READER);
-	error = getcwd_common(cwdi->cwdi_cdir, NULL, &bp, path, MAXPATHLEN / 2,
+	dvp = cwdcdir();
+	error = getcwd_common(dvp, NULL, &bp, path, MAXPATHLEN / 2,
 	    GETCWD_CHECK_ACCESS, l);
-	rw_exit(&cwdi->cwdi_lock);
+	vrele(dvp);
 
 	if (error)
 		goto err;
@@ -1111,6 +1110,7 @@ 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. */
@@ -1119,9 +1119,10 @@ emulexec(struct lwp *l, struct exec_pack
 		emul_find_root(l, epp);
 
 	/* Any old emulation root got removed by fdcloseexec */
-	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);
+	KASSERT(p == curproc);
+	cwdi = cwdenter(RW_WRITER);
+	cwdi->cwdi_edir = epp->ep_emul_root;
+	cwdexit(cwdi);
 	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.239 src/sys/kern/kern_proc.c:1.239.2.1
--- src/sys/kern/kern_proc.c:1.239	Tue Dec 31 13:07:13 2019
+++ src/sys/kern/kern_proc.c	Sat Jan 25 15:54:03 2020
@@ -1,7 +1,7 @@
-/*	$NetBSD: kern_proc.c,v 1.239 2019/12/31 13:07:13 ad Exp $	*/
+/*	$NetBSD: kern_proc.c,v 1.239.2.1 2020/01/25 15:54:03 ad Exp $	*/
 
 /*-
- * Copyright (c) 1999, 2006, 2007, 2008 The NetBSD Foundation, Inc.
+ * Copyright (c) 1999, 2006, 2007, 2008, 2020 The NetBSD Foundation, Inc.
  * All rights reserved.
  *
  * This code is derived from software contributed to The NetBSD Foundation
@@ -62,7 +62,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: kern_proc.c,v 1.239 2019/12/31 13:07:13 ad Exp $");
+__KERNEL_RCSID(0, "$NetBSD: kern_proc.c,v 1.239.2.1 2020/01/25 15:54:03 ad Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_kstack.h"
@@ -106,6 +106,7 @@ __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>
@@ -470,7 +471,7 @@ proc0_init(void)
 	p->p_cred = cred0;
 
 	/* Create the CWD info. */
-	rw_init(&cwdi0.cwdi_lock);
+	mutex_init(&cwdi0.cwdi_lock, MUTEX_DEFAULT, IPL_NONE);
 
 	/* Create the limits structures. */
 	mutex_init(&limit0.pl_lock, MUTEX_DEFAULT, IPL_NONE);
@@ -2588,7 +2589,7 @@ fill_cwd(struct lwp *l, pid_t pid, void 
 	struct proc *p;
 	char *path;
 	char *bp, *bend;
-	struct cwdinfo *cwdi;
+	const struct cwdinfo *cwdi;
 	struct vnode *vp;
 	size_t len, lenused;
 
@@ -2603,11 +2604,12 @@ fill_cwd(struct lwp *l, pid_t pid, void 
 	bend = bp;
 	*(--bp) = '\0';
 
-	cwdi = p->p_cwdi;
-	rw_enter(&cwdi->cwdi_lock, RW_READER);
+	cwdi = cwdlock(p);
 	vp = cwdi->cwdi_cdir;
+	vref(vp);
+	cwdunlock(p);
 	error = getcwd_common(vp, NULL, &bp, path, len/2, 0, l);
-	rw_exit(&cwdi->cwdi_lock);
+	vrele(vp);
 
 	if (error)
 		goto out;

Index: src/sys/kern/uipc_usrreq.c
diff -u src/sys/kern/uipc_usrreq.c:1.194 src/sys/kern/uipc_usrreq.c:1.194.4.1
--- src/sys/kern/uipc_usrreq.c:1.194	Mon Jul 29 09:42:17 2019
+++ src/sys/kern/uipc_usrreq.c	Sat Jan 25 15:54:03 2020
@@ -1,7 +1,7 @@
-/*	$NetBSD: uipc_usrreq.c,v 1.194 2019/07/29 09:42:17 maxv Exp $	*/
+/*	$NetBSD: uipc_usrreq.c,v 1.194.4.1 2020/01/25 15:54:03 ad Exp $	*/
 
 /*-
- * Copyright (c) 1998, 2000, 2004, 2008, 2009 The NetBSD Foundation, Inc.
+ * Copyright (c) 1998, 2000, 2004, 2008, 2009, 2020 The NetBSD Foundation, Inc.
  * All rights reserved.
  *
  * This code is derived from software contributed to The NetBSD Foundation
@@ -96,7 +96,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: uipc_usrreq.c,v 1.194 2019/07/29 09:42:17 maxv Exp $");
+__KERNEL_RCSID(0, "$NetBSD: uipc_usrreq.c,v 1.194.4.1 2020/01/25 15:54:03 ad Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_compat_netbsd.h"
@@ -1395,6 +1395,7 @@ 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;
 
@@ -1404,9 +1405,11 @@ unp_externalize(struct mbuf *rights, str
 		goto noop;
 
 	int * const fdp = kmem_alloc(nfds * sizeof(int), KM_SLEEP);
-	rw_enter(&p->p_cwdi->cwdi_lock, RW_READER);
+
+	KASSERT(l == curlwp);
 
 	/* 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++;
@@ -1420,15 +1423,15 @@ unp_externalize(struct mbuf *rights, str
 		 * sure it's inside the subtree we're allowed
 		 * to access.
 		 */
-		if (p->p_cwdi->cwdi_rdir != NULL && fp->f_type == DTYPE_VNODE) {
+		if (rvp != NULL && fp->f_type == DTYPE_VNODE) {
 			vnode_t *vp = fp->f_vnode;
-			if ((vp->v_type == VDIR) &&
-			    !vn_isunder(vp, p->p_cwdi->cwdi_rdir, l)) {
+			if ((vp->v_type == VDIR) && !vn_isunder(vp, rvp, l)) {
 				error = EPERM;
 				goto out;
 			}
 		}
 	}
+	
 
  restart:
 	/*
@@ -1506,7 +1509,6 @@ 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:
@@ -1516,6 +1518,10 @@ 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 please 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.4 src/sys/kern/vfs_cwd.c:1.4.62.1
--- src/sys/kern/vfs_cwd.c:1.4	Tue Feb 15 15:54:28 2011
+++ src/sys/kern/vfs_cwd.c	Sat Jan 25 15:54:03 2020
@@ -1,7 +1,7 @@
-/*	$NetBSD: vfs_cwd.c,v 1.4 2011/02/15 15:54:28 pooka Exp $	*/
+/*	$NetBSD: vfs_cwd.c,v 1.4.62.1 2020/01/25 15:54:03 ad Exp $	*/
 
 /*-
- * Copyright (c) 2008 The NetBSD Foundation, Inc.
+ * Copyright (c) 2008, 2020 The NetBSD Foundation, Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -31,13 +31,14 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: vfs_cwd.c,v 1.4 2011/02/15 15:54:28 pooka Exp $");
+__KERNEL_RCSID(0, "$NetBSD: vfs_cwd.c,v 1.4.62.1 2020/01/25 15:54:03 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 *);
@@ -64,9 +65,8 @@ cwdinit(void)
 	struct cwdinfo *copy;
 
 	cwdi = pool_cache_get(cwdi_cache, PR_WAITOK);
-	copy = curproc->p_cwdi;
 
-	rw_enter(&copy->cwdi_lock, RW_READER);
+	copy = cwdenter(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;
-	rw_exit(&copy->cwdi_lock);
+	cwdexit(copy);
 
 	return (cwdi);
 }
@@ -88,7 +88,7 @@ cwdi_ctor(void *arg, void *obj, int flag
 {
 	struct cwdinfo *cwdi = obj;
 
-	rw_init(&cwdi->cwdi_lock);
+	mutex_init(&cwdi->cwdi_lock, MUTEX_DEFAULT, IPL_NONE);
 
 	return 0;
 }
@@ -98,7 +98,7 @@ cwdi_dtor(void *arg, void *obj)
 {
 	struct cwdinfo *cwdi = obj;
 
-	rw_destroy(&cwdi->cwdi_lock);
+	mutex_destroy(&cwdi->cwdi_lock);
 }
 
 /*
@@ -159,3 +159,120 @@ 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))
+			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.  This also acts as a global memory barrier,
+		 * meaning we don't need to do anything special with on
+		 * the reader side.
+		 */
+		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.53.2.3 src/sys/kern/vfs_getcwd.c:1.53.2.4
--- src/sys/kern/vfs_getcwd.c:1.53.2.3	Sun Jan 19 21:19:25 2020
+++ src/sys/kern/vfs_getcwd.c	Sat Jan 25 15:54:03 2020
@@ -1,4 +1,4 @@
-/* $NetBSD: vfs_getcwd.c,v 1.53.2.3 2020/01/19 21:19:25 ad Exp $ */
+/* $NetBSD: vfs_getcwd.c,v 1.53.2.4 2020/01/25 15:54:03 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.53.2.3 2020/01/19 21:19:25 ad Exp $");
+__KERNEL_RCSID(0, "$NetBSD: vfs_getcwd.c,v 1.53.2.4 2020/01/25 15:54:03 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	cwdinfo *cwdi;
+	struct	vnode *dvp;
 
 	if (len > MAXPATHLEN * 4)
 		len = MAXPATHLEN * 4;
@@ -496,11 +496,10 @@ 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.
 	 */
-	cwdi = l->l_proc->p_cwdi;
-	rw_enter(&cwdi->cwdi_lock, RW_READER);
-	error = getcwd_common(cwdi->cwdi_cdir, NULL, &bp, path, 
+	dvp = cwdcdir();
+	error = getcwd_common(dvp, NULL, &bp, path, 
 	    len/2, GETCWD_CHECK_ACCESS, l);
-	rw_exit(&cwdi->cwdi_lock);
+	vrele(dvp);
 
 	if (error)
 		goto out;

Index: src/sys/kern/vfs_lookup.c
diff -u src/sys/kern/vfs_lookup.c:1.212.4.8 src/sys/kern/vfs_lookup.c:1.212.4.9
--- src/sys/kern/vfs_lookup.c:1.212.4.8	Fri Jan 24 16:05:37 2020
+++ src/sys/kern/vfs_lookup.c	Sat Jan 25 15:54:03 2020
@@ -1,4 +1,4 @@
-/*	$NetBSD: vfs_lookup.c,v 1.212.4.8 2020/01/24 16:05:37 ad Exp $	*/
+/*	$NetBSD: vfs_lookup.c,v 1.212.4.9 2020/01/25 15:54:03 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.212.4.8 2020/01/24 16:05:37 ad Exp $");
+__KERNEL_RCSID(0, "$NetBSD: vfs_lookup.c,v 1.212.4.9 2020/01/25 15:54:03 ad Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_magiclinks.h"
@@ -536,7 +536,6 @@ 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) {
@@ -547,8 +546,8 @@ namei_getstartdir(struct namei_state *st
 		state->root_referenced = 0;
 	}
 
-	cwdi = self->l_proc->p_cwdi;
-	rw_enter(&cwdi->cwdi_lock, RW_READER);
+	/* NB: we must not block while holding the cwdi read locked. */
+	cwdi = cwdenter(RW_READER);
 
 	/* root dir */
 	if (cwdi->cwdi_rdir == NULL || (cnp->cn_flags & NOCHROOT)) {
@@ -606,7 +605,7 @@ namei_getstartdir(struct namei_state *st
 		vref(state->ndp->ni_erootdir);
 	state->root_referenced = 1;
 
-	rw_exit(&cwdi->cwdi_lock);
+	cwdexit(cwdi);
 	return startdir;
 }
 

Index: src/sys/kern/vfs_mount.c
diff -u src/sys/kern/vfs_mount.c:1.73.2.1 src/sys/kern/vfs_mount.c:1.73.2.2
--- src/sys/kern/vfs_mount.c:1.73.2.1	Fri Jan 17 21:47:35 2020
+++ src/sys/kern/vfs_mount.c	Sat Jan 25 15:54:03 2020
@@ -1,7 +1,7 @@
-/*	$NetBSD: vfs_mount.c,v 1.73.2.1 2020/01/17 21:47:35 ad Exp $	*/
+/*	$NetBSD: vfs_mount.c,v 1.73.2.2 2020/01/25 15:54:03 ad Exp $	*/
 
 /*-
- * Copyright (c) 1997-2019 The NetBSD Foundation, Inc.
+ * Copyright (c) 1997-2020 The NetBSD Foundation, Inc.
  * All rights reserved.
  *
  * This code is derived from software contributed to The NetBSD Foundation
@@ -67,7 +67,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: vfs_mount.c,v 1.73.2.1 2020/01/17 21:47:35 ad Exp $");
+__KERNEL_RCSID(0, "$NetBSD: vfs_mount.c,v 1.73.2.2 2020/01/25 15:54:03 ad Exp $");
 
 #include <sys/param.h>
 #include <sys/kernel.h>
@@ -90,6 +90,7 @@ __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>
@@ -675,18 +676,23 @@ mount_checkdirs(vnode_t *olddp)
 			rele2 = NULL;
 			atomic_inc_uint(&cwdi->cwdi_refcnt);
 			mutex_exit(proc_lock);
-			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_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_exit(&cwdi->cwdi_lock);
+			mutex_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.478.2.2 src/sys/kern/vfs_subr.c:1.478.2.3
--- src/sys/kern/vfs_subr.c:1.478.2.2	Fri Jan 24 16:05:22 2020
+++ src/sys/kern/vfs_subr.c	Sat Jan 25 15:54:03 2020
@@ -1,7 +1,7 @@
-/*	$NetBSD: vfs_subr.c,v 1.478.2.2 2020/01/24 16:05:22 ad Exp $	*/
+/*	$NetBSD: vfs_subr.c,v 1.478.2.3 2020/01/25 15:54:03 ad Exp $	*/
 
 /*-
- * Copyright (c) 1997, 1998, 2004, 2005, 2007, 2008, 2019
+ * Copyright (c) 1997, 1998, 2004, 2005, 2007, 2008, 2019, 2020
  *     The NetBSD Foundation, Inc.
  * All rights reserved.
  *
@@ -69,7 +69,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: vfs_subr.c,v 1.478.2.2 2020/01/24 16:05:22 ad Exp $");
+__KERNEL_RCSID(0, "$NetBSD: vfs_subr.c,v 1.478.2.3 2020/01/25 15:54:03 ad Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_ddb.h"
@@ -1215,24 +1215,25 @@ 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;
-		if (cwdi->cwdi_rdir != NULL) {
+		KASSERT(l == curlwp);
+		rvp = cwdrdir();
+		if (rvp != NULL) {
 			size_t len;
 			char *bp;
 			char *path = PNBUF_GET();
 
 			bp = path + MAXPATHLEN;
 			*--bp = '\0';
-			rw_enter(&cwdi->cwdi_lock, RW_READER);
-			error = getcwd_common(cwdi->cwdi_rdir, rootvnode, &bp,
+			error = getcwd_common(rvp, rootvnode, &bp,
 			    path, MAXPATHLEN / 2, 0, l);
-			rw_exit(&cwdi->cwdi_lock);
+			vrele(rvp);
 			if (error) {
 				PNBUF_PUT(path);
 				return error;

Index: src/sys/kern/vfs_syscalls.c
diff -u src/sys/kern/vfs_syscalls.c:1.539.2.2 src/sys/kern/vfs_syscalls.c:1.539.2.3
--- src/sys/kern/vfs_syscalls.c:1.539.2.2	Sun Jan 19 21:23:36 2020
+++ src/sys/kern/vfs_syscalls.c	Sat Jan 25 15:54:03 2020
@@ -1,7 +1,7 @@
-/*	$NetBSD: vfs_syscalls.c,v 1.539.2.2 2020/01/19 21:23:36 ad Exp $	*/
+/*	$NetBSD: vfs_syscalls.c,v 1.539.2.3 2020/01/25 15:54:03 ad Exp $	*/
 
 /*-
- * Copyright (c) 2008, 2009, 2019 The NetBSD Foundation, Inc.
+ * Copyright (c) 2008, 2009, 2019, 2020 The NetBSD Foundation, Inc.
  * All rights reserved.
  *
  * This code is derived from software contributed to The NetBSD Foundation
@@ -70,7 +70,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: vfs_syscalls.c,v 1.539.2.2 2020/01/19 21:23:36 ad Exp $");
+__KERNEL_RCSID(0, "$NetBSD: vfs_syscalls.c,v 1.539.2.3 2020/01/25 15:54:03 ad Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_fileassoc.h"
@@ -1100,7 +1100,7 @@ int
 dostatvfs(struct mount *mp, struct statvfs *sp, struct lwp *l, int flags,
     int root)
 {
-	struct cwdinfo *cwdi = l->l_proc->p_cwdi;
+	struct vnode *rvp;
 	int error = 0;
 
 	/*
@@ -1111,19 +1111,20 @@ dostatvfs(struct mount *mp, struct statv
 	if (flags == MNT_NOWAIT	|| flags == MNT_LAZY ||
 	    (flags != MNT_WAIT && flags != 0)) {
 		memcpy(sp, &mp->mnt_stat, sizeof(*sp));
-		goto done;
-	}
-
-	/* Get the filesystem stats now */
-	memset(sp, 0, sizeof(*sp));
-	if ((error = VFS_STATVFS(mp, sp)) != 0) {
-		return error;
+		rvp = NULL;
+	} else {
+		/* Get the filesystem stats now */
+		memset(sp, 0, sizeof(*sp));
+		if ((error = VFS_STATVFS(mp, sp)) != 0) {
+			return error;
+		}
+		KASSERT(l == curlwp);
+		rvp = cwdrdir();
+		if (rvp == NULL)
+			(void)memcpy(&mp->mnt_stat, sp, sizeof(mp->mnt_stat));
 	}
 
-	if (cwdi->cwdi_rdir == NULL)
-		(void)memcpy(&mp->mnt_stat, sp, sizeof(mp->mnt_stat));
-done:
-	if (cwdi->cwdi_rdir != NULL) {
+	if (rvp != NULL) {
 		size_t len;
 		char *bp;
 		char c;
@@ -1131,12 +1132,11 @@ done:
 
 		bp = path + MAXPATHLEN;
 		*--bp = '\0';
-		rw_enter(&cwdi->cwdi_lock, RW_READER);
-		error = getcwd_common(cwdi->cwdi_rdir, rootvnode, &bp, path,
+		error = getcwd_common(rvp, rootvnode, &bp, path,
 		    MAXPATHLEN / 2, 0, l);
-		rw_exit(&cwdi->cwdi_lock);
 		if (error) {
 			PNBUF_PUT(path);
+			vrele(rvp);
 			return error;
 		}
 		len = strlen(bp);
@@ -1161,6 +1161,7 @@ done:
 			}
 		}
 		PNBUF_PUT(path);
+		vrele(rvp);
 	}
 	sp->f_flag = mp->mnt_flag & MNT_VISFLAGMASK;
 	return error;
@@ -1330,7 +1331,6 @@ 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;
@@ -1370,8 +1370,7 @@ 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 = p->p_cwdi;
-	rw_enter(&cwdi->cwdi_lock, RW_WRITER);
+	cwdi = cwdenter(RW_WRITER);
 	if (cwdi->cwdi_rdir && !vn_isunder(vp, NULL, l)) {
 		vrele(vp);
 		error = EPERM;	/* operation not permitted */
@@ -1379,7 +1378,7 @@ sys_fchdir(struct lwp *l, const struct s
 		vrele(cwdi->cwdi_cdir);
 		cwdi->cwdi_cdir = vp;
 	}
-	rw_exit(&cwdi->cwdi_lock);
+	cwdexit(cwdi);
 
  out:
 	fd_putfile(fd);
@@ -1393,7 +1392,6 @@ sys_fchdir(struct lwp *l, const struct s
 int
 sys_fchroot(struct lwp *l, const struct sys_fchroot_args *uap, register_t *retval)
 {
-	struct proc *p = l->l_proc;
 	struct vnode	*vp;
 	file_t	*fp;
 	int		 error, fd = SCARG(uap, fd);
@@ -1414,8 +1412,7 @@ sys_fchroot(struct lwp *l, const struct 
 	if (error)
 		goto out;
 	vref(vp);
-
-	change_root(p->p_cwdi, vp, l);
+	change_root(vp);
 
  out:
 	fd_putfile(fd);
@@ -1432,19 +1429,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;
+	struct vnode *vp, *ovp;
 
-	if ((error = chdir_lookup(SCARG(uap, path), UIO_USERSPACE,
-				  &vp, l)) != 0)
+	error = chdir_lookup(SCARG(uap, path), UIO_USERSPACE, &vp, l);
+	if (error != 0)
 		return (error);
-	cwdi = p->p_cwdi;
-	rw_enter(&cwdi->cwdi_lock, RW_WRITER);
-	vrele(cwdi->cwdi_cdir);
+
+	cwdi = cwdenter(RW_WRITER);
+	ovp = cwdi->cwdi_cdir;
 	cwdi->cwdi_cdir = vp;
-	rw_exit(&cwdi->cwdi_lock);
+	cwdexit(cwdi);
+	vrele(ovp);
 	return (0);
 }
 
@@ -1458,20 +1455,17 @@ sys_chroot(struct lwp *l, const struct s
 	/* {
 		syscallarg(const char *) path;
 	} */
-	struct proc *p = l->l_proc;
 	int error;
 	struct vnode *vp;
 
 	if ((error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_CHROOT,
 	    KAUTH_REQ_SYSTEM_CHROOT_CHROOT, NULL, NULL, NULL)) != 0)
 		return (error);
-	if ((error = chdir_lookup(SCARG(uap, path), UIO_USERSPACE,
-				  &vp, l)) != 0)
-		return (error);
 
-	change_root(p->p_cwdi, vp, l);
-
-	return (0);
+	error = chdir_lookup(SCARG(uap, path), UIO_USERSPACE, &vp, l);
+	if (error == 0)
+		change_root(vp);
+	return error;
 }
 
 /*
@@ -1479,14 +1473,16 @@ sys_chroot(struct lwp *l, const struct s
  * NB: callers need to properly authorize the change root operation.
  */
 void
-change_root(struct cwdinfo *cwdi, struct vnode *vp, struct lwp *l)
+change_root(struct vnode *vp)
 {
-	struct proc *p = l->l_proc;
+	struct cwdinfo *cwdi;
 	kauth_cred_t ncred;
+	struct lwp *l = curlwp;
+	struct proc *p = l->l_proc;
 
 	ncred = kauth_cred_alloc();
 
-	rw_enter(&cwdi->cwdi_lock, RW_WRITER);
+	cwdi = cwdenter(RW_WRITER);
 	if (cwdi->cwdi_rdir != NULL)
 		vrele(cwdi->cwdi_rdir);
 	cwdi->cwdi_rdir = vp;
@@ -1505,7 +1501,7 @@ change_root(struct cwdinfo *cwdi, struct
 		vref(vp);
 		cwdi->cwdi_cdir = vp;
 	}
-	rw_exit(&cwdi->cwdi_lock);
+	cwdexit(cwdi);
 
 	/* Get a write lock on the process credential. */
 	proc_crmod_enter();
@@ -4674,21 +4670,15 @@ sys_umask(struct lwp *l, const struct sy
 	/* {
 		syscallarg(mode_t) newmask;
 	} */
-	struct proc *p = l->l_proc;
-	struct cwdinfo *cwdi;
 
 	/*
-	 * cwdi->cwdi_cmask will be read unlocked elsewhere.  What's
-	 * important is that we serialize changes to the mask.  The
-	 * rw_exit() will issue a write memory barrier on our behalf,
-	 * and force the changes out to other CPUs (as it must use an
-	 * atomic operation, draining the local CPU's store buffers).
-	 */
-	cwdi = p->p_cwdi;
-	rw_enter(&cwdi->cwdi_lock, RW_WRITER);
-	*retval = cwdi->cwdi_cmask;
-	cwdi->cwdi_cmask = SCARG(uap, newmask) & ALLPERMS;
-	rw_exit(&cwdi->cwdi_lock);
+	 * cwdi->cwdi_cmask will be read unlocked elsewhere, and no kind of
+	 * serialization with those reads is required.  All that's important
+	 * is that we get the correct answer for the caller of umask() and
+	 * the atomic operation accomplishes.
+	 */
+	*retval = atomic_swap_uint(&curproc->p_cwdi->cwdi_cmask,
+	    SCARG(uap, newmask) & ALLPERMS);
 
 	return (0);
 }
@@ -4699,7 +4689,7 @@ dorevoke(struct vnode *vp, kauth_cred_t 
 	struct vattr vattr;
 	int error, fs_decision;
 
-	vn_lock(vp, LK_SHARED | LK_RETRY);
+	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
 	error = VOP_GETATTR(vp, &vattr, cred);
 	VOP_UNLOCK(vp);
 	if (error != 0)

Index: src/sys/kern/vfs_vnode.c
diff -u src/sys/kern/vfs_vnode.c:1.105.2.5 src/sys/kern/vfs_vnode.c:1.105.2.6
--- src/sys/kern/vfs_vnode.c:1.105.2.5	Fri Jan 24 16:05:22 2020
+++ src/sys/kern/vfs_vnode.c	Sat Jan 25 15:54:03 2020
@@ -1,4 +1,4 @@
-/*	$NetBSD: vfs_vnode.c,v 1.105.2.5 2020/01/24 16:05:22 ad Exp $	*/
+/*	$NetBSD: vfs_vnode.c,v 1.105.2.6 2020/01/25 15:54:03 ad Exp $	*/
 
 /*-
  * Copyright (c) 1997-2011, 2019 The NetBSD Foundation, Inc.
@@ -154,7 +154,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: vfs_vnode.c,v 1.105.2.5 2020/01/24 16:05:22 ad Exp $");
+__KERNEL_RCSID(0, "$NetBSD: vfs_vnode.c,v 1.105.2.6 2020/01/25 15:54:03 ad Exp $");
 
 #include <sys/param.h>
 #include <sys/kernel.h>
@@ -912,6 +912,8 @@ vrele_async(vnode_t *vp)
 /*
  * Vnode reference, where a reference is already held by some other
  * object (for example, a file structure).
+ *
+ * NB: we have lockless code sequences that rely on this not blocking.
  */
 void
 vref(vnode_t *vp)

Index: src/sys/miscfs/procfs/procfs_vnops.c
diff -u src/sys/miscfs/procfs/procfs_vnops.c:1.207 src/sys/miscfs/procfs/procfs_vnops.c:1.207.2.1
--- src/sys/miscfs/procfs/procfs_vnops.c:1.207	Thu Aug 29 06:43:13 2019
+++ src/sys/miscfs/procfs/procfs_vnops.c	Sat Jan 25 15:54:04 2020
@@ -1,7 +1,7 @@
-/*	$NetBSD: procfs_vnops.c,v 1.207 2019/08/29 06:43:13 hannken Exp $	*/
+/*	$NetBSD: procfs_vnops.c,v 1.207.2.1 2020/01/25 15:54:04 ad Exp $	*/
 
 /*-
- * Copyright (c) 2006, 2007, 2008 The NetBSD Foundation, Inc.
+ * Copyright (c) 2006, 2007, 2008, 2020 The NetBSD Foundation, Inc.
  * All rights reserved.
  *
  * This code is derived from software contributed to The NetBSD Foundation
@@ -105,7 +105,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: procfs_vnops.c,v 1.207 2019/08/29 06:43:13 hannken Exp $");
+__KERNEL_RCSID(0, "$NetBSD: procfs_vnops.c,v 1.207.2.1 2020/01/25 15:54:04 ad Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -557,7 +557,7 @@ static void
 procfs_dir(pfstype t, struct lwp *caller, struct proc *target, char **bpp,
     char *path, size_t len)
 {
-	struct cwdinfo *cwdi;
+	const struct cwdinfo *cwdi;
 	struct vnode *vp, *rvp;
 	char *bp;
 
@@ -566,26 +566,25 @@ procfs_dir(pfstype t, struct lwp *caller
 	 * we are interested in to prevent it from disappearing
 	 * before getcwd_common() below.
 	 */
-	rw_enter(&target->p_cwdi->cwdi_lock, RW_READER);
+	cwdi = cwdlock(target);
 	switch (t) {
 	case PFScwd:
-		vp = target->p_cwdi->cwdi_cdir;
+		vp = cwdi->cwdi_cdir;
 		break;
 	case PFSchroot:
-		vp = target->p_cwdi->cwdi_rdir;
+		vp = cwdi->cwdi_rdir;
 		break;
 	default:
-		rw_exit(&target->p_cwdi->cwdi_lock);
+		cwdunlock(target);
 		return;
 	}
 	if (vp != NULL)
 		vref(vp);
-	rw_exit(&target->p_cwdi->cwdi_lock);
+	cwdunlock(target);
 
-	cwdi = caller->l_proc->p_cwdi;
-	rw_enter(&cwdi->cwdi_lock, RW_READER);
+	KASSERT(caller == curlwp);
 
-	rvp = cwdi->cwdi_rdir;
+	rvp = cwdrdir();
 	bp = bpp ? *bpp : NULL;
 
 	/*
@@ -598,12 +597,15 @@ procfs_dir(pfstype t, struct lwp *caller
 			*bpp = bp;
 		}
 		vrele(vp);
-		rw_exit(&cwdi->cwdi_lock);
+		if (rvp != NULL)
+			vrele(rvp);
 		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) {
@@ -617,7 +619,8 @@ procfs_dir(pfstype t, struct lwp *caller
 
 	if (vp != NULL)
 		vrele(vp);
-	rw_exit(&cwdi->cwdi_lock);
+	if (rvp != NULL)
+		vrele(rvp);
 }
 
 /*
@@ -1646,7 +1649,7 @@ procfs_readlink(void *v)
 		len = strlen(bp);
 	} else {
 		file_t *fp;
-		struct vnode *vxp, *vp;
+		struct vnode *vxp, *rvp;
 
 		if ((error = procfs_proc_lock(pfs->pfs_pid, &pown, ESRCH)) != 0)
 			return error;
@@ -1679,14 +1682,13 @@ procfs_readlink(void *v)
 			if (vxp->v_tag == VT_PROCFS) {
 				*--bp = '/';
 			} else {
-				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,
+				if ((rvp = cwdrdir()) == NULL) {
+					rvp = rootvnode;
+					vref(rvp);
+				}
+				error = getcwd_common(vxp, rvp, &bp, path,
 				    MAXPATHLEN / 2, 0, curlwp);
-				rw_exit(&curproc->p_cwdi->cwdi_lock);
+				vrele(rvp);
 			}
 			if (error)
 				break;

Index: src/sys/sys/filedesc.h
diff -u src/sys/sys/filedesc.h:1.65 src/sys/sys/filedesc.h:1.65.2.1
--- src/sys/sys/filedesc.h:1.65	Sun Oct  6 07:15:34 2019
+++ src/sys/sys/filedesc.h	Sat Jan 25 15:54:04 2020
@@ -1,4 +1,4 @@
-/*	$NetBSD: filedesc.h,v 1.65 2019/10/06 07:15:34 mlelstv Exp $	*/
+/*	$NetBSD: filedesc.h,v 1.65.2.1 2020/01/25 15:54:04 ad Exp $	*/
 
 /*-
  * Copyright (c) 2008 The NetBSD Foundation, Inc.
@@ -168,8 +168,8 @@ typedef struct cwdinfo {
 	struct vnode	*cwdi_cdir;	/* current directory */
 	struct vnode	*cwdi_rdir;	/* root directory */
 	struct vnode	*cwdi_edir;	/* emulation root (if known) */
-	krwlock_t	cwdi_lock;	/* lock on entire struct */
-	u_short		cwdi_cmask;	/* mask for file creation */
+	kmutex_t	cwdi_lock;	/* lock on entire struct */
+	u_int		cwdi_cmask;	/* mask for file creation */
 	u_int		cwdi_refcnt;	/* reference count */
 } cwdinfo_t;
 
@@ -215,11 +215,17 @@ 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,

Index: src/sys/sys/vfs_syscalls.h
diff -u src/sys/sys/vfs_syscalls.h:1.26 src/sys/sys/vfs_syscalls.h:1.26.2.1
--- src/sys/sys/vfs_syscalls.h:1.26	Thu Sep 26 01:34:16 2019
+++ src/sys/sys/vfs_syscalls.h	Sat Jan 25 15:54:04 2020
@@ -1,4 +1,4 @@
-/*     $NetBSD: vfs_syscalls.h,v 1.26 2019/09/26 01:34:16 christos Exp $        */
+/*     $NetBSD: vfs_syscalls.h,v 1.26.2.1 2020/01/25 15:54:04 ad Exp $        */
 
 /*
  * Copyright (c) 2007, 2008, 2009 The NetBSD Foundation, Inc.
@@ -82,7 +82,7 @@ int	do_sys_quotactl(const char *, const 
 void	do_sys_sync(struct lwp *);
 
 int	chdir_lookup(const char *, int, struct vnode **, struct lwp *);
-void	change_root(struct cwdinfo *, struct vnode *, struct lwp *);
+void	change_root(struct vnode *);
 
 extern const char *const mountcompatnames[];
 extern const u_int nmountcompatnames;

Reply via email to