diff options
author | delphij <delphij@FreeBSD.org> | 2015-01-10 01:01:12 +0000 |
---|---|---|
committer | delphij <delphij@FreeBSD.org> | 2015-01-10 01:01:12 +0000 |
commit | e6623583d128198b7dd7b6a68d0f525b0d4d19f8 (patch) | |
tree | 0851c5f443f323039d4fb038eda297d81fee5e7b | |
parent | 1009c8aa89624237add7b8bca851e09b29347d8a (diff) | |
download | FreeBSD-src-e6623583d128198b7dd7b6a68d0f525b0d4d19f8.zip FreeBSD-src-e6623583d128198b7dd7b6a68d0f525b0d4d19f8.tar.gz |
MFC r264392 (davide):
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.
-rw-r--r-- | sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c | 24 |
1 files changed, 13 insertions, 11 deletions
diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c index 6749e9f..d90c830 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c @@ -3730,9 +3730,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; @@ -3743,24 +3742,27 @@ zfs_rename(vnode_t *sdvp, char *snm, vnode_t *tdvp, char *tnm, cred_t *cr, 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)); } |