xref: /freebsd/tools/test/stress2/misc/namecache2.sh (revision 9768746b)
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
55newfs $newfs_flags md$mdstart > /dev/null
56mount /dev/md$mdstart $mntpoint
57
58(cd $mntpoint; /tmp/namecache2)
59
60f=`(cd $mntpoint; echo *)`
61if [ "$f" != '*' ]; then
62	echo FAIL
63	echo "echo $mntpoint/*"
64	echo $mntpoint/*
65	 echo ""
66	echo "ls -ali $mntpoint"
67	ls -ali $mntpoint
68	echo ""
69	echo "fsdb -r /dev/md$mdstart"
70	fsdb -r /dev/md$mdstart <<-EF
71	ls
72	quit
73	EF
74fi
75
76while mount | grep $mntpoint | grep -q /dev/md; do
77	umount $mntpoint || sleep 1
78done
79mdconfig -d -u $mdstart
80rm -f /tmp/namecache2
81exit 0
82EOF
83/*
84 * NOTE: This must be run with the current working directory on a local UFS
85 * disk partition, to demonstrate a FreeBSD namecache bug. I have never seen
86 * this bug happen with an NFS partition.
87 */
88
89#include <pthread.h>
90#include <err.h>
91#include <errno.h>
92#include <stdio.h>
93#include <string.h>
94#include <unistd.h>
95#include <fcntl.h>
96#include <stdbool.h>
97#include <sys/types.h>
98#include <sys/stat.h>
99#include <time.h>
100
101int stopping = false;
102char *pFilename = 0;
103
104static void    *
105statThread(void *arg __unused)
106{
107
108	struct stat statData;
109	int rc;
110
111	for (;;) {
112		while (pFilename == 0) {
113			if (stopping)
114				return 0;
115		}
116
117		rc = stat(pFilename, &statData);
118		if (rc < 0 && errno != ENOENT) {
119			printf(" statThread stat() on %s failed with errno %d\n",
120			       pFilename, errno);
121			return 0;
122		}
123	}
124
125	return 0;
126}
127
128int
129main(void)
130{
131	char filename1 [20], filename2[20], filename3[20];
132	pthread_t threadId;
133	struct stat statData;
134	int result, fd;
135	unsigned int number;
136	struct timespec	period;
137	time_t start;
138
139	sprintf(filename1, "tfa0");
140	fd = open(filename1, O_CREAT, S_IRWXU);
141	if (fd < 0) {
142		printf("open(O_CREAT) on %s failed with errno %d\n", filename1, errno);
143		return 0;
144	}
145	if (close(fd) < 0) {
146		printf("close() on %s failed with errno %d\n", filename1, errno);
147		return 0;
148	}
149	result = pthread_create(&threadId, NULL, statThread, NULL);
150	if (result < 0)
151		errc(1, result, "pthread_create()");
152
153	start = time(NULL);
154	for (number = 0; number < 0x001FFFFF; number += 2) {
155		sprintf(filename1, "tfa%u", number);
156		sprintf(filename2, "tfa%u", number + 1);
157		sprintf(filename3, "tfa%u", number + 2);
158		if (rename(filename1, filename2) < 0) {
159			printf(" rename1() from %s to %s failed with errno %d\n",
160			       filename1, filename2, errno);
161			return 0;
162		}
163		pFilename = filename3;
164
165		if (rename(filename2, filename3) < 0) {
166			printf(" rename2() from %s to %s failed with errno %d\n",
167			       filename2, filename3, errno);
168			return 0;
169		}
170		pFilename = 0;
171		period.tv_sec = 0;
172		period.tv_nsec = 500;
173		nanosleep(&period, 0);
174
175		if (stat(filename3, &statData) < 0) {
176			printf("stat(%s) failed with errno %d\n", filename3, errno);
177			stopping = true;
178			period.tv_sec = 0;
179			period.tv_nsec = 500;
180			nanosleep(&period, 0);
181			return 0;
182		}
183		if (time(NULL) - start > 1200) {
184			fprintf(stderr, "Test timed out.\n");
185			break;
186		}
187	}
188	unlink(filename3);
189
190	return 0;
191}
192