From dev-return-17822-apmail-apr-dev-archive=apr.apache.org@apr.apache.org Fri Jan 05 11:20:23 2007 Return-Path: Delivered-To: apmail-apr-dev-archive@www.apache.org Received: (qmail 59964 invoked from network); 5 Jan 2007 11:20:22 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (140.211.11.2) by minotaur.apache.org with SMTP; 5 Jan 2007 11:20:22 -0000 Received: (qmail 21122 invoked by uid 500); 5 Jan 2007 11:20:27 -0000 Delivered-To: apmail-apr-dev-archive@apr.apache.org Received: (qmail 21085 invoked by uid 500); 5 Jan 2007 11:20:26 -0000 Mailing-List: contact dev-help@apr.apache.org; run by ezmlm Precedence: bulk List-Post: List-Help: List-Unsubscribe: List-Id: Delivered-To: mailing list dev@apr.apache.org Received: (qmail 21074 invoked by uid 99); 5 Jan 2007 11:20:26 -0000 Received: from herse.apache.org (HELO herse.apache.org) (140.211.11.133) by apache.org (qpsmtpd/0.29) with ESMTP; Fri, 05 Jan 2007 03:20:26 -0800 X-ASF-Spam-Status: No, hits=0.0 required=10.0 tests= X-Spam-Check-By: apache.org Received-SPF: neutral (herse.apache.org: local policy) Received: from [68.142.198.210] (HELO smtp111.sbc.mail.mud.yahoo.com) (68.142.198.210) by apache.org (qpsmtpd/0.29) with SMTP; Fri, 05 Jan 2007 03:20:14 -0800 Received: (qmail 54381 invoked from network); 5 Jan 2007 11:19:53 -0000 Received: from unknown (HELO wire.p12n.org) (ps.2@sbcglobal.net@71.158.215.15 with login) by smtp111.sbc.mail.mud.yahoo.com with SMTP; 5 Jan 2007 11:19:53 -0000 X-YMail-OSG: qOUi2bsVM1mpbFobba1av_1B0..ANocu416U_hiiyGa9enDRlcjTfJd4cBYrc4B2t4nldqIKTWsVWCeEkYL3g.CViUICV9PXHvQqdBP2WBibq74vE03DyWxFyeKQGwoGryVtclQVOn8NyPk- Received: by wire.p12n.org (Postfix, from userid 1001) id 2B1525C08E7; Fri, 5 Jan 2007 05:19:44 -0600 (CST) Date: Fri, 5 Jan 2007 05:19:44 -0600 From: Peter Samuelson To: dev@apr.apache.org Subject: [PATCH] Linux 2.4 may or may not implement sendfile64() Message-ID: <20070105111943.GA10870@p12n.org> MIME-Version: 1.0 Content-Type: multipart/signed; micalg=pgp-sha1; protocol="application/pgp-signature"; boundary="xHFwDpU9dbj6ez1V" Content-Disposition: inline User-Agent: Mutt/1.5.13 (2006-08-11) X-Virus-Checked: Checked by ClamAV on apache.org --xHFwDpU9dbj6ez1V Content-Type: text/plain; charset=us-ascii Content-Disposition: inline Content-Transfer-Encoding: quoted-printable apr incorrectly detects the sendfile64() syscall on Linux 2.4 on non-i386 architectures. The problem is that on Linux, libc is not tightly coupled to your installed kernel, so libc exposes syscalls which may or may not be implemented kernel-side, requiring runtime detection of errno=3D=3DENOSYS. I wrote this patch in response to http://bugs.debian.org/396631 - the symptom is that Apache sends empty files without realising that anything is wrong. Multiple Debian users (not me) have tested the patch, and it will be in Debian 4.0. (sendfile64 actually does exist on Linux 2.4, but unfortunately nobody bothered to add the entry points to the syscall tables on most non-i386 architectures!) Unlike the epoll case [another situation where runtime detection might be used], disabling sendfile64 where it actually is available would sacrifice real functionality: ability to use apr_socket_sendfile for large files. So I think the case for runtime detection is stronger here than for epoll. Peter --- network_io/unix/sendrecv.c +++ network_io/unix/sendrecv.c @@ -240,31 +240,77 @@ =20 #if defined(__linux__) && defined(HAVE_WRITEV) =20 +/* Helper function for apr_socket_sendfile. + * Takes care of sendfile vs. sendfile64 (must be detected at runtime), + * EINTR restarting, and other details. NOTE: does not necessarily + * update 'off', as callers don't need this. + */ +static +ssize_t do_sendfile(int out, int in, apr_off_t *off, apr_size_t len) +{ +#if !APR_HAS_LARGE_FILES + ssize_t ret; + do + ret =3D sendfile(out, in, off, len); + while (ret =3D=3D -1 && errno =3D=3D EINTR); + return ret; +#else + +#ifdef HAVE_SENDFILE64 + static int sendfile64_enosys; /* sendfile64() syscall not found */ +#endif + off_t offtmp; + ssize_t ret; + + /* Multiple reports have shown sendfile failing with EINVAL if + * passed a >=3D2Gb count value on some 64-bit kernels. It won't + * noticably hurt performance to limit each call to <2Gb at a time, + * so avoid that issue here. (Round down to a common page size.) */ + if (sizeof(off_t) =3D=3D 8 && len > INT_MAX) + len =3D INT_MAX - 8191; + + /* The simple and common case: we don't cross the LFS barrier */ + if (sizeof(off_t) =3D=3D 8 || (apr_int64_t)*off + len <=3D INT_MAX) { + offtmp =3D *off; + do + ret =3D sendfile(out, in, &offtmp, len); + while (ret =3D=3D -1 && errno =3D=3D EINTR); + return ret; + } + + /* From here down we know it's a 32-bit runtime */ +#ifdef HAVE_SENDFILE64 + if (!sendfile64_enosys) { + do + ret =3D sendfile64(out, in, off, len); + while (ret =3D=3D -1 && errno =3D=3D EINTR); + + if (ret !=3D -1 || errno !=3D ENOSYS) + return ret; + + sendfile64_enosys =3D 1; + } +#endif + if (*off > INT_MAX) { + errno =3D EINVAL; + return -1; + } + offtmp =3D *off; + do + ret =3D sendfile(out, in, &offtmp, len); + while (ret =3D=3D -1 && errno =3D=3D EINTR); + return ret; +#endif /* APR_HAS_LARGE_FILES */ +} + + apr_status_t apr_socket_sendfile(apr_socket_t *sock, apr_file_t *file, apr_hdtr_t *hdtr, apr_off_t *offset, apr_size_t *len, apr_int32_t flags) { int rv, nbytes =3D 0, total_hdrbytes, i; apr_status_t arv; - -#if APR_HAS_LARGE_FILES && defined(HAVE_SENDFILE64) apr_off_t off =3D *offset; -#define sendfile sendfile64 - -#elif APR_HAS_LARGE_FILES && SIZEOF_OFF_T =3D=3D 4 - /* 64-bit apr_off_t but no sendfile64(): fail if trying to send - * past the 2Gb limit. */ - off_t off; - =20 - if ((apr_int64_t)*offset + *len > INT_MAX) { - return EINVAL; - } - =20 - off =3D *offset; - -#else - off_t off =3D *offset; -#endif =20 if (!hdtr) { hdtr =3D &no_hdtr; @@ -310,12 +356,10 @@ goto do_select; } =20 - do { - rv =3D sendfile(sock->socketdes, /* socket */ + rv =3D do_sendfile(sock->socketdes, /* socket */ file->filedes, /* open file descriptor of the file t= o be sent */ &off, /* where in the file to start */ *len); /* number of bytes to send */ - } while (rv =3D=3D -1 && errno =3D=3D EINTR); =20 while ((rv =3D=3D -1) && (errno =3D=3D EAGAIN || errno =3D=3D EWOULDBL= OCK)=20 && (sock->timeout > 0)) { @@ -326,12 +370,10 @@ return arv; } else { - do { - rv =3D sendfile(sock->socketdes, /* socket */ + rv =3D do_sendfile(sock->socketdes, /* socket */ file->filedes, /* open file descriptor of th= e file to be sent */ &off, /* where in the file to start */ *len); /* number of bytes to send */ - } while (rv =3D=3D -1 && errno =3D=3D EINTR); } } =20 --xHFwDpU9dbj6ez1V Content-Type: application/pgp-signature; name="signature.asc" Content-Description: Digital signature Content-Disposition: inline -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.6 (GNU/Linux) iD8DBQFFnjRPXk7sIRPQRh0RAm0uAJ4/uFOI0SW3MCU4WIWgXwdmZW6z3QCgmKp9 YVrESOY1s0wj1nK8jznNJqs= =c+E4 -----END PGP SIGNATURE----- --xHFwDpU9dbj6ez1V--