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