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