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