xref: /freebsd/tools/test/stress2/misc/nfsrename.sh (revision 7a7741af18d6c8a804cc643cb7ecda9d730c6aa6)
1#!/bin/sh
2
3#
4# Copyright (c) 2008-2013 Peter Holm <pho@FreeBSD.org>
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[ `id -u ` -ne 0 ] && echo "Must be root!" && exit 1
30
31. ../default.cfg
32
33# Test scenario by jhb@
34
35[ -z "$nfs_export" ] && exit 0
36ping -c 2 `echo $nfs_export | sed 's/:.*//'` > /dev/null 2>&1 ||
37    exit 0
38
39odir=`pwd`
40cd /tmp
41sed '1,/^EOF/d' < $odir/$0 > nfsrename.c
42mycc -o nfsrename -Wall nfsrename.c
43rm -f nfsrename.c
44cd $odir
45
46mount | grep "$mntpoint" | grep nfs > /dev/null && umount $mntpoint
47mount -t nfs -o tcp -o retrycnt=3 -o intr,soft -o rw $nfs_export $mntpoint
48
49for i in `jot 10`; do
50	/tmp/nfsrename  $mntpoint/nfsrename.$i > /dev/null 2>&1 &
51	pids="$pids $!"
52done
53s=0
54for i in $pids; do
55	wait $i
56	[ $? -ne 0 ] && s=1
57done
58pkill nfsrename
59rm -f $mntpoint/nfsrename.*
60
61umount $mntpoint > /dev/null 2>&1
62while mount | grep "$mntpoint" | grep -q nfs; do
63	umount -f $mntpoint > /dev/null 2>&1
64done
65
66rm -f /tmp/nfsrename
67exit $s
68
69EOF
70/*
71 * Try to expose races with doing renames over NFS that require silly
72 * renames.  This results in 2 different RENAME RPCs leaving a race
73 * window where the file may not exist.  It also appears that FreeBSD
74 * with shared lookups in NFS can get confused and possibly reference
75 * the sillyrenamed file in lookup but the file is deleted by the time
76 * open gets to it.
77 */
78
79#include <err.h>
80#include <libgen.h>
81#include <limits.h>
82#include <stdio.h>
83#include <stdlib.h>
84#include <time.h>
85#include <unistd.h>
86
87static char *filename;
88static char *dir;
89
90#define RUNTIME 720
91
92static void
93usage(void)
94{
95
96	fprintf(stderr, "nfsrename: [-n children] file\n");
97	exit(1);
98}
99
100static void
101read_file(void)
102{
103	FILE *fp;
104	char buffer[4096];
105
106	fp = fopen(filename, "r");
107	if (fp == NULL) {
108		return;
109	}
110	while (!feof(fp)) {
111		if (fread(buffer, sizeof(buffer), 1, fp) < sizeof(buffer))
112			break;
113	}
114	if (ferror(fp))
115		warnx("fread encountered an error");
116	fclose(fp);
117}
118
119static void
120write_file(void)
121{
122	FILE *fp;
123	char path[1024];
124	int fd;
125
126	snprintf(path, sizeof(path), "%s/nfsrename.XXXXXX", dir);
127	fd = mkstemp(path);
128	if (fd < 0) {
129		warn("mkstemp");
130		return;
131	}
132
133	fp = fdopen(fd, "w");
134	if (fp == NULL) {
135		warn("fdopen:writer");
136		close(fd);
137		unlink(path);
138	}
139
140	fprintf(fp, "blah blah blah garbage %ld\n", (long)arc4random());
141	fclose(fp);
142	if (rename(path, filename) < 0) {
143		warn("rename");
144		unlink(path);
145	}
146}
147
148static void
149random_sleep(int base, int slop)
150{
151	long val;
152
153	val = arc4random() % slop;
154	usleep(base + val);
155}
156
157static void
158child(void)
159{
160	time_t start;
161
162	start = time(NULL);
163	for (;;) {
164		random_sleep(500, 50);
165		read_file();
166		if (time(NULL) - start > RUNTIME)
167			errx(1, "Timed out");
168	}
169	exit(0);
170}
171
172int
173main(int ac, char **av)
174{
175	time_t start;
176	long i, nchild;
177	char *cp;
178	int ch;
179
180	nchild = 1;
181	while ((ch = getopt(ac, av, "n:")) != -1) {
182		switch (ch) {
183		case 'n':
184			nchild = strtol(optarg, &cp, 0);
185			if (*cp != '\0')
186				errx(1, "Invalid count %s", optarg);
187			break;
188		case '?':
189		default:
190			usage();
191		}
192	}
193	ac -= optind;
194	av += optind;
195
196	if (ac == 0)
197		errx(1, "Missing filename");
198	else if (ac > 1)
199		errx(1, "Extra arguments");
200
201	filename = av[0];
202	dir = dirname(filename);
203	srandomdev();
204	write_file();
205
206	for (i = 0; i < nchild; i++) {
207		switch (fork()) {
208		case 0:
209			child();
210		case -1:
211			err(1, "fork");
212		}
213	}
214
215	start = time(NULL);
216	for (i = 0; i < 10000; i++) {
217		random_sleep(1500, 1000);
218		write_file();
219		if (time(NULL) - start > RUNTIME)
220			errx(1, "Timed out");
221	}
222
223	return (0);
224}
225