svn commit: r192201 - in stable/7/sys: . contrib/pf dev/ath/ath_hal dev/cxgb ufs/ufs

Konstantin Belousov kib at FreeBSD.org
Sat May 16 17:22:05 UTC 2009


Author: kib
Date: Sat May 16 17:22:03 2009
New Revision: 192201
URL: http://svn.freebsd.org/changeset/base/192201

Log:
  MFC r191315:
  In ufs_checkpath(), recheck that '..' still points to the inode with
  the same inode number after VFS_VGET() and relock of the vp. If '..'
  changed, redo the lookup.
  
  Supply the source inode number as an argument to ufs_checkpath() instead
  of the source inode itself.

Modified:
  stable/7/sys/   (props changed)
  stable/7/sys/contrib/pf/   (props changed)
  stable/7/sys/dev/ath/ath_hal/   (props changed)
  stable/7/sys/dev/cxgb/   (props changed)
  stable/7/sys/ufs/ufs/ufs_extern.h
  stable/7/sys/ufs/ufs/ufs_lookup.c
  stable/7/sys/ufs/ufs/ufs_vnops.c

Modified: stable/7/sys/ufs/ufs/ufs_extern.h
==============================================================================
--- stable/7/sys/ufs/ufs/ufs_extern.h	Sat May 16 17:15:26 2009	(r192200)
+++ stable/7/sys/ufs/ufs/ufs_extern.h	Sat May 16 17:22:03 2009	(r192201)
@@ -58,7 +58,7 @@ int	 ufs_bmap(struct vop_bmap_args *);
 int	 ufs_bmaparray(struct vnode *, ufs2_daddr_t, ufs2_daddr_t *,
 	    struct buf *, int *, int *);
 int	 ufs_fhtovp(struct mount *, struct ufid *, struct vnode **);
-int	 ufs_checkpath(struct inode *, struct inode *, struct ucred *);
+int	 ufs_checkpath(ino_t, struct inode *, struct ucred *);
 void	 ufs_dirbad(struct inode *, doff_t, char *);
 int	 ufs_dirbadentry(struct vnode *, struct direct *, int);
 int	 ufs_dirempty(struct inode *, ino_t, struct ucred *);

Modified: stable/7/sys/ufs/ufs/ufs_lookup.c
==============================================================================
--- stable/7/sys/ufs/ufs/ufs_lookup.c	Sat May 16 17:15:26 2009	(r192200)
+++ stable/7/sys/ufs/ufs/ufs_lookup.c	Sat May 16 17:22:03 2009	(r192201)
@@ -1238,69 +1238,81 @@ ufs_dirempty(ip, parentino, cred)
 	return (1);
 }
 
+static int
+ufs_dir_dd_ino(struct vnode *vp, struct ucred *cred, ino_t *dd_ino)
+{
+	struct dirtemplate dirbuf;
+	int error, namlen;
+
+	if (vp->v_type != VDIR)
+		return (ENOTDIR);
+	error = vn_rdwr(UIO_READ, vp, (caddr_t)&dirbuf,
+	    sizeof (struct dirtemplate), (off_t)0, UIO_SYSSPACE,
+	    IO_NODELOCKED | IO_NOMACCHECK, cred, NOCRED, (int *)0, NULL);
+	if (error != 0)
+		return (error);
+#if (BYTE_ORDER == LITTLE_ENDIAN)
+	if (OFSFMT(vp))
+		namlen = dirbuf.dotdot_type;
+	else
+		namlen = dirbuf.dotdot_namlen;
+#else
+	namlen = dirbuf.dotdot_namlen;
+#endif
+	if (namlen != 2 || dirbuf.dotdot_name[0] != '.' ||
+	    dirbuf.dotdot_name[1] != '.')
+		return (ENOTDIR);
+	*dd_ino = dirbuf.dotdot_ino;
+	return (0);
+}
+
 /*
  * Check if source directory is in the path of the target directory.
  * Target is supplied locked, source is unlocked.
  * The target is always vput before returning.
  */
 int
-ufs_checkpath(source, target, cred)
-	struct inode *source, *target;
-	struct ucred *cred;
+ufs_checkpath(ino_t source_ino, struct inode *target, struct ucred *cred)
 {
-	struct vnode *vp;
-	int error, namlen;
-	ino_t rootino;
-	struct dirtemplate dirbuf;
+	struct vnode *vp, *vp1;
+	int error;
+	ino_t dd_ino;
 
 	vp = ITOV(target);
-	if (target->i_number == source->i_number) {
+	if (target->i_number == source_ino) {
 		error = EEXIST;
 		goto out;
 	}
-	rootino = ROOTINO;
 	error = 0;
-	if (target->i_number == rootino)
+	if (target->i_number == ROOTINO)
 		goto out;
 
 	for (;;) {
-		if (vp->v_type != VDIR) {
-			error = ENOTDIR;
-			break;
-		}
-		error = vn_rdwr(UIO_READ, vp, (caddr_t)&dirbuf,
-			sizeof (struct dirtemplate), (off_t)0, UIO_SYSSPACE,
-			IO_NODELOCKED | IO_NOMACCHECK, cred, NOCRED, (int *)0,
-			(struct thread *)0);
+		error = ufs_dir_dd_ino(vp, cred, &dd_ino);
 		if (error != 0)
 			break;
-#		if (BYTE_ORDER == LITTLE_ENDIAN)
-			if (OFSFMT(vp))
-				namlen = dirbuf.dotdot_type;
-			else
-				namlen = dirbuf.dotdot_namlen;
-#		else
-			namlen = dirbuf.dotdot_namlen;
-#		endif
-		if (namlen != 2 ||
-		    dirbuf.dotdot_name[0] != '.' ||
-		    dirbuf.dotdot_name[1] != '.') {
-			error = ENOTDIR;
-			break;
-		}
-		if (dirbuf.dotdot_ino == source->i_number) {
+		if (dd_ino == source_ino) {
 			error = EINVAL;
 			break;
 		}
-		if (dirbuf.dotdot_ino == rootino)
+		if (dd_ino == ROOTINO)
 			break;
-		vput(vp);
-		error = VFS_VGET(vp->v_mount, dirbuf.dotdot_ino,
-		    LK_EXCLUSIVE, &vp);
-		if (error) {
-			vp = NULL;
+		error = vn_vget_ino(vp, dd_ino, LK_EXCLUSIVE, &vp1);
+		if (error != 0)
+			break;
+		/* Recheck that ".." still points to vp1 after relock of vp */
+		error = ufs_dir_dd_ino(vp, cred, &dd_ino);
+		if (error != 0) {
+			vput(vp1);
 			break;
 		}
+		/* Redo the check of ".." if directory was reparented */
+		if (dd_ino != VTOI(vp1)->i_number) {
+			vput(vp1);
+			continue;
+		}
+		vput(vp);
+		vp = vp1;
 	}
 
 out:

Modified: stable/7/sys/ufs/ufs/ufs_vnops.c
==============================================================================
--- stable/7/sys/ufs/ufs/ufs_vnops.c	Sat May 16 17:15:26 2009	(r192200)
+++ stable/7/sys/ufs/ufs/ufs_vnops.c	Sat May 16 17:22:03 2009	(r192201)
@@ -1029,6 +1029,7 @@ ufs_rename(ap)
 	struct direct newdir;
 	int doingdirectory = 0, oldparent = 0, newparent = 0;
 	int error = 0, ioflag;
+	ino_t fvp_ino;
 
 #ifdef INVARIANTS
 	if ((tcnp->cn_flags & HASBUF) == 0 ||
@@ -1139,6 +1140,7 @@ abortit:
 	 * call to checkpath().
 	 */
 	error = VOP_ACCESS(fvp, VWRITE, tcnp->cn_cred, tcnp->cn_thread);
+	fvp_ino = ip->i_number;
 	VOP_UNLOCK(fvp, 0, td);
 	if (oldparent != dp->i_number)
 		newparent = dp->i_number;
@@ -1147,7 +1149,7 @@ abortit:
 			goto bad;
 		if (xp != NULL)
 			vput(tvp);
-		error = ufs_checkpath(ip, dp, tcnp->cn_cred);
+		error = ufs_checkpath(fvp_ino, dp, tcnp->cn_cred);
 		if (error)
 			goto out;
 		if ((tcnp->cn_flags & SAVESTART) == 0)


More information about the svn-src-stable-7 mailing list