xref: /freebsd/tools/test/stress2/misc/sendfile25.sh (revision 397e83df75e0fcd0d3fcb95ae4d794cb7600fc89)
1#!/bin/sh
2
3#
4# SPDX-License-Identifier: BSD-2-Clause
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, *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	if ((buf = malloc(bufsize)) == NULL)
136		err(1, "malloc(%d), %s:%d", bufsize, __FILE__, __LINE__);
137
138	if ((fd = open(outputFile, O_RDWR | O_CREAT | O_TRUNC, 0640)) == -1)
139		err(1, "open(%s)", outputFile);
140
141	for (;;) {
142		if ((n = read(msgsock, buf, bufsize)) < 0)
143			err(1, "read(), %s:%d", __FILE__, __LINE__);
144		if (n == 0)
145			break;
146
147		if ((write(fd, buf, n)) != n)
148			err(1, "write");
149	}
150	close(msgsock);
151	close(fd);
152	return;
153}
154
155static void
156writer(void) {
157	int tcpsock, on;
158	struct sockaddr_in inetaddr;
159	struct hostent *hostent;
160	struct stat statb;
161	off_t off = 0;
162	size_t size;
163	int i, r, fd;
164
165	on = 1;
166	for (i = 1; i < 5; i++) {
167		if ((tcpsock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
168			err(1, "socket(), %s:%d", __FILE__, __LINE__);
169
170		if (setsockopt(tcpsock,
171		    SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)) < 0)
172			err(1, "setsockopt(), %s:%d", __FILE__, __LINE__);
173
174		size = getpagesize() -4;
175		if (setsockopt(tcpsock, SOL_SOCKET, SO_SNDBUF, (void *)&size,
176		    sizeof(size)) < 0)
177			err(1, "setsockopt(SO_SNDBUF), %s:%d",
178			    __FILE__, __LINE__);
179
180		hostent = gethostbyname ("localhost");
181		memcpy (&inetaddr.sin_addr.s_addr, hostent->h_addr,
182			sizeof (struct in_addr));
183
184		inetaddr.sin_family = AF_INET;
185		inetaddr.sin_port = htons(port);
186		inetaddr.sin_len = sizeof(inetaddr);
187
188		r = connect(tcpsock, (struct sockaddr *) &inetaddr,
189			sizeof(inetaddr));
190		if (r == 0)
191			break;
192		sleep(1);
193		close(tcpsock);
194	}
195	if (r < 0)
196		err(1, "connect(), %s:%d", __FILE__, __LINE__);
197
198        if (stat(inputFile, &statb) != 0)
199                err(1, "stat(%s)", inputFile);
200
201	if ((fd = open(inputFile, O_RDONLY)) == -1)
202		err(1, "open(%s)", inputFile);
203
204	off = 12 * 32 * 1024;
205	if (sendfile(fd, tcpsock, 0, statb.st_size, NULL, &off, 0) == -1)
206		err(1, "sendfile");
207
208	return;
209}
210
211int
212main(int argc, char **argv)
213{
214	pid_t pid;
215
216	if (argc != 4) {
217		fprintf(stderr, "Usage: %s <inputFile outputFile portNumber\n",
218		    argv[0]);
219		return (1);
220	}
221	inputFile = argv[1];
222	outputFile = argv[2];
223	port = atoi(argv[3]);
224
225	if ((pid = fork()) == 0) {
226		writer();
227		exit(EXIT_SUCCESS);
228	} else if (pid > 0) {
229		reader();
230		kill(pid, SIGINT);
231	} else
232		err(1, "fork(), %s:%d",  __FILE__, __LINE__);
233
234	return (0);
235}
236