From owner-freebsd-stable Mon Feb 11 3:39:33 2002 Delivered-To: freebsd-stable@freebsd.org Received: from mailman.zeta.org.au (mailman.zeta.org.au [203.26.10.16]) by hub.freebsd.org (Postfix) with ESMTP id C3E7D37B419; Mon, 11 Feb 2002 03:39:00 -0800 (PST) Received: from bde.zeta.org.au (bde.zeta.org.au [203.2.228.102]) by mailman.zeta.org.au (8.9.3/8.8.7) with ESMTP id WAA27682; Mon, 11 Feb 2002 22:38:55 +1100 Date: Mon, 11 Feb 2002 22:41:45 +1100 (EST) From: Bruce Evans X-X-Sender: To: Matteo Cc: , , , Subject: Re: Crash System with MSDOS file-system driver! In-Reply-To: <20020208163715.14085.qmail@web13205.mail.yahoo.com> Message-ID: <20020211221141.R682-100000@gamplex.bde.org> MIME-Version: 1.0 Content-Type: TEXT/PLAIN; charset=US-ASCII Sender: owner-freebsd-stable@FreeBSD.ORG Precedence: bulk List-ID: List-Archive: (Web Archive) List-Help: (List Instructions) List-Subscribe: List-Unsubscribe: X-Loop: FreeBSD.ORG 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 ST1 2 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