Bug#280213: exim4: Thinks it's always out of spool space
John Goerzen
John Goerzen <jgoerzen@complete.org>, 280213@bugs.debian.org
Mon, 8 Nov 2004 13:35:15 -0600
On Mon, Nov 08, 2004 at 09:25:56AM +0100, Andreas Metzler wrote:
> > So you can see there is an issue.
> [...]
> > Architecture: alpha
> > Kernel: Linux 2.6.4-rc2
> [...]
I tried this on an i386 machine and did not see a problem. So I dove
into the source and found that receive.c consistently is casting stuff
in the statvfs() structure (yes, this code uses statvfs(), NOT
statfs()).
Now, on Linux, this structure is defined as:
struct statvfs {
unsigned long f_bsize; /* file system block size */
unsigned long f_frsize; /* fragment size */
fsblkcnt_t f_blocks; /* size of fs in f_frsize units */
fsblkcnt_t f_bfree; /* # free blocks */
fsblkcnt_t f_bavail; /* # free blocks for non-root */
fsfilcnt_t f_files; /* # inodes */
fsfilcnt_t f_ffree; /* # free inodes */
fsfilcnt_t f_favail; /* # free inodes for non-root */
unsigned long f_fsid; /* file system id */
unsigned long f_flag; /* mount flags */
unsigned long f_namemax; /* maximum filename length */
};
fsblkcnt_t is a 32-bit signed value, and fsfilcnt_t is a 32-bit unsigned
value (unless large files are in use, in which case they are both 64-bit
values).
Consider this:
Type | Size i386 | Size Alpha
----------+-----------+-----------
int | 32 bits | 32 bits
long | 32 bits | 64 bits
long long | 64 bits | 64 bits
Now, in received.c, there is code such as:
if (statbuf.F_BAVAIL < (unsigned long)
((((double)check_spool_space) * 1024.0 + (double)msg_size) /
(double)statbuf.F_FRSIZE)
||
This could would break without long files enabled (32-bit value, 64-bit
unsigned long test)?
debug_printf("spool directory %s space = %d blocks; inodes = %d; "
"check_space = %dK (%d blocks); inodes = %d; msg_size = %d (%d blocks)\n",
spool_directory, (int)statbuf.F_BAVAIL, (int)statbuf.F_FAVAIL,
check_spool_space,
(int)(((double)check_spool_space * 1024.0) / (double)statbuf.F_FRSIZE),
check_spool_inodes, msg_size, (int)(msg_size / statbuf.F_FRSIZE));
Here we are casing statbuf.F_BAVAIL to an int, which could break *with*
long files enabled (converting a 64-bit value to a 32-bit one.) I
wonder if the problem is not here necessarily.
However, my theory may not be right, since no manner of changes here
made the statvfs() call actually print out the right stuff. So I'm
confused.
> Please stop exim, and run
> strace -o /tmp/straceout -vf -s 132 exim4 -d -bd 2>&1 |\
> tee /tmp/exim.debug
That never worked, but I connected manually and attached strace to the
new process with -p. Get this:
> kill the exim running as root with <Ctrl>-C and send this info:
> 1) The output of
> grep -2 -E 'stat.*/var/spool/exim4' /tmp/straceout
erwin:~# grep -2 -E 'stat.*/var/spool/exim4' /tmp/traceout
getxpid() = 18039
write(2, "18039 SMTP<< MAIL FROM:<jgoerzen"..., 60) = 60
statfs("/var/spool/exim4", {f_type="REISERFS_SUPER_MAGIC",
f_fbsize=4096, f_blocks=293066, f_bfree=55410, f_bavail=55410,
f_files=0, f_ffree=0, f_fsid={0, 0}, f_namelen=255, f_frsize=4096}) = 0
getxpid() = 18039
write(2, "18039 spool directory /var/spool"..., 145) = 145
> 2) The corresponding "spool directory /var/spool/exim4 space..."-line
> in /tmp/exim.debug
18039 spool directory /var/spool/exim4 space = 0 blocks; inodes = 4096;
check_space = 0K (0 blocks); inodes = 0; msg_size = 1005000 (245 blocks)
18039 spool directory space check failed: space=0 inodes=4096
How's that for weird?
And again, in Python (which calls statvfs too), it all worked fine.
I'm extremely puzzled.
-- John