Author: davide
Date: Sun Apr 13 01:15:37 2014
New Revision: 264392
URL: http://svnweb.freebsd.org/changeset/base/264392

Log:
  Fix a panic in zfs_rename().
  this is due to a wrong dereference of a vnode when it's not locked and
  can be (potentially) recycled. 'sdvp' cannot be locked on zfs_rename()
  entry point because the VFS can't be sure that this scenario is
  LOR-free (it might violate the parent->child lock acquisition rule).
  Dereference 'tdvp' instead, which is already locked on entry, and access
  'sdvp' fields only when it's safe, i.e. under ZFS_ENTER scope.
  
  While at it, remove the usage of VOP_REALVP, as long as this is a NOP
  on FreeBSD.
  
  Discussed with:       avg
  Reviewed by:  pjd

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

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     Sun Apr 
13 01:14:25 2014        (r264391)
+++ head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c     Sun Apr 
13 01:15:37 2014        (r264392)
@@ -3723,9 +3723,8 @@ static int
 zfs_rename(vnode_t *sdvp, char *snm, vnode_t *tdvp, char *tnm, cred_t *cr,
     caller_context_t *ct, int flags)
 {
-       znode_t         *tdzp, *szp, *tzp;
-       znode_t         *sdzp = VTOZ(sdvp);
-       zfsvfs_t        *zfsvfs = sdzp->z_zfsvfs;
+       znode_t         *tdzp, *sdzp, *szp, *tzp;
+       zfsvfs_t        *zfsvfs;
        zilog_t         *zilog;
        vnode_t         *realvp;
        zfs_dirlock_t   *sdl, *tdl;
@@ -3736,24 +3735,27 @@ zfs_rename(vnode_t *sdvp, char *snm, vno
        int             zflg = 0;
        boolean_t       waited = B_FALSE;
 
+       tdzp = VTOZ(tdvp);
+       ZFS_VERIFY_ZP(tdzp);
+       zfsvfs = tdzp->z_zfsvfs;
        ZFS_ENTER(zfsvfs);
-       ZFS_VERIFY_ZP(sdzp);
        zilog = zfsvfs->z_log;
+       sdzp = VTOZ(sdvp);
 
        /*
-        * Make sure we have the real vp for the target directory.
+        * In case sdzp is not valid, let's be sure to exit from the right
+        * zfsvfs_t.
         */
-       if (VOP_REALVP(tdvp, &realvp, ct) == 0)
-               tdvp = realvp;
-
-       tdzp = VTOZ(tdvp);
-       ZFS_VERIFY_ZP(tdzp);
+       if (sdzp->z_sa_hdl == NULL) {
+               ZFS_EXIT(zfsvfs);
+               return (SET_ERROR(EIO));
+       }
 
        /*
         * We check z_zfsvfs rather than v_vfsp here, because snapshots and the
         * ctldir appear to have the same v_vfsp.
         */
-       if (tdzp->z_zfsvfs != zfsvfs || zfsctl_is_node(tdvp)) {
+       if (sdzp->z_zfsvfs != zfsvfs || zfsctl_is_node(tdvp)) {
                ZFS_EXIT(zfsvfs);
                return (SET_ERROR(EXDEV));
        }
_______________________________________________
[email protected] mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "[email protected]"

Reply via email to