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 63bsdlabel -w md$mdstart auto 64newfs $newfs_flags md${mdstart}$part > /dev/null 65mount /dev/md${mdstart}$part $mntpoint 66 67cp /usr/bin/true $mntpoint 68cd $mntpoint 69/tmp/advlock 70r=$? 71cd $odir 72 73while mount | grep "on $mntpoint " | grep -q /dev/md; do 74 umount $mntpoint || sleep 1 75done 76mdconfig -d -u $mdstart 77rm -f /tmp/advlock 78exit $r 79 80EOF 81#include <sys/param.h> 82#include <sys/mman.h> 83#include <sys/stat.h> 84#include <sys/wait.h> 85 86#include <machine/atomic.h> 87 88#include <err.h> 89#include <errno.h> 90#include <fcntl.h> 91#include <signal.h> 92#include <stdio.h> 93#include <stdlib.h> 94#include <time.h> 95#include <unistd.h> 96 97volatile u_int *share; 98char *cmdline[] = { "./true", NULL }; 99const char *tp; 100 101#define SYNC 0 102#define PARALLEL 2 103 104#define RUNTIME (1 * 60) 105 106void 107handler(int i __unused) { 108 109 fprintf(stderr, "ALARM from %s.\n", tp); 110 _exit(1); 111} 112 113void 114slock(void) 115{ 116 int fd; 117 118 setproctitle("%s", __func__); 119 atomic_add_int(&share[SYNC], 1); 120 while (share[SYNC] != PARALLEL) 121 ; 122 123 tp = __func__; 124 alarm(2); 125 if ((fd = open(cmdline[0], O_RDONLY | O_SHLOCK)) == -1) 126 err(1, "open(%s). %d", cmdline[0], __LINE__); 127 usleep(500); 128 close(fd); 129 130 _exit(0); 131} 132 133void 134elock(void) 135{ 136 int fd; 137 138 setproctitle("%s", __func__); 139 atomic_add_int(&share[SYNC], 1); 140 while (share[SYNC] != PARALLEL) 141 ; 142 143 tp = __func__; 144 alarm(2); 145 if ((fd = open(cmdline[0], O_WRONLY | O_EXLOCK)) == -1) { 146 if (errno != ETXTBSY) 147 err(1, "open(%s). %d", cmdline[0], __LINE__); 148 } else { 149 usleep(500); 150 close(fd); 151 } 152 153 _exit(0); 154} 155 156void 157stest(void) 158{ 159 int fd; 160 161 setproctitle("%s", __func__); 162 atomic_add_int(&share[SYNC], 1); 163 while (share[SYNC] != PARALLEL) 164 ; 165 166 tp = __func__; 167 alarm(2); 168 if ((fd = open(cmdline[0], O_RDONLY | O_SHLOCK)) == -1) 169 err(1, "open(%s). %d", cmdline[0], __LINE__); 170 171 if (execve(cmdline[0], cmdline, NULL) == -1) 172 err(1, "execve(%s) @ %d", cmdline[0], __LINE__); 173 174 _exit(0); 175} 176 177void 178etest(void) 179{ 180 int fd; 181 182 setproctitle("%s", __func__); 183 atomic_add_int(&share[SYNC], 1); 184 while (share[SYNC] != PARALLEL) 185 ; 186 187 tp = __func__; 188 alarm(2); 189 if ((fd = open(cmdline[0], O_RDONLY | O_EXLOCK)) == -1) 190 err(1, "open(%s). %d", cmdline[0], __LINE__); 191 192 if (execve(cmdline[0], cmdline, NULL) == -1) 193 err(1, "execve(%s) @ %d", cmdline[0], __LINE__); 194 195 _exit(0); 196} 197 198int 199main(void) 200{ 201 size_t len; 202 time_t start; 203 int i, n, r, s; 204 205 len = PAGE_SIZE; 206 if ((share = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_ANON | MAP_SHARED, 207 -1, 0)) == MAP_FAILED) 208 err(1, "mmap"); 209 210 signal(SIGALRM, handler); 211 n = r = 0; 212 start = time(NULL); 213 while ((time(NULL) - start) < RUNTIME) { 214 n++; 215 share[SYNC] = 0; 216 if (fork() == 0) 217 slock(); 218 if (fork() == 0) 219 stest(); 220 221 for (i = 0; i < PARALLEL; i++) { 222 wait(&s); 223 r += s == 0 ? 0 : 1; 224 } 225 if (r != 0) 226 break; 227 228 share[SYNC] = 0; 229 if (fork() == 0) 230 elock(); 231 if (fork() == 0) 232 etest(); 233 234 for (i = 0; i < PARALLEL; i++) { 235 wait(&s); 236 r += s == 0 ? 0 : 1; 237 } 238 if (r != 0) 239 break; 240 } 241 if (r != 0) 242 fprintf(stderr, "FAIL @ %d\n", n); 243 244 return (r); 245} 246