1#!/bin/sh 2 3# 4# Copyright (c) 2016 Dell EMC Isilon 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# fullpath NULL reference problem hunt. 30 31# From the commit log of r308407: 32# vn_fullpath1() checked VV_ROOT and then unreferenced 33# vp->v_mount->mnt_vnodecovered unlocked. This allowed unmount to race. 34# Lock vnode after we noticed the VV_ROOT flag. See comments for 35# explanation why unlocked check for the flag is considered safe. 36 37# 'panic: namei: garbage in ni_resflags: 1': 38# https://people.freebsd.org/~pho/stress/log/fullpath2.txt 39# Fixed by r367130 40 41[ `id -u ` -ne 0 ] && echo "Must be root!" && exit 1 42. ../default.cfg 43 44cont=/tmp/fullpath2.continue 45dir=/tmp 46odir=`pwd` 47cd $dir 48sed '1,/^EOF/d' < $odir/$0 > $dir/fullpath2.c 49mycc -o fullpath2 -Wall -Wextra -O2 -g fullpath2.c -lprocstat || exit 1 50rm -f fullpath2.c 51cd $odir 52 53mount | grep -q "on $mntpoint " && umount -f $mntpoint 54[ -c /dev/md$mdstart ] && mdconfig -d -u $mdstart 55 56mdconfig -a -t swap -s 1g -u $mdstart 57gpart create -s GPT md$mdstart > /dev/null || exit 1 58gpart add -t freebsd-ufs md$mdstart > /dev/null || exit 1 59newfs -n $newfs_flags md${mdstart}p1 > /dev/null || exit 1 60mount /dev/md${mdstart}p1 $mntpoint 61touch $mntpoint/marker $cont 62trap "rm -f $cont" EXIT INT 63 64daemon sh -c "(cd $odir/../testcases/swap; ./swap -t 4m -i 10 -l 100)" > \ 65 /dev/null 2>&1 66 67for i in `jot $(jot -r 1 2 10)`; do 68 /tmp/fullpath2 $mntpoint & 69 pids="$pids $!" 70done 71 72for i in `jot $(jot -r 1 2 5)`; do 73 while [ -e $cont ]; do find $mntpoint -ls > /dev/null 2>&1; done & 74 pidf="$pidf $!" 75done 76 77umounts=0 78while pgrep -q fullpath2; do 79 for i in `jot 30`; do 80 umount -f $mntpoint && umounts=$((umounts+1)) && 81 mount /dev/md${mdstart}p1 $mntpoint 82 sleep 2 83 done 84done 85echo "$umounts umounts" 86rm -f $cont 87while mount | grep -q "on $mntpoint "; do 88 umount -f $mntpoint 89done 90for i in $pids; do 91 wait $i 92done 93while pgrep -q swap; do 94 pkill -9 swap 95done 96 97kill $pidp $pidf > /dev/null 2>&1 98wait 99 100rm -f $mntpoint/file.* /tmp/fullpath2 fullpath2.core 101mdconfig -d -u $mdstart 102 103exit 0 104EOF 105#include <sys/param.h> 106#include <sys/mman.h> 107#include <sys/stat.h> 108#include <sys/wait.h> 109#include <sys/sysctl.h> 110#include <sys/user.h> 111 112#include <err.h> 113#include <fcntl.h> 114#include <libprocstat.h> 115#include <stdio.h> 116#include <stdlib.h> 117#include <string.h> 118#include <time.h> 119#include <unistd.h> 120 121static volatile u_int *share; 122 123#define NB 1024 124#define RUNTIME 300 125 126/* dtrace -w -n 'fbt::*vn_fullpath1:entry {@rw[execname,probefunc] = count(); }' */ 127 128static void 129getfiles(pid_t pid) 130{ 131 struct filestat_list *head; 132 struct kinfo_proc *p; 133 struct procstat *prstat; 134 unsigned int cnt; 135 136 if ((prstat = procstat_open_sysctl()) == NULL) 137 err(1, "procstat_open_sysctl"); 138 139 if ((p = procstat_getprocs(prstat, KERN_PROC_PID, 140 pid, &cnt)) == NULL) 141 err(1, "procstat_getprocs"); 142 143 if ((head = procstat_getfiles(prstat, p, 0)) == NULL) 144 err(1, "procstat_getfiles"); 145 146 procstat_freefiles(prstat, head); 147 procstat_freeprocs(prstat, p); 148 procstat_close(prstat); 149} 150 151int 152main(int argc, char *argv[]) 153{ 154 size_t len; 155 time_t start; 156 int fd[NB], i, n; 157 pid_t pid; 158 159 len = PAGE_SIZE; 160 if ((share = mmap(NULL, len, PROT_READ | PROT_WRITE, 161 MAP_ANON | MAP_SHARED, -1, 0)) == MAP_FAILED) 162 err(1, "mmap"); 163 164 if ((pid = fork()) == 0) { 165 setproctitle("getfiles"); 166 while (share[0] == 0) 167 getfiles(pid); 168 _exit(0); 169 } 170 171 char file[MAXPATHLEN + 1]; 172 char marker[MAXPATHLEN + 1]; 173 174 if (argc != 2) { 175 fprintf(stderr, "Usage: %s <file path>\n", argv[0]); 176 exit(1); 177 } 178 179 memset(fd, 0, sizeof(fd)); 180 snprintf(marker, sizeof(marker), "%s/marker", argv[1]); 181 i = n = 0; 182 start = time(NULL); 183 while (time(NULL) - start < RUNTIME) { 184 snprintf(file, sizeof(file), "%s/file.%06d.%02d", argv[1], getpid(), i); 185 if (access(marker, R_OK) == -1) 186 continue; 187 if (fd[i] > 0) 188 close(fd[i]); 189 if ((fd[i] = open(file, O_RDWR | O_CREAT | O_APPEND, 190 DEFFILEMODE)) == -1) { 191 if (errno != ENOENT && errno != EBUSY) 192 warn("open(%s)", file); 193 continue; 194 } 195 n++; 196 write(fd[i], "a", 1); 197 usleep(arc4random() % 400); 198 if (arc4random() % 100 < 10) { 199 close(fd[i]); 200 unlink(file); 201 fd[i] = 0; 202 } 203 i++; 204 i = i % NB; 205 } 206 share[0] = 1; 207 208 if (waitpid(pid, NULL, 0) != pid) 209 err(1, "waitpid"); 210 if (n < 100) 211 errx(1, "Short run: %d", n); 212 213 return (0); 214} 215