From owner-svn-src-all@FreeBSD.ORG Thu Apr 16 09:57:08 2009 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 6990F106566C; Thu, 16 Apr 2009 09:57:08 +0000 (UTC) (envelope-from kib@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id 577D98FC1A; Thu, 16 Apr 2009 09:57:08 +0000 (UTC) (envelope-from kib@FreeBSD.org) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.3/8.14.3) with ESMTP id n3G9v8am076067; Thu, 16 Apr 2009 09:57:08 GMT (envelope-from kib@svn.freebsd.org) Received: (from kib@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id n3G9v8ko076066; Thu, 16 Apr 2009 09:57:08 GMT (envelope-from kib@svn.freebsd.org) Message-Id: <200904160957.n3G9v8ko076066@svn.freebsd.org> From: Konstantin Belousov Date: Thu, 16 Apr 2009 09:57:08 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r191137 - head/sys/ufs/ufs X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 16 Apr 2009 09:57:09 -0000 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 (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 "." */