Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 13 Aug 2002 02:39:27 +1000 (EST)
From:      Bruce Evans <bde@zeta.org.au>
To:        Maxim Konovalov <maxim@FreeBSD.ORG>
Cc:        "Semen A. Ustimenko" <semenu@FreeBSD.ORG>, Robert Watson <rwatson@FreeBSD.ORG>, Gavin Atkinson <gavin@ury.york.ac.uk>, <current@FreeBSD.ORG>
Subject:   Re: sendfile(2) is broken (Was: ftpd problem: Input/output error)
Message-ID:  <20020813021023.P25046-100000@gamplex.bde.org>
In-Reply-To: <20020812114358.E56725-100000@news1.macomnet.ru>

next in thread | previous in thread | raw e-mail | index | archive | help
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




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