1#!/bin/sh 2 3# 4# Copyright (c) 2016 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# From r238952's commit log: 30# The first change closes a race where an open() that will block with O_SHLOCK 31# or O_EXLOCK can increase the write count while it waits. If the process 32# holding the current lock on the file then tries to call exec() on the file 33# it has locked, it can fail with ETXTBUSY even though the advisory lock is 34# preventing other threads from successfully completing a writable open(). 35# 36# The second change closes a race where a read-only open() with O_SHLOCK or 37# O_EXLOCK may return successfully while the write count is non-zero due to 38# another descriptor that had the advisory lock and was blocking the open() 39# still being in the process of closing. If the process that completed the 40# open() then attempts to call exec() on the file it locked, it can fail with 41# ETXTBUSY even though the other process that held a write lock has closed 42# the file and released the lock. 43 44# https://people.freebsd.org/~pho/stress/log/kostik859.txt 45# https://people.freebsd.org/~pho/stress/log/kostik860.txt 46 47# Fixed by r294204. 48 49. ../default.cfg 50 51[ `id -u ` -ne 0 ] && echo "Must be root!" && exit 1 52 53dir=/tmp 54odir=`pwd` 55cd $dir 56sed '1,/^EOF/d' < $odir/$0 > $dir/advlock.c 57mycc -o advlock -Wall -Wextra -O0 -g advlock.c || exit 1 58rm -f advlock.c 59 60mount | grep "on $mntpoint " | grep -q /dev/md && umount -f $mntpoint 61mdconfig -l | grep -q md$mdstart && mdconfig -d -u $mdstart 62mdconfig -a -t swap -s 512m -u $mdstart || exit 1 63newfs $newfs_flags md$mdstart > /dev/null 64mount /dev/md$mdstart $mntpoint 65 66cp /usr/bin/true $mntpoint 67cd $mntpoint 68/tmp/advlock 69r=$? 70cd $odir 71 72while mount | grep "on $mntpoint " | grep -q /dev/md; do 73 umount $mntpoint || sleep 1 74done 75mdconfig -d -u $mdstart 76rm -f /tmp/advlock 77exit $r 78 79EOF 80#include <sys/param.h> 81#include <sys/mman.h> 82#include <sys/stat.h> 83#include <sys/wait.h> 84 85#include <machine/atomic.h> 86 87#include <err.h> 88#include <errno.h> 89#include <fcntl.h> 90#include <signal.h> 91#include <stdio.h> 92#include <stdlib.h> 93#include <time.h> 94#include <unistd.h> 95 96volatile u_int *share; 97char *cmdline[] = { "./true", NULL }; 98const char *tp; 99 100#define SYNC 0 101#define PARALLEL 2 102 103#define RUNTIME (1 * 60) 104 105void 106handler(int i __unused) { 107 108 fprintf(stderr, "ALARM from %s.\n", tp); 109 _exit(1); 110} 111 112void 113slock(void) 114{ 115 int fd; 116 117 setproctitle("%s", __func__); 118 atomic_add_int(&share[SYNC], 1); 119 while (share[SYNC] != PARALLEL) 120 ; 121 122 tp = __func__; 123 alarm(2); 124 if ((fd = open(cmdline[0], O_RDONLY | O_SHLOCK)) == -1) 125 err(1, "open(%s). %d", cmdline[0], __LINE__); 126 usleep(500); 127 close(fd); 128 129 _exit(0); 130} 131 132void 133elock(void) 134{ 135 int fd; 136 137 setproctitle("%s", __func__); 138 atomic_add_int(&share[SYNC], 1); 139 while (share[SYNC] != PARALLEL) 140 ; 141 142 tp = __func__; 143 alarm(2); 144 if ((fd = open(cmdline[0], O_WRONLY | O_EXLOCK)) == -1) { 145 if (errno != ETXTBSY) 146 err(1, "open(%s). %d", cmdline[0], __LINE__); 147 } else { 148 usleep(500); 149 close(fd); 150 } 151 152 _exit(0); 153} 154 155void 156stest(void) 157{ 158 int fd; 159 160 setproctitle("%s", __func__); 161 atomic_add_int(&share[SYNC], 1); 162 while (share[SYNC] != PARALLEL) 163 ; 164 165 tp = __func__; 166 alarm(2); 167 if ((fd = open(cmdline[0], O_RDONLY | O_SHLOCK)) == -1) 168 err(1, "open(%s). %d", cmdline[0], __LINE__); 169 170 if (execve(cmdline[0], cmdline, NULL) == -1) 171 err(1, "execve(%s) @ %d", cmdline[0], __LINE__); 172 173 _exit(0); 174} 175 176void 177etest(void) 178{ 179 int fd; 180 181 setproctitle("%s", __func__); 182 atomic_add_int(&share[SYNC], 1); 183 while (share[SYNC] != PARALLEL) 184 ; 185 186 tp = __func__; 187 alarm(2); 188 if ((fd = open(cmdline[0], O_RDONLY | O_EXLOCK)) == -1) 189 err(1, "open(%s). %d", cmdline[0], __LINE__); 190 191 if (execve(cmdline[0], cmdline, NULL) == -1) 192 err(1, "execve(%s) @ %d", cmdline[0], __LINE__); 193 194 _exit(0); 195} 196 197int 198main(void) 199{ 200 size_t len; 201 time_t start; 202 int i, n, r, s; 203 204 len = PAGE_SIZE; 205 if ((share = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_ANON | MAP_SHARED, 206 -1, 0)) == MAP_FAILED) 207 err(1, "mmap"); 208 209 signal(SIGALRM, handler); 210 n = r = 0; 211 start = time(NULL); 212 while ((time(NULL) - start) < RUNTIME) { 213 n++; 214 share[SYNC] = 0; 215 if (fork() == 0) 216 slock(); 217 if (fork() == 0) 218 stest(); 219 220 for (i = 0; i < PARALLEL; i++) { 221 wait(&s); 222 r += s == 0 ? 0 : 1; 223 } 224 if (r != 0) 225 break; 226 227 share[SYNC] = 0; 228 if (fork() == 0) 229 elock(); 230 if (fork() == 0) 231 etest(); 232 233 for (i = 0; i < PARALLEL; i++) { 234 wait(&s); 235 r += s == 0 ? 0 : 1; 236 } 237 if (r != 0) 238 break; 239 } 240 if (r != 0) 241 fprintf(stderr, "FAIL @ %d\n", n); 242 243 return (r); 244} 245