xref: /freebsd/tools/test/stress2/misc/holdcnt0.sh (revision 2b8331622f0b212cf3bb4fc4914a501e5321d506)
1#!/bin/sh
2
3#
4# Copyright (c) 2013 EMC Corp.
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# "panic: cluster_wbuild: page 0xc2eebc10 failed shared busing" seen.
30# "panic: vdrop: holdcnt 0" seen.
31# "panic: cleaned vnode isn't" seen.
32# OoVM seen with r285808:
33# https://people.freebsd.org/~pho/stress/log/holdcnt0.txt
34
35# Test scenario suggestion by alc@
36
37[ `id -u ` -ne 0 ] && echo "Must be root!" && exit 1
38[ `swapinfo | wc -l` -eq 1 ] && exit 0
39[ `sysctl -n hw.physmem` -lt $((32 * 1024 * 1024 * 1024)) ] && exit 0
40
41. ../default.cfg
42
43here=`pwd`
44cd /tmp
45sed '1,/^EOF/d' < $here/$0 > holdcnt0.c
46mycc -o holdcnt0 -Wall -Wextra -g holdcnt0.c || exit 1
47rm -f holdcnt0.c
48cd $here
49
50mount | grep $mntpoint | grep -q /dev/md && umount -f $mntpoint
51mdconfig -l | grep -q md$mdstart &&  mdconfig -d -u $mdstart
52mdconfig -a -t swap -s 5g -u $mdstart
53newfs md$mdstart > /dev/null
54mount /dev/md$mdstart $mntpoint
55
56(cd $mntpoint; /tmp/holdcnt0) &
57pid=$!
58sleep 5
59while kill -0 $! 2> /dev/null; do
60	(cd ../testcases/swap; ./swap -t 1m -i 1) > /dev/null 2>&1
61done
62wait $pid; s=$?
63
64while mount | grep -q md$mdstart; do
65	umount $mntpoint || sleep 1
66done
67mdconfig -d -u $mdstart
68rm -f /tmp/holdcnt0
69exit $s
70EOF
71/*
72   A test that causes the page daemon to generate cached pages
73   within a bunch of files and has some consumer that is trying to
74   allocate new pages to the same files.
75*/
76
77#include <sys/types.h>
78#include <sys/mman.h>
79#include <sys/stat.h>
80#include <sys/wait.h>
81
82#include <err.h>
83#include <errno.h>
84#include <fcntl.h>
85#include <setjmp.h>
86#include <signal.h>
87#include <stdio.h>
88#include <stdlib.h>
89#include <time.h>
90#include <unistd.h>
91
92#define BUFSIZE (1024 * 1024)
93#define FILES 200
94#define RPARALLEL 8
95#define WPARALLEL 2
96
97static jmp_buf jbuf;
98static off_t maxsize;
99static int ps;
100static char *buf;
101static volatile char val;
102
103static void
104hand(int i __unused) {  /* handler */
105
106#if defined(DEBUG)
107	fprintf(stderr, "%d ", i);
108#endif
109        longjmp(jbuf, 1);
110}
111
112static void
113cleanup(void)
114{
115	int i;
116	char file[80];
117
118	for (i = 0; i < FILES; i++) {
119		snprintf(file, sizeof(file), "f%06d", i);
120		unlink(file);
121	}
122}
123
124static void
125init(void)
126{
127	int fd, i;
128	char file[80];
129
130	for (i = 0; i < FILES; i++) {
131		snprintf(file, sizeof(file), "f%06d", i);
132		if ((fd = open(file, O_RDWR | O_CREAT | O_TRUNC, 0644)) ==
133		    -1)
134			err(1, "open(%s)", file);
135		if (write(fd, buf, BUFSIZE) != BUFSIZE)
136			err(1, "write");
137		close(fd);
138	}
139
140}
141
142static void
143writer(void)
144{
145	struct stat statbuf;
146	time_t start;
147	int fd, i;
148	char file[80];
149
150	setproctitle("writer");
151	start = time(NULL);
152	while (time(NULL) - start < 600) {
153		for (i = 0; i < FILES; i++) {
154			snprintf(file, sizeof(file), "f%06d", i);
155			if ((fd = open(file, O_RDWR | O_APPEND)) == -1) {
156				if (errno != ENOENT)
157					err(1, "open(%s) append", file);
158				goto err;
159			}
160			if (fstat(fd, &statbuf) < 0)
161				err(1, "fstat error");
162			if (statbuf.st_size < maxsize) {
163				if (write(fd, buf, ps) != ps) {
164					warn("writer");
165					goto err;
166				}
167			}
168			close(fd);
169		}
170	}
171err:
172	cleanup();
173
174	_exit(0);
175}
176
177static void
178reader(void)
179{
180	struct stat statbuf;
181	void *p;
182	size_t len;
183	int fd, i, j, n;
184	char file[80];
185
186	setproctitle("reader");
187	signal(SIGSEGV, hand);
188	signal(SIGBUS, hand);
189	fd = 0;
190	for (;;) {
191		(void)setjmp(jbuf);
192		for (i = 0; i < FILES; i++) {
193			snprintf(file, sizeof(file), "f%06d", i);
194			if (fd > 0)
195				close(fd);
196			if ((fd = open(file, O_RDWR)) == -1) {
197				if (errno != ENOENT)
198					warn("reader(%s)", file);
199				_exit(0);
200			}
201			if (fstat(fd, &statbuf) < 0)
202				err(1, "fstat error");
203			if (statbuf.st_size >= maxsize) {
204				if (ftruncate(fd, ps) == -1)
205					err(1, "ftruncate");
206				continue;
207			}
208			len = statbuf.st_size;
209			if ((p = mmap(p, len, PROT_READ, MAP_SHARED, fd, 0))
210			    == MAP_FAILED)
211				err(1, "mmap()");
212			close(fd);
213			n = statbuf.st_size / ps;
214			for (j = 0; j < n; j++) {
215				val = *(char *)p;
216				p = p + ps;
217			}
218#if 0
219			if (munmap(p, len) == -1)
220				perror("munmap");
221#endif
222		}
223	}
224	_exit(0);
225}
226int
227main(void)
228{
229	pid_t rpid[RPARALLEL], wpid[WPARALLEL];
230	int e, i, s;
231
232	maxsize = 2LL * 1024 * 1024 * 1024 / FILES;
233	buf = malloc(BUFSIZE);
234	ps = getpagesize();
235
236	init();
237	e = 0;
238	for (i = 0; i < WPARALLEL; i++) {
239		if ((wpid[i] = fork()) == 0)
240			writer();
241	}
242	for (i = 0; i < RPARALLEL; i++) {
243		if ((rpid[i] = fork()) == 0)
244			reader();
245	}
246
247	for (i = 0; i < WPARALLEL; i++) {
248		waitpid(wpid[i], &s, 0);
249		if (e == 0)
250			e = s;
251	}
252	for (i = 0; i < RPARALLEL; i++) {
253		waitpid(rpid[i], &s, 0);
254		if (e == 0)
255			e = s;
256	}
257	free(buf);
258
259	return (e);
260}
261