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