Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 31 May 1999 14:21:37 +1000
From:      Bruce Evans <bde@zeta.org.au>
To:        freebsd-current@FreeBSD.ORG, semen@iclub.nsu.ru
Subject:   Re: How can i fail buf?
Message-ID:  <199905310421.OAA27787@godzilla.zeta.org.au>

next in thread | raw e-mail | index | archive | help
>The problem is following:
>
>FS driver recieves VOP_FSYNC request,
>then it scan the queue and pick up dirty buffers to
>bwrite(bp) them. bwrite calls VOP_STRATEGY, 
>FS's strategy routine is trying to VOP_BMAP buf, and
>fails (suppose it fails), then xxfs_strategy do:
>
>	bp->b_error = error;
>	bp->b_flags |= B_ERROR;
>	biodone(bp);
>	return(bp);
>
>(Looks right, at least IMO)
>But:
>biodone will not rel*se(bp), as it is not B_ASYNC,
>then it returns to bwrite, where it will brelse(bp) after
>biowait(bp). Then bp will come to brelse with B_ERROR set.
>in the begining, brelse:
>
>	...
>
>	if ((bp->b_flags & (B_READ | B_ERROR)) == B_ERROR) {
>		bp->b_flags &= ~B_ERROR;
>		bdirty(bp);
>	} ...
>
>then buffer returns to dirty queue, and is dirty, all 
>repeates infinite.

Also, for async writes, the file may be closed before the write completes
(the write never completes...).  Then vinvalbuf() calls VOP_FSYNC()
to write all dirty buffers and panics when VOP_FSYNC() fails to do this.

>How this is solved?

This isn't solved.  It was less serious before rev.1.196 of vfs_bio.c
when B_ERROR buffers were discarded insead of re-dirtied in the above
code fragment.  See also PR 11697, and about 20 PRs reporting problems
with i/o errors and EOF "errors" (ENOSPC/EINVAL) for (mis)using buffered
devices (especially fd0).

I use the following variant of the patch in PR 11697:

diff -c2 vfs_bio.c~ vfs_bio.c
*** vfs_bio.c~	Thu May 13 14:42:10 1999
--- vfs_bio.c	Thu May 13 16:36:09 1999
***************
*** 744,752 ****
  		bp->b_flags &= ~B_ERROR;
  
! 	if ((bp->b_flags & (B_READ | B_ERROR)) == B_ERROR) {
  		/*
  		 * Failed write, redirty.  Must clear B_ERROR to prevent
! 		 * pages from being scrapped.  Note: B_INVAL is ignored
! 		 * here but will presumably be dealt with later.
  		 */
  		bp->b_flags &= ~B_ERROR;
--- 800,808 ----
  		bp->b_flags &= ~B_ERROR;
  
! 	if ((bp->b_flags & (B_READ | B_ERROR | B_INVAL)) == B_ERROR &&
! 	    (bp->b_error == EIO || bp->b_error == 0)) {
  		/*
  		 * Failed write, redirty.  Must clear B_ERROR to prevent
! 		 * pages from being scrapped.
  		 */
  		bp->b_flags &= ~B_ERROR;

This fixes the primary problem in all cases except the most interesting one:
for real i/o errors.  It doesn't touch the secondary problem that most
VOP_FSYNC() routines don't try hard enough to write all dirty buffers in
the MNT_WAIT case, so vinvalbuf() may panic.

Bruce


To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-current" in the body of the message




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