tech-kern archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

vn_open, EDUPFD, EMOVEFD



A couple days ago it came to my attention that the hack used for
cloning devices (returning a magic error code and stuffing a file
descriptor number in a magic field of struct lwp) is also used by
/dev/stderr, and more importantly, every caller of vn_open in the
kernel (there are many) needs to know about this hack to avoid
returning internal negative errnos to users. Needless to say, none of
them (besides do_open) actually do, plus this is gross.

The following patch does not clean out the hack, but establishes a
containment perimeter inside vn_open; vn_open now returns either a
vnode or a file descriptor number. (And, along with the file
descriptor number, a flag saying whether it was the EDUPFD or EMOVEFD
case.) Callers of vn_open not prepared to deal with file descriptors,
which is all of them besides do_open, can pass NULL for the file
descriptor return parameter, in which case vn_open will instead return
EOPNOTSUPP.

It also takes advantage of having rearranged vn_open's signature to
stop exposing struct nameidata, which is a plus.

There are now eight arguments to vn_open, which is a lot, but it's
still simpler than struct nameidata:
	at_dvp (directory vnode for openat() starting point, NULL ok)	
	pb (pathbuf)
	nmode (additional namei flags)
	fmode (open flags, converted from O_* to F*)
	cmode (creation permissions)
	ret_vp (pointer for returned vnode)
	ret_domove (pointer for returned is-EMOVEFD flag)
	ret_fd (pointer for returned file descriptor)

I have also rearranged the interface to fd_dupopen, which uses the
vn_open results, to match, and so that its return value argument is
last like it ought to be. This was chosen to be incompatible (as
opposed to just moving int arguments around, which isn't safe) in case
there were other calls to it somewhere. (There weren't.)

This patch is missing the doc change to vnsubr(9) but I'll deal with
that before committing.

It also builds but hasn't been tested yet; test results are pending.

Requires a kernel bump because a number of the callers of vn_open are
in modules.

Comments? Objections? Tentative plan is to commit this along with the
VOP_PARSEPATH changes (proposed years back), which also require a
kernel bump, plus some other pending kernel bump stuff other folks
have, in the next few days.

Note that cleaning out the hack entirely would be expensive (because a
similar alternative return value scheme is needed in the open methods
of struct cdevsw and bdevsw) so I'm not going to attempt it yet; plus
it's a natural part of the long-term device plumbing rearrangement I
posted about a few weeks back, and it makes more sense to do it as
part of that than separately.

Oh also, note that a couple of callers of vn_open were passing
LOCKPARENT and relying on vn_open to ignore it. That's been
rectified.

And before I forget: currently uses of vn_open that yield EMOVEFD when
the caller isn't prepared to handle it leak the fd produced. This
patch doesn't change that; doing so without creating new layer
violations would be a major nuisance. Avoiding this behavior sensibly
requires a complete cleanup of the hack, which prompts layering
violations because it's itself a layer violation.

* Does anyone know why dev/kloader.c calls namei and then vn_open on
the same path? I remember seeing this before and leaving it alone
because nobody I could find was sure what the deal was, but it's
unlikely to work as-is and increasingly likely to break over time...


diff -r 4c2d0a182ef8 external/cddl/osnet/sys/sys/vnode.h
--- a/external/cddl/osnet/sys/sys/vnode.h	Sun Jun 27 18:13:54 2021 -0400
+++ b/external/cddl/osnet/sys/sys/vnode.h	Mon Jun 28 11:05:45 2021 -0400
@@ -239,7 +239,6 @@
     vnode_t **vpp, enum create crwhy, mode_t umask)
 {
 	struct pathbuf *pb;
-	struct nameidata nd;
 	int error;
 
 	ASSERT(seg == UIO_SYSSPACE);
@@ -248,11 +247,9 @@
 	ASSERT(umask == 0);
 
 	pb = pathbuf_create(pnamep);
-	NDINIT(&nd, LOOKUP, NOFOLLOW, pb);
-	error = vn_open(&nd, filemode, createmode);
+	error = vn_open(NULL, pb, 0, filemode, createmode, vpp, NULL, NULL);
 	if (error == 0) {
-		VOP_UNLOCK(nd.ni_vp, 0);
-		*vpp = nd.ni_vp;
+		VOP_UNLOCK(*vpp, 0);
 	}
 	pathbuf_destroy(pb);
 	return (error);
diff -r 4c2d0a182ef8 sys/dev/firmload.c
--- a/sys/dev/firmload.c	Sun Jun 27 18:13:54 2021 -0400
+++ b/sys/dev/firmload.c	Mon Jun 28 11:05:45 2021 -0400
@@ -204,7 +204,6 @@
 firmware_open(const char *drvname, const char *imgname, firmware_handle_t *fhp)
 {
 	struct pathbuf *pb;
-	struct nameidata nd;
 	struct vattr va;
 	char *pnbuf, *path, *prefix;
 	firmware_handle_t fh;
@@ -236,8 +235,7 @@
 			error = ENOMEM;
 			break;
 		}
-		NDINIT(&nd, LOOKUP, FOLLOW | NOCHROOT, pb);
-		error = vn_open(&nd, FREAD, 0);
+		error = vn_open(NULL, pb, NOCHROOT, FREAD, 0, &vp, NULL, NULL);
 		pathbuf_destroy(pb);
 		if (error == ENOENT) {
 			continue;
@@ -251,8 +249,6 @@
 		return (error);
 	}
 
-	vp = nd.ni_vp;
-
 	error = VOP_GETATTR(vp, &va, kauth_cred_get());
 	if (error) {
 		VOP_UNLOCK(vp);
diff -r 4c2d0a182ef8 sys/dev/fss.c
--- a/sys/dev/fss.c	Sun Jun 27 18:13:54 2021 -0400
+++ b/sys/dev/fss.c	Mon Jun 28 11:05:45 2021 -0400
@@ -699,10 +699,9 @@
 	uint64_t numsec;
 	unsigned int secsize;
 	struct timespec ts;
-	/* nd -> nd2 to reduce mistakes while updating only some namei calls */
+	/* distinguish lookup 1 from lookup 2 to reduce mistakes */
 	struct pathbuf *pb2;
-	struct nameidata nd2;
-	struct vnode *vp;
+	struct vnode *vp, *vp2;
 
 	/*
 	 * Get the mounted file system.
@@ -789,16 +788,17 @@
 	if (error) {
  		return error;
 	}
-	NDINIT(&nd2, LOOKUP, FOLLOW, pb2);
-	if ((error = vn_open(&nd2, FREAD|FWRITE, 0)) != 0) {
+	error = vn_open(NULL, pb2, 0, FREAD|FWRITE, 0, &vp2, NULL, NULL);
+	if (error != 0) {
 		pathbuf_destroy(pb2);
 		return error;
 	}
-	VOP_UNLOCK(nd2.ni_vp);
+	VOP_UNLOCK(vp2);
 
-	sc->sc_bs_vp = nd2.ni_vp;
+	sc->sc_bs_vp = vp2;
 
-	if (nd2.ni_vp->v_type != VREG && nd2.ni_vp->v_type != VCHR) {
+	if (vp2->v_type != VREG && vp2->v_type != VCHR) {
+		vrele(vp2);
 		pathbuf_destroy(pb2);
 		return EINVAL;
 	}
diff -r 4c2d0a182ef8 sys/dev/kloader.c
--- a/sys/dev/kloader.c	Sun Jun 27 18:13:54 2021 -0400
+++ b/sys/dev/kloader.c	Mon Jun 28 11:05:45 2021 -0400
@@ -586,6 +586,7 @@
 {
 	struct pathbuf *pb;
 	struct nameidata nid;
+	struct vnode *vp;
 	int error;
 
 	pb = pathbuf_create(filename);
@@ -594,8 +595,11 @@
 		return (NULL);
 	}
 
+	/*
+	 * XXX why does this call both namei and vn_open?
+	 */
+
 	NDINIT(&nid, LOOKUP, FOLLOW, pb);
-
 	error = namei(&nid);
 	if (error != 0) {
 		PRINTF("%s: namei failed, errno=%d\n", filename, error);
@@ -603,7 +607,7 @@
 		return (NULL);
 	}
 
-	error = vn_open(&nid, FREAD, 0);
+	error = vn_open(NULL, pb, 0, FREAD, 0, &vp, NULL, NULL);
 	if (error != 0) {
 		PRINTF("%s: open failed, errno=%d\n", filename, error);
 		pathbuf_destroy(pb);
@@ -611,7 +615,7 @@
 	}
 
 	pathbuf_destroy(pb);
-	return (nid.ni_vp);
+	return vp;
 }
 
 void
diff -r 4c2d0a182ef8 sys/dev/vnd.c
--- a/sys/dev/vnd.c	Sun Jun 27 18:13:54 2021 -0400
+++ b/sys/dev/vnd.c	Mon Jun 28 11:05:45 2021 -0400
@@ -1145,7 +1145,7 @@
 	struct vnd_ioctl *vio;
 	struct vattr vattr;
 	struct pathbuf *pb;
-	struct nameidata nd;
+	struct vnode *vp;
 	int error, part, pmask;
 	uint64_t geomsize;
 	int fflags;
@@ -1273,20 +1273,20 @@
 		if (error) {
 			goto unlock_and_exit;
 		}
-		NDINIT(&nd, LOOKUP, FOLLOW, pb);
-		if ((error = vn_open(&nd, fflags, 0)) != 0) {
+		error = vn_open(NULL, pb, 0, fflags, 0, &vp, NULL, NULL);
+		if (error != 0) {
 			pathbuf_destroy(pb);
 			goto unlock_and_exit;
 		}
 		KASSERT(l);
-		error = VOP_GETATTR(nd.ni_vp, &vattr, l->l_cred);
-		if (!error && nd.ni_vp->v_type != VREG)
+		error = VOP_GETATTR(vp, &vattr, l->l_cred);
+		if (!error && vp->v_type != VREG)
 			error = EOPNOTSUPP;
 		if (!error && vattr.va_bytes < vattr.va_size)
 			/* File is definitely sparse, use vn_rdwr() */
 			vnd->sc_flags |= VNF_USE_VN_RDWR;
 		if (error) {
-			VOP_UNLOCK(nd.ni_vp);
+			VOP_UNLOCK(vp);
 			goto close_and_exit;
 		}
 
@@ -1304,19 +1304,19 @@
 			    M_TEMP, M_WAITOK);
 
 			/* read compressed file header */
-			error = vn_rdwr(UIO_READ, nd.ni_vp, (void *)ch,
+			error = vn_rdwr(UIO_READ, vp, (void *)ch,
 			    sizeof(struct vnd_comp_header), 0, UIO_SYSSPACE,
 			    IO_UNIT|IO_NODELOCKED, l->l_cred, NULL, NULL);
 			if (error) {
 				free(ch, M_TEMP);
-				VOP_UNLOCK(nd.ni_vp);
+				VOP_UNLOCK(vp);
 				goto close_and_exit;
 			}
 
 			if (be32toh(ch->block_size) == 0 ||
 			    be32toh(ch->num_blocks) > UINT32_MAX - 1) {
 				free(ch, M_TEMP);
-				VOP_UNLOCK(nd.ni_vp);
+				VOP_UNLOCK(vp);
 				goto close_and_exit;
 			}
 
@@ -1326,7 +1326,7 @@
 			vnd->sc_comp_numoffs = be32toh(ch->num_blocks) + 1;
 			free(ch, M_TEMP);
 			if (!DK_DEV_BSIZE_OK(vnd->sc_comp_blksz)) {
-				VOP_UNLOCK(nd.ni_vp);
+				VOP_UNLOCK(vp);
 				error = EINVAL;
 				goto close_and_exit;
 			}
@@ -1340,7 +1340,7 @@
 			 */
 #if SIZE_MAX <= UINT32_MAX*(64/CHAR_BIT)
 			if (SIZE_MAX/sizeof(uint64_t) < vnd->sc_comp_numoffs) {
-				VOP_UNLOCK(nd.ni_vp);
+				VOP_UNLOCK(vp);
 				error = EINVAL;
 				goto close_and_exit;
 			}
@@ -1350,7 +1350,7 @@
 				sizeof(uint64_t)*vnd->sc_comp_numoffs) ||
 			    (UQUAD_MAX/vnd->sc_comp_blksz <
 				vnd->sc_comp_numoffs - 1)) {
-				VOP_UNLOCK(nd.ni_vp);
+				VOP_UNLOCK(vp);
 				error = EINVAL;
 				goto close_and_exit;
 			}
@@ -1369,13 +1369,13 @@
 				M_DEVBUF, M_WAITOK);
 
 			/* read in the offsets */
-			error = vn_rdwr(UIO_READ, nd.ni_vp,
+			error = vn_rdwr(UIO_READ, vp,
 			    (void *)vnd->sc_comp_offsets,
 			    sizeof(uint64_t) * vnd->sc_comp_numoffs,
 			    sizeof(struct vnd_comp_header), UIO_SYSSPACE,
 			  IO_UNIT|IO_NODELOCKED, l->l_cred, NULL, NULL);
 			if (error) {
-				VOP_UNLOCK(nd.ni_vp);
+				VOP_UNLOCK(vp);
 				goto close_and_exit;
 			}
 			/*
@@ -1414,21 +1414,21 @@
 				if (vnd->sc_comp_stream.msg)
 					printf("vnd%d: compressed file, %s\n",
 					    unit, vnd->sc_comp_stream.msg);
-				VOP_UNLOCK(nd.ni_vp);
+				VOP_UNLOCK(vp);
 				error = EINVAL;
 				goto close_and_exit;
 			}
 
 			vnd->sc_flags |= VNF_COMP | VNF_READONLY;
 #else /* !VND_COMPRESSION */
-			VOP_UNLOCK(nd.ni_vp);
+			VOP_UNLOCK(vp);
 			error = EOPNOTSUPP;
 			goto close_and_exit;
 #endif /* VND_COMPRESSION */
 		}
 
-		VOP_UNLOCK(nd.ni_vp);
-		vnd->sc_vp = nd.ni_vp;
+		VOP_UNLOCK(vp);
+		vnd->sc_vp = vp;
 		vnd->sc_size = btodb(vattr.va_size);	/* note truncation */
 
 		/* get smallest I/O size for underlying device, fall back to
@@ -1553,7 +1553,7 @@
 		break;
 
 close_and_exit:
-		(void) vn_close(nd.ni_vp, fflags, l->l_cred);
+		(void) vn_close(vp, fflags, l->l_cred);
 		pathbuf_destroy(pb);
 unlock_and_exit:
 #ifdef VND_COMPRESSION
diff -r 4c2d0a182ef8 sys/kern/kern_acct.c
--- a/sys/kern/kern_acct.c	Sun Jun 27 18:13:54 2021 -0400
+++ b/sys/kern/kern_acct.c	Mon Jun 28 11:05:45 2021 -0400
@@ -297,7 +297,7 @@
 		syscallarg(const char *) path;
 	} */
 	struct pathbuf *pb;
-	struct nameidata nd;
+	struct vnode *vp;
 	int error;
 
 	/* Make sure that the caller is root. */
@@ -317,18 +317,19 @@
 		if (error) {
 			return error;
 		}
-		NDINIT(&nd, LOOKUP, FOLLOW | TRYEMULROOT, pb);
-		if ((error = vn_open(&nd, FWRITE|O_APPEND, 0)) != 0) {
+		error = vn_open(NULL, pb, TRYEMULROOT, FWRITE|O_APPEND, 0,
+				&vp, NULL, NULL);
+		if (error != 0) {
 			pathbuf_destroy(pb);
 			return error;
 		}
-		if (nd.ni_vp->v_type != VREG) {
-			VOP_UNLOCK(nd.ni_vp);
+		if (vp->v_type != VREG) {
+			VOP_UNLOCK(vp);
 			error = EACCES;
 			goto bad;
 		}
-		if ((error = VOP_GETATTR(nd.ni_vp, &va, l->l_cred)) != 0) {
-			VOP_UNLOCK(nd.ni_vp);
+		if ((error = VOP_GETATTR(vp, &va, l->l_cred)) != 0) {
+			VOP_UNLOCK(vp);
 			goto bad;
 		}
 
@@ -341,13 +342,13 @@
 #endif
 			vattr_null(&va);
 			va.va_size = size;
-			error = VOP_SETATTR(nd.ni_vp, &va, l->l_cred);
+			error = VOP_SETATTR(vp, &va, l->l_cred);
 			if (error != 0) {
-				VOP_UNLOCK(nd.ni_vp);
+				VOP_UNLOCK(vp);
 				goto bad;
 			}
 		}
-		VOP_UNLOCK(nd.ni_vp);
+		VOP_UNLOCK(vp);
 	}
 
 	rw_enter(&acct_lock, RW_WRITER);
@@ -366,7 +367,7 @@
 	 * and schedule the new free space watcher.
 	 */
 	acct_state = ACCT_ACTIVE;
-	acct_vp = nd.ni_vp;
+	acct_vp = vp;
 	acct_cred = l->l_cred;
 	kauth_cred_hold(acct_cred);
 
@@ -389,7 +390,7 @@
 	rw_exit(&acct_lock);
 	return (error);
  bad:
-	vn_close(nd.ni_vp, FWRITE, l->l_cred);
+	vn_close(vp, FWRITE, l->l_cred);
 	pathbuf_destroy(pb);
 	return error;
 }
diff -r 4c2d0a182ef8 sys/kern/kern_core.c
--- a/sys/kern/kern_core.c	Sun Jun 27 18:13:54 2021 -0400
+++ b/sys/kern/kern_core.c	Mon Jun 28 11:05:45 2021 -0400
@@ -123,7 +123,6 @@
 	struct vmspace		*vm;
 	kauth_cred_t		cred;
 	struct pathbuf		*pb;
-	struct nameidata	nd;
 	struct vattr		vattr;
 	struct coredump_iostate	io;
 	struct plimit		*lim;
@@ -240,13 +239,12 @@
 		error = ENOMEM;
 		goto done;
 	}
-	NDINIT(&nd, LOOKUP, NOFOLLOW, pb);
-	if ((error = vn_open(&nd, O_CREAT | O_NOFOLLOW | FWRITE,
-	    S_IRUSR | S_IWUSR)) != 0) {
+	error = vn_open(NULL, pb, 0, O_CREAT | O_NOFOLLOW | FWRITE,
+			S_IRUSR | S_IWUSR, &vp, NULL, NULL);
+	if (error != 0) {
 		pathbuf_destroy(pb);
 		goto done;
 	}
-	vp = nd.ni_vp;
 	pathbuf_destroy(pb);
 
 	/*
diff -r 4c2d0a182ef8 sys/kern/kern_descrip.c
--- a/sys/kern/kern_descrip.c	Sun Jun 27 18:13:54 2021 -0400
+++ b/sys/kern/kern_descrip.c	Mon Jun 28 11:05:45 2021 -0400
@@ -1646,14 +1646,32 @@
 
 /*
  * Duplicate the specified descriptor to a free descriptor.
+ *
+ * old is the original fd.
+ * moveit is true if we should move rather than duplicate.
+ * flags are the open flags (converted from O_* to F*).
+ * newp returns the new fd on success.
+ *
+ * These two cases are produced by the EDUPFD and EMOVEFD magic
+ * errnos, but in the interest of removing that regrettable interface,
+ * vn_open has been changed to intercept them. Now vn_open returns
+ * either a vnode or a filehandle, and the filehandle is accompanied
+ * by a boolean that says whether we should dup (moveit == false) or
+ * move (moveit == true) the fd.
+ *
+ * The dup case is used by /dev/stderr, /proc/self/fd, and such. The
+ * move case is used by cloner devices that allocate a fd of their
+ * own (a layering violation that should go away eventually) that
+ * then needs to be put in the place open() expects it.
  */
 int
-fd_dupopen(int old, int *newp, int mode, int error)
+fd_dupopen(int old, bool moveit, int flags, int *newp)
 {
 	filedesc_t *fdp;
 	fdfile_t *ff;
 	file_t *fp;
 	fdtab_t *dt;
+	int error;
 
 	if ((fp = fd_getfile(old)) == NULL) {
 		return EBADF;
@@ -1665,35 +1683,30 @@
 	/*
 	 * There are two cases of interest here.
 	 *
-	 * For EDUPFD simply dup (old) to file descriptor
-	 * (new) and return.
+	 * 1. moveit == false (used to be the EDUPFD magic errno):
+	 *    simply dup (old) to file descriptor (new) and return.
 	 *
-	 * For EMOVEFD steal away the file structure from (old) and
-	 * store it in (new).  (old) is effectively closed by
-	 * this operation.
-	 *
-	 * Any other error code is just returned.
+	 * 2. moveit == true (used to be the EMOVEFD magic errno):
+	 *    steal away the file structure from (old) and store it in
+	 *    (new).  (old) is effectively closed by this operation.
 	 */
-	switch (error) {
-	case EDUPFD:
+	if (moveit == false) {
 		/*
 		 * Check that the mode the file is being opened for is a
 		 * subset of the mode of the existing descriptor.
 		 */
-		if (((mode & (FREAD|FWRITE)) | fp->f_flag) != fp->f_flag) {
+		if (((flags & (FREAD|FWRITE)) | fp->f_flag) != fp->f_flag) {
 			error = EACCES;
-			break;
+			goto out;
 		}
 
 		/* Copy it. */
 		error = fd_dup(fp, 0, newp, ff->ff_exclose);
-		break;
-
-	case EMOVEFD:
+	} else {
 		/* Copy it. */
 		error = fd_dup(fp, 0, newp, ff->ff_exclose);
 		if (error != 0) {
-			break;
+			goto out;
 		}
 
 		/* Steal away the file pointer from 'old'. */
@@ -1701,6 +1714,7 @@
 		return 0;
 	}
 
+out:
 	fd_putfile(old);
 	return error;
 }
diff -r 4c2d0a182ef8 sys/kern/kern_ktrace_vfs.c
--- a/sys/kern/kern_ktrace_vfs.c	Sun Jun 27 18:13:54 2021 -0400
+++ b/sys/kern/kern_ktrace_vfs.c	Mon Jun 28 11:05:45 2021 -0400
@@ -93,7 +93,6 @@
 	struct vnode *vp = NULL;
 	file_t *fp = NULL;
 	struct pathbuf *pb;
-	struct nameidata nd;
 	int error = 0;
 	int fd;
 
@@ -109,13 +108,12 @@
 			ktrexit(l);
 			return (error);
 		}
-		NDINIT(&nd, LOOKUP, FOLLOW, pb);
-		if ((error = vn_open(&nd, FREAD|FWRITE, 0)) != 0) {
+		error = vn_open(NULL, pb, 0, FREAD|FWRITE, 0, &vp, NULL, NULL);
+		if (error != 0) {
 			pathbuf_destroy(pb);
 			ktrexit(l);
 			return (error);
 		}
-		vp = nd.ni_vp;
 		pathbuf_destroy(pb);
 		VOP_UNLOCK(vp);
 		if (vp->v_type != VREG) {
diff -r 4c2d0a182ef8 sys/kern/kern_module_vfs.c
--- a/sys/kern/kern_module_vfs.c	Sun Jun 27 18:13:54 2021 -0400
+++ b/sys/kern/kern_module_vfs.c	Mon Jun 28 11:05:45 2021 -0400
@@ -150,7 +150,7 @@
     prop_dictionary_t *filedictp)
 {
 	struct pathbuf *pb;
-	struct nameidata nd;
+	struct vnode *vp;
 	struct stat sb;
 	void *base;
 	char *proppath;
@@ -181,14 +181,13 @@
 	}
 	module_print("Loading plist from %s", proppath);
 	
-	NDINIT(&nd, LOOKUP, FOLLOW | (nochroot ? NOCHROOT : 0), pb);
-
-	error = vn_open(&nd, FREAD, 0);
+	error = vn_open(NULL, pb, (nochroot ? NOCHROOT : 0), FREAD, 0,
+			&vp, NULL, NULL);
  	if (error != 0) {
 	 	goto out2;
 	}
 
-	error = vn_stat(nd.ni_vp, &sb);
+	error = vn_stat(vp, &sb);
 	if (error != 0) {
 		goto out3;
 	}
@@ -198,7 +197,7 @@
 	}
 
 	base = kmem_alloc(plistsize, KM_SLEEP);
-	error = vn_rdwr(UIO_READ, nd.ni_vp, base, sb.st_size, 0,
+	error = vn_rdwr(UIO_READ, vp, base, sb.st_size, 0,
 	    UIO_SYSSPACE, IO_NODELOCKED, curlwp->l_cred, &resid, curlwp);
 	*((uint8_t *)base + sb.st_size) = '\0';
 	if (error == 0 && resid != 0) {
@@ -219,8 +218,8 @@
 	KASSERT(error == 0);
 
 out3:
-	VOP_UNLOCK(nd.ni_vp);
-	vn_close(nd.ni_vp, FREAD, kauth_cred_get());
+	VOP_UNLOCK(vp);
+	vn_close(vp, FREAD, kauth_cred_get());
 
 out2:
 	pathbuf_destroy(pb);
diff -r 4c2d0a182ef8 sys/kern/subr_exec_fd.c
--- a/sys/kern/subr_exec_fd.c	Sun Jun 27 18:13:54 2021 -0400
+++ b/sys/kern/subr_exec_fd.c	Mon Jun 28 11:05:45 2021 -0400
@@ -81,7 +81,7 @@
 {
 	struct proc *p;
 	struct pathbuf *pb;
-	struct nameidata nd;
+	struct vnode *vp;
 	filedesc_t *fdp;
 	file_t *fp;
 	fdtab_t *dt;
@@ -108,17 +108,17 @@
 		if (pb == NULL) {
 			return ENOMEM;
 		}
-		NDINIT(&nd, LOOKUP, FOLLOW, pb);
-		if ((error = vn_open(&nd, flags, 0)) != 0) {
+		error = vn_open(NULL, pb, 0, flags, 0, &vp, NULL, NULL);
+		if (error != 0) {
 			pathbuf_destroy(pb);
 			fd_abort(p, fp, fd);
 			return (error);
 		}
 		fp->f_type = DTYPE_VNODE;
-		fp->f_vnode = nd.ni_vp;
+		fp->f_vnode = vp;
 		fp->f_flag = flags;
 		fp->f_ops = &vnops;
-		VOP_UNLOCK(nd.ni_vp);
+		VOP_UNLOCK(vp);
 		fd_affix(p, fp, fd);
 		pathbuf_destroy(pb);
 	}
diff -r 4c2d0a182ef8 sys/kern/subr_kobj_vfs.c
--- a/sys/kern/subr_kobj_vfs.c	Sun Jun 27 18:13:54 2021 -0400
+++ b/sys/kern/subr_kobj_vfs.c	Mon Jun 28 11:05:45 2021 -0400
@@ -150,8 +150,8 @@
 int
 kobj_load_vfs(kobj_t *kop, const char *path, const bool nochroot)
 {
-	struct nameidata nd;
 	struct pathbuf *pb;
+	struct vnode *vp;
 	int error;
 	kobj_t ko;
 
@@ -166,8 +166,8 @@
 		return ENOMEM;
 	}
 
-	NDINIT(&nd, LOOKUP, FOLLOW | (nochroot ? NOCHROOT : 0), pb);
-	error = vn_open(&nd, FREAD, 0);
+	error = vn_open(NULL, pb, (nochroot ? NOCHROOT : 0), FREAD, 0,
+			&vp, NULL, NULL);
 
  	if (error != 0) {
 		pathbuf_destroy(pb);
@@ -177,7 +177,7 @@
 
 	ko->ko_type = KT_VNODE;
 	kobj_setname(ko, path);
-	ko->ko_source = nd.ni_vp;
+	ko->ko_source = vp;
 	ko->ko_read = kobj_read_vfs;
 	ko->ko_close = kobj_close_vfs;
 	pathbuf_destroy(pb);
diff -r 4c2d0a182ef8 sys/kern/tty_ptm.c
--- a/sys/kern/tty_ptm.c	Sun Jun 27 18:13:54 2021 -0400
+++ b/sys/kern/tty_ptm.c	Mon Jun 28 11:05:45 2021 -0400
@@ -141,6 +141,8 @@
 	error = VOP_OPEN(vp, FREAD|FWRITE, lwp0.l_cred);
 
 	if (error) {
+		/* only ptys mean we can't get these */
+		KASSERT(error != EDUPFD && error != EMOVEFD);
 		vput(vp);
 		return error;
 	}
diff -r 4c2d0a182ef8 sys/kern/vfs_syscalls.c
--- a/sys/kern/vfs_syscalls.c	Sun Jun 27 18:13:54 2021 -0400
+++ b/sys/kern/vfs_syscalls.c	Mon Jun 28 11:05:45 2021 -0400
@@ -1635,9 +1635,10 @@
 	struct cwdinfo *cwdi = p->p_cwdi;
 	file_t *fp;
 	struct vnode *vp;
+	int dupfd;
+	bool dupfd_move;
 	int flags, cmode;
 	int indx, error;
-	struct nameidata nd;
 
 	if (open_flags & O_SEARCH) {
 		open_flags &= ~(int)O_SEARCH;
@@ -1660,34 +1661,32 @@
 
 	/* We're going to read cwdi->cwdi_cmask unlocked here. */
 	cmode = ((open_mode &~ cwdi->cwdi_cmask) & ALLPERMS) &~ S_ISTXT;
-	NDINIT(&nd, LOOKUP, FOLLOW | TRYEMULROOT, pb);
-	if (dvp != NULL)
-		NDAT(&nd, dvp);
 	
-	l->l_dupfd = -indx - 1;			/* XXX check for fdopen */
-	if ((error = vn_open(&nd, flags, cmode)) != 0) {
+	error = vn_open(dvp, pb, TRYEMULROOT, flags, cmode,
+			&vp, &dupfd_move, &dupfd);
+	if (error != 0) {
 		fd_abort(p, fp, indx);
-		if ((error == EDUPFD || error == EMOVEFD) &&
-		    l->l_dupfd >= 0 &&			/* XXX from fdopen */
-		    (error =
-			fd_dupopen(l->l_dupfd, &indx, flags, error)) == 0) {
-			*fd = indx;
-			return 0;
-		}
 		if (error == ERESTART)
 			error = EINTR;
 		return error;
 	}
 
-	l->l_dupfd = 0;
-	vp = nd.ni_vp;
-
-	if ((error = open_setfp(l, fp, vp, indx, flags)))
-		return error;
-
-	VOP_UNLOCK(vp);
-	*fd = indx;
-	fd_affix(p, fp, indx);
+	if (vp == NULL) {
+		fd_abort(p, fp, indx);
+		error = fd_dupopen(dupfd, dupfd_move, flags, &indx);
+		if (error == 0) {
+			*fd = indx;
+			return 0;
+		}
+	} else {
+		error = open_setfp(l, fp, vp, indx, flags);
+		if (error)
+			return error;
+		VOP_UNLOCK(vp);
+		*fd = indx;
+		fd_affix(p, fp, indx);
+	}
+
 	return 0;
 }
 
@@ -2114,6 +2113,10 @@
 	fd_abort(p, fp, indx);
 	if (vp != NULL)
 		vput(vp);
+	if (error == EDUPFD || error == EMOVEFD) {
+		/* XXX should probably close curlwp->l_dupfd */
+		error = EOPNOTSUPP;
+	}
 	return (error);
 }
 
diff -r 4c2d0a182ef8 sys/kern/vfs_vnops.c
--- a/sys/kern/vfs_vnops.c	Sun Jun 27 18:13:54 2021 -0400
+++ b/sys/kern/vfs_vnops.c	Mon Jun 28 11:05:45 2021 -0400
@@ -139,10 +139,31 @@
 /*
  * Common code for vnode open operations.
  * Check permissions, and call the VOP_OPEN or VOP_CREATE routine.
+ *
+ * at_dvp is the directory for openat(), if any.
+ * pb is the path.
+ * nmode is additional namei flags, restricted to TRYEMULROOT and NOCHROOT.
+ * fmode is the open flags, converted from O_* to F*
+ * cmode is the creation file permissions.
+ *
+ * XXX shouldn't cmode be mode_t?
+ *
+ * On success produces either a vnode in *ret_vp, or if that is NULL,
+ * a file descriptor number in ret_fd.
+ *
+ * The caller may pass NULL for ret_fd (and ret_domove), in which case
+ * EOPNOTSUPP will be produced in the cases that would otherwise return
+ * a file descriptor.
+ *
+ * Note that callers that want NOFOLLOW should pass O_NOFOLLOW in fmode,
+ * not NOFOLLOW in nmode.
  */
 int
-vn_open(struct nameidata *ndp, int fmode, int cmode)
+vn_open(struct vnode *at_dvp, struct pathbuf *pb,
+	int nmode, int fmode, int cmode,
+	struct vnode **ret_vp, bool *ret_domove, int *ret_fd)
 {
+	struct nameidata nd;
 	struct vnode *vp;
 	struct lwp *l = curlwp;
 	kauth_cred_t cred = l->l_cred;
@@ -150,39 +171,53 @@
 	int error;
 	const char *pathstring;
 
+	KASSERT((nmode & (TRYEMULROOT | NOCHROOT)) == nmode);
+
 	if ((fmode & (O_CREAT | O_DIRECTORY)) == (O_CREAT | O_DIRECTORY))
 		return EINVAL;
 
-	ndp->ni_cnd.cn_flags &= TRYEMULROOT | NOCHROOT;
+	NDINIT(&nd, LOOKUP, FOLLOW | nmode, pb);
+	if (at_dvp != NULL)
+		NDAT(&nd, at_dvp);
+
+	nd.ni_cnd.cn_flags &= TRYEMULROOT | NOCHROOT;
 
 	if (fmode & O_CREAT) {
-		ndp->ni_cnd.cn_nameiop = CREATE;
-		ndp->ni_cnd.cn_flags |= LOCKPARENT | LOCKLEAF;
+		nd.ni_cnd.cn_nameiop = CREATE;
+		nd.ni_cnd.cn_flags |= LOCKPARENT | LOCKLEAF;
 		if ((fmode & O_EXCL) == 0 &&
 		    ((fmode & O_NOFOLLOW) == 0))
-			ndp->ni_cnd.cn_flags |= FOLLOW;
+			nd.ni_cnd.cn_flags |= FOLLOW;
 		if ((fmode & O_EXCL) == 0)
-			ndp->ni_cnd.cn_flags |= NONEXCLHACK;
+			nd.ni_cnd.cn_flags |= NONEXCLHACK;
 	} else {
-		ndp->ni_cnd.cn_nameiop = LOOKUP;
-		ndp->ni_cnd.cn_flags |= LOCKLEAF;
+		nd.ni_cnd.cn_nameiop = LOOKUP;
+		nd.ni_cnd.cn_flags |= LOCKLEAF;
 		if ((fmode & O_NOFOLLOW) == 0)
-			ndp->ni_cnd.cn_flags |= FOLLOW;
+			nd.ni_cnd.cn_flags |= FOLLOW;
 	}
 
-	pathstring = pathbuf_stringcopy_get(ndp->ni_pathbuf);
+	pathstring = pathbuf_stringcopy_get(nd.ni_pathbuf);
 	if (pathstring == NULL) {
 		return ENOMEM;
 	}
 
-	error = namei(ndp);
+	/*
+	 * When this "interface" was exposed to do_open() it used
+	 * to initialize l_dupfd to -newfd-1 (thus passing in the
+	 * new file handle number to use)... but nothing in the
+	 * kernel uses that value. So just send 0.
+	 */
+	l->l_dupfd = 0;
+
+	error = namei(&nd);
 	if (error)
 		goto out;
 
-	vp = ndp->ni_vp;
+	vp = nd.ni_vp;
 
 #if NVERIEXEC > 0
-	error = veriexec_openchk(l, ndp->ni_vp, pathstring, fmode);
+	error = veriexec_openchk(l, nd.ni_vp, pathstring, fmode);
 	if (error) {
 		/* We have to release the locks ourselves */
 		/*
@@ -190,16 +225,16 @@
 		 * get ni_dvp == NULL back if ni_vp exists, and we should
 		 * treat that like the non-O_CREAT case.
 		 */
-		if ((fmode & O_CREAT) != 0 && ndp->ni_dvp != NULL) {
+		if ((fmode & O_CREAT) != 0 && nd.ni_dvp != NULL) {
 			if (vp == NULL) {
-				vput(ndp->ni_dvp);
+				vput(nd.ni_dvp);
 			} else {
-				VOP_ABORTOP(ndp->ni_dvp, &ndp->ni_cnd);
-				if (ndp->ni_dvp == ndp->ni_vp)
-					vrele(ndp->ni_dvp);
+				VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
+				if (nd.ni_dvp == nd.ni_vp)
+					vrele(nd.ni_dvp);
 				else
-					vput(ndp->ni_dvp);
-				ndp->ni_dvp = NULL;
+					vput(nd.ni_dvp);
+				nd.ni_dvp = NULL;
 				vput(vp);
 			}
 		} else {
@@ -212,31 +247,31 @@
 	/*
 	 * 20210604 dholland ditto
 	 */
-	if ((fmode & O_CREAT) != 0 && ndp->ni_dvp != NULL) {
-		if (ndp->ni_vp == NULL) {
+	if ((fmode & O_CREAT) != 0 && nd.ni_dvp != NULL) {
+		if (nd.ni_vp == NULL) {
 			vattr_null(&va);
 			va.va_type = VREG;
 			va.va_mode = cmode;
 			if (fmode & O_EXCL)
 				 va.va_vaflags |= VA_EXCLUSIVE;
-			error = VOP_CREATE(ndp->ni_dvp, &ndp->ni_vp,
-					   &ndp->ni_cnd, &va);
+			error = VOP_CREATE(nd.ni_dvp, &nd.ni_vp,
+					   &nd.ni_cnd, &va);
 			if (error) {
-				vput(ndp->ni_dvp);
+				vput(nd.ni_dvp);
 				goto out;
 			}
 			fmode &= ~O_TRUNC;
-			vp = ndp->ni_vp;
+			vp = nd.ni_vp;
 			vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
-			vput(ndp->ni_dvp);
+			vput(nd.ni_dvp);
 		} else {
-			VOP_ABORTOP(ndp->ni_dvp, &ndp->ni_cnd);
-			if (ndp->ni_dvp == ndp->ni_vp)
-				vrele(ndp->ni_dvp);
+			VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
+			if (nd.ni_dvp == nd.ni_vp)
+				vrele(nd.ni_dvp);
 			else
-				vput(ndp->ni_dvp);
-			ndp->ni_dvp = NULL;
-			vp = ndp->ni_vp;
+				vput(nd.ni_dvp);
+			nd.ni_dvp = NULL;
+			vp = nd.ni_vp;
 			if (fmode & O_EXCL) {
 				error = EEXIST;
 				goto bad;
@@ -251,17 +286,17 @@
 		 * half of the following block. (Besides handle
 		 * ni_dvp, anyway.)
 		 */
-		vp = ndp->ni_vp;
+		vp = nd.ni_vp;
 		KASSERT((fmode & O_EXCL) == 0);
 		fmode &= ~O_CREAT;
 	} else {
-		vp = ndp->ni_vp;
+		vp = nd.ni_vp;
 	}
 	if (vp->v_type == VSOCK) {
 		error = EOPNOTSUPP;
 		goto bad;
 	}
-	if (ndp->ni_vp->v_type == VLNK) {
+	if (nd.ni_vp->v_type == VLNK) {
 		error = EFTYPE;
 		goto bad;
 	}
@@ -291,8 +326,40 @@
 	if (error)
 		vput(vp);
 out:
-	pathbuf_stringcopy_put(ndp->ni_pathbuf, pathstring);
-	return (error);
+	pathbuf_stringcopy_put(nd.ni_pathbuf, pathstring);
+
+	/* if the caller isn't prepared to handle fds, fail for them */
+	if (ret_fd == NULL && (error == EDUPFD || error == EMOVEFD)) {
+		/*
+		 * XXX: for EMOVEFD (cloning devices) this leaks the
+		 * device's file descriptor. That's not good, but
+		 * fixing it here would still be a layer violation and
+		 * callers not currently prepared to deal weren't
+		 * prepared before I rearranged things either and
+		 * would still have leaked the fd, so it's at least
+		 * not a regression.
+		 *    -- dholland 20210627
+		 */
+		error = EOPNOTSUPP;
+	}
+
+	if (error == EDUPFD) {
+		*ret_vp = NULL;
+		*ret_domove = false;
+		*ret_fd = l->l_dupfd;
+		error = 0;
+	} else if (error == EMOVEFD) {
+		*ret_vp = NULL;
+		*ret_domove = true;
+		*ret_fd = l->l_dupfd;
+		error = 0;
+	} else if (error == 0) {
+		*ret_vp = vp;
+		*ret_domove = false;
+		*ret_fd = -1;
+	}
+	l->l_dupfd = 0;
+	return error;
 }
 
 /*
@@ -1235,17 +1302,15 @@
 int
 vn_bdev_openpath(struct pathbuf *pb, struct vnode **vpp, struct lwp *l)
 {
-	struct nameidata nd;
 	struct vnode *vp;
 	dev_t dev;
 	enum vtype vt;
 	int     error;
 
-	NDINIT(&nd, LOOKUP, FOLLOW, pb);
-	if ((error = vn_open(&nd, FREAD | FWRITE, 0)) != 0)
+	error = vn_open(NULL, pb, 0, FREAD | FWRITE, 0, &vp, NULL, NULL);
+	if (error != 0)
 		return error;
 
-	vp = nd.ni_vp;
 	dev = vp->v_rdev;
 	vt = vp->v_type;
 
diff -r 4c2d0a182ef8 sys/miscfs/fdesc/fdesc_vnops.c
--- a/sys/miscfs/fdesc/fdesc_vnops.c	Sun Jun 27 18:13:54 2021 -0400
+++ b/sys/miscfs/fdesc/fdesc_vnops.c	Mon Jun 28 11:05:45 2021 -0400
@@ -326,11 +326,13 @@
 	case Fdesc:
 		/*
 		 * XXX Kludge: set dupfd to contain the value of the
-		 * the file descriptor being sought for duplication. The error
-		 * return ensures that the vnode for this device will be
-		 * released by vn_open. Open will detect this special error and
-		 * take the actions in dupfdopen.  Other callers of vn_open or
-		 * VOP_OPEN will simply report the error.
+		 * the file descriptor being sought for duplication.
+		 * The error return ensures that the vnode for this
+		 * device will be released by vn_open. vn_open will
+		 * then detect this special error and take the actions
+		 * in fd_dupopen. Other callers of vn_open or VOP_OPEN
+		 * not prepared to deal with this situation will
+		 * report a real error.
 		 */
 		curlwp->l_dupfd = VTOFDESC(vp)->fd_fd;	/* XXX */
 		return EDUPFD;
diff -r 4c2d0a182ef8 sys/modules/lua/lua.c
--- a/sys/modules/lua/lua.c	Sun Jun 27 18:13:54 2021 -0400
+++ b/sys/modules/lua/lua.c	Mon Jun 28 11:05:45 2021 -0400
@@ -284,7 +284,7 @@
 	struct lua_state *s;
 	struct lua_module *m;
 	kauth_cred_t cred;
-	struct nameidata nd;
+	struct vnode *vp;
 	struct pathbuf *pb;
 	struct vattr va;
 	struct lua_loadstate ls;
@@ -414,8 +414,8 @@
 				pb = pathbuf_create(load->path);
 				if (pb == NULL)
 					return ENOMEM;
-				NDINIT(&nd, LOOKUP, FOLLOW | NOCHROOT, pb);
-				error = vn_open(&nd, FREAD, 0);
+				error = vn_open(NULL, pb, NOCHROOT, FREAD, 0,
+						&vp, NULL, NULL);
 				pathbuf_destroy(pb);
 				if (error) {
 					if (lua_verbose)
@@ -424,11 +424,11 @@
 						    error);
 					return error;
 				}
-				error = VOP_GETATTR(nd.ni_vp, &va,
+				error = VOP_GETATTR(vp, &va,
 				    kauth_cred_get());
 				if (error) {
-					VOP_UNLOCK(nd.ni_vp);
-					vn_close(nd.ni_vp, FREAD,
+					VOP_UNLOCK(vp);
+					vn_close(vp, FREAD,
 					    kauth_cred_get());
 					if (lua_verbose)
 						device_printf(sc->sc_dev,
@@ -437,19 +437,19 @@
 					return error;
 				}
 				if (va.va_type != VREG) {
-					VOP_UNLOCK(nd.ni_vp);
-					vn_close(nd.ni_vp, FREAD,
+					VOP_UNLOCK(vp);
+					vn_close(vp, FREAD,
 					    kauth_cred_get());
 					return EINVAL;
 				}
-				ls.vp = nd.ni_vp;
+				ls.vp = vp;
 				ls.off = 0L;
 				ls.size = va.va_size;
-				VOP_UNLOCK(nd.ni_vp);
+				VOP_UNLOCK(vp);
 				klua_lock(s->K);
 				error = lua_load(s->K->L, lua_reader, &ls,
 				    strrchr(load->path, '/') + 1, "bt");
-				vn_close(nd.ni_vp, FREAD, cred);
+				vn_close(vp, FREAD, cred);
 				switch (error) {
 				case 0:	/* no error */
 					break;
diff -r 4c2d0a182ef8 sys/sys/filedesc.h
--- a/sys/sys/filedesc.h	Sun Jun 27 18:13:54 2021 -0400
+++ b/sys/sys/filedesc.h	Mon Jun 28 11:05:45 2021 -0400
@@ -192,7 +192,7 @@
  */
 void	fd_sys_init(void);
 int	fd_open(const char*, int, int, int*);
-int	fd_dupopen(int, int *, int, int);
+int	fd_dupopen(int, bool, int, int *);
 int	fd_alloc(struct proc *, int, int *);
 void	fd_tryexpand(struct proc *);
 int	fd_allocfile(file_t **, int *);
diff -r 4c2d0a182ef8 sys/sys/vnode.h
--- a/sys/sys/vnode.h	Sun Jun 27 18:13:54 2021 -0400
+++ b/sys/sys/vnode.h	Mon Jun 28 11:05:45 2021 -0400
@@ -594,7 +594,8 @@
 int	vn_lock(struct vnode *, int);
 void	vn_markexec(struct vnode *);
 int	vn_marktext(struct vnode *);
-int 	vn_open(struct nameidata *, int, int);
+int 	vn_open(struct vnode *, struct pathbuf *, int, int, int,
+	    struct vnode **, bool *, int *);
 int 	vn_rdwr(enum uio_rw, struct vnode *, void *, int, off_t, enum uio_seg,
     int, kauth_cred_t, size_t *, struct lwp *);
 int	vn_readdir(struct file *, char *, int, unsigned int, int *,
diff -r 4c2d0a182ef8 sys/ufs/lfs/ulfs_extattr.c
--- a/sys/ufs/lfs/ulfs_extattr.c	Sun Jun 27 18:13:54 2021 -0400
+++ b/sys/ufs/lfs/ulfs_extattr.c	Mon Jun 28 11:05:45 2021 -0400
@@ -171,7 +171,6 @@
 	struct mount *mp = vp->v_mount;
 	struct ulfsmount *ump = VFSTOULFS(mp);
 	struct vnode *backing_vp;
-	struct nameidata nd;
 	struct pathbuf *pb;
 	char *path;
 	struct ulfs_extattr_fileheader uef;
@@ -223,14 +222,16 @@
 	VOP_UNLOCK(vp);
 
 	pb = pathbuf_create(path);
-	NDINIT(&nd, CREATE, LOCKPARENT, pb);
 	
 	/*
 	 * Since we do not hold ulfs_extattr_uepm_lock anymore,
 	 * another thread may race with us for backend creation,
-	 * but only one can succeed here thanks to O_EXCL
+	 * but only one can succeed here thanks to O_EXCL.
+	 *
+ 	 * backing_vp is the backing store. 
 	 */
-	error = vn_open(&nd, O_CREAT|O_EXCL|O_RDWR, 0600);
+	error = vn_open(NULL, pb, 0, O_CREAT|O_EXCL|O_RDWR, 0600,
+			&backing_vp, NULL, NULL);
 
 	/*
 	 * Reacquire the lock on the vnode
@@ -247,14 +248,9 @@
 		return error;
 	}
 
-	KASSERT(nd.ni_vp != NULL);
-	KASSERT(VOP_ISLOCKED(nd.ni_vp) == LK_EXCLUSIVE);
-	KASSERT(VOP_ISLOCKED(nd.ni_dvp) == 0);
+	KASSERT(backing_vp != NULL);
+	KASSERT(VOP_ISLOCKED(backing_vp) == LK_EXCLUSIVE);
 
-	/*
- 	 * backing_vp is the backing store. 
-	 */	
-	backing_vp = nd.ni_vp;
 	pathbuf_destroy(pb);
 	PNBUF_PUT(path);
 
diff -r 4c2d0a182ef8 sys/ufs/lfs/ulfs_quota1.c
--- a/sys/ufs/lfs/ulfs_quota1.c	Sun Jun 27 18:13:54 2021 -0400
+++ b/sys/ufs/lfs/ulfs_quota1.c	Mon Jun 28 11:05:45 2021 -0400
@@ -312,7 +312,6 @@
 	struct dquot *dq;
 	int error;
 	struct pathbuf *pb;
-	struct nameidata nd;
 
 	if (fs->um_flags & ULFS_QUOTA2) {
 		uprintf("%s: quotas v2 already enabled\n",
@@ -326,12 +325,11 @@
 	if (pb == NULL) {
 		return ENOMEM;
 	}
-	NDINIT(&nd, LOOKUP, FOLLOW, pb);
-	if ((error = vn_open(&nd, FREAD|FWRITE, 0)) != 0) {
+	error = vn_open(NULL, pb, 0, FREAD|FWRITE, 0, &vp, NULL, NULL);
+	if (error != 0) {
 		pathbuf_destroy(pb);
 		return error;
 	}
-	vp = nd.ni_vp;
 	pathbuf_destroy(pb);
 
 	VOP_UNLOCK(vp);
diff -r 4c2d0a182ef8 sys/ufs/ufs/ufs_extattr.c
--- a/sys/ufs/ufs/ufs_extattr.c	Sun Jun 27 18:13:54 2021 -0400
+++ b/sys/ufs/ufs/ufs_extattr.c	Mon Jun 28 11:05:45 2021 -0400
@@ -172,7 +172,6 @@
 	struct mount *mp = vp->v_mount;
 	struct ufsmount *ump = VFSTOUFS(mp);
 	struct vnode *backing_vp;
-	struct nameidata nd;
 	struct pathbuf *pb;
 	char *path;
 	struct ufs_extattr_fileheader uef;
@@ -220,14 +219,16 @@
 	VOP_UNLOCK(vp);
 
 	pb = pathbuf_create(path);
-	NDINIT(&nd, CREATE, LOCKPARENT, pb);
 	
 	/*
 	 * Since we do not hold ufs_extattr_uepm_lock anymore,
 	 * another thread may race with us for backend creation,
-	 * but only one can succeed here thanks to O_EXCL
+	 * but only one can succeed here thanks to O_EXCL.
+	 *
+ 	 * backing_vp is the backing store. 
 	 */
-	error = vn_open(&nd, O_CREAT|O_EXCL|O_RDWR, 0600);
+	error = vn_open(NULL, pb, 0, O_CREAT|O_EXCL|O_RDWR, 0600,
+			&backing_vp, NULL, NULL);
 
 	/*
 	 * Reacquire the lock on the vnode
@@ -244,14 +245,9 @@
 		return error;
 	}
 
-	KASSERT(nd.ni_vp != NULL);
-	KASSERT(VOP_ISLOCKED(nd.ni_vp) == LK_EXCLUSIVE);
-	KASSERT(VOP_ISLOCKED(nd.ni_dvp) == 0);
+	KASSERT(backing_vp != NULL);
+	KASSERT(VOP_ISLOCKED(backing_vp) == LK_EXCLUSIVE);
 
-	/*
- 	 * backing_vp is the backing store. 
-	 */	
-	backing_vp = nd.ni_vp;
 	pathbuf_destroy(pb);
 	PNBUF_PUT(path);
 
diff -r 4c2d0a182ef8 sys/ufs/ufs/ufs_quota1.c
--- a/sys/ufs/ufs/ufs_quota1.c	Sun Jun 27 18:13:54 2021 -0400
+++ b/sys/ufs/ufs/ufs_quota1.c	Mon Jun 28 11:05:45 2021 -0400
@@ -309,7 +309,6 @@
 	struct dquot *dq;
 	int error;
 	struct pathbuf *pb;
-	struct nameidata nd;
 
 	if (type < 0 || type >= MAXQUOTAS)
 		return EINVAL;
@@ -332,12 +331,11 @@
 	if (pb == NULL) {
 		return ENOMEM;
 	}
-	NDINIT(&nd, LOOKUP, FOLLOW, pb);
-	if ((error = vn_open(&nd, FREAD|FWRITE, 0)) != 0) {
+	error = vn_open(NULL, pb, 0, FREAD|FWRITE, 0, &vp, NULL, NULL);
+	if (error != 0) {
 		pathbuf_destroy(pb);
 		return error;
 	}
-	vp = nd.ni_vp;
 	pathbuf_destroy(pb);
 
 	VOP_UNLOCK(vp);



-- 
David A. Holland
dholland%netbsd.org@localhost


Home | Main Index | Thread Index | Old Index