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