svn commit: r197458 -
head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs
Pawel Jakub Dawidek
pjd at FreeBSD.org
Thu Sep 24 15:49:15 UTC 2009
Author: pjd
Date: Thu Sep 24 15:49:15 2009
New Revision: 197458
URL: http://svn.freebsd.org/changeset/base/197458
Log:
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
Modified:
head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_znode.c
Modified: head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_znode.c
==============================================================================
--- head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_znode.c Thu Sep 24 15:34:18 2009 (r197457)
+++ head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_znode.c Thu Sep 24 15:49:15 2009 (r197458)
@@ -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;
}
More information about the svn-src-all
mailing list