1#!/bin/sh 2 3# 4# Copyright (c) 2010 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# Vnode reference leak test scenario by kib@. 30# Will fail with "umount: unmount of /mnt5 failed: Device busy" 31# vnode leak not seen on HEAD. 32 33[ `id -u ` -ne 0 ] && echo "Must be root!" && exit 1 34 35. ../default.cfg 36here=`pwd` 37mounts=2 # Number of parallel scripts 38D=$diskimage 39 40[ -d "$RUNDIR" ] || mkdir $RUNDIR 41cd $RUNDIR 42 43if [ $# -eq 0 ]; then 44 sed '1,/^EOF/d' < $here/$0 > vunref.c 45 mycc -o /tmp/vunref -Wall -Wextra -O2 vunref.c 46 rm -f vunref.c 47 cd $here 48 49 rm -f $RUNDIR/active.* 50 for i in `jot $mounts`; do 51 m=$(( i + mdstart - 1 )) 52 [ ! -d ${mntpoint}$m ] && mkdir ${mntpoint}$m 53 mount | grep "$mntpoint" | grep -q md$m && umount -f ${mntpoint}$m 54 mdconfig -l | grep -q md$m && mdconfig -d -u $m 55 56 dd if=/dev/zero of=$D.$m bs=1m count=10 status=none 57 mdconfig -a -t vnode -f $D.$m -u $m 58 bsdlabel -w md$m auto 59 newfs md${m}$part > /dev/null 2>&1 60 done 61 62 # start the parallel tests 63 for i in `jot $mounts`; do 64 m=$((i + mdstart - 1)) 65 $0 mmap $m & 66 sleep 0.2 67 $0 $m & 68 done 69 70 sleep 2 71 72 while [ ! -z "`ls $RUNDIR/active.* 2>/dev/null`" ] ; do 73 ../testcases/swap/swap -t 2m -i 20 74 done 75 wait 76 77 for i in `jot $mounts`; do 78 m=$((i + mdstart - 1)) 79 mdconfig -d -u $m 80 rm -f $D$m 81 done 82 rm -f /tmp/vunref $RUNDIR/active.* $diskimage.* ${mntpoint}*/p* 83else 84 if [ $1 = mmap ]; then 85 touch $RUNDIR/active.$2 86 for i in `jot 500`; do 87 cd ${mntpoint}$2 88 /tmp/vunref > /dev/null 2>&1 89 cd / 90 [ -f $RUNDIR/active.$2 ] || exit 91 sleep 0.1 92 done 93 rm -f $RUNDIR/active.$2 94 else 95 # The test: Parallel mount and unmounts 96 m=$1 97 mount $opt /dev/md${m}$part ${mntpoint}$m 98 while [ -f $RUNDIR/active.$m ] ; do 99 sleep 0.1 100 n=0 101 while mount | grep -qw $mntpoint$m; do 102 umount ${mntpoint}$m > /dev/null 2>&1 && n=0 103 if [ $((n += 1)) -gt 600 ]; then 104 echo "*** Leak detected ***" 105 fstat $mntpoint$m 106 rm -f $RUNDIR/active.* 107 exit 1 108 fi 109 sleep 0.1 110 done 111 mount $opt /dev/md${m}$part ${mntpoint}$m 112 done 113 mount | grep "$mntpoint" | grep -q md$m && umount ${mntpoint}$m 114 fi 115fi 116exit 117EOF 118#include <sys/param.h> 119#include <sys/mman.h> 120#include <sys/mount.h> 121#include <sys/stat.h> 122#include <sys/wait.h> 123#include <err.h> 124#include <errno.h> 125#include <fcntl.h> 126#include <stdio.h> 127#include <stdlib.h> 128#include <string.h> 129#include <unistd.h> 130 131#define INPUTFILE "/bin/date" 132 133int 134test(void) 135{ 136 int i; 137 pid_t pid; 138 char file[128]; 139 int fdin, fdout; 140 char *src, *dst; 141 struct stat statbuf; 142 143 pid = getpid(); 144 for (i = 0; i < 100; i++) { 145 sprintf(file,"p%05d.%05d", pid, i); 146 147 if ((fdin = open(INPUTFILE, O_RDONLY)) < 0) 148 err(1, INPUTFILE); 149 150 if ((fdout = open(file, O_RDWR | O_CREAT | O_TRUNC, 0600)) < 0) 151 err(1, "%s", file); 152 153 if (fstat(fdin, &statbuf) < 0) 154 err(1, "fstat error"); 155 156 if (lseek(fdout, statbuf.st_size - 1, SEEK_SET) == -1) 157 err(1, "lseek error"); 158 159 /* write a dummy byte at the last location */ 160 if (write(fdout, "", 1) != 1) 161 err(1, "write error"); 162 163 if ((src = mmap(0, statbuf.st_size, PROT_READ, MAP_SHARED, fdin, 0)) == 164 (caddr_t) - 1) 165 err(1, "mmap error for input"); 166 167 if ((dst = mmap(0, statbuf.st_size, PROT_READ | PROT_WRITE, 168 MAP_SHARED, fdout, 0)) == (caddr_t) - 1) 169 err(1, "mmap error for output"); 170 171 memcpy(dst, src, statbuf.st_size); 172 173 if (munmap(src, statbuf.st_size) == -1) 174 err(1, "munmap"); 175 close(fdin); 176 177 if (munmap(dst, statbuf.st_size) == -1) 178 err(1, "munmap"); 179 close(fdout); 180 181 if (unlink(file) == -1) 182 err(3, "unlink(%s)", file); 183 } 184 185 return (0); 186} 187 188int 189main() 190{ 191 int i; 192 char path[MAXPATHLEN+1]; 193 struct statfs buf; 194 195 if (getcwd(path, sizeof(path)) == NULL) 196 err(1, "getcwd()"); 197 198 if (statfs(path, &buf) < 0) 199 err(1, "statfs(%s)", path); 200 201 if (!strcmp(buf.f_mntonname, "/")) 202 return (1); 203 204 for (i = 0; i < 2; i++) { 205 if (fork() == 0) 206 test(); 207 } 208 for (i = 0; i < 2; i++) 209 wait(NULL); 210 211 return (0); 212} 213