1#!/bin/sh
2
3#
4# Copyright (c) 2015 EMC Corp.
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# Open four (sparse) files for random read and write.
30
31# "panic: softdep_deallocate_dependencies: dangling deps" seen:
32# https://people.freebsd.org/~pho/stress/log/kirk075.txt
33
34[ `id -u ` -ne 0 ] && echo "Must be root!" && exit 1
35
36. ../default.cfg
37
38dir=`dirname $diskimage`
39free=`df -k $dir | tail -1 | awk '{print $4}'`
40[ $((free / 1024 / 1024)) -lt 9 ] && echo "Not enough disk space." && exit
41
42odir=`pwd`
43cd /tmp
44sed '1,/^EOF/d' < $odir/$0 > cluster.c
45rm -f /tmp/cluster
46mycc -o cluster -Wall -Wextra -g -O2 cluster.c || exit 1
47rm -f cluster.c
48cd $odir
49
50su $testuser -c "/tmp/cluster $dir abc"
51
52rm -f /tmp/cluster
53exit 0
54EOF
55#include <sys/param.h>
56#include <sys/wait.h>
57
58#include <err.h>
59#include <errno.h>
60#include <fcntl.h>
61#include <stdio.h>
62#include <stdlib.h>
63#include <string.h>
64#include <time.h>
65#include <unistd.h>
66
67#define BSIZE (8 * 1024 * 1024)
68#define MX (8LL * 1024 * 1024 * 1024)
69#define PARALLEL 4
70#define RUNTIME 600
71#define WRLOOPS  1024
72
73int rfd;
74char *buf;
75char *path;
76char *uid;
77char file[MAXPATHLEN + 1];
78
79unsigned long long
80rnd(void) {
81	unsigned long long v;
82
83	read(rfd, &v, sizeof(v));
84	v = v % MX;
85	return (v);
86}
87
88void
89wr(int idx)
90{
91	off_t offset;
92	size_t ln;
93	int fd, i, n;
94
95	snprintf(file, sizeof(file), "%s/f.%s.%06d", path, uid, idx);
96	setproctitle(__func__);
97	if ((fd = open(file, O_RDWR | O_CREAT, 0644)) == -1)
98		err(1, "open(%s)", file);
99	n = arc4random() % WRLOOPS + 1;
100	for (i = 0; i < n; i++) {
101		ln = rnd() % BSIZE + 1;
102		offset = rnd() % (MX - ln);
103		if (lseek(fd, offset, SEEK_SET) == -1)
104			err(1, "lseek in rw 1");
105		while (lockf(fd, F_LOCK, ln) == -1) {
106			if (errno != EDEADLK)
107				err(1, "lockf(%s, F_LOCK)", file);
108		}
109		if (write(fd, buf, ln) < 0)
110			err(1, "write");
111		if (lseek(fd, offset, SEEK_SET) == -1)
112			err(1, "lseek in rw 2");
113		if (lockf(fd, F_ULOCK, ln) == -1)
114			err(1, "lockf(%s, F_ULOCK)", file);
115	}
116	close(fd);
117	_exit(0);
118}
119
120void
121rd(int idx)
122{
123	off_t offset;
124	size_t ln;
125	int fd, i, n;
126
127	snprintf(file, sizeof(file), "%s/f.%s.%06d", path, uid, idx);
128	setproctitle(__func__);
129	for (i = 0; i < 100; i++) {
130		if (access(file, R_OK) == 0)
131			break;
132		usleep(1000);
133	}
134	if ((fd = open(file, O_RDONLY)) == -1)
135		if (errno != ENOENT)
136			err(1, "open(%s)for read", file);
137	n = arc4random() % WRLOOPS + 1;
138	for (i = 0; i < n; i++) {
139		ln = rnd() % BSIZE + 1;
140		offset = rnd() % (MX - ln);
141		if (lseek(fd, offset, SEEK_SET) == -1) {
142			if (errno == EBADF)
143				continue;
144			err(1, "lseek in rd");
145		}
146		if (read(fd, buf, ln) < 0)
147			err(1, "write");
148	}
149	close(fd);
150	_exit(0);
151}
152
153void
154mv(int idx)
155{
156	int i;
157	char file2[MAXPATHLEN + 1];
158
159	snprintf(file, sizeof(file), "%s/f.%s.%06d", path, uid, idx);
160	snprintf(file2, sizeof(file2), "%s/f.%s.%06d.old", path, uid, idx);
161	for (i = 0; i < 100; i++) {
162		if (access(file, R_OK) == 0)
163			break;
164		usleep(1000);
165	}
166	if (rename(file, file2) == -1)
167		if (errno != ENOENT)
168			warn("rename(%s, %s)", file, file2);
169	_exit(0);
170}
171
172void
173tr(int idx)
174{
175	off_t offset;
176	int fd;
177
178	if (arc4random() % 100 < 10) {
179		snprintf(file, sizeof(file), "%s/f.%s.%06d", path, uid, idx);
180		setproctitle(__func__);
181		if ((fd = open(file, O_RDWR | O_CREAT, 0644)) == -1)
182			err(1, "open(%s)for read", file);
183		offset = rnd() % MX;
184		offset = rnd();
185		if (ftruncate(fd, offset) == -1)
186			err(1, "truncate");
187		close(fd);
188	}
189	_exit(0);
190}
191
192void
193rm(int idx)
194{
195	int i;
196	char file2[MAXPATHLEN + 1];
197
198	snprintf(file2, sizeof(file2), "%s/f.%s.%06d.old", path, uid, idx);
199	for (i = 0; i < 100; i++) {
200		if (access(file2, R_OK) == 0)
201			break;
202		usleep(1000);
203	}
204	if (unlink(file2) == -1)
205		if (errno != ENOENT)
206			warn("unlink(%s)", file2);
207	_exit(0);
208}
209
210void
211test2(void (*func)(int nr))
212{
213	time_t start;
214	int i;
215
216	setproctitle(__func__);
217	start = time(NULL);
218	while (time(NULL) - start < RUNTIME) {
219		for (i = 0; i < PARALLEL; i++) {
220			if (fork() == 0)
221				func(i);
222		}
223		for (i = 0; i < PARALLEL; i++)
224			wait(NULL);
225	}
226	_exit(0);
227
228}
229
230void
231test(void (*func)(int nr))
232{
233
234	if (fork() == 0)
235		test2(func);
236}
237
238int
239main(int argc, char *argv[])
240{
241	int i;
242
243	if (argc != 3)
244		errx(1, "Usage: %s <path> <uid>", argv[0]);
245
246	path = argv[1];
247	uid = argv[2];
248
249	if ((rfd = open("/dev/random", O_RDONLY)) == -1)
250		err(1, "open(/dev/random)");
251	setproctitle(__func__);
252	buf = malloc(BSIZE);
253	test(wr);
254	test(rd);
255	test(tr);
256	test(mv);
257	for (i = 0; i < 4; i++)
258		if (wait(NULL) == -1)
259			err(1, "wait");
260
261	for (i = 0; i < PARALLEL; i++) {
262		snprintf(file, sizeof(file), "%s/f.%s.%06d", path, uid, i);
263		unlink(file);
264		snprintf(file, sizeof(file), "%s/f.%s.%06d.old", path, uid, i);
265		unlink(file);
266	}
267
268	return (0);
269}
270