Module Name:    src
Committed By:   dholland
Date:           Sun Jul 17 22:07:59 UTC 2011

Modified Files:
        src/sys/ufs/ufs: ufs_extern.h ufs_lookup.c ufs_wapbl.c

Log Message:
Provide correct locking for ufs_wapbl_rename. Note that this does not
fix the non-wapbl rename; that will be coming soon. This patch also
leaves a lot of the older locking-related code around in #if 0 blocks,
and there's a lot of leftover redundant logic. All that will be going
away later.

Relates to at least these PRs:

  PR kern/24887
  PR kern/41417
  PR kern/42093
  PR kern/43626

and possibly others.


To generate a diff of this commit:
cvs rdiff -u -r1.65 -r1.66 src/sys/ufs/ufs/ufs_extern.h
cvs rdiff -u -r1.110 -r1.111 src/sys/ufs/ufs/ufs_lookup.c
cvs rdiff -u -r1.16 -r1.17 src/sys/ufs/ufs/ufs_wapbl.c

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

Modified files:

Index: src/sys/ufs/ufs/ufs_extern.h
diff -u src/sys/ufs/ufs/ufs_extern.h:1.65 src/sys/ufs/ufs/ufs_extern.h:1.66
--- src/sys/ufs/ufs/ufs_extern.h:1.65	Tue Jul 12 16:59:49 2011
+++ src/sys/ufs/ufs/ufs_extern.h	Sun Jul 17 22:07:59 2011
@@ -1,4 +1,4 @@
-/*	$NetBSD: ufs_extern.h,v 1.65 2011/07/12 16:59:49 dholland Exp $	*/
+/*	$NetBSD: ufs_extern.h,v 1.66 2011/07/17 22:07:59 dholland Exp $	*/
 
 /*-
  * Copyright (c) 1991, 1993, 1994
@@ -135,6 +135,8 @@
 		       struct inode *, ino_t, int, int, int);
 int	ufs_dirempty(struct inode *, ino_t, kauth_cred_t);
 int	ufs_checkpath(struct inode *, struct inode *, kauth_cred_t);
+int	ufs_parentcheck(struct vnode *, struct vnode *, kauth_cred_t,
+			int *, struct vnode **);
 int	ufs_blkatoff(struct vnode *, off_t, char **, struct buf **, bool);
 
 /* ufs_quota.c */

Index: src/sys/ufs/ufs/ufs_lookup.c
diff -u src/sys/ufs/ufs/ufs_lookup.c:1.110 src/sys/ufs/ufs/ufs_lookup.c:1.111
--- src/sys/ufs/ufs/ufs_lookup.c:1.110	Thu Jul 14 16:27:11 2011
+++ src/sys/ufs/ufs/ufs_lookup.c	Sun Jul 17 22:07:59 2011
@@ -1,4 +1,4 @@
-/*	$NetBSD: ufs_lookup.c,v 1.110 2011/07/14 16:27:11 dholland Exp $	*/
+/*	$NetBSD: ufs_lookup.c,v 1.111 2011/07/17 22:07:59 dholland Exp $	*/
 
 /*
  * Copyright (c) 1989, 1993
@@ -37,7 +37,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ufs_lookup.c,v 1.110 2011/07/14 16:27:11 dholland Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ufs_lookup.c,v 1.111 2011/07/17 22:07:59 dholland Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_ffs.h"
@@ -1308,6 +1308,129 @@
 	return (error);
 }
 
+/*
+ * Extract the inode number of ".." from a directory.
+ * Helper for ufs_parentcheck.
+ */
+static int
+ufs_readdotdot(struct vnode *vp, int needswap, kauth_cred_t cred, ino_t *result)
+{
+	struct dirtemplate dirbuf;
+	int namlen, error;
+
+	error = vn_rdwr(UIO_READ, vp, &dirbuf,
+		    sizeof (struct dirtemplate), (off_t)0, UIO_SYSSPACE,
+		    IO_NODELOCKED, cred, NULL, NULL);
+	if (error) {
+		return error;
+	}
+
+#if (BYTE_ORDER == LITTLE_ENDIAN)
+	if (FSFMT(vp) && needswap == 0)
+		namlen = dirbuf.dotdot_type;
+	else
+		namlen = dirbuf.dotdot_namlen;
+#else
+	if (FSFMT(vp) && needswap != 0)
+		namlen = dirbuf.dotdot_type;
+	else
+		namlen = dirbuf.dotdot_namlen;
+#endif
+	if (namlen != 2 ||
+	    dirbuf.dotdot_name[0] != '.' ||
+	    dirbuf.dotdot_name[1] != '.') {
+		printf("ufs_readdotdot: directory %llu contains "
+		       "garbage instead of ..\n",
+		       (unsigned long long) VTOI(vp)->i_number);
+		return ENOTDIR;
+	}
+	*result = ufs_rw32(dirbuf.dotdot_ino, needswap);
+	return 0;
+}
+
+/*
+ * Check if LOWER is a descendent of UPPER. If we find UPPER, return
+ * nonzero in FOUND and return a reference to the immediate descendent
+ * of UPPER in UPPERCHILD. If we don't find UPPER (that is, if we
+ * reach the volume root and that isn't UPPER), return zero in FOUND
+ * and null in UPPERCHILD.
+ *
+ * Neither UPPER nor LOWER should be locked.
+ *
+ * On error (such as a permissions error checking up the directory
+ * tree) fail entirely.
+ *
+ * Note that UPPER and LOWER must be on the same volume, and because
+ * we inspect only that volume NEEDSWAP can be constant.
+ */
+int
+ufs_parentcheck(struct vnode *upper, struct vnode *lower, kauth_cred_t cred,
+		int *found_ret, struct vnode **upperchild_ret)
+{
+	const int needswap = UFS_MPNEEDSWAP(VTOI(lower)->i_ump);
+	ino_t upper_ino, found_ino;
+	struct vnode *current, *next;
+	int error;
+
+	if (upper == lower) {
+		vref(upper);
+		*found_ret = 1;
+		*upperchild_ret = upper;
+		return 0;
+	}
+	if (VTOI(lower)->i_number == ROOTINO) {
+		*found_ret = 0;
+		*upperchild_ret = NULL;
+		return 0;
+	}
+
+	upper_ino = VTOI(upper)->i_number;
+
+	current = lower;
+	vref(current);
+	vn_lock(current, LK_EXCLUSIVE | LK_RETRY);
+
+	for (;;) {
+		error = ufs_readdotdot(current, needswap, cred, &found_ino);
+		if (error) {
+			vput(current);
+			return error;
+		}
+		if (found_ino == upper_ino) {
+			VOP_UNLOCK(current);
+			*found_ret = 1;
+			*upperchild_ret = current;
+			return 0;
+		}
+		if (found_ino == ROOTINO) {
+			vput(current);
+			*found_ret = 0;
+			*upperchild_ret = NULL;
+			return 0;
+		}
+		VOP_UNLOCK(current);
+		error = VFS_VGET(current->v_mount, found_ino, &next);
+		if (error) {
+			vrele(current);
+			return error;
+		}
+		KASSERT(VOP_ISLOCKED(next));
+		if (next->v_type != VDIR) {
+			printf("ufs_parentcheck: inode %llu reached via .. of "
+			       "inode %llu is not a directory\n",
+			    (unsigned long long)VTOI(next)->i_number,
+			    (unsigned long long)VTOI(current)->i_number);
+			vput(next);
+			vrele(current);
+			return ENOTDIR;
+		}
+		vrele(current);
+		current = next;
+	}
+
+	return 0;
+}
+
 #define	UFS_DIRRABLKS 0
 int ufs_dirrablks = UFS_DIRRABLKS;
 

Index: src/sys/ufs/ufs/ufs_wapbl.c
diff -u src/sys/ufs/ufs/ufs_wapbl.c:1.16 src/sys/ufs/ufs/ufs_wapbl.c:1.17
--- src/sys/ufs/ufs/ufs_wapbl.c:1.16	Thu Jul 14 16:27:43 2011
+++ src/sys/ufs/ufs/ufs_wapbl.c	Sun Jul 17 22:07:59 2011
@@ -1,4 +1,4 @@
-/*  $NetBSD: ufs_wapbl.c,v 1.16 2011/07/14 16:27:43 dholland Exp $ */
+/*  $NetBSD: ufs_wapbl.c,v 1.17 2011/07/17 22:07:59 dholland Exp $ */
 
 /*-
  * Copyright (c) 2003,2006,2008 The NetBSD Foundation, Inc.
@@ -66,7 +66,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ufs_wapbl.c,v 1.16 2011/07/14 16:27:43 dholland Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ufs_wapbl.c,v 1.17 2011/07/17 22:07:59 dholland Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -148,6 +148,138 @@
 }
 
 /*
+ * Wrapper for relookup that also updates the supplemental results.
+ */
+static int
+do_relookup(struct vnode *dvp, struct ufs_lookup_results *ulr,
+	    struct vnode **vp, struct componentname *cnp)
+{
+	int error;
+
+	error = relookup(dvp, vp, cnp, 0);
+	if (error) {
+		return error;
+	}
+	/* update the supplemental reasults */
+	*ulr = VTOI(dvp)->i_crap;
+	UFS_CHECK_CRAPCOUNTER(VTOI(dvp));
+	return 0;
+}
+
+/*
+ * Lock and relookup a sequence of two directories and two children.
+ *
+ */
+static int
+lock_vnode_sequence(struct vnode *d1, struct ufs_lookup_results *ulr1,
+		    struct vnode **v1_ret, struct componentname *cn1, 
+		    int v1_missing_ok,
+		    int overlap_error,
+		    struct vnode *d2, struct ufs_lookup_results *ulr2,
+		    struct vnode **v2_ret, struct componentname *cn2, 
+		    int v2_missing_ok)
+{
+	struct vnode *v1, *v2;
+	int error;
+
+	KASSERT(d1 != d2);
+
+	vn_lock(d1, LK_EXCLUSIVE | LK_RETRY);
+	if (VTOI(d1)->i_size == 0) {
+		/* d1 has been rmdir'd */
+		VOP_UNLOCK(d1);
+		return ENOENT;
+	}
+	error = do_relookup(d1, ulr1, &v1, cn1);
+	if (v1_missing_ok) {
+		if (error == ENOENT) {
+			/*
+			 * Note: currently if the name doesn't exist,
+			 * relookup succeeds (it intercepts the
+			 * EJUSTRETURN from VOP_LOOKUP) and sets tvp
+			 * to NULL. Therefore, we will never get
+			 * ENOENT and this branch is not needed.
+			 * However, in a saner future the EJUSTRETURN
+			 * garbage will go away, so let's DTRT.
+			 */
+			v1 = NULL;
+			error = 0;
+		}
+	} else {
+		if (error == 0 && v1 == NULL) {
+			/* This is what relookup sets if v1 disappeared. */
+			error = ENOENT;
+		}
+	}
+	if (error) {
+		VOP_UNLOCK(d1);
+		return error;
+	}
+	if (v1 && v1 == d2) {
+		VOP_UNLOCK(d1);
+		VOP_UNLOCK(v1);
+		vrele(v1);
+		return overlap_error;
+	}
+
+	/*
+	 * The right way to do this is to do lookups without locking
+	 * the results, and lock the results afterwards; then at the
+	 * end we can avoid trying to lock v2 if v2 == v1.
+	 *
+	 * However, for the reasons described in the fdvp == tdvp case
+	 * in rename below, we can't do that safely. So, in the case
+	 * where v1 is not a directory, unlock it and lock it again
+	 * afterwards. This is safe in locking order because a
+	 * non-directory can't be above anything else in the tree. If
+	 * v1 *is* a directory, that's not true, but then because d1
+	 * != d2, v1 != v2.
+	 */
+	if (v1 && v1->v_type != VDIR) {
+		VOP_UNLOCK(v1);
+	}
+	vn_lock(d2, LK_EXCLUSIVE | LK_RETRY);
+	if (VTOI(d2)->i_size == 0) {
+		/* d2 has been rmdir'd */
+		VOP_UNLOCK(d2);
+		if (v1 && v1->v_type == VDIR) {
+			VOP_UNLOCK(v1);
+		}
+		VOP_UNLOCK(d1);
+		vrele(v1);
+		return ENOENT;
+	}
+	error = do_relookup(d2, ulr2, &v2, cn2);
+	if (v2_missing_ok) {
+		if (error == ENOENT) {
+			/* as above */
+			v2 = NULL;
+			error = 0;
+		}
+	} else {
+		if (error == 0 && v2 == NULL) {
+			/* This is what relookup sets if v2 disappeared. */
+			error = ENOENT;
+		}
+	}
+	if (error) {
+		VOP_UNLOCK(d2);
+		if (v1 && v1->v_type == VDIR) {
+			VOP_UNLOCK(v1);
+		}
+		VOP_UNLOCK(d1);
+		vrele(v1);
+		return error;
+	}
+	if (v1 && v1->v_type != VDIR && v1 != v2) {
+		vn_lock(v1, LK_EXCLUSIVE | LK_RETRY);
+	}
+	*v1_ret = v1;
+	*v2_ret = v2;
+	return 0;
+}
+
+/*
  * Rename vnode operation
  * 	rename("foo", "bar");
  * is essentially
@@ -212,70 +344,234 @@
 	UFS_CHECK_CRAPCOUNTER(VTOI(tdvp));
 
 	/*
+	 * Owing to VFS oddities we are currently called with tdvp/tvp
+	 * locked and not fdvp/fvp. In a sane world we'd be passed
+	 * tdvp and fdvp only, unlocked, and two name strings. Pretend
+	 * we have a sane world and unlock tdvp and tvp.
+	 */
+	VOP_UNLOCK(tdvp);
+	if (tvp && tvp != tdvp) {
+		VOP_UNLOCK(tvp);
+	}
+
+	/* Also pretend we have a sane world and vrele fvp/tvp. */
+	vrele(fvp);
+	fvp = NULL;
+	if (tvp) {
+		vrele(tvp);
+		tvp = NULL;
+	}
+
+	/*
 	 * Check for cross-device rename.
 	 */
-	if ((fvp->v_mount != tdvp->v_mount) ||
-	    (tvp && (fvp->v_mount != tvp->v_mount))) {
+	if (fdvp->v_mount != tdvp->v_mount) {
 		error = EXDEV;
  abortit:
-		VOP_ABORTOP(tdvp, tcnp); /* XXX, why not in NFS? */
-		if (tdvp == tvp)
-			vrele(tdvp);
-		else
-			vput(tdvp);
-		if (tvp)
-			vput(tvp);
 		VOP_ABORTOP(fdvp, fcnp); /* XXX, why not in NFS? */
+		VOP_ABORTOP(tdvp, tcnp); /* XXX, why not in NFS? */
+		vrele(tdvp);
+		if (tvp) {
+			vrele(tvp);
+		}
 		vrele(fdvp);
-		vrele(fvp);
+		if (fvp) {
+			vrele(fvp);
+		}
 		return (error);
 	}
 
 	/*
-	 * Check if just deleting a link name.
+	 * Reject "." and ".."
+	 */
+	if ((fcnp->cn_flags & ISDOTDOT) || (tcnp->cn_flags & ISDOTDOT) ||
+	    (fcnp->cn_namelen == 1 && fcnp->cn_nameptr[0] == '.') ||
+	    (tcnp->cn_namelen == 1 && tcnp->cn_nameptr[0] == '.')) {
+		error = EINVAL;
+		goto abortit;
+	}
+	    
+	/*
+	 * Get locks.
 	 */
+
+	/* paranoia */
+	fcnp->cn_flags |= LOCKPARENT|LOCKLEAF;
+	tcnp->cn_flags |= LOCKPARENT|LOCKLEAF;
+
+	if (fdvp == tdvp) {
+		/* One directory. Lock it and relookup both children. */
+		vn_lock(fdvp, LK_EXCLUSIVE | LK_RETRY);
+
+		if (VTOI(fdvp)->i_size == 0) {
+			/* directory has been rmdir'd */
+			VOP_UNLOCK(fdvp);
+			error = ENOENT;
+			goto abortit;
+		}
+
+		error = do_relookup(fdvp, &from_ulr, &fvp, fcnp);
+		if (error == 0 && fvp == NULL) {
+			/* relookup may produce this if fvp disappears */
+			error = ENOENT;
+		}
+		if (error) {
+			VOP_UNLOCK(fdvp);
+			goto abortit;
+		}
+
+		/*
+		 * The right way to do this is to look up both children
+		 * without locking either, and then lock both unless they
+		 * turn out to be the same. However, due to deep-seated
+		 * VFS-level issues all lookups lock the child regardless
+		 * of whether LOCKLEAF is set (if LOCKLEAF is not set,
+		 * the child is locked during lookup and then unlocked)
+		 * so it is not safe to look up tvp while fvp is locked.
+		 *
+		 * Unlocking fvp here temporarily is more or less safe,
+		 * because with the directory locked there's not much
+		 * that can happen to it. However, ideally it wouldn't
+		 * be necessary. XXX.
+		 */
+		VOP_UNLOCK(fvp);
+		/* remember fdvp == tdvp so tdvp is locked */
+		error = do_relookup(tdvp, &to_ulr, &tvp, tcnp);
+		if (error && error != ENOENT) {
+			VOP_UNLOCK(fdvp);
+			goto abortit;
+		}
+		if (error == ENOENT) {
+			/*
+			 * Note: currently if the name doesn't exist,
+			 * relookup succeeds (it intercepts the
+			 * EJUSTRETURN from VOP_LOOKUP) and sets tvp
+			 * to NULL. Therefore, we will never get
+			 * ENOENT and this branch is not needed.
+			 * However, in a saner future the EJUSTRETURN
+			 * garbage will go away, so let's DTRT.
+			 */
+			tvp = NULL;
+		}
+
+		/* tvp is locked; lock fvp if necessary */
+		if (!tvp || tvp != fvp) {
+			vn_lock(fvp, LK_EXCLUSIVE | LK_RETRY);
+		}
+	} else {
+		int found_fdvp;
+		struct vnode *illegal_fvp;
+
+		error = ufs_parentcheck(fdvp, tdvp, fcnp->cn_cred,
+					&found_fdvp, &illegal_fvp);
+		if (error) {
+			goto abortit;
+		}
+		if (found_fdvp) {
+			/* fdvp -> fvp -> tdvp -> tvp */
+			error = lock_vnode_sequence(fdvp, &from_ulr,
+						    &fvp, fcnp, 0,
+						    EINVAL,
+						    tdvp, &to_ulr,
+						    &tvp, tcnp, 1);
+		} else {
+			/* tdvp -> tvp -> fdvp -> fvp */
+			error = lock_vnode_sequence(tdvp, &to_ulr,
+						    &tvp, tcnp, 1,
+						    ENOTEMPTY,
+						    fdvp, &from_ulr,
+						    &fvp, fcnp, 0);
+		}
+		if (error) {
+			if (illegal_fvp) {
+				vrele(illegal_fvp);
+			}
+			goto abortit;
+		}
+		KASSERT(fvp != NULL);
+
+		if (illegal_fvp && fvp == illegal_fvp) {
+			vrele(illegal_fvp);
+			error = EINVAL;
+		abort_withlocks:
+			VOP_UNLOCK(fdvp);
+			if (tdvp != fdvp) {
+				VOP_UNLOCK(tdvp);
+			}
+			VOP_UNLOCK(fvp);
+			if (tvp && tvp != fvp) {
+				VOP_UNLOCK(tvp);
+			}
+			goto abortit;
+		}
+
+		if (illegal_fvp) {
+			vrele(illegal_fvp);
+		}
+	}
+
+	KASSERT(fdvp && VOP_ISLOCKED(fdvp));
+	KASSERT(fvp && VOP_ISLOCKED(fvp));
+	KASSERT(tdvp && VOP_ISLOCKED(tdvp));
+	KASSERT(tvp == NULL || VOP_ISLOCKED(tvp));
+
+	/* --- everything is now locked --- */
+
 	if (tvp && ((VTOI(tvp)->i_flags & (IMMUTABLE | APPEND)) ||
 	    (VTOI(tdvp)->i_flags & APPEND))) {
 		error = EPERM;
-		goto abortit;
+		goto abort_withlocks;
 	}
+
+	/*
+	 * Check if just deleting a link name.
+	 */
 	if (fvp == tvp) {
 		if (fvp->v_type == VDIR) {
 			error = EINVAL;
-			goto abortit;
+			goto abort_withlocks;
 		}
 
-		/* Release destination completely. */
+		/* Release destination completely. Leave fdvp locked. */
 		VOP_ABORTOP(tdvp, tcnp);
-		vput(tdvp);
-		vput(tvp);
+		if (fdvp != tdvp) {
+			VOP_UNLOCK(tdvp);
+		}
+		VOP_UNLOCK(tvp);
+		vrele(tdvp);
+		vrele(tvp);
 
 		/* Delete source. */
+		/* XXX: do we really need to relookup again? */
+
+		/*
+		 * fdvp is still locked, but we just unlocked fvp
+		 * (because fvp == tvp) so just decref fvp
+		 */
 		vrele(fvp);
 		fcnp->cn_flags &= ~(MODMASK);
 		fcnp->cn_flags |= LOCKPARENT | LOCKLEAF;
 		fcnp->cn_nameiop = DELETE;
-		vn_lock(fdvp, LK_EXCLUSIVE | LK_RETRY);
 		if ((error = relookup(fdvp, &fvp, fcnp, 0))) {
 			vput(fdvp);
 			return (error);
 		}
 		return (VOP_REMOVE(fdvp, fvp, fcnp));
 	}
+#if 0
 	if ((error = vn_lock(fvp, LK_EXCLUSIVE)) != 0)
 		goto abortit;
+#endif
 	fdp = VTOI(fdvp);
 	ip = VTOI(fvp);
 	if ((nlink_t) ip->i_nlink >= LINK_MAX) {
-		VOP_UNLOCK(fvp);
 		error = EMLINK;
-		goto abortit;
+		goto abort_withlocks;
 	}
 	if ((ip->i_flags & (IMMUTABLE | APPEND)) ||
 		(fdp->i_flags & APPEND)) {
-		VOP_UNLOCK(fvp);
 		error = EPERM;
-		goto abortit;
+		goto abort_withlocks;
 	}
 	if ((ip->i_mode & IFMT) == IFDIR) {
 		/*
@@ -286,9 +582,8 @@
 		    (fcnp->cn_flags & ISDOTDOT) ||
 		    (tcnp->cn_flags & ISDOTDOT) ||
 		    (ip->i_flag & IN_RENAME)) {
-			VOP_UNLOCK(fvp);
 			error = EINVAL;
-			goto abortit;
+			goto abort_withlocks;
 		}
 		ip->i_flag |= IN_RENAME;
 		doingdirectory = 1;
@@ -297,8 +592,8 @@
 	VN_KNOTE(fdvp, NOTE_WRITE);		/* XXXLUKEM/XXX: right place? */
 
 	/*
-	 * When the target exists, both the directory
-	 * and target vnodes are returned locked.
+	 * Both the directory
+	 * and target vnodes are locked.
 	 */
 	tdp = VTOI(tdvp);
 	txp = NULL;
@@ -308,6 +603,7 @@
 	mp = fdvp->v_mount;
 	fstrans_start(mp, FSTRANS_SHARED);
 
+#if 0
 	/*
 	 * If ".." must be changed (ie the directory gets a new
 	 * parent) then the source directory must not be in the
@@ -318,13 +614,17 @@
 	 * to namei, as the parent directory is unlocked by the
 	 * call to checkpath().
 	 */
+#endif
 	error = VOP_ACCESS(fvp, VWRITE, tcnp->cn_cred);
+#if 0
 	VOP_UNLOCK(fvp);
+#endif
 	if (oldparent != tdp->i_number)
 		newparent = tdp->i_number;
 	if (doingdirectory && newparent) {
 		if (error)	/* write access check above */
 			goto out;
+#if 0
 		if (txp != NULL)
 			vput(tvp);
 		txp = NULL;
@@ -346,15 +646,17 @@
 		/* update the supplemental reasults */
 		to_ulr = tdp->i_crap;
 		UFS_CHECK_CRAPCOUNTER(tdp);
-
 		if (tvp)
 			txp = VTOI(tvp);
+#endif
 	}
 
+#if 0
 	/*
 	 * XXX handle case where fdvp is parent of tdvp,
 	 * by unlocking tdvp and regrabbing it with vget after?
 	 */
+#endif
 
 	/*
 	 * This was moved up to before the journal lock to
@@ -368,6 +670,7 @@
 			error = doingdirectory ? ENOTEMPTY : EISDIR;
 			goto out;
 		}
+#if 0
 		vn_lock(fdvp, LK_EXCLUSIVE | LK_RETRY);
 		if ((error = relookup(fdvp, &fvp, fcnp, 0))) {
 			vput(fdvp);
@@ -390,6 +693,7 @@
 		/* update supplemental lookup results */
 		from_ulr = VTOI(fdvp)->i_crap;
 		UFS_CHECK_CRAPCOUNTER(VTOI(fdvp));
+#endif
 	}
 	if (fvp != NULL) {
 		fxp = VTOI(fvp);
@@ -400,15 +704,19 @@
 		 */
 		if (doingdirectory)
 			panic("rename: lost dir entry");
+#if 0
 		vrele(ap->a_fvp);
+#endif
 		error = ENOENT;	/* XXX ufs_rename sets "0" here */
 		goto out2;
 	}
+#if 0
 	/*
 	 * XXX: if fvp != a_fvp, a_fvp can now have 0 references and yet we
 	 * access a_fvp->inode via ip later.  boom.
 	 */
 	vrele(ap->a_fvp);
+#endif
 
 	error = UFS_WAPBL_BEGIN(fdvp->v_mount);
 	if (error)
@@ -661,6 +969,8 @@
 	/*
 	 * 3) Unlink the source.
 	 */
+
+#if 0
 	/*
 	 * Ensure that the directory entry still exists and has not
 	 * changed while the new name has been entered. If the source is
@@ -670,7 +980,9 @@
 	 * flag ensures that it cannot be moved by another rename or removed
 	 * by a rmdir.
 	 */
+#endif
 	if (fxp != ip) {
+		/* now not possible */
 		if (doingdirectory)
 			panic("rename: lost dir entry");
 	} else {
@@ -694,8 +1006,6 @@
 	goto done;
 
  out:
-	vrele(fvp);
-	vrele(fdvp);
 	goto out2;
 
 	/* exit routines from steps 1 & 2 */
@@ -709,8 +1019,6 @@
 	UFS_WAPBL_UPDATE(fvp, NULL, NULL, 0);
  done:
 	UFS_WAPBL_END(fdvp->v_mount);
-	vput(fdvp);
-	vput(fvp);
  out2:
 	/*
 	 * clear IN_RENAME - some exit paths happen too early to go
@@ -719,13 +1027,20 @@
 	 */
 	ip->i_flag &= ~IN_RENAME;
 
-	if (txp)
-		vput(ITOV(txp));
-	if (tdp) {
-		if (newparent)
-			vput(ITOV(tdp));
-		else
-			vrele(ITOV(tdp));
+	VOP_UNLOCK(fdvp);
+	if (tdvp != fdvp) {
+		VOP_UNLOCK(tdvp);
+	}
+	VOP_UNLOCK(fvp);
+	if (tvp && tvp != fvp) {
+		VOP_UNLOCK(tvp);
+	}
+
+	vrele(fdvp);
+	vrele(tdvp);
+	vrele(fvp);
+	if (tvp) {
+		vrele(tvp);
 	}
 
 	fstrans_done(mp);

Reply via email to