[Dovecot] Misbehavior with Dovecot and Mulberry
Jon Roma
roma at uiuc.edu
Tue Sep 27 03:58:52 EEST 2005
Timo Sirainen <tss at 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.
More information about the dovecot
mailing list