Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 2 Oct 2001 16:12:51 -0700 (PDT)
From:      Matt Dillon <dillon@earth.backplane.com>
To:        Ian Dowse <iedowse@maths.tcd.ie>
Cc:        Yevgeniy Aleynikov <eugenea@infospace.com>, peter@FreeBSD.ORG, ache@FreeBSD.ORG, mckusick@mckusick.com, Ken Pizzini <kenp@infospace.com>, hackers@FreeBSD.ORG
Subject:   patch #3 (was Re: bleh. Re: ufs_rename panic)
Message-ID:  <200110022312.f92NCpp60948@earth.backplane.com>

next in thread | raw e-mail | index | archive | help
    Here is the latest patch I have.  It appears to completely solve the
    problem.  I have shims in unionfs and nfs for the moment.

    The patch is against -stable.

    * Implements SOFTLOCKLEAF namei() option

    * Implements EAGAIN error & appropriate tsleep/retry code

    * Universal for rename() & rmdir(). Final patch will also probably
      implement it on unlink() to solve (pre-existing) unlink/rename regular
      file race.

    * Tested very well w/ UFS, should be compatible with and work for
      direct access to other filesystems that still use IN_RENAME.

    * Tested for collision probability.  Answer: Very low even when
      one tries on purpose.  There is no need to implement a more
      sophisticated fine-grained tsleep.

						-Matt


Index: kern/vfs_lookup.c
===================================================================
RCS file: /home/ncvs/src/sys/kern/vfs_lookup.c,v
retrieving revision 1.38.2.3
diff -u -r1.38.2.3 vfs_lookup.c
--- kern/vfs_lookup.c	2001/08/31 19:36:49	1.38.2.3
+++ kern/vfs_lookup.c	2001/10/02 20:06:33
@@ -372,6 +372,11 @@
 			error = EISDIR;
 			goto bad;
 		}
+		if (cnp->cn_flags & SOFTLOCKLEAF) {
+			if ((error = vsetsoftlock(dp)) != 0)
+				goto bad;
+			VREF(dp);
+		}
 		if (wantparent) {
 			ndp->ni_dvp = dp;
 			VREF(dp);
@@ -565,13 +570,17 @@
 		error = EROFS;
 		goto bad2;
 	}
+	if (cnp->cn_flags & SOFTLOCKLEAF) {
+		if ((error = vsetsoftlock(dp)) != 0)
+			goto bad2;
+		VREF(dp);
+	}
 	if (cnp->cn_flags & SAVESTART) {
 		ndp->ni_startdir = ndp->ni_dvp;
 		VREF(ndp->ni_startdir);
 	}
 	if (!wantparent)
 		vrele(ndp->ni_dvp);
-
 	if ((cnp->cn_flags & LOCKLEAF) == 0)
 		VOP_UNLOCK(dp, 0, p);
 	return (0);
@@ -654,6 +663,11 @@
 			error = ENOTDIR;
 			goto bad;
 		}
+		if (cnp->cn_flags & SOFTLOCKLEAF) {
+			if ((error = vsetsoftlock(dp)) != 0)
+				goto bad;
+			VREF(dp);
+		}
 		if (!(cnp->cn_flags & LOCKLEAF))
 			VOP_UNLOCK(dp, 0, p);
 		*vpp = dp;
@@ -707,6 +721,11 @@
 		error = EROFS;
 		goto bad2;
 	}
+	if (cnp->cn_flags & SOFTLOCKLEAF) {
+		if ((error = vsetsoftlock(dp)) != 0)
+			goto bad2;
+		VREF(dp);
+	}
 	/* ASSERT(dvp == ndp->ni_startdir) */
 	if (cnp->cn_flags & SAVESTART)
 		VREF(dvp);
@@ -715,8 +734,9 @@
 		vrele(dvp);
 
 	if (vn_canvmio(dp) == TRUE &&
-		((cnp->cn_flags & (NOOBJ|LOCKLEAF)) == LOCKLEAF))
+	    ((cnp->cn_flags & (NOOBJ|LOCKLEAF)) == LOCKLEAF)) {
 		vfs_object_create(dp, cnp->cn_proc, cnp->cn_cred);
+	}
 
 	if ((cnp->cn_flags & LOCKLEAF) == 0)
 		VOP_UNLOCK(dp, 0, p);
Index: kern/vfs_subr.c
===================================================================
RCS file: /home/ncvs/src/sys/kern/vfs_subr.c,v
retrieving revision 1.249.2.11
diff -u -r1.249.2.11 vfs_subr.c
--- kern/vfs_subr.c	2001/09/11 09:49:53	1.249.2.11
+++ kern/vfs_subr.c	2001/10/02 22:55:38
@@ -130,6 +132,8 @@
 #endif
 struct nfs_public nfs_pub;	/* publicly exported FS */
 static vm_zone_t vnode_zone;
+static int vagain_count = 1;
+static int vagain_waiting = 0;
 
 /*
  * The workitem queue.
@@ -2927,6 +2963,13 @@
      struct nameidata *ndp;
      const uint flags;
 {
+	if (!(flags & NDF_NO_FREE_SOFTLOCKLEAF) &&
+	    (ndp->ni_cnd.cn_flags & SOFTLOCKLEAF) &&
+	    ndp->ni_vp) {
+		vclearsoftlock(ndp->ni_vp);
+		ndp->ni_cnd.cn_flags &= ~SOFTLOCKLEAF;
+		vrele(ndp->ni_vp);
+	}
 	if (!(flags & NDF_NO_FREE_PNBUF) &&
 	    (ndp->ni_cnd.cn_flags & HASBUF)) {
 		zfree(namei_zone, ndp->ni_cnd.cn_pnbuf);
@@ -2955,3 +2998,55 @@
 		ndp->ni_startdir = NULL;
 	}
 }
+
+/*
+ * vsetsoftlock() -	set the VSOFTLOCK flag on the vnode, return
+ *			EAGAIN if it has already been set by someone else.
+ *
+ *	note: we could further refine the collision by setting a VSOFTLOCKCOLL
+ *	flag and then only waking up waiters when the colliding vnode is
+ *	released.  However, this sort of collision does not happen often
+ *	enough for such an addition to yield any improvement in performance.
+ */
+
+int
+vsetsoftlock(struct vnode *vp)
+{
+	int s;
+	int error = 0;
+
+	s = splbio();
+	if (vp->v_flag & VSOFTLOCK)
+		error = EAGAIN;
+	else
+		vp->v_flag |= VSOFTLOCK;
+	splx(s);
+	return(error);
+}
+
+void
+vclearsoftlock(struct vnode *vp)
+{
+	int s;
+
+	s = splbio();
+	vp->v_flag &= ~VSOFTLOCK;
+	splx(s);
+	if (++vagain_count == 0)
+		vagain_count = 1;
+	if (vagain_waiting) {
+		vagain_waiting = 0;
+		wakeup(&vagain_waiting);
+	}
+}
+
+void
+vagain(int *gc)
+{
+	while (*gc && *gc == vagain_count) {
+		vagain_waiting = 1;
+		tsleep(&vagain_waiting, PVFS, "vagain", 0);
+	}
+	*gc = vagain_count;
+}
+
Index: kern/vfs_syscalls.c
===================================================================
RCS file: /home/ncvs/src/sys/kern/vfs_syscalls.c,v
retrieving revision 1.151.2.9
diff -u -r1.151.2.9 vfs_syscalls.c
--- kern/vfs_syscalls.c	2001/08/12 10:48:00	1.151.2.9
+++ kern/vfs_syscalls.c	2001/10/02 22:19:22
@@ -2631,12 +2631,18 @@
 	register struct vnode *tvp, *fvp, *tdvp;
 	struct nameidata fromnd, tond;
 	int error;
+	int gc = 0;
 
+again:
+	vagain(&gc);
 	bwillwrite();
-	NDINIT(&fromnd, DELETE, WANTPARENT | SAVESTART, UIO_USERSPACE,
-	    SCARG(uap, from), p);
-	if ((error = namei(&fromnd)) != 0)
+	NDINIT(&fromnd, DELETE, WANTPARENT | SAVESTART | SOFTLOCKLEAF,
+	    UIO_USERSPACE, SCARG(uap, from), p);
+	if ((error = namei(&fromnd)) != 0) {
+		if (error == EAGAIN)
+			goto again;
 		return (error);
+	}
 	fvp = fromnd.ni_vp;
 	NDINIT(&tond, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART | NOOBJ,
 	    UIO_USERSPACE, SCARG(uap, to), p);
@@ -2646,7 +2652,7 @@
 		/* Translate error code for rename("dir1", "dir2/."). */
 		if (error == EISDIR && fvp->v_type == VDIR)
 			error = EINVAL;
-		NDFREE(&fromnd, NDF_ONLY_PNBUF);
+		NDFREE(&fromnd, NDF_ONLY_PNBUF & NDF_ONLY_SOFTLOCKLEAF);
 		vrele(fromnd.ni_dvp);
 		vrele(fvp);
 		goto out1;
@@ -2683,12 +2689,14 @@
 		if (tvp) {
 			VOP_LEASE(tvp, p, p->p_ucred, LEASE_WRITE);
 		}
+		fromnd.ni_cnd.cn_flags &= ~SOFTLOCKLEAF;	/* XXX hack */
 		error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd,
 				   tond.ni_dvp, tond.ni_vp, &tond.ni_cnd);
-		NDFREE(&fromnd, NDF_ONLY_PNBUF);
+		fromnd.ni_cnd.cn_flags |= SOFTLOCKLEAF;
+		NDFREE(&fromnd, NDF_ONLY_PNBUF & NDF_ONLY_SOFTLOCKLEAF);
 		NDFREE(&tond, NDF_ONLY_PNBUF);
 	} else {
-		NDFREE(&fromnd, NDF_ONLY_PNBUF);
+		NDFREE(&fromnd, NDF_ONLY_PNBUF & NDF_ONLY_SOFTLOCKLEAF);
 		NDFREE(&tond, NDF_ONLY_PNBUF);
 		if (tdvp == tvp)
 			vrele(tdvp);
@@ -2782,13 +2790,19 @@
 {
 	register struct vnode *vp;
 	int error;
+	int gc = 0;
 	struct nameidata nd;
 
+again:
+	vagain(&gc);
 	bwillwrite();
-	NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE,
-	    SCARG(uap, path), p);
-	if ((error = namei(&nd)) != 0)
+	NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF | SOFTLOCKLEAF,
+	    UIO_USERSPACE, SCARG(uap, path), p);
+	if ((error = namei(&nd)) != 0) {
+		if (error == EAGAIN)
+			goto again;
 		return (error);
+	}
 	vp = nd.ni_vp;
 	if (vp->v_type != VDIR) {
 		error = ENOTDIR;
@@ -2812,7 +2826,7 @@
 		error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
 	}
 out:
-	NDFREE(&nd, NDF_ONLY_PNBUF);
+	NDFREE(&nd, NDF_ONLY_PNBUF & NDF_ONLY_SOFTLOCKLEAF);
 	if (nd.ni_dvp == vp)
 		vrele(nd.ni_dvp);
 	else
Index: miscfs/union/union_vnops.c
===================================================================
RCS file: /home/ncvs/src/sys/miscfs/union/Attic/union_vnops.c,v
retrieving revision 1.72
diff -u -r1.72 union_vnops.c
--- miscfs/union/union_vnops.c	1999/12/15 23:02:14	1.72
+++ miscfs/union/union_vnops.c	2001/10/02 22:48:40
@@ -1380,6 +1380,7 @@
 	struct vnode *fvp = ap->a_fvp;
 	struct vnode *tdvp = ap->a_tdvp;
 	struct vnode *tvp = ap->a_tvp;
+	int setsoftlock = 0;
 
 	/*
 	 * Figure out what fdvp to pass to our upper or lower vnode.  If we
@@ -1456,6 +1457,16 @@
 		fvp = un->un_uppervp;
 		VREF(fvp);
 		vrele(ap->a_fvp);
+		if ((error = vsetsoftlock(fvp)) != 0) {
+			/*
+			 * XXX for now do not support a retry request
+			 */
+			if (error == EAGAIN)
+				error = EINVAL;
+			goto bad;
+		}
+		setsoftlock = 1;
+		VREF(fvp);		/* for softlock */
 	}
 
 	/*
@@ -1505,11 +1516,15 @@
 	}
 
 	/*
-	 * VOP_RENAME releases/vputs prior to returning, so we have no
-	 * cleanup to do.
+	 * VOP_RENAME releases/vputs prior to returning, except for the
+	 * SOFTLOCK, so we have minimal cleanup to do.
 	 */
-
-	return (VOP_RENAME(fdvp, fvp, ap->a_fcnp, tdvp, tvp, ap->a_tcnp));
+	error = VOP_RENAME(fdvp, fvp, ap->a_fcnp, tdvp, tvp, ap->a_tcnp);
+	if (setsoftlock) {
+		vclearsoftlock(fvp);
+		vrele(fvp);
+	}
+	return(error);
 
 	/*
 	 * Error.  We still have to release / vput the various elements.
@@ -1517,8 +1532,13 @@
 
 bad:
 	vrele(fdvp);
-	if (fvp)
+	if (fvp) {
+		if (setsoftlock) {
+			vclearsoftlock(fvp);
+			vrele(fvp);
+		}
 		vrele(fvp);
+	}
 	vput(tdvp);
 	if (tvp != NULLVP) {
 		if (tvp != tdvp)
@@ -1583,7 +1603,16 @@
 	if ((uppervp = union_lock_upper(un, p)) != NULLVP) {
 		if (union_dowhiteout(un, cnp->cn_cred, p))
 			cnp->cn_flags |= DOWHITEOUT;
-		error = VOP_RMDIR(upperdvp, uppervp, ap->a_cnp);
+		if ((error = vsetsoftlock(upperdvp)) != 0) {
+			/*
+			 * XXX for now do not support a retry request
+			 */
+			if (error == EAGAIN)
+				error = EINVAL;
+			
+		} else {
+			error = VOP_RMDIR(upperdvp, uppervp, ap->a_cnp);
+		}
 		union_unlock_upper(uppervp, p);
 	} else {
 		error = union_mkwhiteout(
Index: nfs/nfs_serv.c
===================================================================
RCS file: /home/ncvs/src/sys/nfs/Attic/nfs_serv.c,v
retrieving revision 1.93
diff -u -r1.93 nfs_serv.c
--- nfs/nfs_serv.c	1999/12/18 19:20:05	1.93
+++ nfs/nfs_serv.c	2001/10/02 23:03:34
@@ -2194,7 +2194,7 @@
 	saved_uid = cred->cr_uid;
 	fromnd.ni_cnd.cn_cred = cred;
 	fromnd.ni_cnd.cn_nameiop = DELETE;
-	fromnd.ni_cnd.cn_flags = WANTPARENT | SAVESTART;
+	fromnd.ni_cnd.cn_flags = WANTPARENT | SAVESTART | SOFTLOCKLEAF;
 	error = nfs_namei(&fromnd, ffhp, len, slp, nam, &md,
 		&dpos, &fdirp, procp, (nfsd->nd_flag & ND_KERBAUTH), FALSE);
 	if (fdirp) {
@@ -2207,6 +2207,8 @@
 		}
 	}
 	if (error) {
+		if (error == EAGAIN)	/* XXX EAGAIN not yet supported */
+			error = EINVAL;
 		nfsm_reply(2 * NFSX_WCCDATA(v3));
 		nfsm_srvwcc_data(fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft);
 		nfsm_srvwcc_data(tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft);
@@ -2300,13 +2302,17 @@
 		if (tvp) {
 			nqsrv_getl(tvp, ND_WRITE);
 		}
+		fromnd.ni_cnd.cn_flags &= ~SOFTLOCKLEAF; /* XXX hack */
 		error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd,
 				   tond.ni_dvp, tond.ni_vp, &tond.ni_cnd);
-		fromnd.ni_dvp = NULL;
-		fromnd.ni_vp = NULL;
-		tond.ni_dvp = NULL;
-		tond.ni_vp = NULL;
-		if (error) {
+		/* XXX this is a @!#$!@#$@#$ mess */
+		vclearsoftlock(fromnd.ni_vp);	/* cleanup after SOFTLOCKLEAF */
+		vrele(fromnd.ni_vp);		/* cleanup after SOFTLOCKLEAF */
+		fromnd.ni_dvp = NULL;		/* clear for fall through */
+		fromnd.ni_vp = NULL;		/* clear for fall through */
+		tond.ni_dvp = NULL;		/* clear for fall through */
+		tond.ni_vp = NULL;		/* clear for fall through */
+		if (error) {			/* clear for fall through */
 			fromnd.ni_cnd.cn_flags &= ~HASBUF;
 			tond.ni_cnd.cn_flags &= ~HASBUF;
 		}
@@ -2354,7 +2360,7 @@
 		vrele(fdirp);
 	if (fromnd.ni_startdir)
 		vrele(fromnd.ni_startdir);
-	NDFREE(&fromnd, NDF_ONLY_PNBUF);
+	NDFREE(&fromnd, NDF_ONLY_PNBUF & NDF_ONLY_SOFTLOCKLEAF);
 	if (fromnd.ni_dvp)
 		vrele(fromnd.ni_dvp);
 	if (fromnd.ni_vp)
@@ -2826,7 +2832,7 @@
 	nfsm_srvnamesiz(len);
 	nd.ni_cnd.cn_cred = cred;
 	nd.ni_cnd.cn_nameiop = DELETE;
-	nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF;
+	nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF | SOFTLOCKLEAF;
 	error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos,
 		&dirp, procp, (nfsd->nd_flag & ND_KERBAUTH), FALSE);
 	if (dirp) {
@@ -2839,6 +2845,8 @@
 		}
 	}
 	if (error) {
+		if (error == EAGAIN)	/* XXX EAGAIN not yet supported */
+			error = EINVAL;
 		nfsm_reply(NFSX_WCCDATA(v3));
 		nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
 		error = 0;
@@ -2871,7 +2879,7 @@
 		nqsrv_getl(vp, ND_WRITE);
 		error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
 	}
-	NDFREE(&nd, NDF_ONLY_PNBUF);
+	NDFREE(&nd, NDF_ONLY_PNBUF & NDF_ONLY_SOFTLOCKLEAF);
 
 	if (dirp)
 		diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp);
@@ -2883,7 +2891,7 @@
 	/* fall through */
 
 nfsmout:
-	NDFREE(&nd, NDF_ONLY_PNBUF);
+	NDFREE(&nd, NDF_ONLY_PNBUF & NDF_ONLY_SOFTLOCKLEAF);
 	if (dirp)
 		vrele(dirp);
 	if (nd.ni_dvp) {
Index: nfs/nfs_subs.c
===================================================================
RCS file: /home/ncvs/src/sys/nfs/Attic/nfs_subs.c,v
retrieving revision 1.90.2.1
diff -u -r1.90.2.1 nfs_subs.c
--- nfs/nfs_subs.c	2000/10/28 16:27:27	1.90.2.1
+++ nfs/nfs_subs.c	2001/10/02 23:01:03
@@ -1729,6 +1729,10 @@
 out:
 	if (error) {
 		zfree(namei_zone, cnp->cn_pnbuf);
+		if ((cnp->cn_flags & SOFTLOCKLEAF) && ndp->ni_vp) {
+			vclearsoftlock(ndp->ni_vp);
+			vrele(ndp->ni_vp);
+		}
 		ndp->ni_vp = NULL;
 		ndp->ni_dvp = NULL;
 		ndp->ni_startdir = NULL;
Index: sys/namei.h
===================================================================
RCS file: /home/ncvs/src/sys/sys/namei.h,v
retrieving revision 1.29.2.2
diff -u -r1.29.2.2 namei.h
--- sys/namei.h	2001/09/30 21:12:54	1.29.2.2
+++ sys/namei.h	2001/10/02 18:43:34
@@ -114,7 +114,7 @@
 #define	FOLLOW		0x0040	/* follow symbolic links */
 #define	NOOBJ		0x0080	/* don't create object */
 #define	NOFOLLOW	0x0000	/* do not follow symbolic links (pseudo) */
-#define	MODMASK		0x00fc	/* mask of operational modifiers */
+#define	MODMASK		(0x00fc|SOFTLOCKLEAF)
 /*
  * Namei parameter descriptors.
  *
@@ -143,7 +143,7 @@
 #define	WILLBEDIR	0x080000 /* new files will be dirs; allow trailing / */
 #define	ISUNICODE	0x100000 /* current component name is unicode*/
 #define	PDIRUNLOCK	0x200000 /* file system lookup() unlocked parent dir */
-#define PARAMASK	0x1fff00 /* mask of parameter descriptors */
+#define SOFTLOCKLEAF	0x400000 /* set VSOFTLOCK in vnode */
 /*
  * Initialization of an nameidata structure.
  */
@@ -180,7 +180,9 @@
 #define NDF_NO_VP_PUT		0x0000000c
 #define NDF_NO_STARTDIR_RELE	0x00000010
 #define NDF_NO_FREE_PNBUF	0x00000020
+#define NDF_NO_FREE_SOFTLOCKLEAF 0x00000040
 #define NDF_ONLY_PNBUF		(~NDF_NO_FREE_PNBUF)
+#define NDF_ONLY_SOFTLOCKLEAF	(~NDF_NO_FREE_SOFTLOCKLEAF)
 
 void NDFREE __P((struct nameidata *, const uint));
 
Index: sys/vnode.h
===================================================================
RCS file: /home/ncvs/src/sys/sys/vnode.h,v
retrieving revision 1.111.2.12
diff -u -r1.111.2.12 vnode.h
--- sys/vnode.h	2001/09/22 09:21:48	1.111.2.12
+++ sys/vnode.h	2001/10/02 22:54:37
@@ -169,6 +169,7 @@
 #define	VTBFREE		0x100000 /* This vnode is on the to-be-freelist */
 #define	VONWORKLST	0x200000 /* On syncer work-list */
 #define	VMOUNT		0x400000 /* Mount in progress */
+#define VSOFTLOCK	0x800000 /* Soft lock on vnode (directory entry) */
 
 /*
  * Vnode attributes.  A field value of VNOVAL represents a field whose value
@@ -630,6 +632,9 @@
 void 	vrele __P((struct vnode *vp));
 void	vref __P((struct vnode *vp));
 void	vbusy __P((struct vnode *vp));
+int	vsetsoftlock __P((struct vnode *vp));
+void	vclearsoftlock __P((struct vnode *vp));
+void	vagain __P((int *gc));
 
 extern	vop_t	**default_vnodeop_p;
 extern	vop_t **spec_vnodeop_p;
Index: ufs/ufs/ufs_vnops.c
===================================================================
RCS file: /home/ncvs/src/sys/ufs/ufs/ufs_vnops.c,v
retrieving revision 1.131.2.4
diff -u -r1.131.2.4 ufs_vnops.c
--- ufs/ufs/ufs_vnops.c	2001/08/28 17:28:49	1.131.2.4
+++ ufs/ufs/ufs_vnops.c	2001/10/02 19:16:40
@@ -997,13 +997,11 @@
 		 * Avoid ".", "..", and aliases of "." for obvious reasons.
 		 */
 		if ((fcnp->cn_namelen == 1 && fcnp->cn_nameptr[0] == '.') ||
-		    dp == ip || (fcnp->cn_flags | tcnp->cn_flags) & ISDOTDOT ||
-		    (ip->i_flag & IN_RENAME)) {
+		    dp == ip || (fcnp->cn_flags | tcnp->cn_flags) & ISDOTDOT) {
 			VOP_UNLOCK(fvp, 0, p);
 			error = EINVAL;
 			goto abortit;
 		}
-		ip->i_flag |= IN_RENAME;
 		oldparent = dp->i_number;
 		doingdirectory = 1;
 	}
@@ -1224,13 +1222,12 @@
 		return (0);
 	}
 	/*
-	 * Ensure that the directory entry still exists and has not
-	 * changed while the new name has been entered. If the source is
-	 * a file then the entry may have been unlinked or renamed. In
-	 * either case there is no further work to be done. If the source
-	 * is a directory then it cannot have been rmdir'ed; the IN_RENAME
-	 * flag ensures that it cannot be moved by another rename or removed
-	 * by a rmdir.
+	 * The source has been VSOFTLOCKd by the caller, preventing rename
+	 * or rmdir, but not prevent unlink.  At the moment we allow the unlink
+	 * race and so do not panic if relookup fails or the inodes do not
+	 * match, because files can be hardlinked and our flag is on the vnode
+	 * rather then the directory entry in the namei cache.  But source
+	 * directories must still exist.
 	 */
 	if (xp != ip) {
 		if (doingdirectory)
@@ -1248,7 +1245,6 @@
 			cache_purge(fdvp);
 		}
 		error = ufs_dirremove(fdvp, xp, fcnp->cn_flags, 0);
-		xp->i_flag &= ~IN_RENAME;
 	}
 	VN_KNOTE(fvp, NOTE_RENAME);
 	if (dp)
@@ -1263,13 +1259,10 @@
 		vput(ITOV(xp));
 	vput(ITOV(dp));
 out:
-	if (doingdirectory)
-		ip->i_flag &= ~IN_RENAME;
 	if (vn_lock(fvp, LK_EXCLUSIVE, p) == 0) {
 		ip->i_effnlink--;
 		ip->i_nlink--;
 		ip->i_flag |= IN_CHANGE;
-		ip->i_flag &= ~IN_RENAME;
 		if (DOINGSOFTDEP(fvp))
 			softdep_change_linkcnt(ip);
 		vput(fvp);
@@ -1503,18 +1496,16 @@
 	dp = VTOI(dvp);
 
 	/*
-	 * Do not remove a directory that is in the process of being renamed.
 	 * Verify the directory is empty (and valid). Rmdir ".." will not be
 	 * valid since ".." will contain a reference to the current directory
 	 * and thus be non-empty. Do not allow the removal of mounted on
 	 * directories (this can happen when an NFS exported filesystem
 	 * tries to remove a locally mounted on directory).
+	 *
+	 * The syscall wrapper already protects us from attempting to remove
+	 * a directory that is undergoing a rename.
 	 */
 	error = 0;
-	if (ip->i_flag & IN_RENAME) {
-		error = EINVAL;
-		goto out;
-	}
 	if (ip->i_effnlink != 2 ||
 	    !ufs_dirempty(ip, dp->i_number, cnp->cn_cred)) {
 		error = ENOTEMPTY;

To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-hackers" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200110022312.f92NCpp60948>