Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 7 Jul 2010 10:24:41 -0700
From:      "Ming Fu" <Ming.Fu@watchguard.com>
To:        <freebsd-net@freebsd.org>
Subject:   kern/123095 kern/131602 sendfile
Message-ID:  <7C3D15DD6E8F464998CA1470D8A322F302BB9F72@ES02CO.wgti.net>

next in thread | raw e-mail | index | archive | help
Hi,


I was trying to use sendfile and hit with problem very similar to the
123095 and 131602.=20
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]=3D"\r\n800\r\n";
        char *p =3D str;
        struct stat sb;
        int n;
        fd_set wset;
        int64_t size;
        off_t sbytes;
        off_t sent =3D 0;
        int chunk;

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

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

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

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

$ cc -o co corrupt.c
$./co
$ md5 large=20
MD5 (large) =3D 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






Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?7C3D15DD6E8F464998CA1470D8A322F302BB9F72>