Author: pjd
Date: Thu Apr 15 16:40:54 2010
New Revision: 206667
URL: http://svn.freebsd.org/changeset/base/206667

Log:
  Fix 3-way deadlock that can happen because of ZFS and vnode lock
  order reversal.
  
  thread0 (vfs_fhtovp)  thread1 (vop_getattr)   thread2 (zfs_recv)
  --------------------  ---------------------   ------------------
                        vn_lock
  rrw_enter_read
                                                rrw_enter_write (hangs)
                        rrw_enter_read (hangs)
  vn_lock (hangs)
  
  Submitted by: Attila Nagy <b...@fsn.hu>
  MFC after:    3 days

Modified:
  head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vfsops.c
  head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c

Modified: head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vfsops.c
==============================================================================
--- head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vfsops.c    Thu Apr 
15 16:35:34 2010        (r206666)
+++ head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vfsops.c    Thu Apr 
15 16:40:54 2010        (r206667)
@@ -868,13 +868,15 @@ zfs_root(vfs_t *vfsp, int flags, vnode_t
        ZFS_ENTER_NOERROR(zfsvfs);
 
        error = zfs_zget(zfsvfs, zfsvfs->z_root, &rootzp);
+
+       ZFS_EXIT(zfsvfs);
+
        if (error == 0) {
                *vpp = ZTOV(rootzp);
                error = vn_lock(*vpp, flags);
                (*vpp)->v_vflag |= VV_ROOT;
        }
 
-       ZFS_EXIT(zfsvfs);
        return (error);
 }
 
@@ -1143,13 +1145,13 @@ zfs_vget(vfs_t *vfsp, ino_t ino, int fla
                VN_RELE(ZTOV(zp));
                err = EINVAL;
        }
+       ZFS_EXIT(zfsvfs);
        if (err != 0)
                *vpp = NULL;
        else {
                *vpp = ZTOV(zp);
                vn_lock(*vpp, flags);
        }
-       ZFS_EXIT(zfsvfs);
        return (err);
 }
 
@@ -1237,8 +1239,8 @@ zfs_fhtovp(vfs_t *vfsp, fid_t *fidp, vno
                } else {
                        VN_HOLD(*vpp);
                }
-               vn_lock(*vpp, LK_EXCLUSIVE | LK_RETRY);
                ZFS_EXIT(zfsvfs);
+               vn_lock(*vpp, LK_EXCLUSIVE | LK_RETRY);
                return (0);
        }
 
@@ -1259,10 +1261,11 @@ zfs_fhtovp(vfs_t *vfsp, fid_t *fidp, vno
                return (EINVAL);
        }
 
+       ZFS_EXIT(zfsvfs);
+
        *vpp = ZTOV(zp);
        vn_lock(*vpp, LK_EXCLUSIVE | LK_RETRY);
        vnode_create_vobject(*vpp, zp->z_phys->zp_size, curthread);
-       ZFS_EXIT(zfsvfs);
        return (0);
 }
 

Modified: head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c
==============================================================================
--- head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c     Thu Apr 
15 16:35:34 2010        (r206666)
+++ head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c     Thu Apr 
15 16:40:54 2010        (r206667)
@@ -1209,15 +1209,17 @@ zfs_lookup(vnode_t *dvp, char *nm, vnode
                        ltype = VOP_ISLOCKED(dvp);
                        VOP_UNLOCK(dvp, 0);
                }
+               ZFS_EXIT(zfsvfs);
                error = vn_lock(*vpp, cnp->cn_lkflags);
                if (cnp->cn_flags & ISDOTDOT)
                        vn_lock(dvp, ltype | LK_RETRY);
                if (error != 0) {
                        VN_RELE(*vpp);
                        *vpp = NULL;
-                       ZFS_EXIT(zfsvfs);
                        return (error);
                }
+       } else {
+               ZFS_EXIT(zfsvfs);
        }
 
 #ifdef FREEBSD_NAMECACHE
@@ -1237,8 +1239,6 @@ zfs_lookup(vnode_t *dvp, char *nm, vnode
        }
 #endif
 
-       ZFS_EXIT(zfsvfs);
-
        return (error);
 }
 
_______________________________________________
svn-src-head@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to