1#!/bin/sh 2 3# 4# Copyright (c) 2013 Peter Holm 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# UFS cache inconsistancy for rename(2) demonstrated 30# Fails with: 31# ls -ali /mnt 32# ls: tfa1022: No such file or directory 33# Fixed by r248422 34 35# Test scenario obtained from Rick Miller <vmiller at hostileadmin com> 36 37[ `id -u ` -ne 0 ] && echo "Must be root!" && exit 1 38 39# This threaded test is designed for MP. 40[ `sysctl hw.ncpu | sed 's/.* //'` -eq 1 ] && exit 0 41 42. ../default.cfg 43 44odir=`pwd` 45cd /tmp 46sed '1,/^EOF/d' < $odir/$0 > namecache2.c 47rm -f /tmp/namecache2 48mycc -o namecache2 -Wall -Wextra -g -O2 namecache2.c -lpthread || exit 1 49rm -f namecache2.c 50cd $odir 51 52mount | grep $mntpoint | grep -q /dev/md && umount -f $mntpoint 53mdconfig -l | grep -q md$mdstart && mdconfig -d -u $mdstart 54mdconfig -a -t swap -s 1g -u $mdstart 55bsdlabel -w md$mdstart auto 56newfs $newfs_flags md${mdstart}$part > /dev/null 57mount /dev/md${mdstart}$part $mntpoint 58 59(cd $mntpoint; /tmp/namecache2) 60 61f=`(cd $mntpoint; echo *)` 62if [ "$f" != '*' ]; then 63 echo FAIL 64 echo "echo $mntpoint/*" 65 echo $mntpoint/* 66 echo "" 67 echo "ls -ali $mntpoint" 68 ls -ali $mntpoint 69 echo "" 70 echo "fsdb -r /dev/md${mdstart}$part" 71 fsdb -r /dev/md${mdstart}$part <<-EF 72 ls 73 quit 74 EF 75fi 76 77while mount | grep $mntpoint | grep -q /dev/md; do 78 umount $mntpoint || sleep 1 79done 80mdconfig -d -u $mdstart 81rm -f /tmp/namecache2 82exit 0 83EOF 84/* 85 * NOTE: This must be run with the current working directory on a local UFS 86 * disk partition, to demonstrate a FreeBSD namecache bug. I have never seen 87 * this bug happen with an NFS partition. 88 */ 89 90#include <pthread.h> 91#include <err.h> 92#include <errno.h> 93#include <stdio.h> 94#include <string.h> 95#include <unistd.h> 96#include <fcntl.h> 97#include <stdbool.h> 98#include <sys/types.h> 99#include <sys/stat.h> 100#include <time.h> 101 102int stopping = false; 103char *pFilename = 0; 104 105static void * 106statThread(void *arg __unused) 107{ 108 109 struct stat statData; 110 int rc; 111 112 for (;;) { 113 while (pFilename == 0) { 114 if (stopping) 115 return 0; 116 } 117 118 rc = stat(pFilename, &statData); 119 if (rc < 0 && errno != ENOENT) { 120 printf(" statThread stat() on %s failed with errno %d\n", 121 pFilename, errno); 122 return 0; 123 } 124 } 125 126 return 0; 127} 128 129int 130main(void) 131{ 132 char filename1 [20], filename2[20], filename3[20]; 133 pthread_t threadId; 134 struct stat statData; 135 int result, fd; 136 unsigned int number; 137 struct timespec period; 138 time_t start; 139 140 sprintf(filename1, "tfa0"); 141 fd = open(filename1, O_CREAT, S_IRWXU); 142 if (fd < 0) { 143 printf("open(O_CREAT) on %s failed with errno %d\n", filename1, errno); 144 return 0; 145 } 146 if (close(fd) < 0) { 147 printf("close() on %s failed with errno %d\n", filename1, errno); 148 return 0; 149 } 150 result = pthread_create(&threadId, NULL, statThread, NULL); 151 if (result < 0) 152 errc(1, result, "pthread_create()"); 153 154 start = time(NULL); 155 for (number = 0; number < 0x001FFFFF; number += 2) { 156 sprintf(filename1, "tfa%u", number); 157 sprintf(filename2, "tfa%u", number + 1); 158 sprintf(filename3, "tfa%u", number + 2); 159 if (rename(filename1, filename2) < 0) { 160 printf(" rename1() from %s to %s failed with errno %d\n", 161 filename1, filename2, errno); 162 return 0; 163 } 164 pFilename = filename3; 165 166 if (rename(filename2, filename3) < 0) { 167 printf(" rename2() from %s to %s failed with errno %d\n", 168 filename2, filename3, errno); 169 return 0; 170 } 171 pFilename = 0; 172 period.tv_sec = 0; 173 period.tv_nsec = 500; 174 nanosleep(&period, 0); 175 176 if (stat(filename3, &statData) < 0) { 177 printf("stat(%s) failed with errno %d\n", filename3, errno); 178 stopping = true; 179 period.tv_sec = 0; 180 period.tv_nsec = 500; 181 nanosleep(&period, 0); 182 return 0; 183 } 184 if (time(NULL) - start > 1200) { 185 fprintf(stderr, "Test timed out.\n"); 186 break; 187 } 188 } 189 unlink(filename3); 190 191 return 0; 192} 193