1193323Sed#!/bin/sh
2193323Sed
3193323Sed#
4193323Sed# SPDX-License-Identifier: BSD-2-Clause
5193323Sed#
6193323Sed# Copyright (c) 2020 Peter Holm <pho@FreeBSD.org>
7193323Sed#
8193323Sed# Redistribution and use in source and binary forms, with or without
9193323Sed# modification, are permitted provided that the following conditions
10193323Sed# are met:
11193323Sed# 1. Redistributions of source code must retain the above copyright
12193323Sed#    notice, this list of conditions and the following disclaimer.
13193323Sed# 2. Redistributions in binary form must reproduce the above copyright
14193323Sed#    notice, this list of conditions and the following disclaimer in the
15193323Sed#    documentation and/or other materials provided with the distribution.
16193323Sed#
17193323Sed# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18193323Sed# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19193323Sed# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20199481Srdivacky# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21198090Srdivacky# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22193323Sed# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23193323Sed# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24198090Srdivacky# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25218893Sdim# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26198090Srdivacky# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27218893Sdim# SUCH DAMAGE.
28218893Sdim#
29198090Srdivacky
30198090Srdivacky# Hunt for "panic: ufsdirhash_dirtrunc: bad offset"
31198090Srdivacky# by making the directory inode grow into the indirect blocks.
32198090Srdivacky
33198090Srdivacky# Truncate directories larger than 12 * block_size bytes
34198090Srdivacky# default is 12 * 32768 = 393216, 384k
35198090Srdivacky
36193323Sed# No problems seen.
37193323Sed
38193323Sed. ../default.cfg
39193323Sed[ `id -u` -ne 0 ] && echo "Must be root!" && exit 1
40193323Sed
41193323Seddir=/tmp
42193323Sedodir=`pwd`
43199989Srdivackycd $dir
44193323Sedsed '1,/^EOF/d' < $odir/$0 > $dir/indir.c
45193323Sedsed -i '' -e "s#MNTPOINT#$mntpoint#g" $dir/indir.c
46193323Sedmycc -o indir -Wall -Wextra -O0 -g indir.c || exit 1
47193323Sedrm -f indir.c
48193323Sedcd $odir
49193323Sed
50193323Sedset -e
51193323Sedmount | grep "on $mntpoint " | grep -q /dev/md && umount -f $mntpoint
52193323Sed[ -c /dev/md$mdstart ] &&  mdconfig -d -u $mdstart
53193323Sedmdconfig -a -t swap -s 1g -u $mdstart
54193323Sednewfs -j -n -b 16384 -f 2048 -i 2048 md$mdstart > /dev/null
55193323Sedmount /dev/md$mdstart $mntpoint
56193323Sedifree=`df -i $mntpoint | tail -1 | awk '{print $7 - 50}'`
57193323Sedset +e
58199989Srdivacky
59193323Sedif [ $dtrace ]; then
60193323Sed	dtrace -w -n '*ufsdirhash_dirtrunc:entry {@rw[execname,probefunc] = \
61193323Sed	    count(); }' &
62193323Sed	dpid=$!
63193323Sed	sleep 2
64193323Sedfi
65193323Sed
66193323Sed/tmp/indir $mntpoint $ifree
67193323Sed
68193323Sedif [ $dtrace ]; then
69193323Sed	kill -s TERM $dpid
70193323Sed	wait $dpid
71193323Sedfi
72193323Sed
73193323Sedfor i in `jot 6`; do
74193323Sed	mount | grep -q "on $mntpoint " || break
75193323Sed	umount $mntpoint && break || sleep 10
76193323Sed	[ $i -eq 6 ] &&
77193323Sed	    { echo FATAL; fstat -mf $mntpoint; exit 1; }
78193323Seddone
79193323Sedmdconfig -d -u $mdstart
80193323Sedrm -f /tmp/indir
81193323Sedif [ $dtrace ]; then
82193323Sed	while pgrep -q dtrace; do sleep 1; done
83193323Sed	kldstat | grep -q dtraceall &&
84193323Sed	    kldunload dtraceall.ko
85193323Sedfi
86193323Sedexit 0
87193323SedEOF
88193323Sed#include <sys/param.h>
89193323Sed#include <sys/mman.h>
90193323Sed#include <sys/stat.h>
91193323Sed#include <sys/wait.h>
92193323Sed
93193323Sed#include <err.h>
94193323Sed#include <errno.h>
95193323Sed#include <fcntl.h>
96193323Sed#include <stdatomic.h>
97193323Sed#include <stdio.h>
98193323Sed#include <stdlib.h>
99193323Sed#include <time.h>
100193323Sed#include <unistd.h>
101193323Sed
102193323Sedstatic long files;
103193323Sedstatic char *path;
104193323Sed
105193323Sed#define PARALLEL 64
106193323Sed#define RUNTIME (10 * 60)
107193323Sed
108193323Sedstatic void
109193323Sedtest(int idx)
110193323Sed{
111193323Sed	long j;
112198090Srdivacky	int fd;
113198090Srdivacky	pid_t pid;
114198090Srdivacky	char dir[128], file[128], new[128];
115198090Srdivacky
116193323Sed	sleep(1);
117193323Sed
118193323Sed	snprintf(dir, sizeof(dir), "%s/d%d", path, idx);
119193323Sed	if (mkdir(dir, 0755) == -1) {
120193323Sed		if (errno != EEXIST)
121193323Sed			err(1, "mkdir(%s)", dir);
122193323Sed	}
123193323Sed	if (chdir(dir) == -1)
124193323Sed		err(1, "chdir(%s)", dir);
125193323Sed
126193323Sed	pid = getpid();
127198090Srdivacky	for (j = 0; j < files; j++) {
128198090Srdivacky		sprintf(file,"p%05d.%05ld", pid, j);
129193323Sed		if ((fd = creat(file, 0660)) == -1)
130193323Sed			err(1, "creat(%s). %s:%d", file, __FILE__, __LINE__);
131193323Sed		if (fd != -1 && close(fd) == -1)
132193323Sed			err(2, "close(%ld)", j);
133193323Sed	}
134193323Sed
135193323Sed	for (j = 0; j < files; j++) {
136193323Sed		sprintf(file,"p%05d.%05ld", pid, j);
137193323Sed		sprintf(new,"p%05d.%05ld.old", pid, j);
138193323Sed		if (rename(file, new) == -1)
139193323Sed			err(1, "rename(%s, %s)", file, new);
140193323Sed	}
141193323Sed
142193323Sed	for (j = 0; j < files; j++) {
143193323Sed		sprintf(file,"p%05d.%05ld", pid, j);
144193323Sed		sprintf(new,"p%05d.%05ld.old", pid, j);
145193323Sed		if (rename(new, file) == -1)
146193323Sed			err(1, "rename(%s, %s)", new, file);
147193323Sed	}
148193323Sed
149193323Sed	for (j = 0; j < files; j++) {
150193323Sed		sprintf(file,"p%05d.%05ld", pid, j);
151193323Sed		if (unlink(file) == -1)
152193323Sed			warn("unlink(%s)", file);
153193323Sed
154193323Sed	}
155193323Sed	if (chdir("..") == -1)
156193323Sed		err(1, "chdir ..");
157198090Srdivacky
158198090Srdivacky	_exit(0);
159198090Srdivacky}
160198090Srdivacky
161198090Srdivackyint
162199989Srdivackymain(int argc, char *argv[])
163198090Srdivacky{
164199989Srdivacky	pid_t pids[PARALLEL];
165198090Srdivacky	time_t start;
166198090Srdivacky	int e, i, n, status;
167198090Srdivacky
168198090Srdivacky	if (argc != 3) {
169198090Srdivacky		fprintf(stderr, "Usage %s <path> <files>\n", argv[0]);
170198090Srdivacky		exit(1);
171193323Sed	}
172198090Srdivacky	path = argv[1];
173198090Srdivacky	files = atol(argv[2]) / PARALLEL;
174198090Srdivacky	fprintf(stderr, "Using %ld inodes per dir. %d threads. %ld inodes in total\n",
175198090Srdivacky		files, PARALLEL, files * PARALLEL);
176198090Srdivacky	e = n = 0;
177199989Srdivacky	start = time(NULL);
178198090Srdivacky	while ((time(NULL) - start) < RUNTIME && e == 0) {
179198090Srdivacky		fprintf(stderr, "Loop #%d\n", ++n);
180198090Srdivacky		for (i = 0; i < PARALLEL; i++) {
181198090Srdivacky			if ((pids[i] = fork()) == 0)
182193323Sed				test(i);
183218893Sdim			if (pids[i] == -1)
184218893Sdim				err(1, "fork()");
185218893Sdim		}
186218893Sdim		for (i = 0; i < PARALLEL; i++) {
187218893Sdim			if (waitpid(pids[i], &status, 0) == -1)
188218893Sdim				err(1, "waitpid(%d)", pids[i]);
189221345Sdim			if (status != 0) {
190218893Sdim				if (WIFSIGNALED(status))
191218893Sdim					fprintf(stderr,
192218893Sdim					    "pid %d exit signal %d\n",
193218893Sdim					    pids[i], WTERMSIG(status));
194221345Sdim			}
195221345Sdim			e += status == 0 ? 0 : 1;
196221345Sdim		}
197218893Sdim//		system("(cd MNTPOINT; umount MNTPOINT) > /dev/null 2>&1");
198218893Sdim	}
199218893Sdim
200218893Sdim	return (e);
201218893Sdim}
202218893Sdim