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