xref: /freebsd/tools/test/stress2/misc/namecache2.sh (revision acb1f1269c6f4ff89a0d28ba742f6687e9ef779d)
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