xref: /freebsd/tools/test/stress2/misc/lstat.sh (revision d4eeb02986980bf33dd56c41ceb9fc5f180c0d47)
1#!/bin/sh
2
3#
4# Copyright (c) 2016 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# Hunt for;
30# Bug 204764 - Filesystem deadlock, process in vodead state
31#    https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=204764
32# No problem seen.
33
34. ../default.cfg
35
36dir=/tmp
37odir=`pwd`
38cd $dir
39sed '1,/^EOF/d' < $odir/$0 > $dir/lstat.c
40mycc -o lstat -Wall -Wextra -O0 -g lstat.c || exit 1
41rm -f lstat.c
42cd $odir
43
44mount | grep "on $mntpoint " | grep -q /dev/md && umount -f $mntpoint
45mdconfig -l | grep -q md$mdstart &&  mdconfig -d -u $mdstart
46mdconfig -a -t swap -s 1g -u $mdstart || exit 1
47newfs -n -b 4096 -f 512 -i 1024 md$mdstart > /dev/null
48mount -o async /dev/md$mdstart $mntpoint || exit 1
49
50path=$mntpoint/a/b/c
51mkdir -p $path
52
53$dir/lstat $path
54
55while mount | grep "on $mntpoint " | grep -q /dev/md; do
56	umount $mntpoint || sleep 1
57done
58mdconfig -d -u $mdstart
59rm -rf $dir/lstat $wdir/lstat.tmp.*
60exit
61
62EOF
63#include <sys/param.h>
64#include <sys/mman.h>
65#include <sys/stat.h>
66#include <sys/wait.h>
67
68#include <machine/atomic.h>
69
70#include <err.h>
71#include <errno.h>
72#include <fcntl.h>
73#include <fts.h>
74#include <signal.h>
75#include <stdio.h>
76#include <stdlib.h>
77#include <time.h>
78#include <unistd.h>
79
80static volatile u_int *dirs, *share;
81static char *arg;
82
83#define R1 0
84#define R2 1
85
86#define MXDIRS 3000
87#define PARALLEL 2
88#define RUNTIME 600
89#define SLPTIME 400
90
91static void
92tfts(int idx)
93{
94	FTS *fts;
95	FTSENT *p;
96	struct stat sb;
97	int ftsoptions;
98	char *args[2];
99
100	if (idx != 0)
101		_exit(0);
102
103	ftsoptions = FTS_PHYSICAL;
104	args[0] = arg,
105	args[1] = 0;
106
107	setproctitle("fts");
108	while (share[R2] == 0) {
109		if ((fts = fts_open(args, ftsoptions, NULL)) == NULL)
110			err(1, "fts_open");
111
112		while ((p = fts_read(fts)) != NULL) {
113			lstat(fts->fts_path, &sb);
114			if (share[R2] == 1)
115				break;
116		}
117
118		if (fts_close(fts) == -1)
119			err(1, "fts_close()");
120	}
121
122	_exit(0);
123}
124
125static int
126test(int idx)
127{
128	struct stat sb;
129	pid_t fpid, pd, pid;
130	size_t len;
131	int i, r;
132	char dir[128], path[128];
133
134	atomic_add_int(&share[R1], 1);
135	while (share[R1] != PARALLEL)
136		;
137
138	len = PAGE_SIZE;
139	if ((dirs = mmap(NULL, len, PROT_READ | PROT_WRITE,
140	    MAP_ANON | MAP_SHARED, -1, 0)) == MAP_FAILED)
141		err(1, "mmap");
142
143	if ((fpid = fork()) == 0)
144		tfts(idx);
145
146	pid = getpid();
147	snprintf(dir, sizeof(dir), "%s/dir.%d", arg, pid);
148	if (mkdir(dir, 0777) == -1)
149		err(1, "mkdir(%s)", dir);
150	if (chdir(dir) == -1)
151		err(1, "chdir(%s)", dir);
152	if ((pd = fork()) == 0) {
153		setproctitle("mkdir");
154		i = 0;
155		while (share[R2] == 0) {
156			snprintf(path, sizeof(path), "%s/d.%d.%d", arg, pid,
157			    i);
158			while (dirs[0] > MXDIRS && share[R2] == 0)
159				usleep(SLPTIME);
160			while ((r = mkdir(path, 0777)) == -1) {
161				if (errno != EMLINK)
162					err(1, "mkdir(%s) @ %d", path,
163					    __LINE__);
164				usleep(SLPTIME);
165				if (share[2] == 1)
166					break;
167			}
168			if (r == 0) {
169				atomic_add_int(&dirs[0], 1);
170				i++;
171			}
172		}
173
174		_exit(0);
175	}
176
177	i = 0;
178	setproctitle("rmdir");
179	while (dirs[0] > 0 || share[R2] == 0) {
180		if (dirs[0] < MXDIRS / 2)
181			usleep(SLPTIME);
182		snprintf(path, sizeof(path), "%s/d.%d.%d", arg, pid, i);
183		while (lstat(path, &sb) == -1 && share[R2] == 0) {
184			usleep(SLPTIME);
185		}
186		if (rmdir(path) == -1) {
187			if (errno != ENOENT)
188				err(1, "rmdir(%s)", path);
189		} else {
190			atomic_add_int(&dirs[0], -1);
191			i++;
192		}
193	}
194	waitpid(pd, NULL, 0);
195	waitpid(fpid, NULL, 0);
196
197	chdir("..");
198	if ((rmdir(dir)) == -1)
199		err(1, "unlink(%s)", dir);
200
201	_exit(0);
202}
203
204int
205main(int argc, char *argv[])
206{
207	size_t len;
208	int e, i, pids[PARALLEL], status;
209
210	if (argc != 2)
211		errx(1, "Usage: %s <path>", argv[0]);
212	arg = argv[1];
213
214	e = 0;
215	len = PAGE_SIZE;
216	if ((share = mmap(NULL, len, PROT_READ | PROT_WRITE,
217	    MAP_ANON | MAP_SHARED, -1, 0)) == MAP_FAILED)
218		err(1, "mmap");
219
220	share[R1] = 0;
221	for (i = 0; i < PARALLEL; i++) {
222		if ((pids[i] = fork()) == 0)
223			test(i);
224	}
225	sleep(RUNTIME);
226	share[R2] = 1;
227	for (i = 0; i < PARALLEL; i++) {
228		waitpid(pids[i], &status, 0);
229		e += status == 0 ? 0 : 1;
230	}
231
232	return (e);
233}
234