xref: /freebsd/tools/test/stress2/misc/sendfile13.sh (revision e0c4386e)
1#!/bin/sh
2
3#
4# Copyright (c) 2018 Dell EMC Isilon
5# All rights reserved.
6#
7# Redistribution and use in source and binary forms, with or without
8# modification, are permitted provided that the following conditions
9# are met:
10# 1. Redistributions of source code must retain the above copyright
11#    notice, this list of conditions and the following disclaimer.
12# 2. Redistributions in binary form must reproduce the above copyright
13#    notice, this list of conditions and the following disclaimer in the
14#    documentation and/or other materials provided with the distribution.
15#
16# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26# SUCH DAMAGE.
27#
28
29# Move files between two FSs using sendfile(2).
30# CG checksum errors reported.
31
32# Unrelated gpart page fault seen:
33# https://people.freebsd.org/~pho/stress/log/sendfile13.txt
34# Fixed by r329262
35
36. ../default.cfg
37[ `id -u` -ne 0 ] && echo "Must be root!" && exit 1
38
39dir=/tmp
40odir=`pwd`
41cd $dir
42sed '1,/^EOF/d' < $odir/$0 > $dir/sendfile13.c
43mycc -o sendfile13 -Wall -Wextra -O0 -g sendfile13.c || exit 1
44rm -f sendfile13.c
45cd $odir
46
47set -e
48size="$((`sysctl -n hw.usermem` / 2 / 1024 / 1024 / 1024))"
49size="$((size * 7 / 10))g"
50[ "$size" = "0g" ] && exit 0
51[ "$newfs_flags" = "-U" ] || exit 0
52newfs_flags="-j"
53
54mp1=$mntpoint
55mkdir -p $mp1
56md1=$mdstart
57mount | grep "on $mp1 " | grep -q /dev/md && umount -f $mp1
58[ -c /dev/md$md1 ] && mdconfig -d -u $md1
59mdconfig -a -t swap -s $size -u $md1
60newfs $newfs_flags -n md${md1} > /dev/null 2>&1
61mount /dev/md${md1} $mp1
62
63md2=$((mdstart + 1))
64mp2=${mntpoint}$md2
65mkdir -p $mp2
66mount | grep "on $mp2 " | grep -q /dev/md && umount -f $mp2
67[ -c /dev/md$md2 ] && mdconfig -d -u $md2
68mdconfig -a -t swap -s $size -u $md2
69newfs $newfs_flags -n md${md2} > /dev/null 2>&1
70mount /dev/md${md2} $mp2
71set +e
72
73free=`df $mp1 | tail -1 | awk '{print $4}'`
74$dir/sendfile13 5432 $mp1 $mp2 $((free / 2)) &
75p1=$!
76$dir/sendfile13 5433 $mp2 $mp1 $((free / 2)) &
77p2=$!
78cd $odir
79s=0
80wait $p1; code=$?
81[ $code -ne 0 ] && { s=$code; echo "$p1 exit status $code"; }
82wait $p2; code=$?
83[ $code -ne 0 ] && { s=$code; echo "$p2 exit status $code"; }
84[ -f sendfile13.core -a $s -eq 0 ] &&
85    { ls -l sendfile13.core; mv sendfile13.core /tmp; }
86cd $odir
87
88for i in `jot 6`; do
89	mount | grep -q "on $mp1 " || break
90	umount $mp1 && break || sleep 10
91	[ $i -eq 6 ] &&
92	    { echo FATAL; fstat -mf $mp1; exit 1; }
93done
94for i in `jot 6`; do
95	mount | grep -q "on $mp2 " || break
96	umount $mp2 && break || sleep 10
97	[ $i -eq 6 ] &&
98	    { echo FATAL; fstat -mf $mp2; exit 1; }
99done
100checkfs /dev/md${md1} || s=1
101checkfs /dev/md${md2} || s=1
102mdconfig -d -u $md1 || s=1
103mdconfig -d -u $md2 || s=1
104
105for i in `jot 6`; do
106	mount | grep -q "on $mp2 " || break
107	umount $mp2 && break || sleep 10
108	[ $i -eq 6 ] &&
109	    { echo FATAL; fstat -mf $mp2; exit 1; }
110done
111checkfs /dev/md${md2} || s=1
112
113rm -rf $dir/sendfile13
114exit $s
115
116EOF
117#include <sys/param.h>
118#include <sys/mman.h>
119#include <sys/socket.h>
120#include <sys/stat.h>
121#include <sys/wait.h>
122
123#include <netinet/in.h>
124
125#include <err.h>
126#include <fcntl.h>
127#include <netdb.h>
128#include <signal.h>
129#include <stdio.h>
130#include <stdlib.h>
131#include <string.h>
132#include <time.h>
133#include <unistd.h>
134
135#define BUFSIZE 8192
136#define MAXTHREADS 32
137
138static int files, port;
139static char *fromdir, *todir;
140
141static void
142create(char *path, size_t size)
143{
144	size_t s;
145	int fd, i, ifd;
146	char *cp, file[128], help[128];
147
148	i = 0;
149	while (size > 0) {
150		do {
151			s =arc4random() % size + 1;
152		} while (s > 1024 * 1024 * 1024);
153		size -= s;
154		sprintf(file, "%s/f%06d.%06d", path, getpid(), i++);
155		if ((ifd = open("/dev/zero", O_RDONLY)) == -1)
156			err(1, "open(/dev/zero)");
157		if ((cp = mmap(0, s, PROT_READ, MAP_SHARED, ifd, 0)) ==
158			(caddr_t) - 1)
159			err(1, "mmap error for input");
160		if ((fd = open(file, O_WRONLY | O_CREAT, 0640)) == -1)
161			err(1, "create(%s)", file);
162		if (write(fd, cp, s) != (ssize_t)s)
163			err(1, "write(%s)", file);
164		munmap(cp, s);
165		close(fd);
166		close(ifd);
167		files++;
168	}
169	snprintf(help, sizeof(help),
170	    "umount %s 2>&1 | grep -v 'Device busy'", path);
171	system(help);
172#if defined(DEBUG)
173	fprintf(stderr, "%d files created\n", files);
174#endif
175}
176
177static void
178server(void)
179{
180	pid_t pid;
181        struct sigaction sa;
182	struct sockaddr_in inetaddr, inetpeer;
183	socklen_t len;
184	int tcpsock, msgsock;
185	int *buf, fd, idx, n, on, t __unused;
186	char ofile[128], nfile[128];
187
188        sa.sa_handler = SIG_IGN;
189        sigemptyset(&sa.sa_mask);
190        sa.sa_flags = 0;
191        if (sigaction(SIGCHLD, &sa, 0) == -1)
192                err(1, "sigaction");
193
194	on = 1;
195	if ((tcpsock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
196		err(1, "socket(), %s:%d", __FILE__, __LINE__);
197
198	if (setsockopt(tcpsock,
199	    SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)) < 0)
200		err(1, "setsockopt(), %s:%d", __FILE__, __LINE__);
201
202	inetaddr.sin_family = AF_INET;
203	inetaddr.sin_addr.s_addr = INADDR_ANY;
204	inetaddr.sin_port = htons(port);
205	inetaddr.sin_len = sizeof(inetaddr);
206
207	if (bind(tcpsock,
208	    (struct sockaddr *)&inetaddr, sizeof (inetaddr)) < 0)
209		err(1, "bind(), %s:%d", __FILE__, __LINE__);
210
211	if (listen(tcpsock, 5) < 0)
212		err(1, "listen(), %s:%d", __FILE__, __LINE__);
213
214	idx = 0;
215	len = sizeof(inetpeer);
216	for (;;) {
217		alarm(120);
218		if ((msgsock = accept(tcpsock,
219		    (struct sockaddr *)&inetpeer, &len)) < 0)
220			err(1, "accept(), %s:%d", __FILE__, __LINE__);
221
222		if ((pid = fork()) == 0) {
223			alarm(120);
224			t = 0;
225			if ((buf = malloc(BUFSIZE)) == NULL)
226				err(1, "malloc(%d), %s:%d", BUFSIZE,
227				    __FILE__, __LINE__);
228
229			sprintf(ofile, "%s/g%06d.%06d", todir, getpid(),
230			    idx);
231			sprintf(nfile, "%s/n%06d.%06d", todir, getpid(),
232			    idx);
233			if ((fd = open(ofile, O_RDWR | O_CREAT | O_TRUNC,
234			    0640)) == -1)
235				err(1, "open(%s)", ofile);
236
237			for (;;) {
238				if ((n = read(msgsock, buf, BUFSIZE)) < 0)
239					err(1, "read(), %s:%d", __FILE__,
240					    __LINE__);
241				t += n;
242				if (n == 0) break;
243
244				if ((write(fd, buf, n)) != n)
245					err(1, "write n=%d", n);
246			}
247			close(msgsock);
248			close(fd);
249			if (rename(ofile, nfile) != 0)
250				err(1, "rename(%s, %s)", ofile, nfile);
251			_exit(0);
252		}
253		close(msgsock);
254		if (++idx == files)
255			break;
256	}
257
258	_exit(0);
259}
260
261static void
262writer(char *inputFile) {
263	struct sockaddr_in inetaddr;
264	struct hostent *hostent;
265	struct stat statb;
266	off_t off = 0;
267	size_t size;
268	int i, fd, on, r, tcpsock;
269
270	alarm(120);
271	on = 1;
272	for (i = 1; i < 5; i++) {
273		if ((tcpsock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
274			err(1, "socket(), %s:%d", __FILE__, __LINE__);
275
276		if (setsockopt(tcpsock,
277		    SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)) < 0)
278			err(1, "setsockopt(), %s:%d", __FILE__, __LINE__);
279
280		size = getpagesize();
281		if (setsockopt(tcpsock,
282		    SOL_SOCKET, SO_SNDBUF, (void *)&size, sizeof(size)) < 0)
283			err(1, "setsockopt(SO_SNDBUF), %s:%d", __FILE__,
284			    __LINE__);
285
286		hostent = gethostbyname ("localhost");
287		memcpy (&inetaddr.sin_addr.s_addr, hostent->h_addr,
288			sizeof (struct in_addr));
289
290		inetaddr.sin_family = AF_INET;
291		inetaddr.sin_port = htons(port);
292		inetaddr.sin_len = sizeof(inetaddr);
293
294		r = connect(tcpsock, (struct sockaddr *) &inetaddr,
295			sizeof(inetaddr));
296		if (r == 0)
297			break;
298		sleep(1);
299		close(tcpsock);
300	}
301	if (r < 0)
302		err(1, "connect(), %s:%d", __FILE__, __LINE__);
303
304        if (stat(inputFile, &statb) != 0)
305                err(1, "stat(%s)", inputFile);
306
307	if ((fd = open(inputFile, O_RDWR)) == -1)
308		err(1, "open(%s)", inputFile);
309
310	if (sendfile(fd, tcpsock, 0, statb.st_size, NULL, &off,
311	    SF_NOCACHE) == -1)
312		warn("sendfile()");
313	close(fd);
314
315	return;
316}
317
318static void
319move(int num)
320{
321	char ifile[128];
322
323	sprintf(ifile, "%s/f%06d.%06d", fromdir, getpid(), num);
324	writer(ifile);
325
326	if (unlink(ifile) != 0)
327		err(1, "unlink(%s)", ifile);
328}
329
330int
331main(int argc, char *argv[])
332{
333	pid_t spid;
334	size_t size;
335	int i, status;
336
337	if (argc != 5) {
338		fprintf(stderr,
339		    "Usage %s <port> <from dir> <to dir> <size in k>",
340		    argv[0]);
341		exit(1);
342	}
343	port = atoi(argv[1]);
344	fromdir = argv[2];
345	if (chdir(fromdir) == -1)
346		err(1, "chdir(%s)", fromdir);
347	todir = argv[3];
348	sscanf(argv[4], "%zd", &size);
349	size = size * 1024;
350	create(fromdir, size);
351
352	if ((spid = fork()) == 0)
353		server();
354
355	for (i = 0; i < files; i++) {
356		move(i);
357		sleep(10);
358	}
359	if (waitpid(spid, &status, 0) != spid)
360		err(1, "waitpid");
361	if (status != 0) {
362		if (WIFSIGNALED(status))
363			fprintf(stderr,
364			    "pid %d exit signal %d\n",
365			    spid, WTERMSIG(status));
366	}
367
368	return (status == 0 ? 0 : 1);
369}
370