Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 16 Apr 2009 09:57:08 +0000 (UTC)
From:      Konstantin Belousov <kib@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r191137 - head/sys/ufs/ufs
Message-ID:  <200904160957.n3G9v8ko076066@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: kib
Date: Thu Apr 16 09:57:08 2009
New Revision: 191137
URL: http://svn.freebsd.org/changeset/base/191137

Log:
  Verify that '..' still exists with the same inode number after
  VFS_VGET() has returned in ufs_lookup(). If the '..' lookup started
  immediately before the parent directory was removed, we might return
  either cleared or unrelated inode otherwise.
  
  Ufs_lookup() is split into new function ufs_lookup_() that either does
  lookup, or verifies that directory entry exists and references supplied
  inode number.
  
  Reviewed by:	tegge
  Tested by:	pho,
  	Andreas Tobler <andreast-list fgznet ch> (previous version)
  MFC after:	1 month

Modified:
  head/sys/ufs/ufs/ufs_lookup.c

Modified: head/sys/ufs/ufs/ufs_lookup.c
==============================================================================
--- head/sys/ufs/ufs/ufs_lookup.c	Thu Apr 16 09:37:48 2009	(r191136)
+++ head/sys/ufs/ufs/ufs_lookup.c	Thu Apr 16 09:57:08 2009	(r191137)
@@ -77,6 +77,9 @@ SYSCTL_INT(_debug, OID_AUTO, dircheck, C
 /* true if old FS format...*/
 #define OFSFMT(vp)	((vp)->v_mount->mnt_maxsymlinklen <= 0)
 
+static int ufs_lookup_(struct vnode *, struct vnode **, struct componentname *,
+    ino_t);
+
 /*
  * Convert a component of a pathname into a pointer to a locked inode.
  * This is a very central and rather complicated routine.
@@ -130,7 +133,14 @@ ufs_lookup(ap)
 		struct componentname *a_cnp;
 	} */ *ap;
 {
-	struct vnode *vdp;		/* vnode for directory being searched */
+
+	return (ufs_lookup_(ap->a_dvp, ap->a_vpp, ap->a_cnp, 0));
+}
+
+static int
+ufs_lookup_(struct vnode *vdp, struct vnode **vpp, struct componentname *cnp,
+    ino_t dd_ino)
+{
 	struct inode *dp;		/* inode for directory being searched */
 	struct buf *bp;			/* a buffer of directory entries */
 	struct direct *ep;		/* the current directory entry */
@@ -150,8 +160,6 @@ ufs_lookup(ap)
 	doff_t enduseful;		/* pointer past last used dir slot */
 	u_long bmask;			/* block offset mask */
 	int namlen, error;
-	struct vnode **vpp = ap->a_vpp;
-	struct componentname *cnp = ap->a_cnp;
 	struct ucred *cred = cnp->cn_cred;
 	int flags = cnp->cn_flags;
 	int nameiop = cnp->cn_nameiop;
@@ -164,9 +172,9 @@ ufs_lookup(ap)
  *  XXX there was a soft-update diff about this I couldn't merge.
  * I think this was the equiv.
  */
-	*vpp = NULL;
+	if (vpp != NULL)
+		*vpp = NULL;
 
-	vdp = ap->a_dvp;
 	dp = VTOI(vdp);
 
 	/*
@@ -363,7 +371,7 @@ foundentry:
 					slotoffset = i_offset;
 					slotsize = ep->d_reclen;
 					enduseful = dp->i_size;
-					ap->a_cnp->cn_flags |= ISWHITEOUT;
+					cnp->cn_flags |= ISWHITEOUT;
 					numdirpasses--;
 					goto notfound;
 				}
@@ -397,8 +405,8 @@ notfound:
 	 */
 	if ((nameiop == CREATE || nameiop == RENAME ||
 	     (nameiop == DELETE &&
-	      (ap->a_cnp->cn_flags & DOWHITEOUT) &&
-	      (ap->a_cnp->cn_flags & ISWHITEOUT))) &&
+	      (cnp->cn_flags & DOWHITEOUT) &&
+	      (cnp->cn_flags & ISWHITEOUT))) &&
 	    (flags & ISLASTCN) && dp->i_effnlink != 0) {
 		/*
 		 * Access for write is interpreted as allowing
@@ -453,7 +461,7 @@ notfound:
 	 * Insert name into cache (as non-existent) if appropriate.
 	 */
 	if ((cnp->cn_flags & MAKEENTRY) && nameiop != CREATE)
-		cache_enter(vdp, *vpp, cnp);
+		cache_enter(vdp, NULL, cnp);
 	return (ENOENT);
 
 found:
@@ -479,6 +487,12 @@ found:
 	if ((flags & ISLASTCN) && nameiop == LOOKUP)
 		dp->i_diroff = i_offset &~ (DIRBLKSIZ - 1);
 
+	if (dd_ino != 0) {
+		if (ino != dd_ino)
+			return (ENOENT);
+		return (0);
+	}
+
 	/*
 	 * If deleting, and at end of pathname, return
 	 * parameters which can be used to remove file.
@@ -580,6 +594,18 @@ found:
 		error = vn_vget_ino(pdp, ino, cnp->cn_lkflags, &tdp);
 		if (error)
 			return (error);
+
+		/*
+		 * Recheck that ".." entry in the vdp directory points
+		 * to the inode we looked up before vdp lock was
+		 * dropped.
+		 */
+		error = ufs_lookup_(pdp, NULL, cnp, ino);
+		if (error) {
+			vput(tdp);
+			return (error);
+		}
+
 		*vpp = tdp;
 	} else if (dp->i_number == ino) {
 		VREF(vdp);	/* we want ourself, ie "." */



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