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);