1177636Sdfr/*- 2177636Sdfr * Copyright (c) 2008 Isilon Inc http://www.isilon.com/ 3177636Sdfr * Authors: Doug Rabson <dfr@rabson.org> 4177636Sdfr * Developed with Red Inc: Alfred Perlstein <alfred@freebsd.org> 5177636Sdfr * 6177636Sdfr * Redistribution and use in source and binary forms, with or without 7177636Sdfr * modification, are permitted provided that the following conditions 8177636Sdfr * are met: 9177636Sdfr * 1. Redistributions of source code must retain the above copyright 10177636Sdfr * notice, this list of conditions and the following disclaimer. 11177636Sdfr * 2. Redistributions in binary form must reproduce the above copyright 12177636Sdfr * notice, this list of conditions and the following disclaimer in the 13177636Sdfr * documentation and/or other materials provided with the distribution. 14177636Sdfr * 15177636Sdfr * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16177636Sdfr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17177636Sdfr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18177636Sdfr * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19177636Sdfr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20177636Sdfr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21177636Sdfr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22177636Sdfr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23177636Sdfr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24177636Sdfr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25177636Sdfr * SUCH DAMAGE. 26177636Sdfr * 27177636Sdfr * $FreeBSD$ 28177636Sdfr */ 29177636Sdfr 30177636Sdfr#include <sys/time.h> 31177636Sdfr#ifdef __FreeBSD__ 32177636Sdfr#include <sys/mount.h> 33177636Sdfr#endif 34180025Sdfr#include <sys/stat.h> 35177636Sdfr#include <sys/wait.h> 36177636Sdfr 37177636Sdfr#include <err.h> 38177636Sdfr#include <errno.h> 39177636Sdfr#include <fcntl.h> 40192949Szml#include <pthread.h> 41177636Sdfr#include <signal.h> 42177636Sdfr#include <stdio.h> 43177636Sdfr#include <stdlib.h> 44177636Sdfr#include <string.h> 45177636Sdfr#include <unistd.h> 46177636Sdfr 47177636Sdfr#ifdef __FreeBSD__ 48177638Sdfr#if __FreeBSD_version >= 800028 49177636Sdfr#define HAVE_SYSID 50177636Sdfr#endif 51177636Sdfr#include <sys/cdefs.h> 52177636Sdfr#else 53177636Sdfr#ifndef __unused 54177636Sdfr#define __unused 55177636Sdfr#endif 56177636Sdfr#endif 57177636Sdfr 58177636Sdfrint verbose = 0; 59177636Sdfr 60177636Sdfrstatic int 61180025Sdfrmake_file(const char *pathname, off_t sz) 62177636Sdfr{ 63180025Sdfr struct stat st; 64177636Sdfr const char *template = "/flocktempXXXXXX"; 65177636Sdfr size_t len; 66177636Sdfr char *filename; 67177636Sdfr int fd; 68177636Sdfr 69180025Sdfr if (stat(pathname, &st) == 0) { 70180025Sdfr if (S_ISREG(st.st_mode)) { 71180025Sdfr fd = open(pathname, O_RDWR); 72180025Sdfr if (fd < 0) 73180025Sdfr err(1, "open(%s)", pathname); 74180025Sdfr if (ftruncate(fd, sz) < 0) 75180025Sdfr err(1, "ftruncate"); 76180025Sdfr return (fd); 77180025Sdfr } 78180025Sdfr } 79180025Sdfr 80180025Sdfr len = strlen(pathname) + strlen(template) + 1; 81177636Sdfr filename = malloc(len); 82180025Sdfr strcpy(filename, pathname); 83177636Sdfr strcat(filename, template); 84177636Sdfr fd = mkstemp(filename); 85177636Sdfr if (fd < 0) 86177636Sdfr err(1, "mkstemp"); 87177636Sdfr if (ftruncate(fd, sz) < 0) 88177636Sdfr err(1, "ftruncate"); 89177636Sdfr if (unlink(filename) < 0) 90177636Sdfr err(1, "unlink"); 91177636Sdfr free(filename); 92177636Sdfr 93177636Sdfr return (fd); 94177636Sdfr} 95177636Sdfr 96177636Sdfrstatic void 97177636Sdfrignore_alarm(int __unused sig) 98177636Sdfr{ 99177636Sdfr} 100177636Sdfr 101180025Sdfrstatic int 102180025Sdfrsafe_waitpid(pid_t pid) 103180025Sdfr{ 104180025Sdfr int save_errno; 105180025Sdfr int status; 106180025Sdfr 107180025Sdfr save_errno = errno; 108180025Sdfr errno = 0; 109180025Sdfr while (waitpid(pid, &status, 0) != pid) { 110180025Sdfr if (errno == EINTR) 111180025Sdfr continue; 112180025Sdfr err(1, "waitpid"); 113180025Sdfr } 114180025Sdfr errno = save_errno; 115180025Sdfr 116180025Sdfr return (status); 117180025Sdfr} 118180025Sdfr 119177636Sdfr#define FAIL(test) \ 120177636Sdfr do { \ 121177636Sdfr if (test) { \ 122177636Sdfr printf("FAIL (%s)\n", #test); \ 123177636Sdfr return -1; \ 124177636Sdfr } \ 125177636Sdfr } while (0) 126177636Sdfr 127177636Sdfr#define SUCCEED \ 128177636Sdfr do { printf("SUCCEED\n"); return 0; } while (0) 129177636Sdfr 130177636Sdfr/* 131177636Sdfr * Test 1 - F_GETLK on unlocked region 132177636Sdfr * 133177636Sdfr * If no lock is found that would prevent this lock from being 134177636Sdfr * created, the structure is left unchanged by this function call 135177636Sdfr * except for the lock type which is set to F_UNLCK. 136177636Sdfr */ 137177636Sdfrstatic int 138180025Sdfrtest1(int fd, __unused int argc, const __unused char **argv) 139177636Sdfr{ 140177636Sdfr struct flock fl1, fl2; 141177636Sdfr 142177636Sdfr memset(&fl1, 1, sizeof(fl1)); 143177636Sdfr fl1.l_type = F_WRLCK; 144177636Sdfr fl1.l_whence = SEEK_SET; 145177636Sdfr fl2 = fl1; 146177636Sdfr 147177636Sdfr if (fcntl(fd, F_GETLK, &fl1) < 0) 148177636Sdfr err(1, "F_GETLK"); 149177636Sdfr 150177636Sdfr printf("1 - F_GETLK on unlocked region: "); 151177636Sdfr FAIL(fl1.l_start != fl2.l_start); 152177636Sdfr FAIL(fl1.l_len != fl2.l_len); 153177636Sdfr FAIL(fl1.l_pid != fl2.l_pid); 154177636Sdfr FAIL(fl1.l_type != F_UNLCK); 155177636Sdfr FAIL(fl1.l_whence != fl2.l_whence); 156177636Sdfr#ifdef HAVE_SYSID 157177636Sdfr FAIL(fl1.l_sysid != fl2.l_sysid); 158177636Sdfr#endif 159177636Sdfr 160177636Sdfr SUCCEED; 161177636Sdfr} 162177636Sdfr 163177636Sdfr/* 164177636Sdfr * Test 2 - F_SETLK on locked region 165177636Sdfr * 166177636Sdfr * If a shared or exclusive lock cannot be set, fcntl returns 167177636Sdfr * immediately with EACCES or EAGAIN. 168177636Sdfr */ 169177636Sdfrstatic int 170180025Sdfrtest2(int fd, __unused int argc, const __unused char **argv) 171177636Sdfr{ 172177636Sdfr /* 173177636Sdfr * We create a child process to hold the lock which we will 174177636Sdfr * test. We use a pipe to communicate with the child. 175177636Sdfr */ 176177636Sdfr int pid; 177177636Sdfr int pfd[2]; 178177636Sdfr struct flock fl; 179177636Sdfr char ch; 180177636Sdfr int res; 181177636Sdfr 182177636Sdfr if (pipe(pfd) < 0) 183177636Sdfr err(1, "pipe"); 184177636Sdfr 185177636Sdfr fl.l_start = 0; 186177636Sdfr fl.l_len = 0; 187177636Sdfr fl.l_type = F_WRLCK; 188177636Sdfr fl.l_whence = SEEK_SET; 189177636Sdfr 190177636Sdfr pid = fork(); 191177636Sdfr if (pid < 0) 192177636Sdfr err(1, "fork"); 193177636Sdfr 194177636Sdfr if (pid == 0) { 195177636Sdfr /* 196177636Sdfr * We are the child. We set a write lock and then 197177636Sdfr * write one byte back to the parent to tell it. The 198177636Sdfr * parent will kill us when its done. 199177636Sdfr */ 200177636Sdfr if (fcntl(fd, F_SETLK, &fl) < 0) 201177636Sdfr err(1, "F_SETLK (child)"); 202177636Sdfr if (write(pfd[1], "a", 1) < 0) 203177636Sdfr err(1, "writing to pipe (child)"); 204177636Sdfr pause(); 205177636Sdfr exit(0); 206177636Sdfr } 207177636Sdfr 208177636Sdfr /* 209177636Sdfr * Wait until the child has set its lock and then perform the 210177636Sdfr * test. 211177636Sdfr */ 212177636Sdfr if (read(pfd[0], &ch, 1) != 1) 213177636Sdfr err(1, "reading from pipe (child)"); 214177636Sdfr 215177636Sdfr /* 216177636Sdfr * fcntl should return -1 with errno set to either EACCES or 217177636Sdfr * EAGAIN. 218177636Sdfr */ 219177636Sdfr printf("2 - F_SETLK on locked region: "); 220177636Sdfr res = fcntl(fd, F_SETLK, &fl); 221177636Sdfr kill(pid, SIGTERM); 222177636Sdfr safe_waitpid(pid); 223177636Sdfr close(pfd[0]); 224177636Sdfr close(pfd[1]); 225177636Sdfr FAIL(res == 0); 226177636Sdfr FAIL(errno != EACCES && errno != EAGAIN); 227177636Sdfr 228177636Sdfr SUCCEED; 229177636Sdfr} 230177636Sdfr 231177636Sdfr/* 232177636Sdfr * Test 3 - F_SETLKW on locked region 233177636Sdfr * 234177636Sdfr * If a shared or exclusive lock is blocked by other locks, the 235177636Sdfr * process waits until the request can be satisfied. 236177636Sdfr * 237177636Sdfr * XXX this test hangs on FreeBSD NFS filesystems due to limitations 238177636Sdfr * in FreeBSD's client (and server) lockd implementation. 239177636Sdfr */ 240177636Sdfrstatic int 241180025Sdfrtest3(int fd, __unused int argc, const __unused char **argv) 242177636Sdfr{ 243177636Sdfr /* 244177636Sdfr * We create a child process to hold the lock which we will 245177636Sdfr * test. We use a pipe to communicate with the child. 246177636Sdfr */ 247177636Sdfr int pid; 248177636Sdfr int pfd[2]; 249177636Sdfr struct flock fl; 250177636Sdfr char ch; 251177636Sdfr int res; 252177636Sdfr 253177636Sdfr if (pipe(pfd) < 0) 254177636Sdfr err(1, "pipe"); 255177636Sdfr 256177636Sdfr fl.l_start = 0; 257177636Sdfr fl.l_len = 0; 258177636Sdfr fl.l_type = F_WRLCK; 259177636Sdfr fl.l_whence = SEEK_SET; 260177636Sdfr 261177636Sdfr pid = fork(); 262177636Sdfr if (pid < 0) 263177636Sdfr err(1, "fork"); 264177636Sdfr 265177636Sdfr if (pid == 0) { 266177636Sdfr /* 267177636Sdfr * We are the child. We set a write lock and then 268177636Sdfr * write one byte back to the parent to tell it. The 269177636Sdfr * parent will kill us when its done. 270177636Sdfr */ 271177636Sdfr if (fcntl(fd, F_SETLK, &fl) < 0) 272177636Sdfr err(1, "F_SETLK (child)"); 273177636Sdfr if (write(pfd[1], "a", 1) < 0) 274177636Sdfr err(1, "writing to pipe (child)"); 275177636Sdfr pause(); 276177636Sdfr exit(0); 277177636Sdfr } 278177636Sdfr 279177636Sdfr /* 280177636Sdfr * Wait until the child has set its lock and then perform the 281177636Sdfr * test. 282177636Sdfr */ 283177636Sdfr if (read(pfd[0], &ch, 1) != 1) 284177636Sdfr err(1, "reading from pipe (child)"); 285177636Sdfr 286177636Sdfr /* 287177636Sdfr * fcntl should wait until the alarm and then return -1 with 288177636Sdfr * errno set to EINTR. 289177636Sdfr */ 290177636Sdfr printf("3 - F_SETLKW on locked region: "); 291177636Sdfr 292177636Sdfr alarm(1); 293177636Sdfr 294177636Sdfr res = fcntl(fd, F_SETLKW, &fl); 295177636Sdfr kill(pid, SIGTERM); 296177636Sdfr safe_waitpid(pid); 297177636Sdfr close(pfd[0]); 298177636Sdfr close(pfd[1]); 299177636Sdfr FAIL(res == 0); 300177636Sdfr FAIL(errno != EINTR); 301177636Sdfr 302177636Sdfr SUCCEED; 303177636Sdfr} 304177636Sdfr 305177636Sdfr/* 306177636Sdfr * Test 4 - F_GETLK on locked region 307177636Sdfr * 308177636Sdfr * Get the first lock that blocks the lock. 309177636Sdfr */ 310177636Sdfrstatic int 311180025Sdfrtest4(int fd, __unused int argc, const __unused char **argv) 312177636Sdfr{ 313177636Sdfr /* 314177636Sdfr * We create a child process to hold the lock which we will 315177636Sdfr * test. We use a pipe to communicate with the child. 316177636Sdfr */ 317177636Sdfr int pid; 318177636Sdfr int pfd[2]; 319177636Sdfr struct flock fl; 320177636Sdfr char ch; 321177636Sdfr 322177636Sdfr if (pipe(pfd) < 0) 323177636Sdfr err(1, "pipe"); 324177636Sdfr 325177636Sdfr fl.l_start = 0; 326177636Sdfr fl.l_len = 99; 327177636Sdfr fl.l_type = F_WRLCK; 328177636Sdfr fl.l_whence = SEEK_SET; 329177636Sdfr 330177636Sdfr pid = fork(); 331177636Sdfr if (pid < 0) 332177636Sdfr err(1, "fork"); 333177636Sdfr 334177636Sdfr if (pid == 0) { 335177636Sdfr /* 336177636Sdfr * We are the child. We set a write lock and then 337177636Sdfr * write one byte back to the parent to tell it. The 338177636Sdfr * parent will kill us when its done. 339177636Sdfr */ 340177636Sdfr if (fcntl(fd, F_SETLK, &fl) < 0) 341177636Sdfr err(1, "F_SETLK (child)"); 342177636Sdfr if (write(pfd[1], "a", 1) < 0) 343177636Sdfr err(1, "writing to pipe (child)"); 344177636Sdfr pause(); 345177636Sdfr exit(0); 346177636Sdfr } 347177636Sdfr 348177636Sdfr /* 349177636Sdfr * Wait until the child has set its lock and then perform the 350177636Sdfr * test. 351177636Sdfr */ 352177636Sdfr if (read(pfd[0], &ch, 1) != 1) 353177636Sdfr err(1, "reading from pipe (child)"); 354177636Sdfr 355177636Sdfr /* 356177636Sdfr * fcntl should return a lock structure reflecting the lock we 357177636Sdfr * made in the child process. 358177636Sdfr */ 359177636Sdfr if (fcntl(fd, F_GETLK, &fl) < 0) 360177636Sdfr err(1, "F_GETLK"); 361177636Sdfr 362177636Sdfr printf("4 - F_GETLK on locked region: "); 363177636Sdfr FAIL(fl.l_start != 0); 364177636Sdfr FAIL(fl.l_len != 99); 365177636Sdfr FAIL(fl.l_type != F_WRLCK); 366177636Sdfr FAIL(fl.l_pid != pid); 367177636Sdfr#ifdef HAVE_SYSID 368177636Sdfr FAIL(fl.l_sysid != 0); 369177636Sdfr#endif 370177636Sdfr 371177636Sdfr kill(pid, SIGTERM); 372177636Sdfr safe_waitpid(pid); 373177636Sdfr close(pfd[0]); 374177636Sdfr close(pfd[1]); 375177636Sdfr 376177636Sdfr SUCCEED; 377177636Sdfr} 378177636Sdfr 379177636Sdfr/* 380177636Sdfr * Test 5 - F_SETLKW simple deadlock 381177636Sdfr * 382177636Sdfr * If a blocking shared lock request would cause a deadlock (i.e. the 383177636Sdfr * lock request is blocked by a process which is itself blocked on a 384177636Sdfr * lock currently owned by the process making the new request), 385177636Sdfr * EDEADLK is returned. 386177636Sdfr */ 387177636Sdfrstatic int 388180025Sdfrtest5(int fd, __unused int argc, const __unused char **argv) 389177636Sdfr{ 390177636Sdfr /* 391177636Sdfr * We create a child process to hold the lock which we will 392177636Sdfr * test. Because our test relies on the child process being 393177636Sdfr * blocked on the parent's lock, we can't easily use a pipe to 394177636Sdfr * synchronize so we just sleep in the parent to given the 395177636Sdfr * child a chance to setup. 396177636Sdfr * 397177636Sdfr * To create the deadlock condition, we arrange for the parent 398177636Sdfr * to lock the first byte of the file and the child to lock 399177636Sdfr * the second byte. After locking the second byte, the child 400177636Sdfr * will attempt to lock the first byte of the file, and 401177636Sdfr * block. The parent will then attempt to lock the second byte 402177636Sdfr * (owned by the child) which should cause deadlock. 403177636Sdfr */ 404177636Sdfr int pid; 405177636Sdfr struct flock fl; 406177636Sdfr int res; 407177636Sdfr 408177636Sdfr /* 409177636Sdfr * Lock the first byte in the parent. 410177636Sdfr */ 411177636Sdfr fl.l_start = 0; 412177636Sdfr fl.l_len = 1; 413177636Sdfr fl.l_type = F_WRLCK; 414177636Sdfr fl.l_whence = SEEK_SET; 415177636Sdfr if (fcntl(fd, F_SETLK, &fl) < 0) 416177636Sdfr err(1, "F_SETLK 1 (parent)"); 417177636Sdfr 418177636Sdfr pid = fork(); 419177636Sdfr if (pid < 0) 420177636Sdfr err(1, "fork"); 421177636Sdfr 422177636Sdfr if (pid == 0) { 423177636Sdfr /* 424177636Sdfr * Lock the second byte in the child and then block on 425177636Sdfr * the parent's lock. 426177636Sdfr */ 427177636Sdfr fl.l_start = 1; 428177636Sdfr if (fcntl(fd, F_SETLK, &fl) < 0) 429177636Sdfr err(1, "F_SETLK (child)"); 430177636Sdfr fl.l_start = 0; 431177636Sdfr if (fcntl(fd, F_SETLKW, &fl) < 0) 432177636Sdfr err(1, "F_SETLKW (child)"); 433177636Sdfr exit(0); 434177636Sdfr } 435177636Sdfr 436177636Sdfr /* 437177636Sdfr * Wait until the child has set its lock and then perform the 438177636Sdfr * test. 439177636Sdfr */ 440177636Sdfr sleep(1); 441177636Sdfr 442177636Sdfr /* 443180025Sdfr * fcntl should immediately return -1 with errno set to 444180025Sdfr * EDEADLK. If the alarm fires, we failed to detect the 445180025Sdfr * deadlock. 446177636Sdfr */ 447180025Sdfr alarm(1); 448177636Sdfr printf("5 - F_SETLKW simple deadlock: "); 449177636Sdfr 450177636Sdfr fl.l_start = 1; 451177636Sdfr res = fcntl(fd, F_SETLKW, &fl); 452177636Sdfr kill(pid, SIGTERM); 453177636Sdfr safe_waitpid(pid); 454177636Sdfr 455177636Sdfr FAIL(res == 0); 456177636Sdfr FAIL(errno != EDEADLK); 457177636Sdfr 458177636Sdfr fl.l_start = 0; 459177636Sdfr fl.l_len = 0; 460177636Sdfr fl.l_type = F_UNLCK; 461177636Sdfr if (fcntl(fd, F_SETLK, &fl) < 0) 462177636Sdfr err(1, "F_UNLCK"); 463177636Sdfr 464180025Sdfr /* 465180025Sdfr * Cancel the alarm to avoid confusing later tests. 466180025Sdfr */ 467180025Sdfr alarm(0); 468180025Sdfr 469177636Sdfr SUCCEED; 470177636Sdfr} 471177636Sdfr 472177636Sdfr/* 473177636Sdfr * Test 6 - F_SETLKW complex deadlock. 474177636Sdfr * 475177636Sdfr * This test involves three process, P, C1 and C2. We set things up so 476177636Sdfr * that P locks byte zero, C1 locks byte 1 and C2 locks byte 2. We 477177636Sdfr * also block C2 by attempting to lock byte zero. Lastly, P attempts 478177636Sdfr * to lock a range including byte 1 and 2. This represents a deadlock 479177636Sdfr * (due to C2's blocking attempt to lock byte zero). 480177636Sdfr */ 481177636Sdfrstatic int 482180025Sdfrtest6(int fd, __unused int argc, const __unused char **argv) 483177636Sdfr{ 484177636Sdfr /* 485177636Sdfr * Because our test relies on the child process being blocked 486177636Sdfr * on the parent's lock, we can't easily use a pipe to 487177636Sdfr * synchronize so we just sleep in the parent to given the 488177636Sdfr * children a chance to setup. 489177636Sdfr */ 490177636Sdfr int pid1, pid2; 491177636Sdfr struct flock fl; 492177636Sdfr int res; 493177636Sdfr 494177636Sdfr /* 495177636Sdfr * Lock the first byte in the parent. 496177636Sdfr */ 497177636Sdfr fl.l_start = 0; 498177636Sdfr fl.l_len = 1; 499177636Sdfr fl.l_type = F_WRLCK; 500177636Sdfr fl.l_whence = SEEK_SET; 501177636Sdfr if (fcntl(fd, F_SETLK, &fl) < 0) 502177636Sdfr err(1, "F_SETLK 1 (parent)"); 503177636Sdfr 504177636Sdfr pid1 = fork(); 505177636Sdfr if (pid1 < 0) 506177636Sdfr err(1, "fork"); 507177636Sdfr 508177636Sdfr if (pid1 == 0) { 509177636Sdfr /* 510177636Sdfr * C1 511177636Sdfr * Lock the second byte in the child and then sleep 512177636Sdfr */ 513177636Sdfr fl.l_start = 1; 514177636Sdfr if (fcntl(fd, F_SETLK, &fl) < 0) 515177636Sdfr err(1, "F_SETLK (child1)"); 516177636Sdfr pause(); 517177636Sdfr exit(0); 518177636Sdfr } 519177636Sdfr 520177636Sdfr pid2 = fork(); 521177636Sdfr if (pid2 < 0) 522177636Sdfr err(1, "fork"); 523177636Sdfr 524177636Sdfr if (pid2 == 0) { 525177636Sdfr /* 526177636Sdfr * C2 527177636Sdfr * Lock the third byte in the child and then block on 528177636Sdfr * the parent's lock. 529177636Sdfr */ 530177636Sdfr fl.l_start = 2; 531177636Sdfr if (fcntl(fd, F_SETLK, &fl) < 0) 532177636Sdfr err(1, "F_SETLK (child2)"); 533177636Sdfr fl.l_start = 0; 534177636Sdfr if (fcntl(fd, F_SETLKW, &fl) < 0) 535177636Sdfr err(1, "F_SETLKW (child2)"); 536177636Sdfr exit(0); 537177636Sdfr } 538177636Sdfr 539177636Sdfr /* 540177636Sdfr * Wait until the children have set their locks and then 541177636Sdfr * perform the test. 542177636Sdfr */ 543177636Sdfr sleep(1); 544177636Sdfr 545177636Sdfr /* 546177636Sdfr * fcntl should immediately return -1 with errno set to 547177636Sdfr * EDEADLK. If the alarm fires, we failed to detect the 548177636Sdfr * deadlock. 549177636Sdfr */ 550177636Sdfr alarm(1); 551177636Sdfr printf("6 - F_SETLKW complex deadlock: "); 552177636Sdfr 553177636Sdfr fl.l_start = 1; 554177636Sdfr fl.l_len = 2; 555177636Sdfr res = fcntl(fd, F_SETLKW, &fl); 556177636Sdfr kill(pid1, SIGTERM); 557177636Sdfr safe_waitpid(pid1); 558177636Sdfr kill(pid2, SIGTERM); 559177636Sdfr safe_waitpid(pid2); 560177636Sdfr 561177636Sdfr fl.l_start = 0; 562177636Sdfr fl.l_len = 0; 563177636Sdfr fl.l_type = F_UNLCK; 564177636Sdfr if (fcntl(fd, F_SETLK, &fl) < 0) 565177636Sdfr err(1, "F_UNLCK"); 566177636Sdfr 567177636Sdfr FAIL(res == 0); 568177636Sdfr FAIL(errno != EDEADLK); 569177636Sdfr 570177636Sdfr /* 571177636Sdfr * Cancel the alarm to avoid confusing later tests. 572177636Sdfr */ 573177636Sdfr alarm(0); 574177636Sdfr 575177636Sdfr SUCCEED; 576177636Sdfr} 577177636Sdfr 578177636Sdfr/* 579177636Sdfr * Test 7 - F_SETLK shared lock on exclusive locked region 580177636Sdfr * 581177636Sdfr * If a shared or exclusive lock cannot be set, fcntl returns 582177636Sdfr * immediately with EACCES or EAGAIN. 583177636Sdfr */ 584177636Sdfrstatic int 585180025Sdfrtest7(int fd, __unused int argc, const __unused char **argv) 586177636Sdfr{ 587177636Sdfr /* 588177636Sdfr * We create a child process to hold the lock which we will 589177636Sdfr * test. We use a pipe to communicate with the child. 590177636Sdfr */ 591177636Sdfr int pid; 592177636Sdfr int pfd[2]; 593177636Sdfr struct flock fl; 594177636Sdfr char ch; 595177636Sdfr int res; 596177636Sdfr 597177636Sdfr if (pipe(pfd) < 0) 598177636Sdfr err(1, "pipe"); 599177636Sdfr 600177636Sdfr fl.l_start = 0; 601177636Sdfr fl.l_len = 0; 602177636Sdfr fl.l_type = F_WRLCK; 603177636Sdfr fl.l_whence = SEEK_SET; 604177636Sdfr 605177636Sdfr pid = fork(); 606177636Sdfr if (pid < 0) 607177636Sdfr err(1, "fork"); 608177636Sdfr 609177636Sdfr if (pid == 0) { 610177636Sdfr /* 611177636Sdfr * We are the child. We set a write lock and then 612177636Sdfr * write one byte back to the parent to tell it. The 613177636Sdfr * parent will kill us when its done. 614177636Sdfr */ 615177636Sdfr if (fcntl(fd, F_SETLK, &fl) < 0) 616177636Sdfr err(1, "F_SETLK (child)"); 617177636Sdfr if (write(pfd[1], "a", 1) < 0) 618177636Sdfr err(1, "writing to pipe (child)"); 619177636Sdfr pause(); 620177636Sdfr exit(0); 621177636Sdfr } 622177636Sdfr 623177636Sdfr /* 624177636Sdfr * Wait until the child has set its lock and then perform the 625177636Sdfr * test. 626177636Sdfr */ 627177636Sdfr if (read(pfd[0], &ch, 1) != 1) 628177636Sdfr err(1, "reading from pipe (child)"); 629177636Sdfr 630177636Sdfr /* 631177636Sdfr * fcntl should wait until the alarm and then return -1 with 632177636Sdfr * errno set to EINTR. 633177636Sdfr */ 634177636Sdfr printf("7 - F_SETLK shared lock on exclusive locked region: "); 635177636Sdfr 636177636Sdfr fl.l_type = F_RDLCK; 637177636Sdfr res = fcntl(fd, F_SETLK, &fl); 638177636Sdfr kill(pid, SIGTERM); 639177636Sdfr safe_waitpid(pid); 640177636Sdfr close(pfd[0]); 641177636Sdfr close(pfd[1]); 642177636Sdfr 643177636Sdfr FAIL(res == 0); 644177636Sdfr FAIL(errno != EACCES && errno != EAGAIN); 645177636Sdfr 646177636Sdfr SUCCEED; 647177636Sdfr} 648177636Sdfr 649177636Sdfr/* 650177636Sdfr * Test 8 - F_SETLK shared lock on share locked region 651177636Sdfr * 652177636Sdfr * When a shared lock is set on a segment of a file, other processes 653177636Sdfr * shall be able to set shared locks on that segment or a portion of 654177636Sdfr * it. 655177636Sdfr */ 656177636Sdfrstatic int 657180025Sdfrtest8(int fd, __unused int argc, const __unused char **argv) 658177636Sdfr{ 659177636Sdfr /* 660177636Sdfr * We create a child process to hold the lock which we will 661177636Sdfr * test. We use a pipe to communicate with the child. 662177636Sdfr */ 663177636Sdfr int pid; 664177636Sdfr int pfd[2]; 665177636Sdfr struct flock fl; 666177636Sdfr char ch; 667177636Sdfr int res; 668177636Sdfr 669177636Sdfr if (pipe(pfd) < 0) 670177636Sdfr err(1, "pipe"); 671177636Sdfr 672177636Sdfr fl.l_start = 0; 673177636Sdfr fl.l_len = 0; 674177636Sdfr fl.l_type = F_RDLCK; 675177636Sdfr fl.l_whence = SEEK_SET; 676177636Sdfr 677177636Sdfr pid = fork(); 678177636Sdfr if (pid < 0) 679177636Sdfr err(1, "fork"); 680177636Sdfr 681177636Sdfr if (pid == 0) { 682177636Sdfr /* 683177636Sdfr * We are the child. We set a write lock and then 684177636Sdfr * write one byte back to the parent to tell it. The 685177636Sdfr * parent will kill us when its done. 686177636Sdfr */ 687177636Sdfr if (fcntl(fd, F_SETLK, &fl) < 0) 688177636Sdfr err(1, "F_SETLK (child)"); 689177636Sdfr if (write(pfd[1], "a", 1) < 0) 690177636Sdfr err(1, "writing to pipe (child)"); 691177636Sdfr pause(); 692177636Sdfr exit(0); 693177636Sdfr } 694177636Sdfr 695177636Sdfr /* 696177636Sdfr * Wait until the child has set its lock and then perform the 697177636Sdfr * test. 698177636Sdfr */ 699177636Sdfr if (read(pfd[0], &ch, 1) != 1) 700177636Sdfr err(1, "reading from pipe (child)"); 701177636Sdfr 702177636Sdfr /* 703177636Sdfr * fcntl should wait until the alarm and then return -1 with 704177636Sdfr * errno set to EINTR. 705177636Sdfr */ 706177636Sdfr printf("8 - F_SETLK shared lock on share locked region: "); 707177636Sdfr 708177636Sdfr fl.l_type = F_RDLCK; 709177636Sdfr res = fcntl(fd, F_SETLK, &fl); 710177636Sdfr 711177636Sdfr kill(pid, SIGTERM); 712177636Sdfr safe_waitpid(pid); 713177636Sdfr close(pfd[0]); 714177636Sdfr close(pfd[1]); 715177636Sdfr 716177636Sdfr fl.l_start = 0; 717177636Sdfr fl.l_len = 0; 718177636Sdfr fl.l_type = F_UNLCK; 719177636Sdfr if (fcntl(fd, F_SETLK, &fl) < 0) 720177636Sdfr err(1, "F_UNLCK"); 721177636Sdfr 722177636Sdfr FAIL(res != 0); 723177636Sdfr 724177636Sdfr SUCCEED; 725177636Sdfr} 726177636Sdfr 727177636Sdfr/* 728177636Sdfr * Test 9 - F_SETLK exclusive lock on share locked region 729177636Sdfr * 730177636Sdfr * If a shared or exclusive lock cannot be set, fcntl returns 731177636Sdfr * immediately with EACCES or EAGAIN. 732177636Sdfr */ 733177636Sdfrstatic int 734180025Sdfrtest9(int fd, __unused int argc, const __unused char **argv) 735177636Sdfr{ 736177636Sdfr /* 737177636Sdfr * We create a child process to hold the lock which we will 738177636Sdfr * test. We use a pipe to communicate with the child. 739177636Sdfr */ 740177636Sdfr int pid; 741177636Sdfr int pfd[2]; 742177636Sdfr struct flock fl; 743177636Sdfr char ch; 744177636Sdfr int res; 745177636Sdfr 746177636Sdfr if (pipe(pfd) < 0) 747177636Sdfr err(1, "pipe"); 748177636Sdfr 749177636Sdfr fl.l_start = 0; 750177636Sdfr fl.l_len = 0; 751177636Sdfr fl.l_type = F_RDLCK; 752177636Sdfr fl.l_whence = SEEK_SET; 753177636Sdfr 754177636Sdfr pid = fork(); 755177636Sdfr if (pid < 0) 756177636Sdfr err(1, "fork"); 757177636Sdfr 758177636Sdfr if (pid == 0) { 759177636Sdfr /* 760177636Sdfr * We are the child. We set a write lock and then 761177636Sdfr * write one byte back to the parent to tell it. The 762177636Sdfr * parent will kill us when its done. 763177636Sdfr */ 764177636Sdfr if (fcntl(fd, F_SETLK, &fl) < 0) 765177636Sdfr err(1, "F_SETLK (child)"); 766177636Sdfr if (write(pfd[1], "a", 1) < 0) 767177636Sdfr err(1, "writing to pipe (child)"); 768177636Sdfr pause(); 769177636Sdfr exit(0); 770177636Sdfr } 771177636Sdfr 772177636Sdfr /* 773177636Sdfr * Wait until the child has set its lock and then perform the 774177636Sdfr * test. 775177636Sdfr */ 776177636Sdfr if (read(pfd[0], &ch, 1) != 1) 777177636Sdfr err(1, "reading from pipe (child)"); 778177636Sdfr 779177636Sdfr /* 780177636Sdfr * fcntl should wait until the alarm and then return -1 with 781177636Sdfr * errno set to EINTR. 782177636Sdfr */ 783177636Sdfr printf("9 - F_SETLK exclusive lock on share locked region: "); 784177636Sdfr 785177636Sdfr fl.l_type = F_WRLCK; 786177636Sdfr res = fcntl(fd, F_SETLK, &fl); 787177636Sdfr kill(pid, SIGTERM); 788177636Sdfr safe_waitpid(pid); 789177636Sdfr close(pfd[0]); 790177636Sdfr close(pfd[1]); 791177636Sdfr 792177636Sdfr FAIL(res == 0); 793177636Sdfr FAIL(errno != EACCES && errno != EAGAIN); 794177636Sdfr 795177636Sdfr SUCCEED; 796177636Sdfr} 797177636Sdfr 798177636Sdfr/* 799177636Sdfr * Test 10 - trying to set bogus pid or sysid values 800177636Sdfr * 801177636Sdfr * The l_pid and l_sysid fields are only used with F_GETLK to return 802177636Sdfr * the process ID of the process holding a blocking lock and the 803177636Sdfr * system ID of the system that owns that process 804177636Sdfr */ 805177636Sdfrstatic int 806180025Sdfrtest10(int fd, __unused int argc, const __unused char **argv) 807177636Sdfr{ 808177636Sdfr /* 809177636Sdfr * We create a child process to hold the lock which we will 810177636Sdfr * test. We use a pipe to communicate with the child. 811177636Sdfr */ 812177636Sdfr int pid; 813177636Sdfr int pfd[2]; 814177636Sdfr struct flock fl; 815177636Sdfr char ch; 816177636Sdfr 817177636Sdfr if (pipe(pfd) < 0) 818177636Sdfr err(1, "pipe"); 819177636Sdfr 820177636Sdfr fl.l_start = 0; 821177636Sdfr fl.l_len = 0; 822177636Sdfr fl.l_type = F_WRLCK; 823177636Sdfr fl.l_whence = SEEK_SET; 824177636Sdfr fl.l_pid = 9999; 825177636Sdfr#ifdef HAVE_SYSID 826177636Sdfr fl.l_sysid = 9999; 827177636Sdfr#endif 828177636Sdfr 829177636Sdfr pid = fork(); 830177636Sdfr if (pid < 0) 831177636Sdfr err(1, "fork"); 832177636Sdfr 833177636Sdfr if (pid == 0) { 834177636Sdfr /* 835177636Sdfr * We are the child. We set a write lock and then 836177636Sdfr * write one byte back to the parent to tell it. The 837177636Sdfr * parent will kill us when its done. 838177636Sdfr */ 839177636Sdfr if (fcntl(fd, F_SETLK, &fl) < 0) 840177636Sdfr err(1, "F_SETLK (child)"); 841177636Sdfr if (write(pfd[1], "a", 1) < 0) 842177636Sdfr err(1, "writing to pipe (child)"); 843177636Sdfr pause(); 844177636Sdfr exit(0); 845177636Sdfr } 846177636Sdfr 847177636Sdfr /* 848177636Sdfr * Wait until the child has set its lock and then perform the 849177636Sdfr * test. 850177636Sdfr */ 851177636Sdfr if (read(pfd[0], &ch, 1) != 1) 852177636Sdfr err(1, "reading from pipe (child)"); 853177636Sdfr 854177636Sdfr printf("10 - trying to set bogus pid or sysid values: "); 855177636Sdfr 856177636Sdfr if (fcntl(fd, F_GETLK, &fl) < 0) 857177636Sdfr err(1, "F_GETLK"); 858177636Sdfr 859177636Sdfr kill(pid, SIGTERM); 860177636Sdfr safe_waitpid(pid); 861177636Sdfr close(pfd[0]); 862177636Sdfr close(pfd[1]); 863177636Sdfr 864177636Sdfr FAIL(fl.l_pid != pid); 865177636Sdfr#ifdef HAVE_SYSID 866177636Sdfr FAIL(fl.l_sysid != 0); 867177636Sdfr#endif 868177636Sdfr 869177636Sdfr SUCCEED; 870177636Sdfr} 871177636Sdfr 872177636Sdfr/* 873177636Sdfr * Test 11 - remote locks 874177636Sdfr * 875177636Sdfr * XXX temporary interface which will be removed when the kernel lockd 876177636Sdfr * is added. 877177636Sdfr */ 878177636Sdfrstatic int 879180025Sdfrtest11(int fd, __unused int argc, const __unused char **argv) 880177636Sdfr{ 881177636Sdfr#ifdef F_SETLK_REMOTE 882177636Sdfr struct flock fl; 883177636Sdfr int res; 884177636Sdfr 885177636Sdfr if (geteuid() != 0) 886177636Sdfr return 0; 887177636Sdfr 888177636Sdfr fl.l_start = 0; 889177636Sdfr fl.l_len = 0; 890177636Sdfr fl.l_type = F_WRLCK; 891177636Sdfr fl.l_whence = SEEK_SET; 892177636Sdfr fl.l_pid = 9999; 893177636Sdfr fl.l_sysid = 1001; 894177636Sdfr 895177636Sdfr printf("11 - remote locks: "); 896177636Sdfr 897177636Sdfr res = fcntl(fd, F_SETLK_REMOTE, &fl); 898177636Sdfr FAIL(res != 0); 899177636Sdfr 900177636Sdfr fl.l_sysid = 1002; 901177636Sdfr res = fcntl(fd, F_SETLK_REMOTE, &fl); 902177636Sdfr FAIL(res == 0); 903177636Sdfr FAIL(errno != EACCES && errno != EAGAIN); 904177636Sdfr 905177636Sdfr res = fcntl(fd, F_GETLK, &fl); 906177636Sdfr FAIL(res != 0); 907177636Sdfr FAIL(fl.l_pid != 9999); 908177636Sdfr FAIL(fl.l_sysid != 1001); 909177636Sdfr 910177636Sdfr fl.l_type = F_UNLCK; 911177636Sdfr fl.l_sysid = 1001; 912177636Sdfr fl.l_start = 0; 913177636Sdfr fl.l_len = 0; 914177636Sdfr res = fcntl(fd, F_SETLK_REMOTE, &fl); 915177636Sdfr FAIL(res != 0); 916177636Sdfr 917177636Sdfr fl.l_pid = 1234; 918177636Sdfr fl.l_sysid = 1001; 919177636Sdfr fl.l_start = 0; 920177636Sdfr fl.l_len = 1; 921177636Sdfr fl.l_whence = SEEK_SET; 922177636Sdfr fl.l_type = F_RDLCK; 923177636Sdfr res = fcntl(fd, F_SETLK_REMOTE, &fl); 924177636Sdfr FAIL(res != 0); 925177636Sdfr 926177636Sdfr fl.l_sysid = 1002; 927177636Sdfr res = fcntl(fd, F_SETLK_REMOTE, &fl); 928177636Sdfr FAIL(res != 0); 929177636Sdfr 930177636Sdfr fl.l_type = F_UNLCKSYS; 931177636Sdfr fl.l_sysid = 1001; 932177636Sdfr res = fcntl(fd, F_SETLK_REMOTE, &fl); 933177636Sdfr FAIL(res != 0); 934177636Sdfr 935177636Sdfr fl.l_type = F_WRLCK; 936177636Sdfr res = fcntl(fd, F_GETLK, &fl); 937177636Sdfr FAIL(res != 0); 938177636Sdfr FAIL(fl.l_pid != 1234); 939177636Sdfr FAIL(fl.l_sysid != 1002); 940177636Sdfr 941177636Sdfr fl.l_type = F_UNLCKSYS; 942177636Sdfr fl.l_sysid = 1002; 943177636Sdfr res = fcntl(fd, F_SETLK_REMOTE, &fl); 944177636Sdfr FAIL(res != 0); 945177636Sdfr 946177636Sdfr SUCCEED; 947177636Sdfr#else 948177636Sdfr return 0; 949177636Sdfr#endif 950177636Sdfr} 951177636Sdfr 952177636Sdfr/* 953177636Sdfr * Test 12 - F_SETLKW on locked region which is then unlocked 954177636Sdfr * 955177636Sdfr * If a shared or exclusive lock is blocked by other locks, the 956177636Sdfr * process waits until the request can be satisfied. 957177636Sdfr */ 958177636Sdfrstatic int 959180025Sdfrtest12(int fd, __unused int argc, const __unused char **argv) 960177636Sdfr{ 961177636Sdfr /* 962177636Sdfr * We create a child process to hold the lock which we will 963177636Sdfr * test. We use a pipe to communicate with the child. 964177636Sdfr */ 965177636Sdfr int pid; 966177636Sdfr int pfd[2]; 967177636Sdfr struct flock fl; 968177636Sdfr char ch; 969177636Sdfr int res; 970177636Sdfr 971177636Sdfr if (pipe(pfd) < 0) 972177636Sdfr err(1, "pipe"); 973177636Sdfr 974177636Sdfr fl.l_start = 0; 975177636Sdfr fl.l_len = 0; 976177636Sdfr fl.l_type = F_WRLCK; 977177636Sdfr fl.l_whence = SEEK_SET; 978177636Sdfr 979177636Sdfr pid = fork(); 980177636Sdfr if (pid < 0) 981177636Sdfr err(1, "fork"); 982177636Sdfr 983177636Sdfr if (pid == 0) { 984177636Sdfr /* 985177636Sdfr * We are the child. We set a write lock and then 986177636Sdfr * write one byte back to the parent to tell it. The 987177636Sdfr * parent will kill us when its done. 988177636Sdfr */ 989177636Sdfr if (fcntl(fd, F_SETLK, &fl) < 0) 990177636Sdfr err(1, "F_SETLK (child)"); 991177636Sdfr if (write(pfd[1], "a", 1) < 0) 992177636Sdfr err(1, "writing to pipe (child)"); 993177636Sdfr 994177636Sdfr sleep(1); 995177636Sdfr exit(0); 996177636Sdfr } 997177636Sdfr 998177636Sdfr /* 999177636Sdfr * Wait until the child has set its lock and then perform the 1000177636Sdfr * test. 1001177636Sdfr */ 1002177636Sdfr if (read(pfd[0], &ch, 1) != 1) 1003177636Sdfr err(1, "reading from pipe (child)"); 1004177636Sdfr 1005177636Sdfr /* 1006177636Sdfr * fcntl should wait until the alarm and then return -1 with 1007177636Sdfr * errno set to EINTR. 1008177636Sdfr */ 1009177636Sdfr printf("12 - F_SETLKW on locked region which is then unlocked: "); 1010177636Sdfr 1011177636Sdfr //alarm(1); 1012177636Sdfr 1013177636Sdfr res = fcntl(fd, F_SETLKW, &fl); 1014177636Sdfr kill(pid, SIGTERM); 1015177636Sdfr safe_waitpid(pid); 1016177636Sdfr close(pfd[0]); 1017177636Sdfr close(pfd[1]); 1018177636Sdfr FAIL(res != 0); 1019177636Sdfr 1020177636Sdfr fl.l_start = 0; 1021177636Sdfr fl.l_len = 0; 1022177636Sdfr fl.l_type = F_UNLCK; 1023177636Sdfr if (fcntl(fd, F_SETLK, &fl) < 0) 1024177636Sdfr err(1, "F_UNLCK"); 1025177636Sdfr 1026177636Sdfr SUCCEED; 1027177636Sdfr} 1028177636Sdfr 1029177636Sdfr/* 1030177636Sdfr * Test 13 - F_SETLKW on locked region, race with owner 1031177636Sdfr * 1032177636Sdfr * If a shared or exclusive lock is blocked by other locks, the 1033177636Sdfr * process waits until the request can be satisfied. 1034177636Sdfr */ 1035177636Sdfrstatic int 1036180025Sdfrtest13(int fd, __unused int argc, const __unused char **argv) 1037177636Sdfr{ 1038177636Sdfr /* 1039177636Sdfr * We create a child process to hold the lock which we will 1040177636Sdfr * test. We use a pipe to communicate with the child. 1041177636Sdfr */ 1042177636Sdfr int i; 1043177636Sdfr int pid; 1044177636Sdfr int pfd[2]; 1045177636Sdfr struct flock fl; 1046177636Sdfr char ch; 1047177636Sdfr int res; 1048177636Sdfr struct itimerval itv; 1049177636Sdfr 1050177636Sdfr printf("13 - F_SETLKW on locked region, race with owner: "); 1051177636Sdfr fflush(stdout); 1052177636Sdfr 1053177636Sdfr for (i = 0; i < 100; i++) { 1054177636Sdfr if (pipe(pfd) < 0) 1055177636Sdfr err(1, "pipe"); 1056177636Sdfr 1057177636Sdfr fl.l_start = 0; 1058177636Sdfr fl.l_len = 0; 1059177636Sdfr fl.l_type = F_WRLCK; 1060177636Sdfr fl.l_whence = SEEK_SET; 1061177636Sdfr 1062177636Sdfr pid = fork(); 1063177636Sdfr if (pid < 0) 1064177636Sdfr err(1, "fork"); 1065177636Sdfr 1066177636Sdfr if (pid == 0) { 1067177636Sdfr /* 1068177636Sdfr * We are the child. We set a write lock and then 1069177636Sdfr * write one byte back to the parent to tell it. The 1070177636Sdfr * parent will kill us when its done. 1071177636Sdfr */ 1072177636Sdfr if (fcntl(fd, F_SETLK, &fl) < 0) 1073177636Sdfr err(1, "F_SETLK (child)"); 1074177636Sdfr if (write(pfd[1], "a", 1) < 0) 1075177636Sdfr err(1, "writing to pipe (child)"); 1076177636Sdfr 1077177636Sdfr usleep(1); 1078177636Sdfr exit(0); 1079177636Sdfr } 1080177636Sdfr 1081177636Sdfr /* 1082177636Sdfr * Wait until the child has set its lock and then perform the 1083177636Sdfr * test. 1084177636Sdfr */ 1085177636Sdfr while (read(pfd[0], &ch, 1) != 1) { 1086177636Sdfr if (errno == EINTR) 1087177636Sdfr continue; 1088177636Sdfr err(1, "reading from pipe (child)"); 1089177636Sdfr } 1090177636Sdfr 1091177636Sdfr /* 1092177636Sdfr * fcntl should wait until the alarm and then return -1 with 1093177636Sdfr * errno set to EINTR. 1094177636Sdfr */ 1095177636Sdfr itv.it_interval.tv_sec = 0; 1096177636Sdfr itv.it_interval.tv_usec = 0; 1097177636Sdfr itv.it_value.tv_sec = 0; 1098177636Sdfr itv.it_value.tv_usec = 2; 1099177636Sdfr setitimer(ITIMER_REAL, &itv, NULL); 1100177636Sdfr 1101177636Sdfr res = fcntl(fd, F_SETLKW, &fl); 1102177636Sdfr kill(pid, SIGTERM); 1103177636Sdfr safe_waitpid(pid); 1104177636Sdfr close(pfd[0]); 1105177636Sdfr close(pfd[1]); 1106177636Sdfr FAIL(!(res == 0 || (res == -1 && errno == EINTR))); 1107177636Sdfr 1108177636Sdfr fl.l_start = 0; 1109177636Sdfr fl.l_len = 0; 1110177636Sdfr fl.l_type = F_UNLCK; 1111177636Sdfr if (fcntl(fd, F_SETLK, &fl) < 0) 1112177636Sdfr err(1, "F_UNLCK"); 1113177636Sdfr } 1114177636Sdfr SUCCEED; 1115177636Sdfr} 1116177636Sdfr 1117177636Sdfr/* 1118177636Sdfr * Test 14 - soak test 1119177636Sdfr */ 1120177636Sdfrstatic int 1121180025Sdfrtest14(int fd, int argc, const char **argv) 1122177636Sdfr{ 1123177636Sdfr#define CHILD_COUNT 20 1124177636Sdfr /* 1125177636Sdfr * We create a set of child processes and let each one run 1126177636Sdfr * through a random sequence of locks and unlocks. 1127177636Sdfr */ 1128180025Sdfr int i, j, id, id_base; 1129177636Sdfr int pids[CHILD_COUNT], pid; 1130177636Sdfr char buf[128]; 1131177636Sdfr char tbuf[128]; 1132177636Sdfr int map[128]; 1133177636Sdfr char outbuf[512]; 1134177636Sdfr struct flock fl; 1135177636Sdfr struct itimerval itv; 1136177636Sdfr int status; 1137177636Sdfr 1138180025Sdfr id_base = 0; 1139180025Sdfr if (argc >= 2) 1140180025Sdfr id_base = strtol(argv[1], NULL, 0); 1141180025Sdfr 1142177636Sdfr printf("14 - soak test: "); 1143177636Sdfr fflush(stdout); 1144177636Sdfr 1145177636Sdfr for (i = 0; i < 128; i++) 1146177636Sdfr map[i] = F_UNLCK; 1147177636Sdfr 1148177636Sdfr for (i = 0; i < CHILD_COUNT; i++) { 1149177636Sdfr 1150177636Sdfr pid = fork(); 1151177636Sdfr if (pid < 0) 1152177636Sdfr err(1, "fork"); 1153177636Sdfr if (pid) { 1154177636Sdfr /* 1155177636Sdfr * Parent - record the pid and continue. 1156177636Sdfr */ 1157177636Sdfr pids[i] = pid; 1158177636Sdfr continue; 1159177636Sdfr } 1160177636Sdfr 1161177636Sdfr /* 1162177636Sdfr * Child - do some work and exit. 1163177636Sdfr */ 1164180025Sdfr id = id_base + i; 1165180025Sdfr srandom(getpid()); 1166177636Sdfr 1167177636Sdfr for (j = 0; j < 50; j++) { 1168177636Sdfr int start, end, len; 1169177636Sdfr int set, wrlock; 1170177636Sdfr 1171177636Sdfr do { 1172177636Sdfr start = random() & 127; 1173177636Sdfr end = random() & 127; 1174177636Sdfr } while (end <= start); 1175177636Sdfr 1176177636Sdfr set = random() & 1; 1177177636Sdfr wrlock = random() & 1; 1178177636Sdfr 1179177636Sdfr len = end - start; 1180177636Sdfr fl.l_start = start; 1181177636Sdfr fl.l_len = len; 1182177636Sdfr fl.l_whence = SEEK_SET; 1183177636Sdfr if (set) 1184177636Sdfr fl.l_type = wrlock ? F_WRLCK : F_RDLCK; 1185177636Sdfr else 1186177636Sdfr fl.l_type = F_UNLCK; 1187177636Sdfr 1188177636Sdfr itv.it_interval.tv_sec = 0; 1189177636Sdfr itv.it_interval.tv_usec = 0; 1190177636Sdfr itv.it_value.tv_sec = 0; 1191177636Sdfr itv.it_value.tv_usec = 3000; 1192177636Sdfr setitimer(ITIMER_REAL, &itv, NULL); 1193177636Sdfr 1194177636Sdfr if (fcntl(fd, F_SETLKW, &fl) < 0) { 1195177636Sdfr if (errno == EDEADLK || errno == EINTR) { 1196177636Sdfr if (verbose) { 1197177636Sdfr snprintf(outbuf, sizeof(outbuf), 1198177636Sdfr "%d[%d]: %s [%d .. %d] %s\n", 1199177636Sdfr id, j, 1200177636Sdfr set ? (wrlock ? "write lock" 1201177636Sdfr : "read lock") 1202177636Sdfr : "unlock", start, end, 1203177636Sdfr errno == EDEADLK 1204177636Sdfr ? "deadlock" 1205177636Sdfr : "interrupted"); 1206177636Sdfr write(1, outbuf, 1207177636Sdfr strlen(outbuf)); 1208177636Sdfr } 1209177636Sdfr continue; 1210177636Sdfr } else { 1211177636Sdfr perror("fcntl"); 1212177636Sdfr } 1213177636Sdfr } 1214177636Sdfr 1215177636Sdfr itv.it_interval.tv_sec = 0; 1216177636Sdfr itv.it_interval.tv_usec = 0; 1217177636Sdfr itv.it_value.tv_sec = 0; 1218177636Sdfr itv.it_value.tv_usec = 0; 1219177636Sdfr setitimer(ITIMER_REAL, &itv, NULL); 1220177636Sdfr 1221177636Sdfr if (verbose) { 1222177636Sdfr snprintf(outbuf, sizeof(outbuf), 1223177636Sdfr "%d[%d]: %s [%d .. %d] succeeded\n", 1224177636Sdfr id, j, 1225177636Sdfr set ? (wrlock ? "write lock" : "read lock") 1226177636Sdfr : "unlock", start, end); 1227177636Sdfr write(1, outbuf, strlen(outbuf)); 1228177636Sdfr } 1229177636Sdfr 1230177636Sdfr if (set) { 1231177636Sdfr if (wrlock) { 1232177636Sdfr /* 1233177636Sdfr * We got a write lock - write 1234177636Sdfr * our ID to each byte that we 1235177636Sdfr * managed to claim. 1236177636Sdfr */ 1237177636Sdfr for (i = start; i < end; i++) 1238177636Sdfr map[i] = F_WRLCK; 1239177636Sdfr memset(&buf[start], id, len); 1240177636Sdfr if (pwrite(fd, &buf[start], len, 1241177636Sdfr start) != len) { 1242177636Sdfr printf("%d: short write\n", id); 1243177636Sdfr exit(1); 1244177636Sdfr } 1245177636Sdfr } else { 1246177636Sdfr /* 1247177636Sdfr * We got a read lock - read 1248177636Sdfr * the bytes which we claimed 1249177636Sdfr * so that we can check that 1250177636Sdfr * they don't change 1251177636Sdfr * unexpectedly. 1252177636Sdfr */ 1253177636Sdfr for (i = start; i < end; i++) 1254177636Sdfr map[i] = F_RDLCK; 1255177636Sdfr if (pread(fd, &buf[start], len, 1256177636Sdfr start) != len) { 1257177636Sdfr printf("%d: short read\n", id); 1258177636Sdfr exit(1); 1259177636Sdfr } 1260177636Sdfr } 1261177636Sdfr } else { 1262177636Sdfr for (i = start; i < end; i++) 1263177636Sdfr map[i] = F_UNLCK; 1264177636Sdfr } 1265177636Sdfr 1266177636Sdfr usleep(1000); 1267177636Sdfr 1268177636Sdfr /* 1269177636Sdfr * Read back the whole region so that we can 1270177636Sdfr * check that all the bytes we have some kind 1271177636Sdfr * of claim to have the correct value. 1272177636Sdfr */ 1273177636Sdfr if (pread(fd, tbuf, sizeof(tbuf), 0) != sizeof(tbuf)) { 1274177636Sdfr printf("%d: short read\n", id); 1275177636Sdfr exit(1); 1276177636Sdfr } 1277177636Sdfr 1278177636Sdfr for (i = 0; i < 128; i++) { 1279177636Sdfr if (map[i] != F_UNLCK && buf[i] != tbuf[i]) { 1280177636Sdfr snprintf(outbuf, sizeof(outbuf), 1281177636Sdfr "%d: byte %d expected %d, " 1282177636Sdfr "got %d\n", id, i, buf[i], tbuf[i]); 1283177636Sdfr write(1, outbuf, strlen(outbuf)); 1284177636Sdfr exit(1); 1285177636Sdfr } 1286177636Sdfr } 1287177636Sdfr } 1288177636Sdfr if (verbose) 1289177636Sdfr printf("%d[%d]: done\n", id, j); 1290177636Sdfr 1291177636Sdfr exit(0); 1292177636Sdfr } 1293177636Sdfr 1294177636Sdfr status = 0; 1295177636Sdfr for (i = 0; i < CHILD_COUNT; i++) { 1296177636Sdfr status += safe_waitpid(pids[i]); 1297177636Sdfr } 1298177636Sdfr if (status) 1299177636Sdfr FAIL(status != 0); 1300177636Sdfr 1301177636Sdfr SUCCEED; 1302177636Sdfr} 1303177636Sdfr 1304180025Sdfr/* 1305180025Sdfr * Test 15 - flock(2) semantcs 1306180025Sdfr * 1307180025Sdfr * When a lock holder has a shared lock and attempts to upgrade that 1308180025Sdfr * shared lock to exclusive, it must drop the shared lock before 1309180025Sdfr * blocking on the exclusive lock. 1310180025Sdfr * 1311180025Sdfr * To test this, we first arrange for two shared locks on the file, 1312180025Sdfr * and then attempt to upgrade one of them to exclusive. This should 1313180025Sdfr * drop one of the shared locks and block. We interrupt the blocking 1314180025Sdfr * lock request and examine the lock state of the file after dropping 1315180025Sdfr * the other shared lock - there should be no active locks at this 1316180025Sdfr * point. 1317180025Sdfr */ 1318180025Sdfrstatic int 1319180025Sdfrtest15(int fd, __unused int argc, const __unused char **argv) 1320180025Sdfr{ 1321180025Sdfr#ifdef LOCK_EX 1322180025Sdfr /* 1323180025Sdfr * We create a child process to hold the lock which we will 1324180025Sdfr * test. We use a pipe to communicate with the child. 1325180025Sdfr * 1326180025Sdfr * Since we only have one file descriptors and lock ownership 1327180025Sdfr * for flock(2) goes with the file descriptor, we use fcntl to 1328180025Sdfr * set the child's shared lock. 1329180025Sdfr */ 1330180025Sdfr int pid; 1331180025Sdfr int pfd[2]; 1332180025Sdfr int fd2; 1333180025Sdfr struct flock fl; 1334180025Sdfr char ch; 1335180025Sdfr int res; 1336180025Sdfr 1337180025Sdfr if (pipe(pfd) < 0) 1338180025Sdfr err(1, "pipe"); 1339180025Sdfr 1340180025Sdfr pid = fork(); 1341180025Sdfr if (pid < 0) 1342180025Sdfr err(1, "fork"); 1343180025Sdfr 1344180025Sdfr if (pid == 0) { 1345180025Sdfr /* 1346180025Sdfr * We are the child. We set a shared lock and then 1347180025Sdfr * write one byte back to the parent to tell it. The 1348180025Sdfr * parent will kill us when its done. 1349180025Sdfr */ 1350180025Sdfr fl.l_start = 0; 1351180025Sdfr fl.l_len = 0; 1352180025Sdfr fl.l_type = F_RDLCK; 1353180025Sdfr fl.l_whence = SEEK_SET; 1354180025Sdfr if (fcntl(fd, F_SETLK, &fl) < 0) 1355180025Sdfr err(1, "fcntl(F_SETLK) (child)"); 1356180025Sdfr if (write(pfd[1], "a", 1) < 0) 1357180025Sdfr err(1, "writing to pipe (child)"); 1358180025Sdfr pause(); 1359180025Sdfr exit(0); 1360180025Sdfr } 1361180025Sdfr 1362180025Sdfr /* 1363180025Sdfr * Wait until the child has set its lock and then perform the 1364180025Sdfr * test. 1365180025Sdfr */ 1366180025Sdfr if (read(pfd[0], &ch, 1) != 1) 1367180025Sdfr err(1, "reading from pipe (child)"); 1368180025Sdfr 1369180025Sdfr fd2 = dup(fd); 1370180025Sdfr if (flock(fd, LOCK_SH) < 0) 1371180025Sdfr err(1, "flock shared"); 1372180025Sdfr 1373180025Sdfr /* 1374180025Sdfr * flock should wait until the alarm and then return -1 with 1375180025Sdfr * errno set to EINTR. 1376180025Sdfr */ 1377180025Sdfr printf("15 - flock(2) semantics: "); 1378180025Sdfr 1379180025Sdfr alarm(1); 1380180025Sdfr flock(fd, LOCK_EX); 1381180025Sdfr 1382180025Sdfr /* 1383180025Sdfr * Kill the child to force it to drop its locks. 1384180025Sdfr */ 1385180025Sdfr kill(pid, SIGTERM); 1386180025Sdfr safe_waitpid(pid); 1387180025Sdfr 1388180025Sdfr fl.l_start = 0; 1389180025Sdfr fl.l_len = 0; 1390180025Sdfr fl.l_type = F_WRLCK; 1391180025Sdfr fl.l_whence = SEEK_SET; 1392180025Sdfr res = fcntl(fd, F_GETLK, &fl); 1393180025Sdfr 1394180025Sdfr close(pfd[0]); 1395180025Sdfr close(pfd[1]); 1396180025Sdfr FAIL(res != 0); 1397180025Sdfr FAIL(fl.l_type != F_UNLCK); 1398180025Sdfr 1399180025Sdfr SUCCEED; 1400180025Sdfr#else 1401180025Sdfr return 0; 1402180025Sdfr#endif 1403180025Sdfr} 1404180025Sdfr 1405192949Szmlstruct test_ctx { 1406192949Szml struct flock tc_fl; 1407192949Szml int tc_fd; 1408192949Szml}; 1409192949Szml 1410192949Szmlstatic void * 1411192949Szmltest16_func(void *tc_in) 1412192949Szml{ 1413192949Szml uintptr_t error; 1414192949Szml struct test_ctx *tc = tc_in; 1415192949Szml 1416192949Szml error = fcntl(tc->tc_fd, F_SETLKW, &tc->tc_fl); 1417192949Szml 1418192949Szml pthread_exit((void *)error); 1419192949Szml} 1420192949Szml 1421192949Szml#define THREADS 10 1422192949Szml 1423192949Szml/* 1424192949Szml * Test 16 - F_SETLKW from two threads 1425192949Szml * 1426192949Szml * If two threads within a process are blocked on a lock and the lock 1427192949Szml * is granted, make sure things are sane. 1428192949Szml */ 1429192949Szmlstatic int 1430192949Szmltest16(int fd, __unused int argc, const __unused char **argv) 1431192949Szml{ 1432192949Szml /* 1433192949Szml * We create a child process to hold the lock which we will 1434192949Szml * test. We use a pipe to communicate with the child. 1435192949Szml */ 1436192949Szml int pid; 1437192949Szml int pfd[2]; 1438192949Szml struct test_ctx tc = { .tc_fd = fd }; 1439192949Szml char ch; 1440192949Szml int i; 1441192949Szml int error; 1442192949Szml pthread_t thr[THREADS]; 1443192949Szml 1444192949Szml if (pipe(pfd) < 0) 1445192949Szml err(1, "pipe"); 1446192949Szml 1447192949Szml tc.tc_fl.l_start = 0; 1448192949Szml tc.tc_fl.l_len = 0; 1449192949Szml tc.tc_fl.l_type = F_WRLCK; 1450192949Szml tc.tc_fl.l_whence = SEEK_SET; 1451192949Szml 1452192949Szml pid = fork(); 1453192949Szml if (pid < 0) 1454192949Szml err(1, "fork"); 1455192949Szml 1456192949Szml if (pid == 0) { 1457192949Szml /* 1458192949Szml * We are the child. We set a write lock and then 1459192949Szml * write one byte back to the parent to tell it. The 1460192949Szml * parent will kill us when its done. 1461192949Szml */ 1462192949Szml if (fcntl(fd, F_SETLK, &tc.tc_fl) < 0) 1463192949Szml err(1, "F_SETLK (child)"); 1464192949Szml if (write(pfd[1], "a", 1) < 0) 1465192949Szml err(1, "writing to pipe (child)"); 1466192949Szml pause(); 1467192949Szml exit(0); 1468192949Szml } 1469192949Szml 1470192949Szml /* 1471192949Szml * Wait until the child has set its lock and then perform the 1472192949Szml * test. 1473192949Szml */ 1474192949Szml if (read(pfd[0], &ch, 1) != 1) 1475192949Szml err(1, "reading from pipe (child)"); 1476192949Szml 1477192949Szml /* 1478192949Szml * fcntl should wait until the alarm and then return -1 with 1479192949Szml * errno set to EINTR. 1480192949Szml */ 1481192949Szml printf("16 - F_SETLKW on locked region by two threads: "); 1482192949Szml 1483192949Szml for (i = 0; i < THREADS; i++) { 1484192949Szml error = pthread_create(&thr[i], NULL, test16_func, &tc); 1485192949Szml if (error) 1486192949Szml err(1, "pthread_create"); 1487192949Szml } 1488192949Szml 1489192949Szml /* 1490192949Szml * Sleep, then kill the child. This makes me a little sad, but it's 1491192949Szml * tricky to tell whether the threads are all really blocked by this 1492192949Szml * point. 1493192949Szml */ 1494192949Szml sleep(1); 1495192949Szml kill(pid, SIGTERM); 1496192949Szml safe_waitpid(pid); 1497192949Szml close(pfd[0]); 1498192949Szml close(pfd[1]); 1499192949Szml 1500192949Szml for (i = 0; i < THREADS; i++) { 1501192949Szml void *res; 1502192949Szml error = pthread_join(thr[i], &res); 1503192949Szml if (error) 1504192949Szml err(1, "pthread_join"); 1505192949Szml FAIL((uintptr_t)res != 0); 1506192949Szml } 1507192949Szml 1508192949Szml SUCCEED; 1509192949Szml} 1510192949Szml 1511177636Sdfrstruct test { 1512180025Sdfr int (*testfn)(int, int, const char **); /* function to perform the test */ 1513177636Sdfr int num; /* test number */ 1514177636Sdfr int intr; /* non-zero if the test interrupts a lock */ 1515177636Sdfr}; 1516177636Sdfr 1517177636Sdfrstruct test tests[] = { 1518177636Sdfr { test1, 1, 0 }, 1519177636Sdfr { test2, 2, 0 }, 1520177636Sdfr { test3, 3, 1 }, 1521177636Sdfr { test4, 4, 0 }, 1522177636Sdfr { test5, 5, 1 }, 1523177636Sdfr { test6, 6, 1 }, 1524177636Sdfr { test7, 7, 0 }, 1525177636Sdfr { test8, 8, 0 }, 1526177636Sdfr { test9, 9, 0 }, 1527177636Sdfr { test10, 10, 0 }, 1528177636Sdfr { test11, 11, 1 }, 1529177636Sdfr { test12, 12, 0 }, 1530177636Sdfr { test13, 13, 1 }, 1531177636Sdfr { test14, 14, 0 }, 1532180025Sdfr { test15, 15, 1 }, 1533192949Szml { test16, 16, 1 }, 1534177636Sdfr}; 1535177636Sdfrint test_count = sizeof(tests) / sizeof(tests[0]); 1536177636Sdfr 1537177636Sdfrint 1538177636Sdfrmain(int argc, const char *argv[]) 1539177636Sdfr{ 1540177636Sdfr int testnum; 1541177636Sdfr int fd; 1542177636Sdfr int nointr; 1543177636Sdfr int i; 1544177636Sdfr struct sigaction sa; 1545180025Sdfr int test_argc; 1546180025Sdfr const char **test_argv; 1547177636Sdfr 1548180025Sdfr if (argc < 2) { 1549180025Sdfr errx(1, "usage: flock <directory> [test number] ..."); 1550177636Sdfr } 1551177636Sdfr 1552177636Sdfr fd = make_file(argv[1], 1024); 1553180025Sdfr if (argc >= 3) { 1554177636Sdfr testnum = strtol(argv[2], NULL, 0); 1555180025Sdfr test_argc = argc - 2; 1556180025Sdfr test_argv = argv + 2; 1557180025Sdfr } else { 1558177636Sdfr testnum = 0; 1559180025Sdfr test_argc = 0; 1560180025Sdfr test_argv = 0; 1561180025Sdfr } 1562177636Sdfr 1563177636Sdfr sa.sa_handler = ignore_alarm; 1564177636Sdfr sigemptyset(&sa.sa_mask); 1565177636Sdfr sa.sa_flags = 0; 1566177636Sdfr sigaction(SIGALRM, &sa, 0); 1567177636Sdfr 1568177636Sdfr nointr = 0; 1569180025Sdfr#if defined(__FreeBSD__) && __FreeBSD_version < 800040 1570177636Sdfr { 1571177636Sdfr /* 1572180025Sdfr * FreeBSD with userland NLM can't interrupt a blocked 1573180025Sdfr * lock request on an NFS mounted filesystem. 1574177636Sdfr */ 1575177636Sdfr struct statfs st; 1576177636Sdfr fstatfs(fd, &st); 1577177636Sdfr nointr = !strcmp(st.f_fstypename, "nfs"); 1578177636Sdfr } 1579177636Sdfr#endif 1580177636Sdfr 1581177636Sdfr for (i = 0; i < test_count; i++) { 1582177636Sdfr if (tests[i].intr && nointr) 1583177636Sdfr continue; 1584177636Sdfr if (!testnum || tests[i].num == testnum) 1585180025Sdfr tests[i].testfn(fd, test_argc, test_argv); 1586177636Sdfr } 1587177636Sdfr 1588177636Sdfr return 0; 1589177636Sdfr} 1590