Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 6 Oct 2008 22:30:04 GMT
From:      Nate Eldredge <neldredge@math.ucsd.edu>
To:        freebsd-fs@FreeBSD.org
Subject:   Re: kern/127213: [tmpfs] sendfile on tmpfs data corruption
Message-ID:  <200810062230.m96MU4lE091342@freefall.freebsd.org>

next in thread | raw e-mail | index | archive | help
The following reply was made to PR kern/127213; it has been noted by GNATS.

From: Nate Eldredge <neldredge@math.ucsd.edu>
To: Maxim Konovalov <maxim@macomnet.ru>
Cc: bug-followup@freebsd.org, JH <jh275@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@math.ucsd.edu



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