Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 11 Feb 2002 22:41:45 +1100 (EST)
From:      Bruce Evans <bde@zeta.org.au>
To:        Matteo <drummino@yahoo.com>
Cc:        <freebsd-stable@FreeBSD.ORG>, <freebsd-bugs@FreeBSD.ORG>, <aiuto@gufi.org>, <dillon@FreeBSD.ORG>
Subject:   Re: Crash System with MSDOS file-system driver!
Message-ID:  <20020211221141.R682-100000@gamplex.bde.org>
In-Reply-To: <20020208163715.14085.qmail@web13205.mail.yahoo.com>

next in thread | previous in thread | raw e-mail | index | archive | help
On Fri, 8 Feb 2002, Matteo wrote:

> Hi all,
>
> I've 4.5-RELEASE and 4.4-STABLE.
>
> Try to follow this steps:
>
> 1) Mount a msdos floppy write protected in /floppy
> 2) cd /floppy
> 3) rm somefile
> At this point kernel show this message:
>
> fd0c: hard error writing fsbn 56 of 56-63 (ST0
> 40<abnrml> ST1 2<write_prosend out a error messages...
> etc etc
>
> Next Step:
>
> 4) ls
>
> And system halt! I try with a UFS floppy and it's all
> ok.

%%%
The hang is caused by msdosfs_readdir() "handling" reads of 0 bytes by
spinning forever.  msdosfs_read() seems to have the same bug.
ufs_readdir() works because it calls VOP_READ() == ffs_read() which
treats reads of 0 bytes as EOF instead of spinning forever.

Reads of 0 bytes and other short reads shouldn't happen, but they
happen because failed writes clobber b_resid and breadn() later returns
with the clobbered value.  Filesystems use b_resid to determine the
extent of i/o in a few places (all (?) cloned from ufs_readwrite.c).
This is probably wrong and very incomplete -- most places, including
critical block allocation code, just assume that breadn() returns an
error if everything could not be read.

The patch mainly just resets b_resid in breadn().  Determining the
value after the i/o that filled the buffer doesn't seem to be easy,
but it should be 0.

Index: vfs_bio.c
===================================================================
RCS file: /home/ncvs/src/sys/kern/vfs_bio.c,v
retrieving revision 1.296
diff -u -r1.296 vfs_bio.c
--- vfs_bio.c	31 Jan 2002 18:39:44 -0000	1.296
+++ vfs_bio.c	11 Feb 2002 11:09:22 -0000
@@ -614,6 +614,13 @@
 		vfs_busy_pages(bp, 0);
 		VOP_STRATEGY(vp, bp);
 		++readwait;
+	} else {
+		/*
+		 * Recover from failed writes clobbering b_resid.  b_resid is
+		 * strictly only valid after i/o, but some filesystems expect
+		 * it to give the part of `size' that was not readable here.
+		 */
+		bp->b_resid = 0;
 	}

 	for (i = 0; i < cnt; i++, rablkno++, rabsize++) {
@@ -640,6 +647,16 @@

 	if (readwait) {
 		rv = bufwait(bp);
+		/*
+		 * Convert short reads to i/o errors, since short reads aren't
+		 * useful for the buffer cache and they are mostly not handled
+		 * in callers.
+		 * XXX we don't always get here for read-ahead blocks.
+		 * b_resid for read-ahead blocks may be clobbered by failed
+		 * attempts to write the blocks.
+		 */
+		if (rv == 0 && bp->b_resid != 0)
+			rv = EIO;
 	}
 	return (rv);
 }
%%%

Bruce


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




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