xref: /freebsd/tools/test/stress2/misc/sendfile22.sh (revision 994297b01b98816bea1abf45ae4bac1bc69ee7a0)
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# Variation of sendfile21.sh: without the use of socketpair().
31# No problems seen.
32
33. ../default.cfg
34[ `id -u` -ne 0 ] && echo "Must be root!" && exit 1
35
36dir=/tmp
37odir=`pwd`
38cd $dir
39sed '1,/^EOF/d' < $odir/$0 > $dir/sendfile22.c
40mycc -o sendfile22 -Wall -Wextra -O0 -g sendfile22.c || exit 1
41rm -f sendfile22.c
42cd $odir
43
44set -e
45mount | grep "on $mntpoint " | grep -q /dev/md && umount -f $mntpoint
46[ -c /dev/md$mdstart ] &&  mdconfig -d -u $mdstart
47mdconfig -a -t swap -s 1g -u $mdstart
48bsdlabel -w md$mdstart auto
49newfs_flags=""
50newfs $newfs_flags -n md$mdstart > /dev/null
51mount /dev/md$mdstart $mntpoint
52set +e
53
54cd $mntpoint
55dd if=/dev/random of=input bs=4k count=100 status=none
56
57(cd $odir/../testcases/swap; ./swap -t 5m -i 20 -l 100 > /dev/null) &
58sleep 30
59n=1
60start=` date +%s`
61while [ $((` date +%s` - start)) -lt 180 ]; do
62	rm -f output
63	umount $mntpoint 2>/dev/null # busy umount
64	$dir/sendfile22
65	s=$?
66	[ $s -ne 0 ] &&
67	    pkill sendfile22
68	cmp -s input output || break
69	[ `stat -f '%z' input` -ne ` stat -f '%z' output` ] && break
70	n=$((n + 1))
71done
72while pgrep -q swap; do
73	pkill swap
74done
75cmp -s input output || { echo "Loop #$n"; ls -l; s=1; }
76wait
77[ -f sendfile22.core -a $s -eq 0 ] &&
78    { ls -l sendfile22.core; mv sendfile22.core $dir; s=1; }
79cd $odir
80
81for i in `jot 18`; do
82	mount | grep -q "on $mntpoint " || break
83	umount $mntpoint && break || sleep 10
84	[ $i -eq 18 ] &&
85	    { echo FATAL; fstat -mf $mntpoint; exit 1; }
86done
87mdconfig -d -u $mdstart
88rm -rf $dir/sendfile22
89exit $s
90
91EOF
92#include <sys/param.h>
93#include <sys/fcntl.h>
94#include <sys/mman.h>
95#include <sys/socket.h>
96#include <sys/stat.h>
97#include <sys/uio.h>
98#include <sys/wait.h>
99
100#include <netinet/in.h>
101
102#include <err.h>
103#include <errno.h>
104#include <fcntl.h>
105#include <netdb.h>
106#include <stdio.h>
107#include <stdlib.h>
108#include <string.h>
109#include <strings.h>
110#include <unistd.h>
111
112static void
113test(void)
114{
115	struct stat st;
116	struct sockaddr_in inetaddr, inetpeer;
117	struct hostent *hostent;
118	socklen_t len;
119	off_t i, j, rd, written, pos;
120	pid_t pid;
121	int error, from, i1, msgsock, n, on, port, r, status, tcpsock, to;
122	char buf[4086], *cp;
123	const char *from_name, *to_name;
124
125	from_name = "input";
126	to_name = "output";
127	port = 12345;
128
129	if ((from = open(from_name, O_RDONLY)) == -1)
130		err(1, "open read %s", from_name);
131
132	if ((error = fstat(from, &st)) == -1)
133		err(1, "stat %s", from_name);
134
135	pid = fork();
136	if (pid == -1)
137		err(1, "fork");
138	else if (pid != 0) {
139		setproctitle("parent");
140
141		alarm(300);
142		on = 1;
143		for (i1 = 1; i1 < 5; i1++) {
144			if ((tcpsock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
145				err(1, "socket(), %s:%d", __FILE__, __LINE__);
146
147			if (setsockopt(tcpsock,
148			    SOL_SOCKET, SO_REUSEADDR, (char *)&on,
149			    sizeof(on)) < 0)
150				err(1, "setsockopt(), %s:%d", __FILE__,
151						__LINE__);
152
153			hostent = gethostbyname ("localhost");
154			bzero((char *) &inetaddr, sizeof(inetaddr));
155			memcpy (&inetaddr.sin_addr.s_addr, hostent->h_addr,
156				sizeof (struct in_addr));
157
158			inetaddr.sin_family = AF_INET;
159			inetaddr.sin_port = htons(port);
160			inetaddr.sin_len = sizeof(inetaddr);
161
162			r = connect(tcpsock, (struct sockaddr *) &inetaddr,
163				sizeof(inetaddr));
164			if (r == 0)
165				break;
166			sleep(1);
167			close(tcpsock);
168		}
169		if (r < 0)
170			err(1, "connect(), %s:%d", __FILE__, __LINE__);
171
172		if ((cp = mmap(NULL, st.st_size, PROT_READ,
173		    MAP_PRIVATE, from, 0)) == MAP_FAILED)
174			err(1, "mmap");
175		if (fsync(from) == -1)
176			err(1, "fsync()");
177
178		for (i = 0, j = 0; i < st.st_size; i += PAGE_SIZE, j++) {
179			(void)cp[i];
180			if (j % 2 == 1) {
181				if (msync(cp + i, PAGE_SIZE, MS_INVALIDATE)
182				    == -1)
183					err(1, "msync(), j = %d", (int)j);
184			}
185		}
186		if (munmap(cp, st.st_size) == -1)
187			err(1, "munmap()");
188
189		pos = 0;
190		for (;;) {
191			error = sendfile(from, tcpsock, pos, st.st_size -
192			    pos, NULL, &written, 0);
193			if (error == -1)
194				err(1, "sendfile");
195			if (written != st.st_size)
196				fprintf(stderr, "sendfile sent %d bytes\n",
197				    (int)written);
198			pos += written;
199			if (pos == st.st_size)
200				break;
201		}
202		if (pos != st.st_size)
203			fprintf(stderr, "%d written, expected %d\n",
204			    (int)pos, (int)st.st_size);
205		close(tcpsock);
206		if (waitpid(pid, &status, 0) != pid)
207			err(1, "waitpid(%d)", pid);
208	} else {
209		setproctitle("child");
210		close(from);
211		alarm(300);
212		on = 1;
213		if ((tcpsock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
214			err(1, "socket(), %s:%d", __FILE__, __LINE__);
215
216		if (setsockopt(tcpsock,
217		    SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)) < 0)
218			err(1, "setsockopt(), %s:%d", __FILE__, __LINE__);
219
220		inetaddr.sin_family = AF_INET;
221		inetaddr.sin_addr.s_addr = INADDR_ANY;
222		inetaddr.sin_port = htons(port);
223		inetaddr.sin_len = sizeof(inetaddr);
224
225		if (bind(tcpsock,
226		    (struct sockaddr *)&inetaddr, sizeof (inetaddr)) < 0)
227			err(1, "bind(), %s:%d", __FILE__, __LINE__);
228
229		if (listen(tcpsock, 5) < 0)
230			err(1, "listen(), %s:%d", __FILE__, __LINE__);
231
232		len = sizeof(inetpeer);
233		if ((msgsock = accept(tcpsock,
234		    (struct sockaddr *)&inetpeer, &len)) < 0)
235			err(1, "accept(), %s:%d", __FILE__, __LINE__);
236
237		if ((to = open(to_name, O_RDWR | O_CREAT, DEFFILEMODE)) ==
238		    -1)
239			err(1, "open write %s", to_name);
240
241		rd = 0;
242		for (;;) {
243			n = read(msgsock, buf, sizeof(buf));
244			if (n == -1)
245				err(1, "read");
246			else if (n == 0)
247				break;
248			rd += n;
249			if (write(to, buf, n) != n)
250				err(1, "write()");
251		}
252		close(to);
253		if (rd != st.st_size)
254			fprintf(stderr, "Short read %d, expected %d\n",
255			    (int)rd, (int)st.st_size);
256		_exit(0);
257	}
258
259	_exit(0);
260}
261
262int
263main(void)
264{
265	pid_t pid;
266	int e, status;
267
268	e = 0;
269	if ((pid = fork()) == 0)
270		test();
271	if (pid == -1)
272		err(1, "fork()");
273	if (waitpid(pid, &status, 0) == -1)
274		err(1, "waitpid(%d)", pid);
275	if (status != 0) {
276		if (WIFSIGNALED(status))
277			fprintf(stderr,
278			    "pid %d exit signal %d\n",
279			    pid, WTERMSIG(status));
280	}
281	e += status == 0 ? 0 : 1;
282
283	return (e);
284}
285