kern/127213: [tmpfs] sendfile on tmpfs data corruption
Nate Eldredge
neldredge at math.ucsd.edu
Mon Oct 6 22:30:04 UTC 2008
The following reply was made to PR kern/127213; it has been noted by GNATS.
From: Nate Eldredge <neldredge at math.ucsd.edu>
To: Maxim Konovalov <maxim at macomnet.ru>
Cc: bug-followup at freebsd.org, JH <jh275 at s6.sector6.net>
Subject: Re: kern/127213: [tmpfs] sendfile on tmpfs data corruption
Date: Mon, 6 Oct 2008 15:22:57 -0700 (PDT)
On Mon, 6 Oct 2008, Maxim Konovalov wrote:
> Hello,
>
> On Mon, 6 Oct 2008, 06:40-0000, Nate Eldredge wrote:
>
> [...]
>> Incidentally, to the initial reporter, what application do you have
>> that requires sendfile? In my experience, most things will fall
>> back to a read/write loop if sendfile fails, since sendfile isn't
>> available on all systems or under all circumstances. So if you
>> apply the quick fix so that sendfile always fails, it might at
>> least get your application working again.
>>
> As stated in the PR Andrey used nginx (ports/www/nginx). But I could
> easily reproduce the bug with the stock ftpd(8) with the ftproot on
> tmpfs.
To simplify matters further, here is the testcase I used when testing
this, which uses sendfile to send some data over a unix domain socket.
Do:
./server /tmpfs/data mysocket &
./client mysocket >data.out
cmp /tmpfs/data data.out
If things work right, data and data.out should be identical. But if data
is a file on a tmpfs, data.out contains apparently random kernel memory
contents.
# This is a shell archive. Save it in a file, remove anything before
# this line, and then unpack it by entering "sh file". Note, it may
# create directories; files and directories will be owned by you and
# have default permissions.
#
# This archive contains:
#
# Makefile
# client.c
# server.c
# util.c
# util.h
#
echo x - Makefile
sed 's/^X//' >Makefile << 'END-of-Makefile'
XCC = gcc
XCFLAGS = -Wall -W -g
X
Xall : server client
X
Xserver : server.o util.o
X $(CC) -o $@ $>
X
Xclient : client.o util.o
X $(CC) -o $@ $>
X
Xserver.o client.o util.o : util.h
X
Xclean :
X rm -f server client *.o
END-of-Makefile
echo x - client.c
sed 's/^X//' >client.c << 'END-of-client.c'
X#include <stdio.h>
X#include <fcntl.h>
X#include <unistd.h>
X#include <stdlib.h>
X#include "util.h"
X
Xint main(int argc, char *argv[]) {
X int s;
X if (argc < 2) {
X fprintf(stderr, "Usage: %s socketname\n", argv[0]);
X exit(1);
X }
X if ((s = connect_unix_socket(argv[1])) < 0) {
X exit(1);
X }
X fake_sendfile(s, 1);
X return 0;
X}
X
X
X
END-of-client.c
echo x - server.c
sed 's/^X//' >server.c << 'END-of-server.c'
X#include <stdio.h>
X#include <fcntl.h>
X#include <unistd.h>
X#include <stdlib.h>
X#include "util.h"
X
Xint main(int argc, char *argv[]) {
X int f, listener, connection;
X if (argc < 3) {
X fprintf(stderr, "Usage: %s filename socketname\n", argv[0]);
X exit(1);
X }
X if ((f = open(argv[1], O_RDONLY)) < 0) {
X perror(argv[1]);
X exit(1);
X }
X if ((listener = listen_unix_socket(argv[2])) < 0) {
X exit(1);
X }
X if ((connection = accept_unix_socket(listener)) >= 0) {
X real_sendfile(f, connection);
X }
X return 0;
X}
X
X
X
END-of-server.c
echo x - util.c
sed 's/^X//' >util.c << 'END-of-util.c'
X/* send data from file to unix domain socket */
X
X#include <stdio.h>
X#include <time.h>
X#include <signal.h>
X#include <errno.h>
X#include <sys/types.h>
X#include <sys/socket.h>
X#include <sys/un.h>
X#include <string.h>
X#include <stdlib.h>
X#include <unistd.h>
X
Xint create_unix_socket(void) {
X int fd;
X if ((fd = socket(PF_LOCAL, SOCK_STREAM, 0)) < 0) {
X perror("socket");
X return -1;
X }
X return fd;
X}
X
Xint make_unix_sockaddr(const char *pathname, struct sockaddr_un *sa) {
X memset(sa, 0, sizeof(*sa));
X sa->sun_family = PF_LOCAL;
X if (strlen(pathname) + 1 > sizeof(sa->sun_path)) {
X fprintf(stderr, "%s: pathname too long (max %lu)\n",
X pathname, sizeof(sa->sun_path));
X errno = ENAMETOOLONG;
X return -1;
X }
X strcpy(sa->sun_path, pathname);
X return 0;
X}
X
Xstatic char *sockname;
Xvoid delete_socket(void) {
X unlink(sockname);
X}
X
Xint listen_unix_socket(const char *path) {
X int fd;
X struct sockaddr_un sa;
X if (make_unix_sockaddr(path, &sa) < 0)
X return -1;
X if ((fd = create_unix_socket()) < 0)
X return -1;
X if (bind(fd, (struct sockaddr *)&sa, sizeof(sa)) < 0) {
X perror("bind");
X close(fd);
X return -1;
X }
X sockname = strdup(path);
X atexit(delete_socket);
X
X if (listen(fd, 5) < 0) {
X perror("listen");
X close(fd);
X return -1;
X }
X return fd;
X}
X
Xint accept_unix_socket(int fd) {
X int s;
X if ((s = accept(fd, NULL, 0)) < 0) {
X perror("accept");
X return -1;
X }
X return s;
X}
X
Xint connect_unix_socket(const char *path) {
X int fd;
X struct sockaddr_un sa;
X if (make_unix_sockaddr(path, &sa) < 0)
X return -1;
X if ((fd = create_unix_socket()) < 0)
X return -1;
X if (connect(fd, (struct sockaddr *)&sa, sizeof(sa)) < 0) {
X perror("connect");
X return -1;
X }
X return fd;
X}
X
X#define BUFSIZE 65536
X
Xint fake_sendfile(int from, int to) {
X char buf[BUFSIZE];
X int v;
X int sent = 0;
X while ((v = read(from, buf, BUFSIZE)) > 0) {
X int d = 0;
X while (d < v) {
X int w = write(to, buf, v - d);
X if (w <= 0) {
X perror("write");
X return -1;
X }
X d += w;
X sent += w;
X }
X }
X if (v != 0) {
X perror("read");
X return -1;
X }
X return sent;
X}
X
Xint real_sendfile(int from, int to) {
X int v;
X v = sendfile(from, to, 0, 0, NULL, NULL, 0);
X if (v < 0) {
X perror("sendfile");
X }
X return v;
X}
X
X
END-of-util.c
echo x - util.h
sed 's/^X//' >util.h << 'END-of-util.h'
X/* send data from file to unix domain socket */
X
X#include <stdio.h>
X#include <time.h>
X#include <signal.h>
X#include <errno.h>
X#include <sys/types.h>
X#include <sys/socket.h>
X#include <sys/un.h>
X
Xint create_unix_socket(void);
Xint make_unix_sockaddr(const char *pathname, struct sockaddr_un *sa);
Xint listen_unix_socket(const char *path);
Xint accept_unix_socket(int fd);
Xint connect_unix_socket(const char *path);
Xint fake_sendfile(int from, int to);
Xint real_sendfile(int from, int to);
X
X
END-of-util.h
exit
--
Nate Eldredge
neldredge at math.ucsd.edu
More information about the freebsd-fs
mailing list