From a8cef9c4881c82972a55e21902d1c509cf24f94c Mon Sep 17 00:00:00 2001 From: pfg Date: Wed, 23 May 2012 02:43:28 +0000 Subject: [PATCH] MFC: r235508 Fix a couple of issues that appear to be inherited from the old 8.x code: - If the lock cannot be acquired immediately unlocks 'bar' vnode and then locks both vnodes in order. - wrong vnode type panics from cache_enter_time after calls by ext2_lookup. The fix merges changes from ufs/ufs_lookup.c. Submitted by: Mateusz Guzik Approved by: jhb (mentor) git-svn-id: svn://svn.freebsd.org/base/stable/9@235820 ccf9f872-aa2e-dd11-9fc8-001c23d0bc1f --- sys/fs/ext2fs/ext2_lookup.c | 58 ++++++++++++++++++++++++++++++------- sys/fs/ext2fs/ext2_vnops.c | 6 +++- 2 files changed, 52 insertions(+), 12 deletions(-) diff --git a/sys/fs/ext2fs/ext2_lookup.c b/sys/fs/ext2fs/ext2_lookup.c index 35ab63125..c279998fb 100644 --- a/sys/fs/ext2fs/ext2_lookup.c +++ b/sys/fs/ext2fs/ext2_lookup.c @@ -115,6 +115,8 @@ static u_char dt_to_ext2_ft[] = { static int ext2_dirbadentry(struct vnode *dp, struct ext2fs_direct_2 *de, int entryoffsetinblock); +static int ext2_lookup_ino(struct vnode *vdp, struct vnode **vpp, + struct componentname *cnp, ino_t *dd_ino); /* * Vnode op for reading directories. @@ -285,7 +287,14 @@ ext2_lookup(ap) struct componentname *a_cnp; } */ *ap; { - struct vnode *vdp; /* vnode for directory being searched */ + + return (ext2_lookup_ino(ap->a_dvp, ap->a_vpp, ap->a_cnp, NULL)); +} + +static int +ext2_lookup_ino(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 ext2fs_direct_2 *ep; /* the current directory entry */ @@ -305,22 +314,22 @@ ext2_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; - ino_t ino; + ino_t ino, ino1; int ltype; - int DIRBLKSIZ = VTOI(ap->a_dvp)->i_e2fs->e2fs_bsize; + int DIRBLKSIZ = VTOI(vdp)->i_e2fs->e2fs_bsize; + + if (vpp != NULL) + *vpp = NULL; - bp = NULL; - slotoffset = -1; - *vpp = NULL; - vdp = ap->a_dvp; dp = VTOI(vdp); bmask = VFSTOEXT2(vdp->v_mount)->um_mountp->mnt_stat.f_iosize - 1; +restart: + bp = NULL; + slotoffset = -1; /* * We now have a segment name to search for, and a directory to search. @@ -536,10 +545,12 @@ searchloop: * 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: + if (dd_ino != NULL) + *dd_ino = ino; if (numdirpasses == 2) nchstats.ncs_pass2++; /* @@ -582,6 +593,8 @@ found: dp->i_count = 0; else dp->i_count = dp->i_offset - prevoff; + if (dd_ino != NULL) + return (0); if (dp->i_number == ino) { VREF(vdp); *vpp = vdp; @@ -622,6 +635,8 @@ found: */ if (dp->i_number == ino) return (EISDIR); + if (dd_ino != NULL) + return (0); if ((error = VFS_VGET(vdp->v_mount, ino, LK_EXCLUSIVE, &tdp)) != 0) return (error); @@ -629,6 +644,8 @@ found: cnp->cn_flags |= SAVENAME; return (0); } + if (dd_ino != NULL) + return (0); /* * Step through the translation in the name. We do not `vput' the @@ -655,8 +672,27 @@ found: VOP_UNLOCK(pdp, 0); /* race to get the inode */ error = VFS_VGET(vdp->v_mount, ino, cnp->cn_lkflags, &tdp); vn_lock(pdp, ltype | LK_RETRY); - if (error != 0) + if (pdp->v_iflag & VI_DOOMED) { + if (error == 0) + vput(tdp); + error = ENOENT; + } + if (error) return (error); + /* + * Recheck that ".." entry in the vdp directory points + * to the inode we looked up before vdp lock was + * dropped. + */ + error = ext2_lookup_ino(pdp, NULL, cnp, &ino1); + if (error) { + vput(tdp); + return (error); + } + if (ino1 != ino) { + vput(tdp); + goto restart; + } *vpp = tdp; } else if (dp->i_number == ino) { VREF(vdp); /* we want ourself, ie "." */ diff --git a/sys/fs/ext2fs/ext2_vnops.c b/sys/fs/ext2fs/ext2_vnops.c index 18a9dd297..ed862f0ae 100644 --- a/sys/fs/ext2fs/ext2_vnops.c +++ b/sys/fs/ext2fs/ext2_vnops.c @@ -1342,7 +1342,11 @@ ext2_rmdir(ap) error = ext2_truncate(vp, (off_t)0, IO_SYNC, cnp->cn_cred, cnp->cn_thread); cache_purge(ITOV(ip)); - vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY); + if (vn_lock(dvp, LK_EXCLUSIVE | LK_NOWAIT) != 0) { + VOP_UNLOCK(vp, 0); + vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY); + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); + } out: return (error); } -- 2.45.0