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, 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 while (dirs[0] > MXDIRS && share[R2] == 0) 160 usleep(SLPTIME); 161 while ((r = mkdir(path, 0777)) == -1) { 162 if (errno != EMLINK) 163 err(1, "mkdir(%s) @ %d", path, 164 __LINE__); 165 usleep(SLPTIME); 166 if (share[2] == 1) 167 break; 168 } 169 if (r == 0) { 170 atomic_add_int(&dirs[0], 1); 171 i++; 172 } 173 } 174 175 _exit(0); 176 } 177 178 i = 0; 179 setproctitle("rmdir"); 180 while (dirs[0] > 0 || share[R2] == 0) { 181 if (dirs[0] < MXDIRS / 2) 182 usleep(SLPTIME); 183 snprintf(path, sizeof(path), "%s/d.%d.%d", arg, pid, i); 184 while (lstat(path, &sb) == -1 && share[R2] == 0) { 185 usleep(SLPTIME); 186 } 187 if (rmdir(path) == -1) { 188 if (errno != ENOENT) 189 err(1, "rmdir(%s)", path); 190 } else { 191 atomic_add_int(&dirs[0], -1); 192 i++; 193 } 194 } 195 waitpid(pd, NULL, 0); 196 waitpid(fpid, NULL, 0); 197 198 chdir(".."); 199 if ((rmdir(dir)) == -1) 200 err(1, "unlink(%s)", dir); 201 202 _exit(0); 203} 204 205int 206main(int argc, char *argv[]) 207{ 208 size_t len; 209 int e, i, pids[PARALLEL], status; 210 211 if (argc != 2) 212 errx(1, "Usage: %s <path>", argv[0]); 213 arg = argv[1]; 214 215 e = 0; 216 len = PAGE_SIZE; 217 if ((share = mmap(NULL, len, PROT_READ | PROT_WRITE, 218 MAP_ANON | MAP_SHARED, -1, 0)) == MAP_FAILED) 219 err(1, "mmap"); 220 221 share[R1] = 0; 222 for (i = 0; i < PARALLEL; i++) { 223 if ((pids[i] = fork()) == 0) 224 test(i); 225 } 226 sleep(RUNTIME); 227 share[R2] = 1; 228 for (i = 0; i < PARALLEL; i++) { 229 waitpid(pids[i], &status, 0); 230 e += status == 0 ? 0 : 1; 231 } 232 233 return (e); 234} 235