xref: /freebsd/tools/test/stress2/misc/sendfile25.sh (revision dc318a4ffabcbfa23bb56a33403aad36e6de30af)
1#!/bin/sh
2
3#
4# SPDX-License-Identifier: BSD-2-Clause-FreeBSD
5#
6# Copyright (c) 2020 Peter Holm <pho@FreeBSD.org>
7#
8# Redistribution and use in source and binary forms, with or without
9# modification, are permitted provided that the following conditions
10# are met:
11# 1. Redistributions of source code must retain the above copyright
12#    notice, this list of conditions and the following disclaimer.
13# 2. Redistributions in binary form must reproduce the above copyright
14#    notice, this list of conditions and the following disclaimer in the
15#    documentation and/or other materials provided with the distribution.
16#
17# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27# SUCH DAMAGE.
28#
29
30# sendfile(2) test with disk read errors
31# "panic: vm_page_readahead_finish: 0xfffffe000d88d758 is invalid" seen:
32# https://people.freebsd.org/~pho/stress/log/sendfile25.txt
33
34# Test scenario suggestion by chs@
35# Fixed by
36
37[ `id -u` -ne 0 ] && echo "Must be root!" && exit 1
38kldstat | grep -q geom_nop || { gnop load 2>/dev/null || exit 0 &&
39    notloaded=1; }
40gnop status || exit 1
41
42. ../default.cfg
43
44dir=/tmp
45odir=`pwd`
46cd $dir
47sed '1,/^EOF/d' < $odir/$0 > $dir/sendfile25.c
48mycc -o sendfile25 -Wall -Wextra -O0 -g sendfile25.c || exit 1
49cd $odir
50
51set -e
52mount | grep $mntpoint | grep -q /dev/md && umount -f $mntpoint
53[ -c /dev/md$mdstart ] &&  mdconfig -d -u $mdstart
54
55mdconfig -a -t swap -s 2g -u $mdstart
56gnop create /dev/md$mdstart
57newfs $newfs_flags -n -b $((32 * 1024)) /dev/md$mdstart.nop > /dev/null
58mount /dev/md$mdstart.nop $mntpoint
59chmod 777 $mntpoint
60set +e
61
62dd if=/dev/zero of=$mntpoint/file bs=416k count=1 status=none
63start=`date +%s`
64echo 'Expect:
65    sendfile25: sendfile: sendfile25: read(), sendfile25.c:61: Broken pipe
66    Connection reset by peer'
67while [ $((`date +%s` - start)) -lt 10 ]; do
68	umount $mntpoint
69	mount /dev/md$mdstart.nop $mntpoint
70	ls -l $mntpoint > /dev/null
71	gnop configure -e 5 -r 1 /dev/md$mdstart.nop
72	/tmp/sendfile25 $mntpoint/file /dev/null 12345
73	gnop configure -e 5 -r 0 /dev/md$mdstart.nop
74done
75umount $mntpoint
76
77gnop destroy /dev/md$mdstart.nop
78mdconfig -d -u $mdstart
79[ $notloaded ] && gnop unload
80rm -f /tmp/sendfile25 /tmp/sendfile25.c
81
82exit 0
83EOF
84#include <sys/param.h>
85#include <sys/socket.h>
86#include <sys/stat.h>
87#include <err.h>
88#include <fcntl.h>
89#include <netdb.h>
90#include <netinet/in.h>
91#include <signal.h>
92#include <stdio.h>
93#include <stdlib.h>
94#include <string.h>
95#include <unistd.h>
96
97int port;
98char *inputFile;
99char *outputFile;
100int bufsize = 4096;
101
102static void
103reader(void) {
104	int tcpsock, msgsock;
105	int on;
106	socklen_t len;
107	struct sockaddr_in inetaddr, inetpeer;
108	int n, t, *buf, fd;
109
110	on = 1;
111	if ((tcpsock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
112		err(1, "socket(), %s:%d", __FILE__, __LINE__);
113
114	if (setsockopt(tcpsock,
115	    SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)) < 0)
116		err(1, "setsockopt(), %s:%d", __FILE__, __LINE__);
117
118	inetaddr.sin_family = AF_INET;
119	inetaddr.sin_addr.s_addr = INADDR_ANY;
120	inetaddr.sin_port = htons(port);
121	inetaddr.sin_len = sizeof(inetaddr);
122
123	if (bind(tcpsock,
124	    (struct sockaddr *)&inetaddr, sizeof (inetaddr)) < 0)
125		err(1, "bind(), %s:%d", __FILE__, __LINE__);
126
127	if (listen(tcpsock, 5) < 0)
128		err(1, "listen(), %s:%d", __FILE__, __LINE__);
129
130	len = sizeof(inetpeer);
131	if ((msgsock = accept(tcpsock,
132	    (struct sockaddr *)&inetpeer, &len)) < 0)
133		err(1, "accept(), %s:%d", __FILE__, __LINE__);
134
135	t = 0;
136	if ((buf = malloc(bufsize)) == NULL)
137		err(1, "malloc(%d), %s:%d", bufsize, __FILE__, __LINE__);
138
139	if ((fd = open(outputFile, O_RDWR | O_CREAT | O_TRUNC, 0640)) == -1)
140		err(1, "open(%s)", outputFile);
141
142	for (;;) {
143		if ((n = read(msgsock, buf, bufsize)) < 0)
144			err(1, "read(), %s:%d", __FILE__, __LINE__);
145		t += n;
146		if (n == 0)
147			break;
148
149		if ((write(fd, buf, n)) != n)
150			err(1, "write");
151	}
152	close(msgsock);
153	close(fd);
154	return;
155}
156
157static void
158writer(void) {
159	int tcpsock, on;
160	struct sockaddr_in inetaddr;
161	struct hostent *hostent;
162	struct stat statb;
163	off_t off = 0;
164	size_t size;
165	int i, r, fd;
166
167	on = 1;
168	for (i = 1; i < 5; i++) {
169		if ((tcpsock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
170			err(1, "socket(), %s:%d", __FILE__, __LINE__);
171
172		if (setsockopt(tcpsock,
173		    SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)) < 0)
174			err(1, "setsockopt(), %s:%d", __FILE__, __LINE__);
175
176		size = getpagesize() -4;
177		if (setsockopt(tcpsock, SOL_SOCKET, SO_SNDBUF, (void *)&size,
178		    sizeof(size)) < 0)
179			err(1, "setsockopt(SO_SNDBUF), %s:%d",
180			    __FILE__, __LINE__);
181
182		hostent = gethostbyname ("localhost");
183		memcpy (&inetaddr.sin_addr.s_addr, hostent->h_addr,
184			sizeof (struct in_addr));
185
186		inetaddr.sin_family = AF_INET;
187		inetaddr.sin_port = htons(port);
188		inetaddr.sin_len = sizeof(inetaddr);
189
190		r = connect(tcpsock, (struct sockaddr *) &inetaddr,
191			sizeof(inetaddr));
192		if (r == 0)
193			break;
194		sleep(1);
195		close(tcpsock);
196	}
197	if (r < 0)
198		err(1, "connect(), %s:%d", __FILE__, __LINE__);
199
200        if (stat(inputFile, &statb) != 0)
201                err(1, "stat(%s)", inputFile);
202
203	if ((fd = open(inputFile, O_RDONLY)) == -1)
204		err(1, "open(%s)", inputFile);
205
206	off = 12 * 32 * 1024;
207	if (sendfile(fd, tcpsock, 0, statb.st_size, NULL, &off, 0) == -1)
208		err(1, "sendfile");
209
210	return;
211}
212
213int
214main(int argc, char **argv)
215{
216	pid_t pid;
217
218	if (argc != 4) {
219		fprintf(stderr, "Usage: %s <inputFile outputFile portNumber\n",
220		    argv[0]);
221		return (1);
222	}
223	inputFile = argv[1];
224	outputFile = argv[2];
225	port = atoi(argv[3]);
226
227	if ((pid = fork()) == 0) {
228		writer();
229		exit(EXIT_SUCCESS);
230	} else if (pid > 0) {
231		reader();
232		kill(pid, SIGINT);
233	} else
234		err(1, "fork(), %s:%d",  __FILE__, __LINE__);
235
236	return (0);
237}
238