kern/123095 kern/131602 sendfile

Ming Fu Ming.Fu at watchguard.com
Wed Jul 7 17:48:30 UTC 2010


Hi,


I was trying to use sendfile and hit with problem very similar to the
123095 and 131602. 
It seems that when the file is large enough (in megs), the file can be
corrupted even if it is open read-only and exist on disk as read-only
file, though the filesystem is mounted read-write.

I have a small program to reliably reproduce the problem.

---------- corrupt.c -----------------

#include <sys/types.h>
#include <sys/socket.h>
#include <sys/uio.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <sys/select.h>
#include <sys/stat.h>
#include <strings.h>
#include <stdio.h>
#include <err.h>
main () {
        int s, f;
        struct sockaddr_in addr;
        int flags;
        char str[32]="\r\n800\r\n";
        char *p = str;
        struct stat sb;
        int n;
        fd_set wset;
        int64_t size;
        off_t sbytes;
        off_t sent = 0;
        int chunk;

        s = socket(AF_INET, SOCK_STREAM, 0);
        bzero(&addr, sizeof(addr));
        addr.sin_family = AF_INET;
        addr.sin_port = htons(7000);
        addr.sin_addr.s_addr = inet_addr("10.1.19.16");

        n = connect(s, (struct sockaddr *)&addr, sizeof (addr));
        if (n < 0)
                warn ("fail to connect");
        flags = fcntl(s, F_GETFL);
        flags |= O_NONBLOCK;
        fcntl(s, F_SETFL);

        f = open("large", O_RDONLY);
        if (f<0)
                warn("fail to open file");
        n = fstat(f, &sb);
        if (n<0)
                warn("fstat failed");

        size = sb.st_size;
        chunk = 0;
        while (size > 0) {
                FD_ZERO(&wset);
                FD_SET(s, &wset);
                n = select(f+1, NULL, &wset, NULL, NULL);
                if (n < 0)
                        continue;
                if (chunk > 0) {
                        sbytes = 0;
                        n = sendfile(f, s, sent, chunk, NULL, &sbytes,
0);
                        if (n < 0)
                                continue;
                        chunk -= sbytes;
                        size -= sbytes;
                        sent += sbytes;
                        continue;
                }
                if (size > 2048)
                        chunk = 2048;
                else
                        chunk = size;
                n = sprintf(str, "\r\n%x\r\n", 2048);
                p = str;
                write(s, p, n);
        }
}

------------- end ---------------------------------------------

Run nc to receive the sendfile
$ nc -l 7000

Copy a large from for sendfile to send
$ cp /usr/lib/libc_pic.a large

$ md5 large
MD5 (large) = 252def82f9d75df11df7123e9fd376f6

$ cc -o co corrupt.c
$./co
$ md5 large 
MD5 (large) = 81ee84e55f4611434459f637c83b892e

I run this on 8.0-RELEASE. The same happens on 7.2 and 6.3. The disk are
SATA ide. I run all these command under unprivileged user account. I
also run the same program on several different hardware, the result is
the same. Although the corrupted file is not the same. The corruption
looks random to me.

I know a bit of the network side of FreeBSD kernel code, but the I have
no idea how the filesystem side work. I can dig a bit further if someone
give me a hint as where to look.

Best Regards,

Ming





More information about the freebsd-net mailing list