1#!/bin/sh 2 3# 4# Copyright (c) 2014 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# Simplified version of mmap10.sh with focus on core dumps 30# Deadlock seen: 31# http://people.freebsd.org/~pho/stress/log/kostik673.txt 32# No issues seen with r272060. 33 34# panic: vm_reserv_populate: reserv 0xfffff807cbd46300 is already promoted 35# http://people.freebsd.org/~pho/stress/log/kostik764.txt 36# Fixed by r280238 37 38# panic: vm_reserv_break: reserv 0xfffff807cbe9af00 is full 39# https://people.freebsd.org/~pho/stress/log/alan006.txt 40 41# panic: vm_page_dirty: page is invalid! 42# https://people.freebsd.org/~pho/stress/log/kostik818.txt 43 44[ `id -u ` -ne 0 ] && echo "Must be root!" && exit 1 45 46. ../default.cfg 47 48here=`pwd` 49cd /tmp 50sed '1,/^EOF/d' < $here/$0 > mmap14.c 51mycc -o mmap14 -Wall -Wextra -O2 -g mmap14.c -lpthread || exit 1 52rm -f mmap14.c 53 54daemon sh -c "(cd $here/../testcases/swap; ./swap -t 2m -i 20 -k -h)" 55sleep `jot -r 1 1 10` 56wire=$((`sysctl -n vm.max_user_wired` - \ 57 `sysctl -n vm.stats.vm.v_user_wire_count`)) 58for i in `jot 2`; do 59 /tmp/mmap14 $wire 60done 61while pgrep -q swap; do 62 pkill -9 swap 63done 64 65rm -f /tmp/mmap14 /tmp/mmap14.core 66exit 0 67EOF 68#include <sys/types.h> 69#include <sys/mman.h> 70#include <sys/resource.h> 71#include <sys/stat.h> 72#include <sys/time.h> 73#include <sys/wait.h> 74 75#include <err.h> 76#include <errno.h> 77#include <fcntl.h> 78#include <pthread.h> 79#include <pthread_np.h> 80#include <sched.h> 81#include <signal.h> 82#include <stdio.h> 83#include <stdlib.h> 84#include <string.h> 85#include <time.h> 86#include <unistd.h> 87 88#define LOOPS 2 89#define N (128 * 1024 / (int)sizeof(u_int32_t)) 90#define PARALLEL 50 91 92static void *p; 93static u_int32_t r[N]; 94 95static unsigned long 96makearg(void) 97{ 98 unsigned long val; 99 unsigned int i; 100 101 val = arc4random(); 102 i = arc4random() % 100; 103 if (i < 20) 104 val = val & 0xff; 105 if (i >= 20 && i < 40) 106 val = val & 0xffff; 107 if (i >= 40 && i < 60) 108 val = (unsigned long)(r) | (val & 0xffff); 109#if defined(__LP64__) 110 if (i >= 60) { 111 val = (val << 32) | arc4random(); 112 if (i > 80) 113 val = val & 0x00007fffffffffffUL; 114 } 115#endif 116 117 return(val); 118} 119 120static void * 121makeptr(void) 122{ 123 unsigned long val; 124 125 if (p != MAP_FAILED && p != NULL) 126 val = (unsigned long)p + arc4random(); 127 else 128 val = makearg(); 129 val = trunc_page(val); 130 131 return ((void *)val); 132} 133 134static void * 135tmmap(void *arg __unused) 136{ 137 size_t len; 138 int i, fd; 139 140 pthread_set_name_np(pthread_self(), __func__); 141 len = 1LL * 1024 * 1024 * 1024; 142 143 for (i = 0; i < 100; i++) { 144 if ((fd = open("/dev/zero", O_RDWR)) == -1) 145 err(1,"open()"); 146 147 if ((p = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 148 0)) != MAP_FAILED) { 149 usleep(100); 150 munmap(p, len); 151 } 152 153 if ((p = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_ANON, -1, 0)) != 154 MAP_FAILED) { 155 usleep(100); 156 munmap(p, len); 157 } 158 close(fd); 159 } 160 161 return (NULL); 162} 163 164static void * 165tmlock(void *arg __unused) 166{ 167 size_t len; 168 int i, n; 169 170 pthread_set_name_np(pthread_self(), __func__); 171 n = 0; 172 for (i = 0; i < 200; i++) { 173 len = trunc_page(makearg()); 174 if (mlock(makeptr(), len) == 0) 175 n++; 176 len = trunc_page(makearg()); 177 if (arc4random() % 100 < 50) 178 if (munlock(makeptr(), len) == 0) 179 n++; 180 } 181 if (n < 10) 182 fprintf(stderr, "Note: tmlock() only succeeded %d times.\n", 183 n); 184 185 return (NULL); 186} 187 188static void 189test(void) 190{ 191 pthread_t tid[4]; 192 int i, rc; 193 194 if ((rc = pthread_create(&tid[0], NULL, tmmap, NULL)) != 0) 195 errc(1, rc, "tmmap()"); 196 if ((rc = pthread_create(&tid[1], NULL, tmlock, NULL)) != 0) 197 errc(1, rc, "tmlock()"); 198 199 for (i = 0; i < 100; i++) { 200 if (fork() == 0) { 201 usleep(10000); 202 _exit(0); 203 } 204 wait(NULL); 205 } 206 207 raise(SIGSEGV); 208 209 for (i = 0; i < 2; i++) 210 if ((rc = pthread_join(tid[i], NULL)) != 0) 211 errc(1, rc, "pthread_join(%d)", i); 212 _exit(0); 213} 214 215int 216main(int argc, char *argv[]) 217{ 218 struct rlimit rl; 219 rlim_t maxlock; 220 int i, j; 221 222 if (argc != 2) { 223 fprintf(stderr, "Usage:%s <max pages to lock.>\n", argv[0]); 224 exit(1); 225 } 226 if (getrlimit(RLIMIT_MEMLOCK, &rl) == -1) 227 warn("getrlimit"); 228 maxlock = atol(argv[1]); 229 if (maxlock == 0) 230 errx(1, "Argument is zero"); 231 maxlock = (maxlock / 10 * 8) / PARALLEL * PAGE_SIZE; 232 if (maxlock < rl.rlim_cur) { 233 rl.rlim_max = rl.rlim_cur = maxlock; 234 if (setrlimit(RLIMIT_MEMLOCK, &rl) == -1) 235 warn("setrlimit"); 236 } 237 238 for (i = 0; i < N; i++) 239 r[i] = arc4random(); 240 241 for (i = 0; i < LOOPS; i++) { 242 for (j = 0; j < PARALLEL; j++) { 243 if (fork() == 0) 244 test(); 245 } 246 247 for (j = 0; j < PARALLEL; j++) 248 wait(NULL); 249 } 250 251 return (0); 252} 253