Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 7 Jul 2007 14:26:17 +0100
From:      Doug Rabson <dfr@rabson.org>
To:        current@freebsd.org
Subject:   ZFS leaking vnodes (sort of)
Message-ID:  <200707071426.18202.dfr@rabson.org>

next in thread | raw e-mail | index | archive | help
I've been testing ZFS recently and I noticed some performance issues 
while doing large-scale port builds on a ZFS mounted /usr/ports tree. 
Eventually I realised that virtually nothing ever ended up on the vnode 
free list. This meant that when the system reached its maximum vnode 
limit, it had to resort to reclaiming vnodes from the various 
filesystem's active vnode lists (via vlrureclaim). Since those lists 
are not sorted in LRU order, this led to pessimal cache performance 
after the system got into that state.

I looked a bit closer at the ZFS code and poked around with DDB and I 
think the problem was caused by a couple of extraneous calls to vhold 
when creating a new ZFS vnode. On FreeBSD, getnewvnode returns a vnode 
which is already held (not on the free list) so there is no need to 
call vhold again.

This patch appears to fix the problem (only very lightly tested):

Index: zfs_vnops.c
===================================================================
RCS 
file: /home/ncvs/src/sys/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c,v
retrieving revision 1.22
diff -u -r1.22 zfs_vnops.c
--- zfs_vnops.c	28 May 2007 02:37:43 -0000	1.22
+++ zfs_vnops.c	7 Jul 2007 13:01:41 -0000
@@ -3493,7 +3493,7 @@
 		rele = 0;
 	vp->v_data = NULL;
 	ASSERT(vp->v_holdcnt > 1);
-	vdropl(vp);
+	VI_UNLOCK(vp);
 	if (!zp->z_unlinked && rele)
 		VFS_RELE(zfsvfs->z_vfs);
 	return (0);
Index: zfs_znode.c
===================================================================
RCS 
file: /home/ncvs/src/sys/contrib/opensolaris/uts/common/fs/zfs/zfs_znode.c,v
retrieving revision 1.8
diff -u -r1.8 zfs_znode.c
--- zfs_znode.c	6 May 2007 19:05:37 -0000	1.8
+++ zfs_znode.c	7 Jul 2007 13:17:32 -0000
@@ -115,7 +115,6 @@
 		ASSERT(error == 0);
 		zp->z_vnode = vp;
 		vp->v_data = (caddr_t)zp;
-		vhold(vp);
 		vp->v_vnlock->lk_flags |= LK_CANRECURSE;
 		vp->v_vnlock->lk_flags &= ~LK_NOSHARE;
 	} else {
@@ -601,7 +600,6 @@
 			ASSERT(err == 0);
 			vp = ZTOV(zp);
 			vp->v_data = (caddr_t)zp;
-			vhold(vp);
 			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);



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200707071426.18202.dfr>