18a272653SPeter Holm#!/bin/sh 28a272653SPeter Holm 38a272653SPeter Holm# 48a272653SPeter Holm# Copyright (c) 2013 Peter Holm <pho@FreeBSD.org> 58a272653SPeter Holm# All rights reserved. 68a272653SPeter Holm# 78a272653SPeter Holm# Redistribution and use in source and binary forms, with or without 88a272653SPeter Holm# modification, are permitted provided that the following conditions 98a272653SPeter Holm# are met: 108a272653SPeter Holm# 1. Redistributions of source code must retain the above copyright 118a272653SPeter Holm# notice, this list of conditions and the following disclaimer. 128a272653SPeter Holm# 2. Redistributions in binary form must reproduce the above copyright 138a272653SPeter Holm# notice, this list of conditions and the following disclaimer in the 148a272653SPeter Holm# documentation and/or other materials provided with the distribution. 158a272653SPeter Holm# 168a272653SPeter Holm# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 178a272653SPeter Holm# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 188a272653SPeter Holm# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 198a272653SPeter Holm# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 208a272653SPeter Holm# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 218a272653SPeter Holm# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 228a272653SPeter Holm# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 238a272653SPeter Holm# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 248a272653SPeter Holm# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 258a272653SPeter Holm# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 268a272653SPeter Holm# SUCH DAMAGE. 278a272653SPeter Holm# 288a272653SPeter Holm 298a272653SPeter Holm# Test scenario by Nate Eldredge neldredge math ucsdnedu 308a272653SPeter Holm# kern/127213: [tmpfs] sendfile on tmpfs data corruption 318a272653SPeter Holm# Variation of tmpfs7.sh where UFS is used instead of tmpfs. 328a272653SPeter Holm 338a272653SPeter Holm[ `id -u ` -ne 0 ] && echo "Must be root!" && exit 1 348a272653SPeter Holm 358a272653SPeter Holm. ../default.cfg 368a272653SPeter Holm 378a272653SPeter Holmset -e 388a272653SPeter Holm 398a272653SPeter Holmodir=`pwd` 408a272653SPeter Holmcd /tmp 418a272653SPeter Holmcat > sendfile6_server.c <<EOF 428a272653SPeter Holm#include <stdio.h> 438a272653SPeter Holm#include <fcntl.h> 448a272653SPeter Holm#include <unistd.h> 458a272653SPeter Holm#include <stdlib.h> 468a272653SPeter Holm#include "util.h" 478a272653SPeter Holm 488a272653SPeter Holmint main(int argc, char *argv[]) { 498a272653SPeter Holm int f, listener, connection; 508a272653SPeter Holm if (argc < 3) { 518a272653SPeter Holm fprintf(stderr, "Usage: %s filename socketname\n", argv[0]); 528a272653SPeter Holm exit(1); 538a272653SPeter Holm } 548a272653SPeter Holm if ((f = open(argv[1], O_RDONLY)) < 0) { 558a272653SPeter Holm perror(argv[1]); 568a272653SPeter Holm exit(1); 578a272653SPeter Holm } 588a272653SPeter Holm if ((listener = listen_unix_socket(argv[2])) < 0) { 598a272653SPeter Holm exit(1); 608a272653SPeter Holm } 618a272653SPeter Holm if ((connection = accept_unix_socket(listener)) >= 0) { 628a272653SPeter Holm real_sendfile(f, connection); 638a272653SPeter Holm } 648a272653SPeter Holm return 0; 658a272653SPeter Holm} 668a272653SPeter HolmEOF 678a272653SPeter Holmcat > sendfile6_client.c <<EOF 688a272653SPeter Holm#include <stdio.h> 698a272653SPeter Holm#include <fcntl.h> 708a272653SPeter Holm#include <unistd.h> 718a272653SPeter Holm#include <stdlib.h> 728a272653SPeter Holm#include "util.h" 738a272653SPeter Holm 748a272653SPeter Holmint main(int argc, char *argv[]) { 758a272653SPeter Holm int s; 768a272653SPeter Holm if (argc < 2) { 778a272653SPeter Holm fprintf(stderr, "Usage: %s socketname\n", argv[0]); 788a272653SPeter Holm exit(1); 798a272653SPeter Holm } 808a272653SPeter Holm if ((s = connect_unix_socket(argv[1])) < 0) { 818a272653SPeter Holm exit(1); 828a272653SPeter Holm } 838a272653SPeter Holm fake_sendfile(s, 1); 848a272653SPeter Holm return 0; 858a272653SPeter Holm} 868a272653SPeter HolmEOF 878a272653SPeter Holm 888a272653SPeter Holmcat > util.c <<EOF 898a272653SPeter Holm/* send data from file to unix domain socket */ 908a272653SPeter Holm 918a272653SPeter Holm#include <stdio.h> 928a272653SPeter Holm#include <time.h> 938a272653SPeter Holm#include <signal.h> 948a272653SPeter Holm#include <errno.h> 958a272653SPeter Holm#include <sys/types.h> 968a272653SPeter Holm#include <sys/socket.h> 978a272653SPeter Holm#include <sys/un.h> 988a272653SPeter Holm#include <string.h> 998a272653SPeter Holm#include <stdlib.h> 1008a272653SPeter Holm#include <unistd.h> 1018a272653SPeter Holm 1028a272653SPeter Holmint create_unix_socket(void) { 1038a272653SPeter Holm int fd; 1048a272653SPeter Holm if ((fd = socket(PF_LOCAL, SOCK_STREAM, 0)) < 0) { 1058a272653SPeter Holm perror("socket"); 1068a272653SPeter Holm return -1; 1078a272653SPeter Holm } 1088a272653SPeter Holm return fd; 1098a272653SPeter Holm} 1108a272653SPeter Holm 1118a272653SPeter Holmint make_unix_sockaddr(const char *pathname, struct sockaddr_un *sa) { 1128a272653SPeter Holm memset(sa, 0, sizeof(*sa)); 1138a272653SPeter Holm sa->sun_family = PF_LOCAL; 1148a272653SPeter Holm if (strlen(pathname) + 1 > sizeof(sa->sun_path)) { 1158a272653SPeter Holm// fprintf(stderr, "%s: pathname too long (max %lu)\n", 1168a272653SPeter Holm// pathname, sizeof(sa->sun_path)); 1178a272653SPeter Holm errno = ENAMETOOLONG; 1188a272653SPeter Holm return -1; 1198a272653SPeter Holm } 1208a272653SPeter Holm strcpy(sa->sun_path, pathname); 1218a272653SPeter Holm return 0; 1228a272653SPeter Holm} 1238a272653SPeter Holm 1248a272653SPeter Holmstatic char *sockname; 1258a272653SPeter Holmvoid delete_socket(void) { 1268a272653SPeter Holm unlink(sockname); 1278a272653SPeter Holm} 1288a272653SPeter Holm 1298a272653SPeter Holmint listen_unix_socket(const char *path) { 1308a272653SPeter Holm int fd; 1318a272653SPeter Holm struct sockaddr_un sa; 1328a272653SPeter Holm if (make_unix_sockaddr(path, &sa) < 0) 1338a272653SPeter Holm return -1; 1348a272653SPeter Holm if ((fd = create_unix_socket()) < 0) 1358a272653SPeter Holm return -1; 1368a272653SPeter Holm if (bind(fd, (struct sockaddr *)&sa, sizeof(sa)) < 0) { 1378a272653SPeter Holm perror("bind"); 1388a272653SPeter Holm close(fd); 1398a272653SPeter Holm return -1; 1408a272653SPeter Holm } 1418a272653SPeter Holm sockname = strdup(path); 1428a272653SPeter Holm atexit(delete_socket); 1438a272653SPeter Holm 1448a272653SPeter Holm if (listen(fd, 5) < 0) { 1458a272653SPeter Holm perror("listen"); 1468a272653SPeter Holm close(fd); 1478a272653SPeter Holm return -1; 1488a272653SPeter Holm } 1498a272653SPeter Holm return fd; 1508a272653SPeter Holm} 1518a272653SPeter Holm 1528a272653SPeter Holmint accept_unix_socket(int fd) { 1538a272653SPeter Holm int s; 1548a272653SPeter Holm if ((s = accept(fd, NULL, 0)) < 0) { 1558a272653SPeter Holm perror("accept"); 1568a272653SPeter Holm return -1; 1578a272653SPeter Holm } 1588a272653SPeter Holm return s; 1598a272653SPeter Holm} 1608a272653SPeter Holm 1618a272653SPeter Holmint connect_unix_socket(const char *path) { 1628a272653SPeter Holm int fd; 1638a272653SPeter Holm struct sockaddr_un sa; 1648a272653SPeter Holm if (make_unix_sockaddr(path, &sa) < 0) 1658a272653SPeter Holm return -1; 1668a272653SPeter Holm if ((fd = create_unix_socket()) < 0) 1678a272653SPeter Holm return -1; 1688a272653SPeter Holm if (connect(fd, (struct sockaddr *)&sa, sizeof(sa)) < 0) { 1698a272653SPeter Holm perror("connect"); 1708a272653SPeter Holm return -1; 1718a272653SPeter Holm } 1728a272653SPeter Holm return fd; 1738a272653SPeter Holm} 1748a272653SPeter Holm 1758a272653SPeter Holm#define BUFSIZE 65536 1768a272653SPeter Holm 1778a272653SPeter Holmint fake_sendfile(int from, int to) { 1788a272653SPeter Holm char buf[BUFSIZE]; 1798a272653SPeter Holm int v; 1808a272653SPeter Holm int sent = 0; 1818a272653SPeter Holm while ((v = read(from, buf, BUFSIZE)) > 0) { 1828a272653SPeter Holm int d = 0; 1838a272653SPeter Holm while (d < v) { 1848a272653SPeter Holm int w = write(to, buf, v - d); 1858a272653SPeter Holm if (w <= 0) { 1868a272653SPeter Holm perror("write"); 1878a272653SPeter Holm return -1; 1888a272653SPeter Holm } 1898a272653SPeter Holm d += w; 1908a272653SPeter Holm sent += w; 1918a272653SPeter Holm } 1928a272653SPeter Holm } 1938a272653SPeter Holm if (v != 0) { 1948a272653SPeter Holm perror("read"); 1958a272653SPeter Holm return -1; 1968a272653SPeter Holm } 1978a272653SPeter Holm return sent; 1988a272653SPeter Holm} 1998a272653SPeter Holm 2008a272653SPeter Holmint real_sendfile(int from, int to) { 2018a272653SPeter Holm int v; 2028a272653SPeter Holm v = sendfile(from, to, 0, 0, NULL, NULL, 0); 2038a272653SPeter Holm if (v < 0) { 2048a272653SPeter Holm perror("sendfile"); 2058a272653SPeter Holm } 2068a272653SPeter Holm return v; 2078a272653SPeter Holm} 2088a272653SPeter HolmEOF 2098a272653SPeter Holm 2108a272653SPeter Holmcat > util.h <<EOF 2118a272653SPeter Holm/* send data from file to unix domain socket */ 2128a272653SPeter Holm 2138a272653SPeter Holm#include <stdio.h> 2148a272653SPeter Holm#include <time.h> 2158a272653SPeter Holm#include <signal.h> 2168a272653SPeter Holm#include <errno.h> 2178a272653SPeter Holm#include <sys/types.h> 2188a272653SPeter Holm#include <sys/socket.h> 2198a272653SPeter Holm#include <sys/un.h> 2208a272653SPeter Holm 2218a272653SPeter Holmint create_unix_socket(void); 2228a272653SPeter Holmint make_unix_sockaddr(const char *pathname, struct sockaddr_un *sa); 2238a272653SPeter Holmint listen_unix_socket(const char *path); 2248a272653SPeter Holmint accept_unix_socket(int fd); 2258a272653SPeter Holmint connect_unix_socket(const char *path); 2268a272653SPeter Holmint fake_sendfile(int from, int to); 2278a272653SPeter Holmint real_sendfile(int from, int to); 2288a272653SPeter HolmEOF 2298a272653SPeter Holm 2308a272653SPeter Holmmycc -c -Wall -Wextra -O2 util.c 2318a272653SPeter Holmmycc -o sendfile6_server -Wall -Wextra -O2 sendfile6_server.c util.o 2328a272653SPeter Holmmycc -o sendfile6_client -Wall -Wextra -O2 sendfile6_client.c util.o 2338a272653SPeter Holmrm -f sendfile6_server.c sendfile6_client.c util.c util.o util.h mysocket 2348a272653SPeter Holm 2358a272653SPeter Holmmount | grep "on $mntpoint " | grep -q /dev/md && umount -f $mntpoint 2368a272653SPeter Holmmdconfig -l | grep -q md$mdstart && mdconfig -d -u $mdstart 2378a272653SPeter Holm 2388a272653SPeter Holmmdconfig -a -t swap -s 1g -u $mdstart || exit 1 239608c97bfSPeter Holmnewfs $newfs_flags md$mdstart > /dev/null 240608c97bfSPeter Holmmount /dev/md$mdstart $mntpoint 2418a272653SPeter Holm 2428a272653SPeter Holmdd if=/dev/random of=$mntpoint/data bs=123456 count=1 status=none 2438a272653SPeter Holm./sendfile6_server $mntpoint/data mysocket & 2448a272653SPeter Holmsleep 0.2 2458a272653SPeter Holm./sendfile6_client mysocket > data.$$ 2468a272653SPeter Holmwait 2478a272653SPeter Holmcmp $mntpoint/data data.$$ || 2488a272653SPeter Holm { echo "FAIL Data mismatch"; ls -l $mntpoint/data data.$$; } 2498a272653SPeter Holmrm -f data.$$ sendfile6_server sendfile6_client mysocket 2508a272653SPeter Holm 2518a272653SPeter Holmwhile mount | grep "on $mntpoint " | grep -q /dev/md; do 2528a272653SPeter Holm umount $mntpoint || sleep 1 2538a272653SPeter Holmdone 2548a272653SPeter Holmmdconfig -d -u $mdstart 255