summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordelphij <delphij@FreeBSD.org>2015-01-10 01:01:12 +0000
committerdelphij <delphij@FreeBSD.org>2015-01-10 01:01:12 +0000
commite6623583d128198b7dd7b6a68d0f525b0d4d19f8 (patch)
tree0851c5f443f323039d4fb038eda297d81fee5e7b
parent1009c8aa89624237add7b8bca851e09b29347d8a (diff)
downloadFreeBSD-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.c24
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));
}
OpenPOWER on IntegriCloud