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