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# Demonstrate "wrong handling for suspend". 30# https://www.mail-archive.com/freebsd-current@freebsd.org/msg166333.html 31 32# Variation of nfs15lockd.sh 33 34# Threads marked as stopped, but can not be killed. 35# Fixed by r302215. 36 37# Also seen and not fixed: 38# $ fstat -mf /mnt 39# USER CMD PID FD MOUNT INUM MODE SZ|DV R/W 40# $ umount /mnt 41# umount: unmount of /mnt failed: Device busy 42# $ 43 44[ `id -u ` -ne 0 ] && echo "Must be root!" && exit 1 45pgrep -q lockd || { echo "lockd not running."; exit 1; } 46 47. ../default.cfg 48 49[ -z "$nfs_export" ] && exit 0 50ping -c 2 `echo $nfs_export | sed 's/:.*//'` > /dev/null 2>&1 || 51 exit 0 52 53here=`pwd` 54cd /tmp 55sed '1,/^EOF/d' < $here/$0 > nfs15lockd3.c 56mycc -o nfs15lockd3 -Wall -Wextra -O2 -g nfs15lockd3.c -lpthread || exit 1 57rm -f nfs15lockd3.c 58cd $here 59 60mount | grep "on $mntpoint " | grep nfs > /dev/null && umount $mntpoint 61 62[ $# -ne 0 ] && 63 # Problem only seen with lockd 64 { echo "Not using lockd"; debug="-o nolockd"; } 65mount -t nfs -o tcp -o retrycnt=3 -o soft -o rw $debug \ 66 $nfs_export $mntpoint 67sleep 2 68 69s=0 70lockf -t 10 $mntpoint/$$.lock sleep 2 > /tmp/$$.log 2>&1 71if grep -q "No locks available" /tmp/$$.log; then 72 echo "Is lockd running on the remote host?" 73 rm /tmp/$$.log 74 s=1 75fi 76 77wd=$mntpoint/nfs15lockd3-`jot -rc 8 a z | tr -d '\n'`.dir 78rm -rf $wd 79mkdir $wd 80 81(cd $wd; /tmp/nfs15lockd3) & 82start=`date '+%s'` 83while [ $((`date '+%s'` - start)) -lt 600 ]; do 84 pgrep -q nfs15lockd || break 85 sleep 2 86done 87if pgrep -q nfs15lockd; then 88 s=2 89 echo "Thread suspension issue:" 90 ps -lx | grep -v grep | grep nfs15lockd | grep "T+" | \ 91 awk '{print $2}' | while read pid; do 92 ps -lp$pid 93 procstat -k $pid 94 kill -9 $pid 95 done 96 pkill nfs15lockd 97fi 98wait 99rm -rf $wd 100 101n=0 102while mount | grep "on $mntpoint " | grep -q nfs; do 103 umount $mntpoint && break 104 n=$((n + 1)) 105 if [ $n -gt 60 ]; then 106 fstat -mf $mntpoint 107 s=3 108 break 109 fi 110 sleep 2 111done 112 113rm -f /tmp/nfs15lockd3 nfs15lockd3.core file.0????? 114exit $s 115EOF 116#include <sys/stat.h> 117#include <sys/param.h> 118#include <sys/mman.h> 119#include <sys/wait.h> 120 121#include <machine/atomic.h> 122 123#include <err.h> 124#include <errno.h> 125#include <fcntl.h> 126#include <pthread.h> 127#include <signal.h> 128#include <stdio.h> 129#include <stdlib.h> 130#include <string.h> 131#include <unistd.h> 132 133#define PARALLEL 4 134#define RUNTIME 300 135#define SYNC 0 136 137volatile u_int *share; 138 139static void * 140t1(void *data __unused) 141{ 142 atomic_add_int(&share[SYNC], 1); 143 usleep(arc4random() % 8000); 144 raise(SIGABRT); 145 146 return (NULL); 147} 148 149static void * 150t2(void *data __unused) 151{ 152 int fd, i, r; 153 char file[80]; 154 155 for (i = 0; i < 10; i++) { 156 atomic_add_int(&share[SYNC], 1); 157 snprintf(file, sizeof(file), "file.%06d", i); 158 if ((fd = open(file, O_WRONLY | O_CREAT | O_APPEND, 159 DEFFILEMODE)) == -1) 160 err(1, "open(%s)", file); 161 do { 162 r = lockf(fd, F_LOCK, 0); 163 } while (r == -1 && (errno == EDEADLK || errno == EINTR)); 164 if (r == -1) 165 err(1, "lockf(%s, F_LOCK)", file); 166 write(fd, "x", 1); 167 usleep(arc4random() % 1000); 168 if (lseek(fd, 0, SEEK_SET) == -1) 169 err(1, "lseek"); 170 if (lockf(fd, F_ULOCK, 0) == -1) 171 err(1, "lockf(%s, F_ULOCK)", file); 172 close(fd); 173 } 174 175 return (NULL); 176} 177 178int 179test(void) 180{ 181 pthread_t tid[3]; 182 int i, rc; 183 184 for (i = 0; i < 5; i++) { 185 if ((rc = pthread_create(&tid[0], NULL, t2, NULL)) == -1) 186 errc(1, rc, "pthread_create"); 187 if ((rc = pthread_create(&tid[1], NULL, t2, NULL)) == -1) 188 errc(1, rc, "pthread_create"); 189 if ((rc = pthread_create(&tid[2], NULL, t1, NULL)) == -1) 190 errc(1, rc, "pthread_create"); 191 192 if ((rc = pthread_join(tid[0], NULL)) == -1) 193 errc(1, rc, "pthread_join"); 194 if ((rc = pthread_join(tid[1], NULL)) == -1) 195 errc(1, rc, "pthread_join"); 196 if ((rc = pthread_join(tid[2], NULL)) == -1) 197 errc(1, rc, "pthread_join"); 198 } 199 200 _exit(0); 201} 202 203int 204main(void) 205{ 206 pid_t pids[PARALLEL]; 207 size_t len; 208 time_t start; 209 int i, n, status; 210 211 len = PAGE_SIZE; 212 if ((share = mmap(NULL, len, PROT_READ | PROT_WRITE, 213 MAP_ANON | MAP_SHARED, -1, 0)) == MAP_FAILED) 214 err(1, "mmap"); 215 216 start = time(NULL); 217 n = 0; 218 while (time(NULL) - start < RUNTIME) { 219 n++; 220 for (i = 0; i < PARALLEL; i++) { 221 if ((pids[i] = fork()) == 0) 222 test(); 223 } 224 225 for(;;) { 226 if (share[SYNC] > 0) 227 atomic_add_int(&share[SYNC], -1); 228 for (i = 0; i < PARALLEL; i++) 229 kill(pids[i], SIGSTOP); 230 usleep(1000); 231 for (i = 0; i < PARALLEL; i++) 232 kill(pids[i], SIGCONT); 233 usleep(100 + arc4random() % 400); 234 if (share[SYNC] == 0) { /* If all procs are done */ 235 usleep(500); 236 if (share[SYNC] == 0) 237 break; 238 } 239 } 240 241 for (i = 0; i < PARALLEL; i++) { 242 if (waitpid(pids[i], &status, 0) != pids[i]) 243 err(1, "waitpid"); 244 } 245 if (n > 2) 246 break; 247 } 248 249 return (0); 250} 251