xref: /freebsd/tools/test/stress2/misc/suj30.sh (revision 02e9120893770924227138ba49df1edb3896112a)
1#!/bin/sh
2
3#
4# Copyright (c) 2012 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# SUJ rename test scenario by Andrey Zonov <zont@FreeBSD.org>
30# "panic: flush_pagedep_deps: MKDIR_PARENT" seen:
31# http://people.freebsd.org/~pho/stress/log/suj30.txt
32
33# Hang seen: https://people.freebsd.org/~pho/stress/log/log0337.txt
34
35[ `id -u ` -ne 0 ] && echo "Must be root!" && exit 1
36
37. ../default.cfg
38
39here=`pwd`
40cd /tmp
41sed '1,/^EOF/d' < $here/$0 > suj30.c
42mycc -o suj30 -Wall -Wextra -O2 suj30.c -lpthread
43rm -f suj30.c
44
45mount | grep "on $mntpoint " | grep -q md$mdstart && umount $mntpoint
46mdconfig -l | grep -q md$mdstart &&  mdconfig -d -u $mdstart
47
48mdconfig -a -t swap -s 4g -u $mdstart
49newfs -j md$mdstart > /dev/null
50mount /dev/md$mdstart $mntpoint
51chmod 777 $mntpoint
52
53for i in `jot 10`; do
54	/tmp/suj30 $mntpoint/test-$i 100000 &
55done
56wait
57
58while mount | grep -q $mntpoint; do
59	umount $mntpoint || sleep 1
60done
61mdconfig -d -u $mdstart
62rm -f /tmp/suj30
63exit 0
64EOF
65/*
66 * Andrey Zonov (c) 2012
67 *
68 * compile as `cc -o rename rename.c -lpthread'
69 */
70
71#include <sys/types.h>
72#include <sys/stat.h>
73#include <sys/time.h>
74#include <sys/queue.h>
75#include <err.h>
76#include <errno.h>
77#include <fcntl.h>
78#include <pthread.h>
79#ifdef __FreeBSD__
80#include <pthread_np.h>
81#define	__NP__
82#endif
83#include <sched.h>
84#include <stdio.h>
85#include <stdlib.h>
86#include <string.h>
87#include <time.h>
88#include <unistd.h>
89
90#define	LOCK(x)		pthread_mutex_lock(&x.mtx)
91#define	UNLOCK(x)	pthread_mutex_unlock(&x.mtx)
92#define	SIGNAL(x)	pthread_cond_signal(&x.wait)
93#define	WAIT(x)		pthread_cond_wait(&x.wait, &x.mtx)
94
95int max;
96int exited;
97char *dirname1;
98char *dirname2;
99
100struct file {
101	char *name;
102	STAILQ_ENTRY(file) next;
103};
104
105struct files {
106	pthread_mutex_t mtx;
107	pthread_cond_t wait;
108	STAILQ_HEAD(, file) list;
109};
110
111static struct files newfiles;
112static struct files renamedfiles;
113
114void *loop_create(void *arg __unused);
115void *loop_rename(void *arg __unused);
116void *loop_unlink(void *arg __unused);
117
118int
119main(int argc, char **argv)
120{
121	int i;
122	int rc;
123	pthread_t tid[3];
124
125	if (argc != 3)
126		errx(1, "usage: pthread_count <dirname> <max>");
127
128	asprintf(&dirname1, "%s.1", argv[1]);
129	asprintf(&dirname2, "%s.2", argv[1]);
130	if (mkdir(dirname1, 0755) == -1)
131		err(1, "mkdir(%s)", dirname1);
132	if (mkdir(dirname2, 0755) == -1)
133		err(1, "mkdir(%s)", dirname2);
134	max = atoi(argv[2]);
135
136	STAILQ_INIT(&newfiles.list);
137	STAILQ_INIT(&renamedfiles.list);
138
139	rc = pthread_mutex_init(&newfiles.mtx, NULL);
140	if (rc != 0)
141		errc(1, rc, "pthread_mutex_init()");
142	rc = pthread_cond_init(&newfiles.wait, NULL);
143	if (rc != 0)
144		errc(1, rc, "pthread_cond_init()");
145	rc = pthread_mutex_init(&renamedfiles.mtx, NULL);
146	if (rc != 0)
147		errc(1, rc, "pthread_mutex_init()");
148	rc = pthread_cond_init(&renamedfiles.wait, NULL);
149	if (rc != 0)
150		errc(1, rc, "pthread_cond_init()");
151
152	rc = pthread_create(&tid[0], NULL, loop_create, NULL);
153	if (rc != 0)
154		errc(1, rc, "pthread_create()");
155	rc = pthread_create(&tid[1], NULL, loop_rename, NULL);
156	if (rc != 0)
157		errc(1, rc, "pthread_create()");
158	rc = pthread_create(&tid[2], NULL, loop_unlink, NULL);
159	if (rc != 0)
160		errc(1, rc, "pthread_create()");
161
162	for (i = 0; i < 3; i++) {
163		rc = pthread_join(tid[i], NULL);
164		if (rc != 0)
165			errc(1, rc, "pthread_join(%d)", i);
166	}
167
168	rc = pthread_mutex_destroy(&newfiles.mtx);
169	if (rc != 0)
170		errc(1, rc, "pthread_mutex_destroy(newfiles)");
171	rc = pthread_cond_destroy(&newfiles.wait);
172	if (rc != 0)
173		errc(1, rc, "pthread_cond_destroy(newfiles)");
174	rc = pthread_mutex_destroy(&renamedfiles.mtx);
175	if (rc != 0)
176		errc(1, rc, "pthread_mutex_destroy(renamedfiles)");
177	rc = pthread_cond_destroy(&renamedfiles.wait);
178	if (rc != 0)
179		errc(1, rc, "pthread_cond_destroy(renamedfiles)");
180	rmdir(dirname1);
181	rmdir(dirname2);
182	free(dirname1);
183	free(dirname2);
184
185	exit(0);
186}
187
188void *
189loop_create(void *arg __unused)
190{
191	int i;
192	struct file *file;
193
194#ifdef __NP__
195	pthread_set_name_np(pthread_self(), __func__);
196#endif
197
198	for (i = 0; i < max; i++) {
199		file = malloc(sizeof(*file));
200		asprintf(&file->name, "%s/filename_too-long:%d", dirname1, i);
201		if (mkdir(file->name, 0666) == -1) {
202			warn("mkdir(%s)", file->name);
203			free(file->name);
204			free(file);
205			break;
206		}
207		LOCK(newfiles);
208		STAILQ_INSERT_TAIL(&newfiles.list, file, next);
209		UNLOCK(newfiles);
210		SIGNAL(newfiles);
211	}
212	exited = 1;
213	SIGNAL(newfiles);
214	pthread_exit(NULL);
215}
216
217void *
218loop_rename(void *arg __unused)
219{
220	char *filename, *newname;
221	struct file *file;
222
223#ifdef	__NP__
224	pthread_set_name_np(pthread_self(), __func__);
225#endif
226
227	for ( ;; ) {
228		LOCK(newfiles);
229		while (STAILQ_EMPTY(&newfiles.list) && exited < 1)
230			WAIT(newfiles);
231		if (STAILQ_EMPTY(&newfiles.list) && exited == 1) {
232			UNLOCK(newfiles);
233			break;
234		}
235		file = STAILQ_FIRST(&newfiles.list);
236		STAILQ_REMOVE_HEAD(&newfiles.list, next);
237		UNLOCK(newfiles);
238		filename = strrchr(file->name, '/');
239		asprintf(&newname, "%s/%s", dirname2, filename);
240		if (rename(file->name, newname) == -1)
241			err(1, "rename(%s, %s)", file->name, newname);
242		free(file->name);
243		file->name = newname;
244		LOCK(renamedfiles);
245		STAILQ_INSERT_TAIL(&renamedfiles.list, file, next);
246		UNLOCK(renamedfiles);
247		SIGNAL(renamedfiles);
248	}
249	exited = 2;
250	SIGNAL(renamedfiles);
251	pthread_exit(NULL);
252}
253
254void *
255loop_unlink(void *arg __unused)
256{
257	struct file *file;
258
259#ifdef	__NP__
260	pthread_set_name_np(pthread_self(), __func__);
261#endif
262
263	for ( ;; ) {
264		LOCK(renamedfiles);
265		while (STAILQ_EMPTY(&renamedfiles.list) && exited < 2)
266			WAIT(renamedfiles);
267		if (STAILQ_EMPTY(&renamedfiles.list) && exited == 2) {
268			UNLOCK(renamedfiles);
269			break;
270		}
271		file = STAILQ_FIRST(&renamedfiles.list);
272		STAILQ_REMOVE_HEAD(&renamedfiles.list, next);
273		UNLOCK(renamedfiles);
274		rmdir(file->name);
275		free(file->name);
276		free(file);
277	}
278	pthread_exit(NULL);
279}
280