xref: /freebsd/tools/test/stress2/misc/sendfile6.sh (revision 38a52bd3)
1#!/bin/sh
2
3#
4# Copyright (c) 2013 Peter Holm <pho@FreeBSD.org>
5# All rights reserved.
6#
7# Redistribution and use in source and binary forms, with or without
8# modification, are permitted provided that the following conditions
9# are met:
10# 1. Redistributions of source code must retain the above copyright
11#    notice, this list of conditions and the following disclaimer.
12# 2. Redistributions in binary form must reproduce the above copyright
13#    notice, this list of conditions and the following disclaimer in the
14#    documentation and/or other materials provided with the distribution.
15#
16# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26# SUCH DAMAGE.
27#
28
29# Test scenario by Nate Eldredge neldredge math ucsdnedu
30# kern/127213: [tmpfs] sendfile on tmpfs data corruption
31# Variation of tmpfs7.sh where UFS is used instead of tmpfs.
32
33[ `id -u ` -ne 0 ] && echo "Must be root!" && exit 1
34
35. ../default.cfg
36
37set -e
38
39odir=`pwd`
40cd /tmp
41cat > sendfile6_server.c <<EOF
42#include <stdio.h>
43#include <fcntl.h>
44#include <unistd.h>
45#include <stdlib.h>
46#include "util.h"
47
48int main(int argc, char *argv[]) {
49	int f, listener, connection;
50	if (argc < 3) {
51		fprintf(stderr, "Usage: %s filename socketname\n", argv[0]);
52		exit(1);
53	}
54	if ((f = open(argv[1], O_RDONLY)) < 0) {
55		perror(argv[1]);
56		exit(1);
57	}
58	if ((listener = listen_unix_socket(argv[2])) < 0) {
59		exit(1);
60	}
61	if ((connection = accept_unix_socket(listener)) >= 0) {
62		real_sendfile(f, connection);
63	}
64	return 0;
65}
66EOF
67cat > sendfile6_client.c <<EOF
68#include <stdio.h>
69#include <fcntl.h>
70#include <unistd.h>
71#include <stdlib.h>
72#include "util.h"
73
74int main(int argc, char *argv[]) {
75	int s;
76	if (argc < 2) {
77		fprintf(stderr, "Usage: %s socketname\n", argv[0]);
78		exit(1);
79	}
80	if ((s = connect_unix_socket(argv[1])) < 0) {
81		exit(1);
82	}
83	fake_sendfile(s, 1);
84	return 0;
85}
86EOF
87
88cat > util.c <<EOF
89/* send data from file to unix domain socket */
90
91#include <stdio.h>
92#include <time.h>
93#include <signal.h>
94#include <errno.h>
95#include <sys/types.h>
96#include <sys/socket.h>
97#include <sys/un.h>
98#include <string.h>
99#include <stdlib.h>
100#include <unistd.h>
101
102int create_unix_socket(void) {
103	int fd;
104	if ((fd = socket(PF_LOCAL, SOCK_STREAM, 0)) < 0) {
105		perror("socket");
106		return -1;
107	}
108	return fd;
109}
110
111int make_unix_sockaddr(const char *pathname, struct sockaddr_un *sa) {
112	memset(sa, 0, sizeof(*sa));
113	sa->sun_family = PF_LOCAL;
114	if (strlen(pathname) + 1 > sizeof(sa->sun_path)) {
115//		fprintf(stderr, "%s: pathname too long (max %lu)\n",
116//			pathname, sizeof(sa->sun_path));
117		errno = ENAMETOOLONG;
118		return -1;
119	}
120	strcpy(sa->sun_path, pathname);
121	return 0;
122}
123
124static char *sockname;
125void delete_socket(void) {
126	unlink(sockname);
127}
128
129int listen_unix_socket(const char *path) {
130	int fd;
131	struct sockaddr_un sa;
132	if (make_unix_sockaddr(path, &sa) < 0)
133		return -1;
134	if ((fd = create_unix_socket()) < 0)
135		return -1;
136	if (bind(fd, (struct sockaddr *)&sa, sizeof(sa)) < 0) {
137		perror("bind");
138		close(fd);
139		return -1;
140	}
141	sockname = strdup(path);
142	atexit(delete_socket);
143
144	if (listen(fd, 5) < 0) {
145		perror("listen");
146		close(fd);
147		return -1;
148	}
149	return fd;
150}
151
152int accept_unix_socket(int fd) {
153	int s;
154	if ((s = accept(fd, NULL, 0)) < 0) {
155		perror("accept");
156		return -1;
157	}
158	return s;
159}
160
161int connect_unix_socket(const char *path) {
162	int fd;
163	struct sockaddr_un sa;
164	if (make_unix_sockaddr(path, &sa) < 0)
165		return -1;
166	if ((fd = create_unix_socket()) < 0)
167		return -1;
168	if (connect(fd, (struct sockaddr *)&sa, sizeof(sa)) < 0) {
169		perror("connect");
170		return -1;
171	}
172	return fd;
173}
174
175#define BUFSIZE 65536
176
177int fake_sendfile(int from, int to) {
178	char buf[BUFSIZE];
179	int v;
180	int sent = 0;
181	while ((v = read(from, buf, BUFSIZE)) > 0) {
182		int d = 0;
183		while (d < v) {
184			int w = write(to, buf, v - d);
185			if (w <= 0) {
186				perror("write");
187				return -1;
188			}
189			d += w;
190			sent += w;
191		}
192	}
193	if (v != 0) {
194		perror("read");
195		return -1;
196	}
197	return sent;
198}
199
200int real_sendfile(int from, int to) {
201	int v;
202	v = sendfile(from, to, 0, 0, NULL, NULL, 0);
203	if (v < 0) {
204		perror("sendfile");
205	}
206	return v;
207}
208EOF
209
210cat > util.h <<EOF
211/* send data from file to unix domain socket */
212
213#include <stdio.h>
214#include <time.h>
215#include <signal.h>
216#include <errno.h>
217#include <sys/types.h>
218#include <sys/socket.h>
219#include <sys/un.h>
220
221int create_unix_socket(void);
222int make_unix_sockaddr(const char *pathname, struct sockaddr_un *sa);
223int listen_unix_socket(const char *path);
224int accept_unix_socket(int fd);
225int connect_unix_socket(const char *path);
226int fake_sendfile(int from, int to);
227int real_sendfile(int from, int to);
228EOF
229
230mycc -c -Wall -Wextra -O2 util.c
231mycc -o sendfile6_server -Wall -Wextra -O2 sendfile6_server.c util.o
232mycc -o sendfile6_client -Wall -Wextra -O2 sendfile6_client.c util.o
233rm -f sendfile6_server.c sendfile6_client.c util.c util.o util.h mysocket
234
235mount | grep "on $mntpoint " | grep -q /dev/md && umount -f $mntpoint
236mdconfig -l | grep -q md$mdstart &&  mdconfig -d -u $mdstart
237
238mdconfig -a -t swap -s 1g -u $mdstart || exit 1
239newfs $newfs_flags md$mdstart > /dev/null
240mount /dev/md$mdstart $mntpoint
241
242dd if=/dev/random of=$mntpoint/data bs=123456 count=1 status=none
243./sendfile6_server $mntpoint/data mysocket &
244sleep 0.2
245./sendfile6_client mysocket > data.$$
246wait
247cmp $mntpoint/data data.$$ ||
248	{ echo "FAIL Data mismatch"; ls -l $mntpoint/data data.$$; }
249rm -f data.$$ sendfile6_server sendfile6_client mysocket
250
251while mount | grep "on $mntpoint " | grep -q /dev/md; do
252	umount $mntpoint || sleep 1
253done
254mdconfig -d -u $mdstart
255