summaryrefslogtreecommitdiffstats
path: root/sys/cddl/contrib
diff options
context:
space:
mode:
authorpjd <pjd@FreeBSD.org>2009-09-24 15:49:15 +0000
committerpjd <pjd@FreeBSD.org>2009-09-24 15:49:15 +0000
commit534a0875d3f4fbdd8697194f7919403b3e61fb34 (patch)
tree5fb2a3298c141850549c51b8288e6e87624140ec /sys/cddl/contrib
parent9485b3f20f55236d1fb8b9e6ac48a4cd0ae9c4e2 (diff)
downloadFreeBSD-src-534a0875d3f4fbdd8697194f7919403b3e61fb34.zip
FreeBSD-src-534a0875d3f4fbdd8697194f7919403b3e61fb34.tar.gz
Close race in zfs_zget(). We have to increase usecount first and then
check for VI_DOOMED flag. Before this change vnode could be reclaimed between checking for the flag and increasing usecount. MFC after: 3 days
Diffstat (limited to 'sys/cddl/contrib')
-rw-r--r--sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_znode.c28
1 files changed, 19 insertions, 9 deletions
diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_znode.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_znode.c
index 082198f..c43a850 100644
--- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_znode.c
+++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_znode.c
@@ -890,17 +890,25 @@ again:
if (zp->z_unlinked) {
err = ENOENT;
} else {
- if ((vp = ZTOV(zp)) != NULL) {
- VI_LOCK(vp);
+ int dying = 0;
+
+ vp = ZTOV(zp);
+ if (vp == NULL)
+ dying = 1;
+ else {
+ VN_HOLD(vp);
if ((vp->v_iflag & VI_DOOMED) != 0) {
- VI_UNLOCK(vp);
- vp = NULL;
- } else
- VI_UNLOCK(vp);
+ dying = 1;
+ /*
+ * Don't VN_RELE() vnode here, because
+ * it can call vn_lock() which creates
+ * LOR between vnode lock and znode
+ * lock. We will VN_RELE() the vnode
+ * after droping znode lock.
+ */
+ }
}
- if (vp != NULL)
- VN_HOLD(vp);
- else {
+ if (dying) {
if (first) {
ZFS_LOG(1, "dying znode detected (zp=%p)", zp);
first = 0;
@@ -912,6 +920,8 @@ again:
dmu_buf_rele(db, NULL);
mutex_exit(&zp->z_lock);
ZFS_OBJ_HOLD_EXIT(zfsvfs, obj_num);
+ if (vp != NULL)
+ VN_RELE(vp);
tsleep(zp, 0, "zcollide", 1);
goto again;
}
OpenPOWER on IntegriCloud