xref: /freebsd/tools/test/stress2/misc/indir_trunc.sh (revision 6ba2210ee039f2f12878c217bcf058e9c8b26b29)
1#!/bin/sh
2
3#
4# SPDX-License-Identifier: BSD-2-Clause-FreeBSD
5#
6# Copyright (c) 2019 Dell EMC Isilon
7#
8# Redistribution and use in source and binary forms, with or without
9# modification, are permitted provided that the following conditions
10# are met:
11# 1. Redistributions of source code must retain the above copyright
12#    notice, this list of conditions and the following disclaimer.
13# 2. Redistributions in binary form must reproduce the above copyright
14#    notice, this list of conditions and the following disclaimer in the
15#    documentation and/or other materials provided with the distribution.
16#
17# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27# SUCH DAMAGE.
28#
29
30# No problems seen.
31# Test scenario inspired by:
32# syzbot+6532e9aab8911f58beeb@syzkaller.appspotmail.com
33
34. ../default.cfg
35[ `id -u` -ne 0 ] && echo "Must be root!" && exit 1
36[ `uname -m` = "i386" ] && exit 0 # OOM killing
37
38dir=/tmp
39odir=`pwd`
40cd $dir
41sed '1,/^EOF/d' < $odir/$0 > $dir/indir_trunc.c
42mycc -o indir_trunc -Wall -Wextra -O0 -g indir_trunc.c -lpthread || exit 1
43rm -f indir_trunc.c
44cd $odir
45
46set -e
47mount | grep "on $mntpoint " | grep -q /dev/md && umount -f $mntpoint
48[ -c /dev/md$mdstart ] &&  mdconfig -d -u $mdstart
49mdconfig -a -t swap -s 40g -u $mdstart
50newfs $newfs_flags -n md$mdstart > /dev/null
51mount /dev/md$mdstart $mntpoint
52set +e
53
54###(cd ../testcases/swap; ./swap -t 5m -i 20) &
55cd $mntpoint
56$dir/indir_trunc
57s=$?
58while pkill swap; do :; done
59wait
60[ -f indir_trunc.core -a $s -eq 0 ] &&
61    { ls -l indir_trunc.core; mv indir_trunc.core $dir; s=1; }
62cd $odir
63
64for i in `jot 6`; do
65	mount | grep -q "on $mntpoint " || break
66	umount $mntpoint && break || sleep 10
67	[ $i -eq 6 ] &&
68	    { echo FATAL; fstat -mf $mntpoint; exit 1; }
69done
70mdconfig -d -u $mdstart
71rm -rf $dir/indir_trunc
72exit $s
73
74EOF
75#include <sys/param.h>
76#include <sys/mman.h>
77#include <sys/stat.h>
78#include <sys/wait.h>
79
80#include <machine/atomic.h>
81
82#include <err.h>
83#include <errno.h>
84#include <fcntl.h>
85#include <pthread.h>
86#include <stdio.h>
87#include <stdlib.h>
88#include <time.h>
89#include <unistd.h>
90
91static volatile u_int *share;
92
93#if defined(__LP64__)
94#define MASK 0x7ffffffffffffULL
95#else
96#define MASK 0xffffffff
97#endif
98#define PARALLEL 64
99#define RUNTIME (5 * 60)
100#define SYNC 0
101
102static int fd;
103
104static void *
105t1(void *data __unused)
106{
107	off_t offset;
108	time_t start;
109        char *cmdline[] = { "/usr/bin/true", NULL };
110
111	start = time(NULL);
112	while (time(NULL) - start < 60) {
113		offset = arc4random();
114		offset = (offset << 32) | arc4random();
115		offset &= MASK;
116		if (lseek(fd, offset, SEEK_SET) == -1)
117			err(1, "lseek(%jd)", offset);
118		if (write(fd, "a", 1) != 1)
119			err(1, "write");
120		usleep(10);
121		if (arc4random() % 1000 < 2) {
122			if (execve(cmdline[0], cmdline, NULL) == -1)
123				err(1, "execve");
124		}
125	}
126
127	return (NULL);
128}
129static void *
130t2(void *data __unused)
131{
132	off_t offset, old;
133	time_t start;
134	void *p;
135	char *c;
136
137	old = 0;
138	start = time(NULL);
139	while (time(NULL) - start < 60) {
140		if (old != 0)
141			munmap(p, old);
142		offset = arc4random();
143		offset = (offset << 32) | arc4random();
144		offset &= MASK;
145		if (ftruncate(fd, offset) == -1)
146			err(1, "ftruncate(%jd)", offset);
147		write(fd, "b", 1);
148		p = mmap(NULL, offset, PROT_READ | PROT_WRITE, MAP_SHARED,
149		    fd, 0);
150		if (p == MAP_FAILED)
151			old = 0;
152		else {
153			old = offset;
154			c = p;
155			c[offset / 2] = 1;
156			if (offset > 0)
157				c[offset - 1] = 2;
158		}
159		usleep(10);
160	}
161	return (NULL);
162}
163
164static void
165test(void)
166{
167	pthread_t tid[2];
168	int r;
169	char file[80];
170
171	atomic_add_int(&share[SYNC], 1);
172	while (share[SYNC] != PARALLEL)
173		;
174
175	snprintf(file, sizeof(file), "file.%d", getpid());
176	if ((fd = open(file, O_RDWR | O_CREAT, DEFFILEMODE)) == -1)
177		err(1, "open(%s)", file);
178
179	if ((r = pthread_create(&tid[0], NULL, t1, NULL)) != 0)
180		errc(1, r, "pthread_create");
181	if ((r = pthread_create(&tid[1], NULL, t2, NULL)) != 0)
182		errc(1, r, "pthread_create");
183
184	if ((r = pthread_join(tid[0], NULL)) != 0)
185		errc(1, r, "pthread_join");
186	if ((r = pthread_join(tid[1], NULL)) != 0)
187		errc(1, r, "pthread_join");
188	close(fd);
189	unlink(file);
190
191	_exit(0);
192}
193
194int
195main(void)
196{
197	pid_t pids[PARALLEL];
198	size_t len;
199	time_t start;
200	int e, i, status;
201
202	e = 0;
203	len = PAGE_SIZE;
204	if ((share = mmap(NULL, len, PROT_READ | PROT_WRITE,
205	    MAP_ANON | MAP_SHARED, -1, 0)) == MAP_FAILED)
206		err(1, "mmap");
207
208	start = time(NULL);
209	while ((time(NULL) - start) < RUNTIME && e == 0) {
210		share[SYNC] = 0;
211		for (i = 0; i < PARALLEL; i++) {
212			if ((pids[i] = fork()) == 0)
213				test();
214			if (pids[i] == -1)
215				err(1, "fork()");
216		}
217		for (i = 0; i < PARALLEL; i++) {
218			if (waitpid(pids[i], &status, 0) == -1)
219				err(1, "waitpid(%d)", pids[i]);
220			if (status != 0) {
221				if (WIFSIGNALED(status))
222					fprintf(stderr,
223					    "pid %d exit signal %d\n",
224					    pids[i], WTERMSIG(status));
225			}
226			e += status == 0 ? 0 : 1;
227		}
228	}
229
230	return (e);
231}
232