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