xref: /freebsd/tools/test/stress2/misc/sendfile19.sh (revision 81ad6265)
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# "panic: Memory modified after free" seen:
31# https://people.freebsd.org/~pho/stress/log/sendfile19.txt
32# Broken by r358995-r359002
33# Fixed by r359778
34
35. ../default.cfg
36
37[ `id -u ` -ne 0 ] && echo "Must be root!" && exit 1
38[ -z "$nfs_export" ] && exit 0
39ping -c 2 `echo $nfs_export | sed 's/:.*//'` > /dev/null 2>&1 ||
40    exit 0
41
42odir=`pwd`
43cd /tmp
44sed '1,/^EOF/d' < $odir/$0 > sendfile19.c
45mycc -o sendfile19 -Wall sendfile19.c -pthread || exit 1
46rm -f sendfile19.c
47
48(cd $odir/../testcases/swap; ./swap -t 5m -i 20 -l 100) &
49sleep 5
50mount | grep "$mntpoint" | grep -q nfs && umount $mntpoint
51mount -t nfs -o tcp -o retrycnt=3 -o intr,soft -o rw $nfs_export $mntpoint
52
53cd $mntpoint
54parallel=1000
55for i in `jot $parallel`; do
56	size=`jot -r 1 1 $((2 * 1024 * 1024))`
57	dd if=/dev/zero of=input.$i bs=$size count=1 status=none
58done
59cd $odir
60while mount | grep "$mntpoint " | grep -q nfs; do
61	umount -f $mntpoint
62done
63sleep 1
64mount -t nfs -o tcp -o retrycnt=3 -o intr,soft -o rw $nfs_export $mntpoint
65spid=$!
66cd $mntpoint
67pids=
68for i in `jot $parallel`; do
69	/tmp/sendfile19 input.$i output.$i 1234$i &
70	pids="$pids $!"
71done
72for p in $pids; do
73	wait $p
74done
75for i in `jot $parallel`; do
76	rm -f input.$i output.$i
77done
78while pkill swap; do :; done
79wait $spid
80
81cd $odir
82umount $mntpoint
83while mount | grep "$mntpoint " | grep -q nfs; do
84	umount -f $mntpoint
85done
86rm -f /tmp/sendfile19
87exit 0
88EOF
89/* Slightly modified scenario from sendfile.sh */
90#include <err.h>
91#include <fcntl.h>
92#include <netdb.h>
93#include <netinet/in.h>
94#include <signal.h>
95#include <stdio.h>
96#include <stdlib.h>
97#include <string.h>
98#include <sys/param.h>
99#include <sys/socket.h>
100#include <sys/stat.h>
101#include <unistd.h>
102
103int port;
104char *inputFile;
105char *outputFile;
106int bufsize = 4096;
107
108static void
109reader(void) {
110	int tcpsock, msgsock;
111	int on;
112	socklen_t len;
113	struct sockaddr_in inetaddr, inetpeer;
114	int n, t, *buf, fd;
115
116	on = 1;
117	if ((tcpsock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
118		err(1, "socket(), %s:%d", __FILE__, __LINE__);
119
120	if (setsockopt(tcpsock,
121	    SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)) < 0)
122		err(1, "setsockopt(), %s:%d", __FILE__, __LINE__);
123
124	inetaddr.sin_family = AF_INET;
125	inetaddr.sin_addr.s_addr = INADDR_ANY;
126	inetaddr.sin_port = htons(port);
127	inetaddr.sin_len = sizeof(inetaddr);
128
129	if (bind(tcpsock,
130	    (struct sockaddr *)&inetaddr, sizeof (inetaddr)) < 0)
131		err(1, "bind(), %s:%d", __FILE__, __LINE__);
132
133	if (listen(tcpsock, 5) < 0)
134		err(1, "listen(), %s:%d", __FILE__, __LINE__);
135
136	len = sizeof(inetpeer);
137	if ((msgsock = accept(tcpsock,
138	    (struct sockaddr *)&inetpeer, &len)) < 0)
139		err(1, "accept(), %s:%d", __FILE__, __LINE__);
140
141	t = 0;
142	if ((buf = malloc(bufsize)) == NULL)
143		err(1, "malloc(%d), %s:%d", bufsize, __FILE__, __LINE__);
144
145	if ((fd = open(outputFile, O_RDWR | O_CREAT | O_TRUNC, 0640)) == -1)
146		err(1, "open(%s)", outputFile);
147
148	for (;;) {
149		if ((n = read(msgsock, buf, bufsize)) < 0)
150			err(1, "read(), %s:%d", __FILE__, __LINE__);
151		t += n;
152		if (n == 0)
153			break;
154
155		if ((write(fd, buf, n)) != n)
156			err(1, "write");
157	}
158	close(msgsock);
159	close(fd);
160	return;
161}
162
163static void
164writer(void) {
165	int tcpsock, on;
166	struct sockaddr_in inetaddr;
167	struct hostent *hostent;
168	struct stat statb;
169	int i, r, fd;
170	off_t off = 0;
171#if 1
172	size_t size;
173#endif
174
175	on = 1;
176	for (i = 1; i < 5; i++) {
177		if ((tcpsock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
178			err(1, "socket(), %s:%d", __FILE__, __LINE__);
179
180		if (setsockopt(tcpsock,
181		    SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)) < 0)
182			err(1, "setsockopt(), %s:%d", __FILE__, __LINE__);
183
184#if 1		/* livelock trigger */
185		size = getpagesize() -4;
186		if (setsockopt(tcpsock, SOL_SOCKET, SO_SNDBUF, (void *)&size,
187		    sizeof(size)) < 0)
188			err(1, "setsockopt(SO_SNDBUF), %s:%d",
189			    __FILE__, __LINE__);
190#endif
191
192		hostent = gethostbyname ("localhost");
193		memcpy (&inetaddr.sin_addr.s_addr, hostent->h_addr,
194			sizeof (struct in_addr));
195
196		inetaddr.sin_family = AF_INET;
197		inetaddr.sin_port = htons(port);
198		inetaddr.sin_len = sizeof(inetaddr);
199
200		r = connect(tcpsock, (struct sockaddr *) &inetaddr,
201			sizeof(inetaddr));
202		if (r == 0)
203			break;
204		sleep(1);
205		close(tcpsock);
206	}
207	if (r < 0)
208		err(1, "connect(), %s:%d", __FILE__, __LINE__);
209
210        if (stat(inputFile, &statb) != 0)
211                err(1, "stat(%s)", inputFile);
212
213	if ((fd = open(inputFile, O_RDONLY)) == -1)
214		err(1, "open(%s)", inputFile);
215
216	if (sendfile(fd, tcpsock, 0, statb.st_size, NULL, &off, SF_NOCACHE) == -1)
217		err(1, "sendfile");
218
219	return;
220}
221
222int
223main(int argc, char **argv)
224{
225	pid_t pid;
226
227	if (argc != 4) {
228		fprintf(stderr, "Usage: %s <inputFile outputFile portNumber\n",
229		    argv[0]);
230		return (1);
231	}
232	inputFile = argv[1];
233	outputFile = argv[2];
234	port = atoi(argv[3]);
235
236	if ((pid = fork()) == 0) {
237		writer();
238		exit(EXIT_SUCCESS);
239	} else if (pid > 0) {
240		reader();
241		kill(pid, SIGINT);
242	} else
243		err(1, "fork(), %s:%d",  __FILE__, __LINE__);
244
245	return (0);
246}
247