Subject: kern/3694: Buffer cache bug causes LFS lossage
To: None <gnats-bugs@gnats.netbsd.org>
From: None <perseant@hhhh.org>
List: netbsd-bugs
Date: 05/31/1997 20:00:59
>Number:         3694
>Category:       kern
>Synopsis:       Buffer erroneously calls biowait(), causeing LFS to hang
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    kern-bug-people (Kernel Bug People)
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Sat May 31 20:05:01 1997
>Last-Modified:
>Originator:     Konrad Schroder
>Organization:
University of Washington
>Release:        1.2 (and -current)
>Environment:
System: NetBSD inle 1.2 NetBSD 1.2 (INLE) #73: Fri May 30 22:07:38 PDT 1997 perseant@inle:/usr/src/sys/arch/i386/compile/INLE i386
>Description:
	bread() sometimes calls biowait() even though no physical read was
    started in bio_doread().  This causes writes to LFS filesystems to
    hang.
>How-To-Repeat:
	newlfs -L /dev/sd1a
    mount -t /dev/sd1a /mnt
    cp /netbsd /mnt
>Fix:
	I suggest the following patch.  Apparently ffs does not call bread()
    if the desired block is already in the cache, and so does not
    trigger the problem, nor is it affected at all by the patch.  Lfs,
    on the other hand, now works to the extent that I can copy kernel
    sources onto an LFS filesystem and build a fully functional kernel.

diff -r -C2 /usr/src/sys/kern/vfs_bio.c /var/src/sys/kern/vfs_bio.c
*** /usr/src/sys/kern/vfs_bio.c	Fri May 30 20:28:12 1997
--- /var/src/sys/kern/vfs_bio.c	Fri May 30 20:35:42 1997
***************
*** 101,105 ****
  
  static __inline struct buf *bio_doread __P((struct vnode *, daddr_t, int,
! 					    struct ucred *, int));
  int count_lock_queue __P((void));
  
--- 101,105 ----
  
  static __inline struct buf *bio_doread __P((struct vnode *, daddr_t, int,
! 					    struct ucred *, int, int *));
  int count_lock_queue __P((void));
  
***************
*** 163,167 ****
  
  static __inline struct buf *
! bio_doread(vp, blkno, size, cred, async)
  	struct vnode *vp;
  	daddr_t blkno;
--- 163,167 ----
  
  static __inline struct buf *
! bio_doread(vp, blkno, size, cred, async, mustwait)
  	struct vnode *vp;
  	daddr_t blkno;
***************
*** 169,172 ****
--- 169,173 ----
  	struct ucred *cred;
  	int async;
+ 	int *mustwait;
  {
  	register struct buf *bp;
***************
*** 187,190 ****
--- 188,192 ----
  		}
  		VOP_STRATEGY(bp);
+ 		(*mustwait)++;
  
  		/* Pay for the read. */
***************
*** 210,219 ****
  {
  	register struct buf *bp;
  
  	/* Get buffer for block. */
! 	bp = *bpp = bio_doread(vp, blkno, size, cred, 0);
  
  	/* Wait for the read to complete, and return result. */
! 	return (biowait(bp));
  }
  
--- 212,229 ----
  {
  	register struct buf *bp;
+ 	int mustwait=0;
  
  	/* Get buffer for block. */
! 	bp = *bpp = bio_doread(vp, blkno, size, cred, 0, &mustwait);
  
  	/* Wait for the read to complete, and return result. */
! 	if(mustwait)
! 		return (biowait(bp));
! 	else {
! 		if(ISSET(bp->b_flags,B_ERROR))
! 			return(bp->b_error ? bp->b_error : EIO);
! 		else
! 			return 0;
! 	}
  }
  
***************
*** 232,238 ****
  {
  	register struct buf *bp;
! 	int i;
  
! 	bp = *bpp = bio_doread(vp, blkno, size, cred, 0);
  
  	/*
--- 242,248 ----
  {
  	register struct buf *bp;
! 	int i, mustwait=0;
  
! 	bp = *bpp = bio_doread(vp, blkno, size, cred, 0, &mustwait);
  
  	/*
***************
*** 245,253 ****
  
  		/* Get a buffer for the read-ahead block */
! 		(void) bio_doread(vp, rablks[i], rasizes[i], cred, B_ASYNC);
  	}
  
  	/* Otherwise, we had to start a read for it; wait until it's valid. */
! 	return (biowait(bp));
  }
  
--- 255,270 ----
  
  		/* Get a buffer for the read-ahead block */
! 		(void) bio_doread(vp, rablks[i], rasizes[i], cred, B_ASYNC, &mustwait);
  	}
  
  	/* Otherwise, we had to start a read for it; wait until it's valid. */
! 	if(mustwait)
! 		return (biowait(bp));
! 	else {
! 		if(ISSET(bp->b_flags,B_ERROR))
! 			return(bp->b_error ? bp->b_error : EIO);
! 		else
! 			return 0;
! 	}
  }
  
>Audit-Trail:
>Unformatted: