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>