Author: pfg
Date: Wed May 23 02:43:28 2012
New Revision: 235820
URL: http://svn.freebsd.org/changeset/base/235820

Log:
  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)

Modified:
  stable/9/sys/fs/ext2fs/ext2_lookup.c
  stable/9/sys/fs/ext2fs/ext2_vnops.c
Directory Properties:
  stable/9/sys/   (props changed)
  stable/9/sys/fs/   (props changed)

Modified: stable/9/sys/fs/ext2fs/ext2_lookup.c
==============================================================================
--- stable/9/sys/fs/ext2fs/ext2_lookup.c        Wed May 23 02:12:00 2012        
(r235819)
+++ stable/9/sys/fs/ext2fs/ext2_lookup.c        Wed May 23 02:43:28 2012        
(r235820)
@@ -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 "." */

Modified: stable/9/sys/fs/ext2fs/ext2_vnops.c
==============================================================================
--- stable/9/sys/fs/ext2fs/ext2_vnops.c Wed May 23 02:12:00 2012        
(r235819)
+++ stable/9/sys/fs/ext2fs/ext2_vnops.c Wed May 23 02:43:28 2012        
(r235820)
@@ -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);
 }
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to