From owner-freebsd-current Mon Aug 12 9:34:33 2002 Delivered-To: freebsd-current@freebsd.org Received: from mx1.FreeBSD.org (mx1.FreeBSD.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id E1BC437B400; Mon, 12 Aug 2002 09:34:29 -0700 (PDT) Received: from mailman.zeta.org.au (mailman.zeta.org.au [203.26.10.16]) by mx1.FreeBSD.org (Postfix) with ESMTP id 5AC5243E42; Mon, 12 Aug 2002 09:34:28 -0700 (PDT) (envelope-from bde@zeta.org.au) 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 CAA24207; Tue, 13 Aug 2002 02:34:25 +1000 Date: Tue, 13 Aug 2002 02:39:27 +1000 (EST) From: Bruce Evans X-X-Sender: bde@gamplex.bde.org To: Maxim Konovalov Cc: "Semen A. Ustimenko" , Robert Watson , Gavin Atkinson , Subject: Re: sendfile(2) is broken (Was: ftpd problem: Input/output error) In-Reply-To: <20020812114358.E56725-100000@news1.macomnet.ru> Message-ID: <20020813021023.P25046-100000@gamplex.bde.org> MIME-Version: 1.0 Content-Type: TEXT/PLAIN; charset=US-ASCII Sender: owner-freebsd-current@FreeBSD.ORG Precedence: bulk List-ID: List-Archive: (Web Archive) List-Help: (List Instructions) List-Subscribe: List-Unsubscribe: X-Loop: FreeBSD.ORG On Mon, 12 Aug 2002, Maxim Konovalov wrote: > On 03:37+0700, Aug 12, 2002, Semen A. Ustimenko wrote: > > David reviewed the patch and I have committed it few minutes ago. > > Looks like a hack BDE is speaking about: passing a storage for residue > but never check it. See another reply about this. > Anyway I don't understand why VOP_READ in vn_rdwr() returns a residue > in uio.uio_resid when all data trasferred actually? It actually does this when only some (or none) of the data has been transferred. The idea is that most layers don't interpret the residual; they just pass it up to the caller and it hopefully makes it all the way up to a top level which actually understands nonzero residuals. From vfs_vnops.c: % if (aresid != NULL) % *aresid = auio.uio_resid; This is hopefully the usual case. We just return the residual without looking at it if we can. % else % if (auio.uio_resid != 0 && error == 0) % error = EIO; Otherwise, we turn nonzero residuals into errors since there is no other way to tell the caller that not all the data was transferred. BTW, the residual handling code for the read() and write family seems to have been broken since the beginning of history. From sys_generic.c: % if ((error = fo_read(fp, &auio, fp->f_cred, flags, td))) { % if (auio.uio_resid != cnt && (error == ERESTART || % error == EINTR || error == EWOULDBLOCK)) % error = 0; % } This is sort of the reverse of the conversion of `error' in vn_rdwr(). Some (most or all?) i/o routines return useful values in both uio_resid and `error'. This only matters if there is both an error and a nonzero residual (which is the usual case if an error occurs in the middle of a transfer). Both of these values should be passed up as far as possible, but there is no way to pass both across the kernel/userland boundary. We must choose one, and I think it is best to pass the residual (inverted to be a count) in all cases. POSIX requires this for read() and write() anyway. The above only does this conversion if the error is one of ERESTART, EINTR and EWOULDBLOCK. I think the correct code (modulo optimizations) is: error = fo_read(...); if (auio.uio_resid != cnt) error = 0; Bruce To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-current" in the body of the message