1#!/bin/sh 2 3# 4# SPDX-License-Identifier: BSD-2-Clause-FreeBSD 5# 6# Copyright (c) 2018 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# Handle the race between fork/vm_object_split() and faults. 31# 32# If fault started before vmspace_fork() locked the map, and then during 33# fork, vm_map_copy_entry()->vm_object_split() is executed, it is 34# possible that the fault instantiate the page into the original object 35# when the page was already copied into the new object (see 36# vm_map_split() for the orig/new objects terminology). This can happen 37# if split found a busy page (e.g. from the fault) and slept dropping 38# the objects lock, which allows the swap pager to instantiate 39# read-behind pages for the fault. Then the restart of the scan can see 40# a page in the scanned range, where it was already copied to the upper 41# object. 42 43# No problems seen. 44 45. ../default.cfg 46 47dir=/tmp 48odir=`pwd` 49cd $dir 50sed '1,/^EOF/d' < $odir/$0 > $dir/template.c 51mycc -o template -Wall -Wextra -O0 -g template.c || exit 1 52rm -f template.c 53export MAXSWAPPCT=101 54(cd $odir/../testcases/swap; ./swap -t 5m -i 30 -l 100 -h) > /dev/null & 55$dir/template > /dev/null 56s=$? 57[ -f template.core -a $s -eq 0 ] && 58 { ls -l template.core; mv template.core $dir; s=1; } 59wait 60 61rm -rf $dir/template 62exit $s 63EOF 64#include <sys/param.h> 65#include <sys/mman.h> 66#include <sys/stat.h> 67#include <sys/wait.h> 68 69#include <machine/atomic.h> 70 71#include <err.h> 72#include <errno.h> 73#include <fcntl.h> 74#include <stdio.h> 75#include <stdlib.h> 76#include <time.h> 77#include <unistd.h> 78 79static volatile u_int *share; 80static volatile char *cp; 81 82#define PARALLEL 16 83#define RUNTIME (5 * 60) 84#define SYNC 0 85 86static void 87test(void) 88{ 89 size_t len; 90 pid_t pid; 91 int i; 92 93 atomic_add_int(&share[SYNC], 1); 94 while (share[SYNC] != PARALLEL) 95 usleep(200); 96 len = 1280 * PAGE_SIZE; 97 if ((cp = mmap(NULL, len, PROT_READ | PROT_WRITE, 98 MAP_ANON | MAP_PRIVATE, -1, 0)) == MAP_FAILED) 99 err(1, "mmap"); 100 101 for (i = 0; i < (int)(len / sizeof(char)); i += PAGE_SIZE) 102 cp[i] = 1; 103 usleep(arc4random() % 500000); 104 if ((pid = fork()) == 0) { 105 usleep(arc4random() % 1000); 106 for (i = 0; i < (int)(len); i += PAGE_SIZE) 107 cp[i] = 2; 108 fprintf(stdout, ".\n"); fflush(stdout); 109 _exit(0); 110 } 111 if (pid == -1) 112 err(1, "fork()"); 113 for (i = 0; i < (int)(len / sizeof(char)); i += PAGE_SIZE) 114 cp[i] = 3; 115 if (waitpid(pid, NULL, 0) != pid) 116 err(1, "waitpid(%d)", pid); 117 118 _exit(0); 119} 120 121int 122main(void) 123{ 124 pid_t pids[PARALLEL]; 125 size_t len; 126 time_t start; 127 int e, i, status; 128 129 e = 0; 130 len = PAGE_SIZE; 131 if ((share = mmap(NULL, len, PROT_READ | PROT_WRITE, 132 MAP_ANON | MAP_SHARED, -1, 0)) == MAP_FAILED) 133 err(1, "mmap"); 134 135 start = time(NULL); 136 while ((time(NULL) - start) < RUNTIME && e == 0) { 137 share[SYNC] = 0; 138 for (i = 0; i < PARALLEL; i++) { 139 if ((pids[i] = fork()) == 0) 140 test(); 141 if (pids[i] == -1) 142 err(1, "fork()"); 143 } 144 for (i = 0; i < PARALLEL; i++) { 145 if (waitpid(pids[i], &status, 0) == -1) 146 err(1, "waitpid(%d)", pids[i]); 147 if (status != 0) { 148 if (WIFSIGNALED(status)) 149 fprintf(stderr, 150 "pid %d exit signal %d\n", 151 pids[i], WTERMSIG(status)); 152 } 153 e += status == 0 ? 0 : 1; 154 } 155 } 156 157 return (e); 158} 159