kern/52338: fd(4) floppy disk driver & non-blocking I/O
bde at zeta.org.au
Sat May 17 07:40:08 PDT 2003
The following reply was made to PR kern/52338; it has been noted by GNATS.
From: Bruce Evans <bde at zeta.org.au>
To: Yar Tikhiy <yar at comp.chem.msu.su>
Cc: FreeBSD-gnats-submit at freebsd.org, freebsd-bugs at freebsd.org,
joerg at freebsd.org
Subject: Re: kern/52338: fd(4) floppy disk driver & non-blocking I/O
Date: Sun, 18 May 2003 00:39:03 +1000 (EST)
On Sat, 17 May 2003, Yar Tikhiy wrote:
> I'm testing a somewhat different patch:
> But its first part yields an unexpected result: No error from
> read() is reported at all! That happens because fdstrategy() doesn't
> set bp->b_resid when indicating a error on a buffer; consequently,
> the corresponding uio structure gets indication in physio() that
> the data has been transferred; and dofileread() will clear the error
> status if any bytes have been transferred and the error status is
> EAGAIN or EINTR (see kern/sys_generic.c at line 195).
It should set bp->bio_resid (to bp->bio_bcount) (bio_resid and bio_bcount
are the same as b_resid and b_bcount here; strategy routines only have
access to a struct bio so they must use the former).
Strategy routines can return an error together with a count of bytes
sucessfully transferred. They do this by setting BIO_ERROR and b_error
as usual for an error, and returning the number of bytes _not_
successfully transferred in bio_resid. physio() actually understands
this, although the upper layers are mostly broken (they should clear
the error status and return the count of bytes successfully transferred
in most cases, since there is no way to return both to the application
layer and POSIX and POLA specify returning the count), but as you
noticed they only do this for the EAGAIN and EINTR cases.
This is a very old bug. Long ago, e.g., in FreeBSD-1, b_resid was
(ab)used for a temporary variable by disksort(), so it was garbage in
strategy routines unless they set it, but fdstrategy() didn't set it
for early errors even in FreeBSD-1. Clobbering of b_resid in disksort()
made early settings of it just bogus. Now, b_resid tends to stick at 0
which gives the fail-unsafe behaviour that you saw.
More information about the freebsd-bugs