xref: /dflybsd-src/test/stress/stress2/misc/sendfile.sh (revision 86d7f5d305c6adaa56ff4582ece9859d73106103)
186d7f5d3SJohn Marino#!/bin/sh
286d7f5d3SJohn Marino
386d7f5d3SJohn Marino#
486d7f5d3SJohn Marino# Copyright (c) 2009 Peter Holm <pho@FreeBSD.org>
586d7f5d3SJohn Marino# All rights reserved.
686d7f5d3SJohn Marino#
786d7f5d3SJohn Marino# Redistribution and use in source and binary forms, with or without
886d7f5d3SJohn Marino# modification, are permitted provided that the following conditions
986d7f5d3SJohn Marino# are met:
1086d7f5d3SJohn Marino# 1. Redistributions of source code must retain the above copyright
1186d7f5d3SJohn Marino#    notice, this list of conditions and the following disclaimer.
1286d7f5d3SJohn Marino# 2. Redistributions in binary form must reproduce the above copyright
1386d7f5d3SJohn Marino#    notice, this list of conditions and the following disclaimer in the
1486d7f5d3SJohn Marino#    documentation and/or other materials provided with the distribution.
1586d7f5d3SJohn Marino#
1686d7f5d3SJohn Marino# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1786d7f5d3SJohn Marino# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1886d7f5d3SJohn Marino# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1986d7f5d3SJohn Marino# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2086d7f5d3SJohn Marino# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2186d7f5d3SJohn Marino# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2286d7f5d3SJohn Marino# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2386d7f5d3SJohn Marino# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2486d7f5d3SJohn Marino# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2586d7f5d3SJohn Marino# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2686d7f5d3SJohn Marino# SUCH DAMAGE.
2786d7f5d3SJohn Marino#
2886d7f5d3SJohn Marino# $FreeBSD$
2986d7f5d3SJohn Marino#
3086d7f5d3SJohn Marino
3186d7f5d3SJohn Marino# Test scenario for sendfile livelock seen on 7.2-STABLE for non SMP
3286d7f5d3SJohn Marino
3386d7f5d3SJohn Marino# Scenario by kib@
3486d7f5d3SJohn Marino
3586d7f5d3SJohn Marino. ../default.cfg
3686d7f5d3SJohn Marino
3786d7f5d3SJohn Marinoodir=`pwd`
3886d7f5d3SJohn Marino
3986d7f5d3SJohn Marinocd /tmp
4086d7f5d3SJohn Marinosed '1,/^EOF/d' < $odir/$0 > sendfile.c
4186d7f5d3SJohn Marinocc -o sendfile -Wall sendfile.c -pthread
4286d7f5d3SJohn Marinorm -f sendfile.c
4386d7f5d3SJohn Marino[ -d "$RUNDIR" ] || mkdir -p $RUNDIR
4486d7f5d3SJohn Marinocd $RUNDIR
4586d7f5d3SJohn Marino
4686d7f5d3SJohn Marinoin=/tmp/inputFile
4786d7f5d3SJohn Marinoout=/tmp/outputFile
4886d7f5d3SJohn Marino
4986d7f5d3SJohn Marinofor i in 1 2 3 4 8 16 1k 2k 3k 4k 5k 1m 2m 3m 4m 5m ; do
5086d7f5d3SJohn Marino	rm -f $in $out
5186d7f5d3SJohn Marino	dd if=/dev/random of=$in bs=$i count=1 2>&1 | \
5286d7f5d3SJohn Marino		egrep -v "records|transferred"
5386d7f5d3SJohn Marino	/tmp/sendfile $in $out 12345
5486d7f5d3SJohn Marino	cmp $in $out || ls -l $in $out
5586d7f5d3SJohn Marino	rm -f $in $out
5686d7f5d3SJohn Marinodone
5786d7f5d3SJohn Marinorm -f /tmp/sendfile
5886d7f5d3SJohn Marinoexit
5986d7f5d3SJohn MarinoEOF
6086d7f5d3SJohn Marino#include <err.h>
6186d7f5d3SJohn Marino#include <fcntl.h>
6286d7f5d3SJohn Marino#include <netdb.h>
6386d7f5d3SJohn Marino#include <netinet/in.h>
6486d7f5d3SJohn Marino#include <signal.h>
6586d7f5d3SJohn Marino#include <stdio.h>
6686d7f5d3SJohn Marino#include <stdlib.h>
6786d7f5d3SJohn Marino#include <string.h>
6886d7f5d3SJohn Marino#include <sys/param.h>
6986d7f5d3SJohn Marino#include <sys/socket.h>
7086d7f5d3SJohn Marino#include <sys/stat.h>
7186d7f5d3SJohn Marino#include <unistd.h>
7286d7f5d3SJohn Marino
7386d7f5d3SJohn Marinoint port;
7486d7f5d3SJohn Marinochar *inputFile;
7586d7f5d3SJohn Marinochar *outputFile;
7686d7f5d3SJohn Marinoint bufsize = 4096;
7786d7f5d3SJohn Marino
7886d7f5d3SJohn Marinostatic void
7986d7f5d3SJohn Marinoreader(void) {
8086d7f5d3SJohn Marino	int tcpsock, msgsock;
8186d7f5d3SJohn Marino	int on;
8286d7f5d3SJohn Marino	socklen_t len;
8386d7f5d3SJohn Marino	struct sockaddr_in inetaddr, inetpeer;
8486d7f5d3SJohn Marino	int n, t, *buf, fd;
8586d7f5d3SJohn Marino
8686d7f5d3SJohn Marino	on = 1;
8786d7f5d3SJohn Marino	if ((tcpsock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
8886d7f5d3SJohn Marino		err(1, "socket(), %s:%d", __FILE__, __LINE__);
8986d7f5d3SJohn Marino
9086d7f5d3SJohn Marino	if (setsockopt(tcpsock,
9186d7f5d3SJohn Marino	    SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)) < 0)
9286d7f5d3SJohn Marino		err(1, "setsockopt(), %s:%d", __FILE__, __LINE__);
9386d7f5d3SJohn Marino
9486d7f5d3SJohn Marino	inetaddr.sin_family = AF_INET;
9586d7f5d3SJohn Marino	inetaddr.sin_addr.s_addr = INADDR_ANY;
9686d7f5d3SJohn Marino	inetaddr.sin_port = htons(port);
9786d7f5d3SJohn Marino	inetaddr.sin_len = sizeof(inetaddr);
9886d7f5d3SJohn Marino
9986d7f5d3SJohn Marino	if (bind(tcpsock,
10086d7f5d3SJohn Marino	    (struct sockaddr *)&inetaddr, sizeof (inetaddr)) < 0)
10186d7f5d3SJohn Marino		err(1, "bind(), %s:%d", __FILE__, __LINE__);
10286d7f5d3SJohn Marino
10386d7f5d3SJohn Marino	if (listen(tcpsock, 5) < 0)
10486d7f5d3SJohn Marino		err(1, "listen(), %s:%d", __FILE__, __LINE__);
10586d7f5d3SJohn Marino
10686d7f5d3SJohn Marino	len = sizeof(inetpeer);
10786d7f5d3SJohn Marino	if ((msgsock = accept(tcpsock,
10886d7f5d3SJohn Marino	    (struct sockaddr *)&inetpeer, &len)) < 0)
10986d7f5d3SJohn Marino		err(1, "accept(), %s:%d", __FILE__, __LINE__);
11086d7f5d3SJohn Marino
11186d7f5d3SJohn Marino	t = 0;
11286d7f5d3SJohn Marino	if ((buf = malloc(bufsize)) == NULL)
11386d7f5d3SJohn Marino			err(1, "malloc(%d), %s:%d", bufsize, __FILE__, __LINE__);
11486d7f5d3SJohn Marino
11586d7f5d3SJohn Marino	if ((fd = open(outputFile, O_RDWR | O_CREAT | O_TRUNC, 0640)) == -1)
11686d7f5d3SJohn Marino			err(1, "open(%s)", outputFile);
11786d7f5d3SJohn Marino
11886d7f5d3SJohn Marino	for (;;) {
11986d7f5d3SJohn Marino		if ((n = read(msgsock, buf, bufsize)) < 0)
12086d7f5d3SJohn Marino			err(1, "read(), %s:%d", __FILE__, __LINE__);
12186d7f5d3SJohn Marino		t += n;
12286d7f5d3SJohn Marino		if (n == 0) break;
12386d7f5d3SJohn Marino
12486d7f5d3SJohn Marino		if ((write(fd, buf, n)) != n)
12586d7f5d3SJohn Marino			err(1, "write");
12686d7f5d3SJohn Marino	}
12786d7f5d3SJohn Marino	close(msgsock);
12886d7f5d3SJohn Marino	close(fd);
12986d7f5d3SJohn Marino	return;
13086d7f5d3SJohn Marino}
13186d7f5d3SJohn Marino
13286d7f5d3SJohn Marinostatic void
13386d7f5d3SJohn Marinowriter(void) {
13486d7f5d3SJohn Marino	int tcpsock, on;
13586d7f5d3SJohn Marino	struct sockaddr_in inetaddr;
13686d7f5d3SJohn Marino	struct hostent *hostent;
13786d7f5d3SJohn Marino	struct stat statb;
13886d7f5d3SJohn Marino	int i, r, fd;
13986d7f5d3SJohn Marino	off_t off = 0;
14086d7f5d3SJohn Marino#if 1
14186d7f5d3SJohn Marino	size_t size;
14286d7f5d3SJohn Marino#endif
14386d7f5d3SJohn Marino
14486d7f5d3SJohn Marino	on = 1;
14586d7f5d3SJohn Marino	for (i = 1; i < 5; i++) {
14686d7f5d3SJohn Marino		if ((tcpsock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
14786d7f5d3SJohn Marino			err(1, "socket(), %s:%d", __FILE__, __LINE__);
14886d7f5d3SJohn Marino
14986d7f5d3SJohn Marino		if (setsockopt(tcpsock,
15086d7f5d3SJohn Marino		    SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)) < 0)
15186d7f5d3SJohn Marino			err(1, "setsockopt(), %s:%d", __FILE__, __LINE__);
15286d7f5d3SJohn Marino
15386d7f5d3SJohn Marino#if 1		/* livelock trigger */
15486d7f5d3SJohn Marino		size = getpagesize() -4;
15586d7f5d3SJohn Marino		if (setsockopt(tcpsock,
15686d7f5d3SJohn Marino		    SOL_SOCKET, SO_SNDBUF, (void *)&size, sizeof(size)) < 0)
15786d7f5d3SJohn Marino			err(1, "setsockopt(SO_SNDBUF), %s:%d", __FILE__, __LINE__);
15886d7f5d3SJohn Marino#endif
15986d7f5d3SJohn Marino
16086d7f5d3SJohn Marino		hostent = gethostbyname ("localhost");
16186d7f5d3SJohn Marino		memcpy (&inetaddr.sin_addr.s_addr, hostent->h_addr,
16286d7f5d3SJohn Marino			sizeof (struct in_addr));
16386d7f5d3SJohn Marino
16486d7f5d3SJohn Marino		inetaddr.sin_family = AF_INET;
16586d7f5d3SJohn Marino		inetaddr.sin_addr.s_addr = INADDR_ANY;
16686d7f5d3SJohn Marino		inetaddr.sin_port = htons(port);
16786d7f5d3SJohn Marino		inetaddr.sin_len = sizeof(inetaddr);
16886d7f5d3SJohn Marino
16986d7f5d3SJohn Marino		r = connect(tcpsock, (struct sockaddr *) &inetaddr,
17086d7f5d3SJohn Marino			sizeof(inetaddr));
17186d7f5d3SJohn Marino		if (r == 0)
17286d7f5d3SJohn Marino			break;
17386d7f5d3SJohn Marino		sleep(1);
17486d7f5d3SJohn Marino		close(tcpsock);
17586d7f5d3SJohn Marino	}
17686d7f5d3SJohn Marino	if (r < 0)
17786d7f5d3SJohn Marino		err(1, "connect(), %s:%d", __FILE__, __LINE__);
17886d7f5d3SJohn Marino
17986d7f5d3SJohn Marino        if (stat(inputFile, &statb) != 0)
18086d7f5d3SJohn Marino                err(1, "stat(%s)", inputFile);
18186d7f5d3SJohn Marino
18286d7f5d3SJohn Marino	if ((fd = open(inputFile, O_RDONLY)) == -1)
18386d7f5d3SJohn Marino		err(1, "open(%s)", inputFile);
18486d7f5d3SJohn Marino
18586d7f5d3SJohn Marino	if (sendfile(fd, tcpsock, 0, statb.st_size, NULL, &off, 0) == -1)
18686d7f5d3SJohn Marino		err(1, "sendfile");
18786d7f5d3SJohn Marino
18886d7f5d3SJohn Marino	return;
18986d7f5d3SJohn Marino}
19086d7f5d3SJohn Marino
19186d7f5d3SJohn Marinoint
19286d7f5d3SJohn Marinomain(int argc, char **argv)
19386d7f5d3SJohn Marino{
19486d7f5d3SJohn Marino	pid_t pid;
19586d7f5d3SJohn Marino
19686d7f5d3SJohn Marino	if (argc != 4) {
19786d7f5d3SJohn Marino		fprintf(stderr, "Usage: %s <inputFile outputFile portNumber\n", argv[0]);
19886d7f5d3SJohn Marino			return (1);
19986d7f5d3SJohn Marino	}
20086d7f5d3SJohn Marino	inputFile = argv[1];
20186d7f5d3SJohn Marino	outputFile = argv[2];
20286d7f5d3SJohn Marino	port = atoi(argv[3]);
20386d7f5d3SJohn Marino
20486d7f5d3SJohn Marino	if ((pid = fork()) == 0) {
20586d7f5d3SJohn Marino		writer();
20686d7f5d3SJohn Marino		exit(EXIT_SUCCESS);
20786d7f5d3SJohn Marino
20886d7f5d3SJohn Marino	} else if (pid > 0) {
20986d7f5d3SJohn Marino		reader();
21086d7f5d3SJohn Marino		kill(pid, SIGINT);
21186d7f5d3SJohn Marino	} else
21286d7f5d3SJohn Marino		err(1, "fork(), %s:%d",  __FILE__, __LINE__);
21386d7f5d3SJohn Marino
21486d7f5d3SJohn Marino	return (0);
21586d7f5d3SJohn Marino}
216