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# fcntl(2) locking scenario, using UFS and a nullfs mount. 30# No problems seen. 31 32[ `id -u ` -ne 0 ] && echo "Must be root!" && exit 1 33 34. ../default.cfg 35 36here=`pwd` 37cd /tmp 38sed '1,/^EOF/d' < $here/$0 > nullfs22.c 39mycc -o nullfs22 -Wall -Wextra -O0 -g nullfs22.c || exit 1 40rm -f nullfs22.c 41 42mp2=${mntpoint}2 43[ -d $mp2 ] || mkdir -p $mp2 44mount | grep -q "on $mp2 " && umount $mp2 45mount | grep "on $mntpoint " | grep -q /dev/md && umount -f $mntpoint 46[ -c /dev/md$mdstart ] && mdconfig -d -u $mdstart 47mdconfig -a -t swap -s 512m -u $mdstart || exit 1 48bsdlabel -w md$mdstart auto 49newfs -n md${mdstart}$part > /dev/null 50mount /dev/md${mdstart}$part $mntpoint 51 52mount -t nullfs $mntpoint $mp2 53 54/tmp/nullfs22 $mntpoint $mp2 55status=$? 56 57while mount | grep -q "on $mp2 "; do 58 umount $mp2 59done 60while mount | grep "on $mntpoint " | grep -q /dev/md; do 61 umount $mntpoint || sleep 1 62done 63mdconfig -d -u $mdstart 64rm -f /tmp/nullfs22 65exit $status 66EOF 67#include <sys/param.h> 68#include <sys/mman.h> 69#include <sys/wait.h> 70 71#include <machine/atomic.h> 72 73#include <err.h> 74#include <errno.h> 75#include <fcntl.h> 76#include <signal.h> 77#include <stdio.h> 78#include <stdlib.h> 79#include <string.h> 80#include <unistd.h> 81 82#define LOOPS 1024 83#define N (512) 84#define PARALLEL 4 85 86#define DONE 1 87#define SYNC 0 88 89int fd; 90volatile u_int *share; 91char name1[80], name2[80]; 92 93static void 94ahandler(int s __unused) 95{ 96 fprintf(stderr, "In alarm handler\n"); 97 unlink(name1); 98 _exit(1); 99} 100 101void 102add(int n, int increment) 103{ 104 struct flock fl; 105 off_t pos; 106 long val, oval; 107 int r; 108 109 pos = n * sizeof(val); 110 memset(&fl, 0, sizeof(fl)); 111 fl.l_start = pos; 112 fl.l_len = sizeof(val); 113 fl.l_type = F_WRLCK; 114 fl.l_whence = SEEK_SET; 115 116 while (fcntl(fd, F_SETLKW, &fl) < 0) { 117 if (errno != EAGAIN) 118 err(1, "F_SETLKW (child)"); 119 usleep(100); 120 } 121 122 if (lseek(fd, pos, SEEK_SET) == -1) 123 err(1, "lseek"); 124 oval = 999999; 125 while ((r = read(fd, &val, sizeof(val)) != sizeof(val))) { 126 if (r == -1 && errno != EAGAIN) 127 err(1, "read"); 128 if (lseek(fd, pos, SEEK_SET) == -1) 129 err(1, "lseek"); 130 } 131 oval = val; 132 val = val + increment; 133#if defined(DEBUG) 134 fprintf(stderr, "add(%d, %d) @ pos %ld: %ld = %ld + %d\n", 135 n, increment, (long)pos, val, oval, increment); 136#endif 137 if (lseek(fd, pos, SEEK_SET) == -1) 138 err(1, "lseek"); 139 while ((r = write(fd, &val, sizeof(val)) != sizeof(val))) { 140 if (r == -1 && errno != EAGAIN) 141 err(1, "write"); 142 if (lseek(fd, pos, SEEK_SET) == -1) 143 err(1, "lseek"); 144 } 145 146 fl.l_type = F_UNLCK; 147 if (fcntl(fd, F_SETLK, &fl) < 0) 148 err(1, "F_UNLCK"); 149 150} 151 152void 153count(int val) 154{ 155 int i, j; 156 char help[80], *name; 157 158 if (val == 1) 159 name = name1; 160 else 161 name = name2; 162 snprintf(help, sizeof(help), "%s %d %s", __func__, val, name); 163 setproctitle("%s", help); 164 atomic_add_int(&share[SYNC], 1); 165 while (share[SYNC] != 2 * PARALLEL) 166 ; 167 168 /* Need to re-open after a fork() */ 169 close(fd); 170 if ((fd = open(name, O_RDWR)) == -1) 171 err(1, "open(%s)", name); 172 173 for (i = 0; i < LOOPS; i++) { 174 for (j = 0; j < N; j++) 175 add(j, val); 176 } 177 178 atomic_add_int(&share[DONE], 1); 179 180 _exit(0); 181} 182 183int 184main(int argc, char *argv[]) 185{ 186 off_t len; 187 size_t mlen; 188 long val, sum; 189 int i, s, stat; 190 191 if (argc != 3) { 192 fprintf(stderr, "Usage: %s <dir1> <dir2>\n", argv[0]); 193 exit(1); 194 } 195 196 mlen = PAGE_SIZE; 197 if ((share = mmap(NULL, mlen, PROT_READ | PROT_WRITE, 198 MAP_ANON | MAP_SHARED, -1, 0)) == MAP_FAILED) 199 err(1, "mmap"); 200 snprintf(name1, sizeof(name1), "%s/work", argv[1]); 201 snprintf(name2, sizeof(name2), "%s/work", argv[2]); 202 signal(SIGALRM, ahandler); 203 alarm(300); 204 if ((fd = open(name1, O_RDWR | O_CREAT | O_TRUNC, 0640)) == -1) 205 err(1, "open(%s)", name1); 206 len = N * sizeof(val); 207 if (ftruncate(fd, len) == -1) 208 err(1, "ftruncate"); 209 210 for (i = 0; i < PARALLEL; i++) { 211 if (fork() == 0) 212 count(1); 213 } 214 for (i = 0; i < PARALLEL; i++) { 215 if (fork() == 0) 216 count(-1); 217 } 218 219 while (share[DONE] != 2 * PARALLEL) 220 usleep(10000); 221 222 if (lseek(fd, 0, SEEK_SET) == -1) 223 err(1, "lseek"); 224 sum = 0; 225 for (i = 0; i < N; i++) { 226 if (read(fd, &val, sizeof(val)) != sizeof(val)) 227 err(1, "Final read"); 228 if (val != 0) 229 fprintf(stderr, "index %d: %ld\n", i, val); 230 sum += val; 231 } 232 if (sum != 0) 233 fprintf(stderr, "FAIL\n"); 234 unlink(name1); 235 236 s = 0; 237 for (i = 0; i < PARALLEL; i++) { 238 wait(&stat); 239 s += WEXITSTATUS(stat); 240 wait(&stat); 241 s += WEXITSTATUS(stat); 242 } 243 244 close(fd); 245 246 return (sum != 0 || s != 0); 247} 248