kern/132068: page fault when using ZFS over NFS on 7.1-RELEASE/amd64

Jaakko Heinonen jh at saunalahti.fi
Thu Feb 26 09:50:03 PST 2009


The following reply was made to PR kern/132068; it has been noted by GNATS.

From: Jaakko Heinonen <jh at saunalahti.fi>
To: Edward Fisk <7ogcg7g02 at sneakemail.com>
Cc: bug-followup at FreeBSD.org
Subject: Re: kern/132068: page fault when using ZFS over NFS on
	7.1-RELEASE/amd64
Date: Thu, 26 Feb 2009 19:44:21 +0200

 On 2009-02-24, Edward Fisk wrote:
 >  (kgdb) p *nvp
 >  $1 = {v_type = VBAD, v_tag = 0xffffffff807e5627 "none", v_op = 0xffffffff80a18220, v_data = 0x0, v_mount = 0x0, v_nmntvnodes = {
 
 Thanks for the info. If you can't try 8.0-CURRENT here is an attempt to
 backport some bits from head to RELENG_7. I have only compile tested the
 patch so be careful.
 
 --- patch begins here ---
 Index: sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_znode.c
 ===================================================================
 --- sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_znode.c	(revision 189044)
 +++ sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_znode.c	(working copy)
 @@ -554,10 +554,10 @@ zfs_zget(zfsvfs_t *zfsvfs, uint64_t obj_
  	dmu_buf_t	*db;
  	znode_t		*zp;
  	vnode_t		*vp;
 -	int err;
 +	int err, first = 1;
  
  	*zpp = NULL;
 -
 +again:
  	ZFS_OBJ_HOLD_ENTER(zfsvfs, obj_num);
  
  	err = dmu_bonus_hold(zfsvfs->z_os, obj_num, NULL, &db);
 @@ -574,64 +574,60 @@ zfs_zget(zfsvfs_t *zfsvfs, uint64_t obj_
  		return (EINVAL);
  	}
  
 -	ASSERT(db->db_object == obj_num);
 -	ASSERT(db->db_offset == -1);
 -	ASSERT(db->db_data != NULL);
 -
  	zp = dmu_buf_get_user(db);
 -
  	if (zp != NULL) {
  		mutex_enter(&zp->z_lock);
  
 +		/*
 +		 * Since we do immediate eviction of the z_dbuf, we
 +		 * should never find a dbuf with a znode that doesn't
 +		 * know about the dbuf.
 +		 */
 +		ASSERT3P(zp->z_dbuf, ==, db);
  		ASSERT3U(zp->z_id, ==, obj_num);
  		if (zp->z_unlinked) {
 -			dmu_buf_rele(db, NULL);
 -			mutex_exit(&zp->z_lock);
 -			ZFS_OBJ_HOLD_EXIT(zfsvfs, obj_num);
 -			return (ENOENT);
 -		} else if (zp->z_dbuf_held) {
 -			dmu_buf_rele(db, NULL);
 +			err = ENOENT;
  		} else {
 -			zp->z_dbuf_held = 1;
 -			VFS_HOLD(zfsvfs->z_vfs);
 -		}
 -
 -		if (ZTOV(zp) != NULL)
 -			VN_HOLD(ZTOV(zp));
 -		else {
 -			err = getnewvnode("zfs", zfsvfs->z_vfs, &zfs_vnodeops,
 -			    &zp->z_vnode);
 -			ASSERT(err == 0);
 -			vp = ZTOV(zp);
 -			vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, curthread);
 -			vp->v_data = (caddr_t)zp;
 -			vp->v_vnlock->lk_flags |= LK_CANRECURSE;
 -			vp->v_vnlock->lk_flags &= ~LK_NOSHARE;
 -			vp->v_type = IFTOVT((mode_t)zp->z_phys->zp_mode);
 -			if (vp->v_type == VDIR)
 -				zp->z_zn_prefetch = B_TRUE;	/* z_prefetch default is enabled */
 -			vp->v_vflag |= VV_FORCEINSMQ;
 -			err = insmntque(vp, zfsvfs->z_vfs);
 -			vp->v_vflag &= ~VV_FORCEINSMQ;
 -			KASSERT(err == 0, ("insmntque() failed: error %d", err));
 -			VOP_UNLOCK(vp, 0, curthread);
 +			if (ZTOV(zp) != NULL)
 +				VN_HOLD(ZTOV(zp));
 +			else {
 +				if (first) {
 +					ZFS_LOG(1, "dying znode detected (zp=%p)", zp);
 +					first = 0;
 +				}
 +				/*
 +				 * znode is dying so we can't reuse it, we must
 +				 * wait until destruction is completed.
 +				 */
 +				dmu_buf_rele(db, NULL);
 +				mutex_exit(&zp->z_lock);
 +				ZFS_OBJ_HOLD_EXIT(zfsvfs, obj_num);
 +				tsleep(zp, 0, "zcollide", 1);
 +				goto again;
 +			}
 +			*zpp = zp;
 +			err = 0;
  		}
 +		dmu_buf_rele(db, NULL);
  		mutex_exit(&zp->z_lock);
  		ZFS_OBJ_HOLD_EXIT(zfsvfs, obj_num);
 -		*zpp = zp;
 -		return (0);
 +		return (err);
  	}
  
  	/*
  	 * Not found create new znode/vnode
  	 */
  	zp = zfs_znode_alloc(zfsvfs, db, obj_num, doi.doi_data_block_size);
 -	ASSERT3U(zp->z_id, ==, obj_num);
 -	zfs_znode_dmu_init(zp);
 +
 +	vp = ZTOV(zp);
 +	vp->v_vflag |= VV_FORCEINSMQ;
 +	err = insmntque(vp, zfsvfs->z_vfs);
 +	vp->v_vflag &= ~VV_FORCEINSMQ;
 +	KASSERT(err == 0, ("insmntque() failed: error %d", err));
 +	VOP_UNLOCK(vp, 0, curthread);
 +
  	ZFS_OBJ_HOLD_EXIT(zfsvfs, obj_num);
  	*zpp = zp;
 -	if ((vp = ZTOV(zp)) != NULL)
 -		VOP_UNLOCK(vp, 0, curthread);
  	return (0);
  }
  
 Index: sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c
 ===================================================================
 --- sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c	(revision 189044)
 +++ sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c	(working copy)
 @@ -3475,9 +3475,9 @@ zfs_freebsd_reclaim(ap)
  	ASSERT(zp->z_phys);
  	ASSERT(zp->z_dbuf_held);
  	zfsvfs = zp->z_zfsvfs;
 +	ZTOV(zp) = NULL;
  	if (!zp->z_unlinked) {
  		zp->z_dbuf_held = 0;
 -		ZTOV(zp) = NULL;
  		mutex_exit(&zp->z_lock);
  		dmu_buf_rele(zp->z_dbuf, NULL);
  	} else {
 --- patch ends here ---
 
 -- 
 Jaakko


More information about the freebsd-fs mailing list