1#!/bin/sh 2 3# 4# Copyright (c) 2008 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# $FreeBSD$ 29# 30 31[ `id -u ` -ne 0 ] && echo "Must be root!" && exit 1 32 33 34. ../default.cfg 35 36# Test scenario by jhb@ 37 38odir=`pwd` 39cd /tmp 40sed '1,/^EOF/d' < $odir/$0 > nfsrename.c 41cc -o nfsrename -Wall nfsrename.c 42rm -f nfsrename.c 43cd $odir 44 45mount | grep "$mntpoint" | grep nfs > /dev/null && umount $mntpoint 46mount -t nfs -o tcp -o retrycnt=3 -o intr -o soft -o rw 127.0.0.1:/tmp $mntpoint 47 48 49#export RUNDIR=$mntpoint/stressX 50#export runRUNTIME=2m 51#(cd /home/pho/stress2; ./run.sh disk.cfg) & 52 53for i in `jot 10`; do 54 /tmp/nfsrename $mntpoint/nfsrename.$i & 55done 56for i in `jot 10`; do 57 wait 58done 59killall nfsrename 60rm -f $mntpoint/nfsrename.* 61 62umount $mntpoint > /dev/null 2>&1 63while mount | grep "$mntpoint" | grep -q nfs; do 64 umount -f $mntpoint > /dev/null 2>&1 65done 66 67rm -f /tmp/nfsrename 68exit 69 70EOF 71/* 72 * Try to expose races with doing renames over NFS that require silly 73 * renames. This results in 2 different RENAME RPCs leaving a race 74 * window where the file may not exist. It also appears that FreeBSD 75 * with shared lookups in NFS can get confused and possibly reference 76 * the sillyrenamed file in lookup but the file is deleted by the time 77 * open gets to it. 78 */ 79 80#include <err.h> 81#include <libgen.h> 82#include <limits.h> 83#include <stdio.h> 84#include <stdlib.h> 85#include <unistd.h> 86 87const char *filename; 88const char *dir; 89 90static void 91usage(void) 92{ 93 94 fprintf(stderr, "nfsrename: [-n children] file\n"); 95 exit(1); 96} 97 98static void 99read_file(void) 100{ 101 FILE *fp; 102 char buffer[4096]; 103 104 fp = fopen(filename, "r"); 105 if (fp == NULL) { 106 warn("fopen"); 107 return; 108 } 109 while (!feof(fp)) { 110 if (fread(buffer, sizeof(buffer), 1, fp) < sizeof(buffer)) 111 break; 112 } 113 if (ferror(fp)) 114 warnx("fread encountered an error"); 115 fclose(fp); 116} 117 118static void 119write_file(void) 120{ 121 FILE *fp; 122 char path[1024]; 123 int fd; 124 125 snprintf(path, sizeof(path), "%s/nfsrename.XXXXXX", dir); 126 fd = mkstemp(path); 127 if (fd < 0) { 128 warn("mkstemp"); 129 return; 130 } 131 132 fp = fdopen(fd, "w"); 133 if (fp == NULL) { 134 warn("fopen:writer"); 135 close(fd); 136 unlink(path); 137 } 138 139 fprintf(fp, "blah blah blah garbage %ld\n", random()); 140 fclose(fp); 141 if (rename(path, filename) < 0) { 142 warn("rename"); 143 unlink(path); 144 } 145} 146 147static void 148random_sleep(int base, int slop) 149{ 150 long val; 151 152 val = random() % slop; 153 usleep(base + val); 154} 155 156static void 157child(void) 158{ 159 160 for (;;) { 161 random_sleep(500, 50); 162 read_file(); 163 } 164 exit(0); 165} 166 167int 168main(int ac, char **av) 169{ 170 long i, nchild; 171 char *cp; 172 int ch; 173 174 nchild = 1; 175 while ((ch = getopt(ac, av, "n:")) != -1) { 176 switch (ch) { 177 case 'n': 178 nchild = strtol(optarg, &cp, 0); 179 if (*cp != '\0') 180 errx(1, "Invalid count %s", optarg); 181 break; 182 case '?': 183 default: 184 usage(); 185 } 186 } 187 ac -= optind; 188 av += optind; 189 190 if (ac == 0) 191 errx(1, "Missing filename"); 192 else if (ac > 1) 193 errx(1, "Extra arguments"); 194 195 filename = av[0]; 196 dir = dirname(filename); 197 srandomdev(); 198 write_file(); 199 200 for (i = 0; i < nchild; i++) { 201 switch (fork()) { 202 case 0: 203 child(); 204 case -1: 205 err(1, "fork"); 206 } 207 } 208 209 for (i = 0; i < 10000; i++) { 210 random_sleep(1500, 1000); 211 write_file(); 212 } 213 214 return (0); 215} 216