Timo Sirainen <tss@iki.fi> wrote:
On Sun, 2005-09-25 at 18:00 -0500, Jon Roma wrote:
Your speed amazes me. :-)
Both HAVE_WRITEV and HAVE_STRUCT_IOVEC are defined in config.h. The platform is AIX 5.1 -- forgot to mention that in my most recent post.
The compile/run of the test program yields the following results:
3243: cc -o test_writev test_writev.c 3244: ./test_writev 8 4 4
So it's a 32bit system?
The hardware is 32-bit and the machine is running the 32-bit kernel, though the same OS has a 64-bit version that runs on newer hardware, with binary compatibility for old executables.
More is at
<http://www.developer.ibm.com/isv/tech/faq/individual?oid=2:79647>
and (fluffy marketing stuff) at
<http://www-03.ibm.com/servers/aix/os/51spec.html>
The AIX man page for write/writev, etc. is at
<http://publibn.boulder.ibm.com/doc_link/en_US/a_doc_lib/libs/basetrf2/write.htm>
Now, re-reading this man page and looking through the include files gives me an idea what is happening.
Dovecot, in file src/lib/ostream-file.c, is using the UIO_MAXIOV preprocessor variable to determine how many iovec objects can be handed to the writev(2) system call.
Now, the AIX 5.1 man page says that the maximum vector count must be less than IOV_MAX, which AIX defines as 16 in <sys/limits.h> and <sys/uio.h>. And the call returns EINVAL if the vector count is zero or >= 16.
AIX does define UIO_MAXIOV in <sys/socket.h> at 1024 -- not sure what this variable is supposed to mean under AIX given the writev(2) says it uses IOV_MAX instead. Anyway since Dovecot is using this value, it's not hard to see why it's getting EINVAL errors when the underlying system only allows a vector count < 16.
For a comparison, I looked on another system (running Red Hat Enterprise Linux 3), and it gets even more murky.
The Linux man page for writev(2) says that the vector count must be between 0 and MAX_IOVEC. MAX_IOVEC is defined as 10 in <linux/sunrpc/xprt.h>, which doesn't seem a logical place for it. Anyway, on RHEL 3, UIO_MAXIOV is defined in <linux/uio.h> and <bits/uio.h> and IOV_MAX is defined in <bits/stdio_lim.h> -- and is defined as 1024 in these definitions. There's also a _POSIX_UIO_MAXIOV defined at 16 in <bits/posix1_lim.h>.
My suspicion is that the Linux man page is wrong with respect to the preprocessor variable that matters.
I have also looked at Solaris 9 system. The man page is at
<http://docs.sun.com/app/docs/doc/816-5167/6mbb2jama?a=view>
and it like AIX refers to IOV_MAX (which is defined in <limits.h>. In fact Solaris doesn't have *any* definition for UIO_MAXIOV.
So I wonder if IOV_MAX is the better or more portable way to make this work, and that some of this worked by coincidence because UIO_MAXIOV and IOV_MAX happened to be the same on Linux, which is probably the most common platform people have tested on.
Since Dovecot, in src/lib/ostream-file.c, defines UIO_MAXIOV as 16 for any system (like Solaris) which doesn't have that variable defined, this all works fine on that platform too.
Anyway, I think this all looks promising and I'll throw together a patch after dinner to see if it fixes the weirdness for me. I'll let you know how it goes later tonight.
Of course I could just manually unset HAVE_WRITEV as you suggested in your debugging hints, but I'm sure being able to use the native writev(2) would be more efficient and thus preferable.