Subject: kern/5013: lfs_fastvget "vnode leak"
To: None <gnats-bugs@gnats.netbsd.org, perseant@hhhh.org>
From: None <perseant@hhhh.org>
List: netbsd-bugs
Date: 02/17/1998 21:50:28
>Number:         5013
>Category:       kern
>Synopsis:       lfs_fastvget locks inodes, then they are forgotten
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    kern-bug-people (Kernel Bug People)
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Tue Feb 17 22:05:01 1998
>Last-Modified:
>Originator:     Konrad Schroder
>Organization:
						Konrad Schroder
						perseant@hhhh.org
>Release:        1.3, plus patches for PR #s 4641, 4812, 4965.
>Environment:
System: NetBSD inle 1.3 NetBSD 1.3 (INLE) #101: Tue Feb 17 19:14:12 PST 1998 perseant@inle:/usr/src/sys/arch/i386/compile/INLE i386

>Description:
        lfs_fastvget has two mechanisms by which it retrieves vnodes: it
        either pulls them out of the hash list using ufs_ihashlookup(),
        (using an unlocked access to prevent deadlocking) or creates
        new, locked, vnodes using getnewvnode().

        lfs_fastvget does not make any distinction between these two
        types of inodes; so lfs_markv (the only caller of lfs_fastvget)
        does not VOP_UNLOCK the vnodes when it is done with them, as it
        has no way of knkowing whether they are locked or not, and if
        so, by whom.
>How-To-Repeat:
        Make an LFS, and create/delete/modify files on it until the
        cleaner cleans a few segments.  (You will need the patches
        mentioned above to get this far.)  The process writing to the
        LFS will hang, as will any other process that tries to access
        *any* filesystem.
>Fix:
        My solution simply has lfs_fastvget return whether the retrieved
        vnode should be VOP_UNLOCKed by the caller or not.  A patch follows.

*** lfs_extern.h.dist	Tue Feb 17 18:57:12 1998
--- lfs_extern.h	Tue Feb 17 18:57:31 1998
***************
*** 106,110 ****
  
  /* lfs_syscalls.c */
! int lfs_fastvget __P((struct mount *, ino_t, daddr_t, struct vnode **, struct dinode *));
  struct buf *lfs_fakebuf __P((struct vnode *, int, size_t, caddr_t));
  
--- 106,110 ----
  
  /* lfs_syscalls.c */
! int lfs_fastvget __P((struct mount *, ino_t, daddr_t, struct vnode **, struct dinode *, int *));
  struct buf *lfs_fakebuf __P((struct vnode *, int, size_t, caddr_t));
  
*** lfs_syscalls.c.dist	Mon Jan 12 18:25:35 1998
--- lfs_syscalls.c	Tue Feb 17 19:13:26 1998
***************
*** 108,112 ****
  	daddr_t b_daddr, v_daddr;
  	u_long bsize;
! 	int cnt, error;
  
  	if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
--- 108,112 ----
  	daddr_t b_daddr, v_daddr;
  	u_long bsize;
! 	int cnt, error, lfs_fastvget_unlock;
  
  	if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
***************
*** 150,153 ****
--- 150,155 ----
  
  				lfs_writeinode(fs, sp, ip);
+ 				if(lfs_fastvget_unlock)
+ 					VOP_UNLOCK(vp);
  				lfs_vunref(vp);
  			}
***************
*** 176,180 ****
  			if (lfs_fastvget(mntp, blkp->bi_inode, v_daddr, &vp,
  			    blkp->bi_lbn == LFS_UNUSED_LBN ? 
! 			    blkp->bi_bp : NULL)) {
  #ifdef DIAGNOSTIC
  				printf("lfs_markv: VFS_VGET failed (%d)\n",
--- 178,182 ----
  			if (lfs_fastvget(mntp, blkp->bi_inode, v_daddr, &vp,
  			    blkp->bi_lbn == LFS_UNUSED_LBN ? 
! 			    blkp->bi_bp : NULL, &lfs_fastvget_unlock)) {
  #ifdef DIAGNOSTIC
  				printf("lfs_markv: VFS_VGET failed (%d)\n",
***************
*** 449,453 ****
   */
  int
! lfs_fastvget(mp, ino, daddr, vpp, dinp)
  	struct mount *mp;
  	ino_t ino;
--- 451,455 ----
   */
  int
! lfs_fastvget(mp, ino, daddr, vpp, dinp, need_unlock)
  	struct mount *mp;
  	ino_t ino;
***************
*** 455,458 ****
--- 457,461 ----
  	struct vnode **vpp;
  	struct dinode *dinp;
+ 	int *need_unlock;
  {
  	register struct inode *ip;
***************
*** 465,468 ****
--- 468,472 ----
  	ump = VFSTOUFS(mp);
  	dev = ump->um_dev;
+ 	*need_unlock = 0;
  	/*
  	 * This is playing fast and loose.  Someone may have the inode
***************
*** 557,560 ****
--- 561,565 ----
  	VREF(ip->i_devvp);
  	*vpp = vp;
+ 	*need_unlock = 1;
  	return (0);
  }
>Audit-Trail:
>Unformatted: