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# $FreeBSD$
29#
30
31# Scenario that causes "panic: brelse: free buffer onto another queue???"
32# Idea for scenario by kib@. Fixed in r203818
33
34[ `id -u ` -ne 0 ] && echo "Must be root!" && exit 1
35
36. ../default.cfg
37here=`pwd`
38
39cd /tmp
40sed '1,/^EOF/d' < $here/$0 > fragments.c
41rm -f /tmp/fragments
42cc -o fragments -Wall -Wextra -O2 -g fragments.c
43rm -f fragments.c
44cd $here
45
46mount | grep "$mntpoint" | grep -q md$mdstart && umount -f ${mntpoint}
47mdconfig -l | grep -q md$mdstart &&  mdconfig -d -u $mdstart
48
49mdconfig -a -t swap -s 1g -u $mdstart
50bsdlabel -w md$mdstart auto
51newfs -U -m 0 md${mdstart}${part} > /dev/null 2>&1
52mount /dev/md${mdstart}${part} /mnt
53chmod 777 /mnt
54
55cd /mnt
56su ${testuser} -c "/tmp/fragments"
57cd $here
58
59umount /mnt
60mount | grep "$mntpoint" | grep -q md$mdstart && umount -f ${mntpoint}
61mdconfig -l | grep -q md$mdstart &&  mdconfig -d -u $mdstart
62
63rm -f /tmp/fragments
64exit
65EOF
66#include <err.h>
67#include <errno.h>
68#include <fcntl.h>
69#include <stdio.h>
70#include <stdlib.h>
71#include <string.h>
72#include <sys/mount.h>
73#include <sys/param.h>
74#include <sys/stat.h>
75#include <sys/wait.h>
76#include <unistd.h>
77
78#define LOOPS 50000
79#define PARALLEL 8
80
81static	pid_t pid;
82static	char *buf;
83
84void
85cleanup(int n)
86{
87	int i, j, start;
88	int nb = 0;
89	char file[128];
90	struct statfs sbuf;
91	struct stat sb;
92
93	if (n == -1) {
94		for (i = 0; i < LOOPS; i++) {
95			sprintf(file,"t%05d", i);
96			unlink(file);
97		}
98		return;
99	}
100
101	start = arc4random() % n;
102	for (i = 0; i < LOOPS; i++) {
103		j = (start + i) % LOOPS;
104		sprintf(file,"t%05d", j);
105		if (stat(file, &sb) != 0)
106			continue;
107
108		if (sb.st_size == 0) {
109			unlink(file);
110			continue;
111		}
112		if (truncate(file, 0) == 0) {
113			nb++;
114			continue;
115		}
116		if (nb > 10)
117			break;
118	}
119
120
121	for (i = 0; i < 10; i++) {
122		if (statfs(".", &sbuf) < 0)
123			err(1, "statfs(%s)", ".");
124
125		if (sbuf.f_bfree > 8)
126			return;
127	}
128
129	for (i = 0; i < LOOPS; i++) {
130		j = (start + i) % LOOPS;
131		sprintf(file,"t%05d", j);
132		if (unlink(file) == 0) {
133			return;
134		}
135	}
136}
137
138void
139fragments(void)
140{
141	int i, len;
142	char file[128];
143	int fd;
144
145	for (i = 0;; i++) {
146		sprintf(file,"d%d/f%05d.%05d", i/1000, pid, i);
147
148		if ((fd = open(file, O_RDWR | O_CREAT | O_TRUNC, 0600)) < 0) {
149			if (errno != ENOSPC)
150				warn("open(%s)", file);
151			break;
152		}
153
154		len =  2 * 1024;
155		if (write(fd, buf, len) != len) {
156		}
157
158		close(fd);
159	}
160}
161
162void
163blocks(void)
164{
165	int i, len;
166	char file[128];
167	int fd;
168
169	for (i = 0;; i++) {
170		sprintf(file,"d%d/b%05d.%05d", i/1000, pid, i);
171
172		if ((fd = open(file, O_RDWR | O_CREAT | O_TRUNC, 0600)) < 0) {
173			if (errno != ENOSPC)
174				warn("open(%s)", file);
175			break;
176		}
177
178		len =  16 * 1024;
179		if (write(fd, buf, len) != len) {
180		}
181
182		close(fd);
183	}
184}
185
186void
187setup(void)
188{
189	int i;
190	char file[128];
191
192	for (i = 0; i < 300; i++) {
193		sprintf(file,"d%d", i);
194		if (mkdir(file, 0700) == -1)
195			warn("mkdir(%s)", file);
196	}
197
198	blocks();
199	fragments();
200
201	for (i = 0;i < 8; i++) {
202		sprintf(file,"d%d/b%05d.%05d", i/1000, pid, i);
203		unlink(file);
204		unlink(file);
205	}
206	for (i = 0;i < 1; i++) {
207		sprintf(file,"d%d/f%05d.%05d", i/1000, pid, i);
208		unlink(file);
209	}
210
211}
212
213int
214test(void)
215{
216	int i, len, n;
217	char file[128];
218	int fd;
219
220	for (i = 0; i < LOOPS; i++) {
221		sprintf(file,"t%05d", i);
222
223		if ((fd = open(file, O_RDWR | O_CREAT | O_EXCL, 0600)) < 0) {
224			continue;
225		}
226//		n = arc4random() % (12 + 1);
227		n = 0;
228                len = (arc4random() % (16 * 1024) + 1) + n * 16;
229		while (len > 0) {
230			if (write(fd, buf, len) == len)
231				break;
232			len = len / 2;
233			usleep(1000);
234		}
235		close(fd);
236		if (len == 0) {
237			cleanup(i);
238		}
239	}
240
241	exit(0);
242
243	return (0);
244}
245
246int
247main()
248{
249	int i, j, status;
250
251	pid = getpid();
252	if ((buf = malloc(12 * 16 * 1024)) == NULL)
253		err(1, "malloc()");
254
255	setup();
256	for (j = 0; j < 50; j++) {
257		for (i = 0; i < PARALLEL; i++) {
258			if (fork() == 0)
259				test();
260		}
261		for (i = 0; i < PARALLEL; i++)
262			wait(&status);
263		cleanup(-1);
264	}
265        return (0);
266}
267