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 30277527Sngie#include <sys/param.h> 31268385Skib#include <sys/file.h> 32177636Sdfr#include <sys/time.h> 33177636Sdfr#ifdef __FreeBSD__ 34177636Sdfr#include <sys/mount.h> 35177636Sdfr#endif 36180025Sdfr#include <sys/stat.h> 37177636Sdfr#include <sys/wait.h> 38177636Sdfr 39177636Sdfr#include <err.h> 40177636Sdfr#include <errno.h> 41177636Sdfr#include <fcntl.h> 42192949Szml#include <pthread.h> 43177636Sdfr#include <signal.h> 44268385Skib#include <stdint.h> 45177636Sdfr#include <stdio.h> 46177636Sdfr#include <stdlib.h> 47177636Sdfr#include <string.h> 48177636Sdfr#include <unistd.h> 49177636Sdfr 50177636Sdfr#ifdef __FreeBSD__ 51177638Sdfr#if __FreeBSD_version >= 800028 52177636Sdfr#define HAVE_SYSID 53177636Sdfr#endif 54177636Sdfr#include <sys/cdefs.h> 55177636Sdfr#else 56277527Sngie#ifndef nitems 57277527Sngie#define nitems(x) (sizeof((x)) / sizeof((x)[0])) 58277527Sngie#endif 59277527Sngie 60177636Sdfr#ifndef __unused 61268385Skib#ifdef __GNUC__ 62268385Skib#define __unused __attribute__((__unused__)) 63268385Skib#else 64177636Sdfr#define __unused 65177636Sdfr#endif 66177636Sdfr#endif 67268385Skib#endif 68177636Sdfr 69277527Sngiestatic int verbose = 0; 70177636Sdfr 71177636Sdfrstatic int 72180025Sdfrmake_file(const char *pathname, off_t sz) 73177636Sdfr{ 74180025Sdfr struct stat st; 75177636Sdfr const char *template = "/flocktempXXXXXX"; 76177636Sdfr size_t len; 77177636Sdfr char *filename; 78177636Sdfr int fd; 79177636Sdfr 80180025Sdfr if (stat(pathname, &st) == 0) { 81180025Sdfr if (S_ISREG(st.st_mode)) { 82180025Sdfr fd = open(pathname, O_RDWR); 83180025Sdfr if (fd < 0) 84180025Sdfr err(1, "open(%s)", pathname); 85180025Sdfr if (ftruncate(fd, sz) < 0) 86180025Sdfr err(1, "ftruncate"); 87180025Sdfr return (fd); 88180025Sdfr } 89180025Sdfr } 90180025Sdfr 91180025Sdfr len = strlen(pathname) + strlen(template) + 1; 92177636Sdfr filename = malloc(len); 93180025Sdfr strcpy(filename, pathname); 94177636Sdfr strcat(filename, template); 95177636Sdfr fd = mkstemp(filename); 96177636Sdfr if (fd < 0) 97177636Sdfr err(1, "mkstemp"); 98177636Sdfr if (ftruncate(fd, sz) < 0) 99177636Sdfr err(1, "ftruncate"); 100177636Sdfr if (unlink(filename) < 0) 101177636Sdfr err(1, "unlink"); 102177636Sdfr free(filename); 103177636Sdfr 104177636Sdfr return (fd); 105177636Sdfr} 106177636Sdfr 107177636Sdfrstatic void 108177636Sdfrignore_alarm(int __unused sig) 109177636Sdfr{ 110177636Sdfr} 111177636Sdfr 112180025Sdfrstatic int 113180025Sdfrsafe_waitpid(pid_t pid) 114180025Sdfr{ 115180025Sdfr int save_errno; 116180025Sdfr int status; 117180025Sdfr 118180025Sdfr save_errno = errno; 119180025Sdfr errno = 0; 120180025Sdfr while (waitpid(pid, &status, 0) != pid) { 121180025Sdfr if (errno == EINTR) 122180025Sdfr continue; 123180025Sdfr err(1, "waitpid"); 124180025Sdfr } 125180025Sdfr errno = save_errno; 126180025Sdfr 127180025Sdfr return (status); 128180025Sdfr} 129180025Sdfr 130177636Sdfr#define FAIL(test) \ 131177636Sdfr do { \ 132177636Sdfr if (test) { \ 133177636Sdfr printf("FAIL (%s)\n", #test); \ 134177636Sdfr return -1; \ 135177636Sdfr } \ 136177636Sdfr } while (0) 137177636Sdfr 138177636Sdfr#define SUCCEED \ 139177636Sdfr do { printf("SUCCEED\n"); return 0; } while (0) 140177636Sdfr 141177636Sdfr/* 142177636Sdfr * Test 1 - F_GETLK on unlocked region 143177636Sdfr * 144177636Sdfr * If no lock is found that would prevent this lock from being 145177636Sdfr * created, the structure is left unchanged by this function call 146177636Sdfr * except for the lock type which is set to F_UNLCK. 147177636Sdfr */ 148177636Sdfrstatic int 149180025Sdfrtest1(int fd, __unused int argc, const __unused char **argv) 150177636Sdfr{ 151177636Sdfr struct flock fl1, fl2; 152177636Sdfr 153177636Sdfr memset(&fl1, 1, sizeof(fl1)); 154177636Sdfr fl1.l_type = F_WRLCK; 155177636Sdfr fl1.l_whence = SEEK_SET; 156177636Sdfr fl2 = fl1; 157177636Sdfr 158177636Sdfr if (fcntl(fd, F_GETLK, &fl1) < 0) 159177636Sdfr err(1, "F_GETLK"); 160177636Sdfr 161177636Sdfr printf("1 - F_GETLK on unlocked region: "); 162177636Sdfr FAIL(fl1.l_start != fl2.l_start); 163177636Sdfr FAIL(fl1.l_len != fl2.l_len); 164177636Sdfr FAIL(fl1.l_pid != fl2.l_pid); 165177636Sdfr FAIL(fl1.l_type != F_UNLCK); 166177636Sdfr FAIL(fl1.l_whence != fl2.l_whence); 167177636Sdfr#ifdef HAVE_SYSID 168177636Sdfr FAIL(fl1.l_sysid != fl2.l_sysid); 169177636Sdfr#endif 170177636Sdfr 171177636Sdfr SUCCEED; 172177636Sdfr} 173177636Sdfr 174177636Sdfr/* 175177636Sdfr * Test 2 - F_SETLK on locked region 176177636Sdfr * 177177636Sdfr * If a shared or exclusive lock cannot be set, fcntl returns 178177636Sdfr * immediately with EACCES or EAGAIN. 179177636Sdfr */ 180177636Sdfrstatic int 181180025Sdfrtest2(int fd, __unused int argc, const __unused char **argv) 182177636Sdfr{ 183177636Sdfr /* 184177636Sdfr * We create a child process to hold the lock which we will 185177636Sdfr * test. We use a pipe to communicate with the child. 186177636Sdfr */ 187177636Sdfr int pid; 188177636Sdfr int pfd[2]; 189177636Sdfr struct flock fl; 190177636Sdfr char ch; 191177636Sdfr int res; 192177636Sdfr 193177636Sdfr if (pipe(pfd) < 0) 194177636Sdfr err(1, "pipe"); 195177636Sdfr 196177636Sdfr fl.l_start = 0; 197177636Sdfr fl.l_len = 0; 198177636Sdfr fl.l_type = F_WRLCK; 199177636Sdfr fl.l_whence = SEEK_SET; 200177636Sdfr 201177636Sdfr pid = fork(); 202177636Sdfr if (pid < 0) 203177636Sdfr err(1, "fork"); 204177636Sdfr 205177636Sdfr if (pid == 0) { 206177636Sdfr /* 207177636Sdfr * We are the child. We set a write lock and then 208177636Sdfr * write one byte back to the parent to tell it. The 209177636Sdfr * parent will kill us when its done. 210177636Sdfr */ 211177636Sdfr if (fcntl(fd, F_SETLK, &fl) < 0) 212177636Sdfr err(1, "F_SETLK (child)"); 213177636Sdfr if (write(pfd[1], "a", 1) < 0) 214177636Sdfr err(1, "writing to pipe (child)"); 215177636Sdfr pause(); 216177636Sdfr exit(0); 217177636Sdfr } 218177636Sdfr 219177636Sdfr /* 220177636Sdfr * Wait until the child has set its lock and then perform the 221177636Sdfr * test. 222177636Sdfr */ 223177636Sdfr if (read(pfd[0], &ch, 1) != 1) 224177636Sdfr err(1, "reading from pipe (child)"); 225177636Sdfr 226177636Sdfr /* 227177636Sdfr * fcntl should return -1 with errno set to either EACCES or 228177636Sdfr * EAGAIN. 229177636Sdfr */ 230177636Sdfr printf("2 - F_SETLK on locked region: "); 231177636Sdfr res = fcntl(fd, F_SETLK, &fl); 232177636Sdfr kill(pid, SIGTERM); 233177636Sdfr safe_waitpid(pid); 234177636Sdfr close(pfd[0]); 235177636Sdfr close(pfd[1]); 236177636Sdfr FAIL(res == 0); 237177636Sdfr FAIL(errno != EACCES && errno != EAGAIN); 238177636Sdfr 239177636Sdfr SUCCEED; 240177636Sdfr} 241177636Sdfr 242177636Sdfr/* 243177636Sdfr * Test 3 - F_SETLKW on locked region 244177636Sdfr * 245177636Sdfr * If a shared or exclusive lock is blocked by other locks, the 246177636Sdfr * process waits until the request can be satisfied. 247177636Sdfr * 248177636Sdfr * XXX this test hangs on FreeBSD NFS filesystems due to limitations 249177636Sdfr * in FreeBSD's client (and server) lockd implementation. 250177636Sdfr */ 251177636Sdfrstatic int 252180025Sdfrtest3(int fd, __unused int argc, const __unused char **argv) 253177636Sdfr{ 254177636Sdfr /* 255177636Sdfr * We create a child process to hold the lock which we will 256177636Sdfr * test. We use a pipe to communicate with the child. 257177636Sdfr */ 258177636Sdfr int pid; 259177636Sdfr int pfd[2]; 260177636Sdfr struct flock fl; 261177636Sdfr char ch; 262177636Sdfr int res; 263177636Sdfr 264177636Sdfr if (pipe(pfd) < 0) 265177636Sdfr err(1, "pipe"); 266177636Sdfr 267177636Sdfr fl.l_start = 0; 268177636Sdfr fl.l_len = 0; 269177636Sdfr fl.l_type = F_WRLCK; 270177636Sdfr fl.l_whence = SEEK_SET; 271177636Sdfr 272177636Sdfr pid = fork(); 273177636Sdfr if (pid < 0) 274177636Sdfr err(1, "fork"); 275177636Sdfr 276177636Sdfr if (pid == 0) { 277177636Sdfr /* 278177636Sdfr * We are the child. We set a write lock and then 279177636Sdfr * write one byte back to the parent to tell it. The 280177636Sdfr * parent will kill us when its done. 281177636Sdfr */ 282177636Sdfr if (fcntl(fd, F_SETLK, &fl) < 0) 283177636Sdfr err(1, "F_SETLK (child)"); 284177636Sdfr if (write(pfd[1], "a", 1) < 0) 285177636Sdfr err(1, "writing to pipe (child)"); 286177636Sdfr pause(); 287177636Sdfr exit(0); 288177636Sdfr } 289177636Sdfr 290177636Sdfr /* 291177636Sdfr * Wait until the child has set its lock and then perform the 292177636Sdfr * test. 293177636Sdfr */ 294177636Sdfr if (read(pfd[0], &ch, 1) != 1) 295177636Sdfr err(1, "reading from pipe (child)"); 296177636Sdfr 297177636Sdfr /* 298177636Sdfr * fcntl should wait until the alarm and then return -1 with 299177636Sdfr * errno set to EINTR. 300177636Sdfr */ 301177636Sdfr printf("3 - F_SETLKW on locked region: "); 302177636Sdfr 303177636Sdfr alarm(1); 304177636Sdfr 305177636Sdfr res = fcntl(fd, F_SETLKW, &fl); 306177636Sdfr kill(pid, SIGTERM); 307177636Sdfr safe_waitpid(pid); 308177636Sdfr close(pfd[0]); 309177636Sdfr close(pfd[1]); 310177636Sdfr FAIL(res == 0); 311177636Sdfr FAIL(errno != EINTR); 312177636Sdfr 313177636Sdfr SUCCEED; 314177636Sdfr} 315177636Sdfr 316177636Sdfr/* 317177636Sdfr * Test 4 - F_GETLK on locked region 318177636Sdfr * 319177636Sdfr * Get the first lock that blocks the lock. 320177636Sdfr */ 321177636Sdfrstatic int 322180025Sdfrtest4(int fd, __unused int argc, const __unused char **argv) 323177636Sdfr{ 324177636Sdfr /* 325177636Sdfr * We create a child process to hold the lock which we will 326177636Sdfr * test. We use a pipe to communicate with the child. 327177636Sdfr */ 328177636Sdfr int pid; 329177636Sdfr int pfd[2]; 330177636Sdfr struct flock fl; 331177636Sdfr char ch; 332177636Sdfr 333177636Sdfr if (pipe(pfd) < 0) 334177636Sdfr err(1, "pipe"); 335177636Sdfr 336177636Sdfr fl.l_start = 0; 337177636Sdfr fl.l_len = 99; 338177636Sdfr fl.l_type = F_WRLCK; 339177636Sdfr fl.l_whence = SEEK_SET; 340177636Sdfr 341177636Sdfr pid = fork(); 342177636Sdfr if (pid < 0) 343177636Sdfr err(1, "fork"); 344177636Sdfr 345177636Sdfr if (pid == 0) { 346177636Sdfr /* 347177636Sdfr * We are the child. We set a write lock and then 348177636Sdfr * write one byte back to the parent to tell it. The 349177636Sdfr * parent will kill us when its done. 350177636Sdfr */ 351177636Sdfr if (fcntl(fd, F_SETLK, &fl) < 0) 352177636Sdfr err(1, "F_SETLK (child)"); 353177636Sdfr if (write(pfd[1], "a", 1) < 0) 354177636Sdfr err(1, "writing to pipe (child)"); 355177636Sdfr pause(); 356177636Sdfr exit(0); 357177636Sdfr } 358177636Sdfr 359177636Sdfr /* 360177636Sdfr * Wait until the child has set its lock and then perform the 361177636Sdfr * test. 362177636Sdfr */ 363177636Sdfr if (read(pfd[0], &ch, 1) != 1) 364177636Sdfr err(1, "reading from pipe (child)"); 365177636Sdfr 366177636Sdfr /* 367177636Sdfr * fcntl should return a lock structure reflecting the lock we 368177636Sdfr * made in the child process. 369177636Sdfr */ 370177636Sdfr if (fcntl(fd, F_GETLK, &fl) < 0) 371177636Sdfr err(1, "F_GETLK"); 372177636Sdfr 373177636Sdfr printf("4 - F_GETLK on locked region: "); 374177636Sdfr FAIL(fl.l_start != 0); 375177636Sdfr FAIL(fl.l_len != 99); 376177636Sdfr FAIL(fl.l_type != F_WRLCK); 377177636Sdfr FAIL(fl.l_pid != pid); 378177636Sdfr#ifdef HAVE_SYSID 379177636Sdfr FAIL(fl.l_sysid != 0); 380177636Sdfr#endif 381177636Sdfr 382177636Sdfr kill(pid, SIGTERM); 383177636Sdfr safe_waitpid(pid); 384177636Sdfr close(pfd[0]); 385177636Sdfr close(pfd[1]); 386177636Sdfr 387177636Sdfr SUCCEED; 388177636Sdfr} 389177636Sdfr 390177636Sdfr/* 391177636Sdfr * Test 5 - F_SETLKW simple deadlock 392177636Sdfr * 393177636Sdfr * If a blocking shared lock request would cause a deadlock (i.e. the 394177636Sdfr * lock request is blocked by a process which is itself blocked on a 395177636Sdfr * lock currently owned by the process making the new request), 396177636Sdfr * EDEADLK is returned. 397177636Sdfr */ 398177636Sdfrstatic int 399180025Sdfrtest5(int fd, __unused int argc, const __unused char **argv) 400177636Sdfr{ 401177636Sdfr /* 402177636Sdfr * We create a child process to hold the lock which we will 403177636Sdfr * test. Because our test relies on the child process being 404177636Sdfr * blocked on the parent's lock, we can't easily use a pipe to 405177636Sdfr * synchronize so we just sleep in the parent to given the 406177636Sdfr * child a chance to setup. 407177636Sdfr * 408177636Sdfr * To create the deadlock condition, we arrange for the parent 409177636Sdfr * to lock the first byte of the file and the child to lock 410177636Sdfr * the second byte. After locking the second byte, the child 411177636Sdfr * will attempt to lock the first byte of the file, and 412177636Sdfr * block. The parent will then attempt to lock the second byte 413177636Sdfr * (owned by the child) which should cause deadlock. 414177636Sdfr */ 415177636Sdfr int pid; 416177636Sdfr struct flock fl; 417177636Sdfr int res; 418177636Sdfr 419177636Sdfr /* 420177636Sdfr * Lock the first byte in the parent. 421177636Sdfr */ 422177636Sdfr fl.l_start = 0; 423177636Sdfr fl.l_len = 1; 424177636Sdfr fl.l_type = F_WRLCK; 425177636Sdfr fl.l_whence = SEEK_SET; 426177636Sdfr if (fcntl(fd, F_SETLK, &fl) < 0) 427177636Sdfr err(1, "F_SETLK 1 (parent)"); 428177636Sdfr 429177636Sdfr pid = fork(); 430177636Sdfr if (pid < 0) 431177636Sdfr err(1, "fork"); 432177636Sdfr 433177636Sdfr if (pid == 0) { 434177636Sdfr /* 435177636Sdfr * Lock the second byte in the child and then block on 436177636Sdfr * the parent's lock. 437177636Sdfr */ 438177636Sdfr fl.l_start = 1; 439177636Sdfr if (fcntl(fd, F_SETLK, &fl) < 0) 440177636Sdfr err(1, "F_SETLK (child)"); 441177636Sdfr fl.l_start = 0; 442177636Sdfr if (fcntl(fd, F_SETLKW, &fl) < 0) 443177636Sdfr err(1, "F_SETLKW (child)"); 444177636Sdfr exit(0); 445177636Sdfr } 446177636Sdfr 447177636Sdfr /* 448177636Sdfr * Wait until the child has set its lock and then perform the 449177636Sdfr * test. 450177636Sdfr */ 451177636Sdfr sleep(1); 452177636Sdfr 453177636Sdfr /* 454180025Sdfr * fcntl should immediately return -1 with errno set to 455180025Sdfr * EDEADLK. If the alarm fires, we failed to detect the 456180025Sdfr * deadlock. 457177636Sdfr */ 458180025Sdfr alarm(1); 459177636Sdfr printf("5 - F_SETLKW simple deadlock: "); 460177636Sdfr 461177636Sdfr fl.l_start = 1; 462177636Sdfr res = fcntl(fd, F_SETLKW, &fl); 463177636Sdfr kill(pid, SIGTERM); 464177636Sdfr safe_waitpid(pid); 465177636Sdfr 466177636Sdfr FAIL(res == 0); 467177636Sdfr FAIL(errno != EDEADLK); 468177636Sdfr 469177636Sdfr fl.l_start = 0; 470177636Sdfr fl.l_len = 0; 471177636Sdfr fl.l_type = F_UNLCK; 472177636Sdfr if (fcntl(fd, F_SETLK, &fl) < 0) 473177636Sdfr err(1, "F_UNLCK"); 474177636Sdfr 475180025Sdfr /* 476180025Sdfr * Cancel the alarm to avoid confusing later tests. 477180025Sdfr */ 478180025Sdfr alarm(0); 479180025Sdfr 480177636Sdfr SUCCEED; 481177636Sdfr} 482177636Sdfr 483177636Sdfr/* 484177636Sdfr * Test 6 - F_SETLKW complex deadlock. 485177636Sdfr * 486177636Sdfr * This test involves three process, P, C1 and C2. We set things up so 487177636Sdfr * that P locks byte zero, C1 locks byte 1 and C2 locks byte 2. We 488177636Sdfr * also block C2 by attempting to lock byte zero. Lastly, P attempts 489177636Sdfr * to lock a range including byte 1 and 2. This represents a deadlock 490177636Sdfr * (due to C2's blocking attempt to lock byte zero). 491177636Sdfr */ 492177636Sdfrstatic int 493180025Sdfrtest6(int fd, __unused int argc, const __unused char **argv) 494177636Sdfr{ 495177636Sdfr /* 496177636Sdfr * Because our test relies on the child process being blocked 497177636Sdfr * on the parent's lock, we can't easily use a pipe to 498177636Sdfr * synchronize so we just sleep in the parent to given the 499177636Sdfr * children a chance to setup. 500177636Sdfr */ 501177636Sdfr int pid1, pid2; 502177636Sdfr struct flock fl; 503177636Sdfr int res; 504177636Sdfr 505177636Sdfr /* 506177636Sdfr * Lock the first byte in the parent. 507177636Sdfr */ 508177636Sdfr fl.l_start = 0; 509177636Sdfr fl.l_len = 1; 510177636Sdfr fl.l_type = F_WRLCK; 511177636Sdfr fl.l_whence = SEEK_SET; 512177636Sdfr if (fcntl(fd, F_SETLK, &fl) < 0) 513177636Sdfr err(1, "F_SETLK 1 (parent)"); 514177636Sdfr 515177636Sdfr pid1 = fork(); 516177636Sdfr if (pid1 < 0) 517177636Sdfr err(1, "fork"); 518177636Sdfr 519177636Sdfr if (pid1 == 0) { 520177636Sdfr /* 521177636Sdfr * C1 522177636Sdfr * Lock the second byte in the child and then sleep 523177636Sdfr */ 524177636Sdfr fl.l_start = 1; 525177636Sdfr if (fcntl(fd, F_SETLK, &fl) < 0) 526177636Sdfr err(1, "F_SETLK (child1)"); 527177636Sdfr pause(); 528177636Sdfr exit(0); 529177636Sdfr } 530177636Sdfr 531177636Sdfr pid2 = fork(); 532177636Sdfr if (pid2 < 0) 533177636Sdfr err(1, "fork"); 534177636Sdfr 535177636Sdfr if (pid2 == 0) { 536177636Sdfr /* 537177636Sdfr * C2 538177636Sdfr * Lock the third byte in the child and then block on 539177636Sdfr * the parent's lock. 540177636Sdfr */ 541177636Sdfr fl.l_start = 2; 542177636Sdfr if (fcntl(fd, F_SETLK, &fl) < 0) 543177636Sdfr err(1, "F_SETLK (child2)"); 544177636Sdfr fl.l_start = 0; 545177636Sdfr if (fcntl(fd, F_SETLKW, &fl) < 0) 546177636Sdfr err(1, "F_SETLKW (child2)"); 547177636Sdfr exit(0); 548177636Sdfr } 549177636Sdfr 550177636Sdfr /* 551177636Sdfr * Wait until the children have set their locks and then 552177636Sdfr * perform the test. 553177636Sdfr */ 554177636Sdfr sleep(1); 555177636Sdfr 556177636Sdfr /* 557177636Sdfr * fcntl should immediately return -1 with errno set to 558177636Sdfr * EDEADLK. If the alarm fires, we failed to detect the 559177636Sdfr * deadlock. 560177636Sdfr */ 561177636Sdfr alarm(1); 562177636Sdfr printf("6 - F_SETLKW complex deadlock: "); 563177636Sdfr 564177636Sdfr fl.l_start = 1; 565177636Sdfr fl.l_len = 2; 566177636Sdfr res = fcntl(fd, F_SETLKW, &fl); 567177636Sdfr kill(pid1, SIGTERM); 568177636Sdfr safe_waitpid(pid1); 569177636Sdfr kill(pid2, SIGTERM); 570177636Sdfr safe_waitpid(pid2); 571177636Sdfr 572177636Sdfr fl.l_start = 0; 573177636Sdfr fl.l_len = 0; 574177636Sdfr fl.l_type = F_UNLCK; 575177636Sdfr if (fcntl(fd, F_SETLK, &fl) < 0) 576177636Sdfr err(1, "F_UNLCK"); 577177636Sdfr 578177636Sdfr FAIL(res == 0); 579177636Sdfr FAIL(errno != EDEADLK); 580177636Sdfr 581177636Sdfr /* 582177636Sdfr * Cancel the alarm to avoid confusing later tests. 583177636Sdfr */ 584177636Sdfr alarm(0); 585177636Sdfr 586177636Sdfr SUCCEED; 587177636Sdfr} 588177636Sdfr 589177636Sdfr/* 590177636Sdfr * Test 7 - F_SETLK shared lock on exclusive locked region 591177636Sdfr * 592177636Sdfr * If a shared or exclusive lock cannot be set, fcntl returns 593177636Sdfr * immediately with EACCES or EAGAIN. 594177636Sdfr */ 595177636Sdfrstatic int 596180025Sdfrtest7(int fd, __unused int argc, const __unused char **argv) 597177636Sdfr{ 598177636Sdfr /* 599177636Sdfr * We create a child process to hold the lock which we will 600177636Sdfr * test. We use a pipe to communicate with the child. 601177636Sdfr */ 602177636Sdfr int pid; 603177636Sdfr int pfd[2]; 604177636Sdfr struct flock fl; 605177636Sdfr char ch; 606177636Sdfr int res; 607177636Sdfr 608177636Sdfr if (pipe(pfd) < 0) 609177636Sdfr err(1, "pipe"); 610177636Sdfr 611177636Sdfr fl.l_start = 0; 612177636Sdfr fl.l_len = 0; 613177636Sdfr fl.l_type = F_WRLCK; 614177636Sdfr fl.l_whence = SEEK_SET; 615177636Sdfr 616177636Sdfr pid = fork(); 617177636Sdfr if (pid < 0) 618177636Sdfr err(1, "fork"); 619177636Sdfr 620177636Sdfr if (pid == 0) { 621177636Sdfr /* 622177636Sdfr * We are the child. We set a write lock and then 623177636Sdfr * write one byte back to the parent to tell it. The 624177636Sdfr * parent will kill us when its done. 625177636Sdfr */ 626177636Sdfr if (fcntl(fd, F_SETLK, &fl) < 0) 627177636Sdfr err(1, "F_SETLK (child)"); 628177636Sdfr if (write(pfd[1], "a", 1) < 0) 629177636Sdfr err(1, "writing to pipe (child)"); 630177636Sdfr pause(); 631177636Sdfr exit(0); 632177636Sdfr } 633177636Sdfr 634177636Sdfr /* 635177636Sdfr * Wait until the child has set its lock and then perform the 636177636Sdfr * test. 637177636Sdfr */ 638177636Sdfr if (read(pfd[0], &ch, 1) != 1) 639177636Sdfr err(1, "reading from pipe (child)"); 640177636Sdfr 641177636Sdfr /* 642177636Sdfr * fcntl should wait until the alarm and then return -1 with 643177636Sdfr * errno set to EINTR. 644177636Sdfr */ 645177636Sdfr printf("7 - F_SETLK shared lock on exclusive locked region: "); 646177636Sdfr 647177636Sdfr fl.l_type = F_RDLCK; 648177636Sdfr res = fcntl(fd, F_SETLK, &fl); 649177636Sdfr kill(pid, SIGTERM); 650177636Sdfr safe_waitpid(pid); 651177636Sdfr close(pfd[0]); 652177636Sdfr close(pfd[1]); 653177636Sdfr 654177636Sdfr FAIL(res == 0); 655177636Sdfr FAIL(errno != EACCES && errno != EAGAIN); 656177636Sdfr 657177636Sdfr SUCCEED; 658177636Sdfr} 659177636Sdfr 660177636Sdfr/* 661177636Sdfr * Test 8 - F_SETLK shared lock on share locked region 662177636Sdfr * 663177636Sdfr * When a shared lock is set on a segment of a file, other processes 664177636Sdfr * shall be able to set shared locks on that segment or a portion of 665177636Sdfr * it. 666177636Sdfr */ 667177636Sdfrstatic int 668180025Sdfrtest8(int fd, __unused int argc, const __unused char **argv) 669177636Sdfr{ 670177636Sdfr /* 671177636Sdfr * We create a child process to hold the lock which we will 672177636Sdfr * test. We use a pipe to communicate with the child. 673177636Sdfr */ 674177636Sdfr int pid; 675177636Sdfr int pfd[2]; 676177636Sdfr struct flock fl; 677177636Sdfr char ch; 678177636Sdfr int res; 679177636Sdfr 680177636Sdfr if (pipe(pfd) < 0) 681177636Sdfr err(1, "pipe"); 682177636Sdfr 683177636Sdfr fl.l_start = 0; 684177636Sdfr fl.l_len = 0; 685177636Sdfr fl.l_type = F_RDLCK; 686177636Sdfr fl.l_whence = SEEK_SET; 687177636Sdfr 688177636Sdfr pid = fork(); 689177636Sdfr if (pid < 0) 690177636Sdfr err(1, "fork"); 691177636Sdfr 692177636Sdfr if (pid == 0) { 693177636Sdfr /* 694177636Sdfr * We are the child. We set a write lock and then 695177636Sdfr * write one byte back to the parent to tell it. The 696177636Sdfr * parent will kill us when its done. 697177636Sdfr */ 698177636Sdfr if (fcntl(fd, F_SETLK, &fl) < 0) 699177636Sdfr err(1, "F_SETLK (child)"); 700177636Sdfr if (write(pfd[1], "a", 1) < 0) 701177636Sdfr err(1, "writing to pipe (child)"); 702177636Sdfr pause(); 703177636Sdfr exit(0); 704177636Sdfr } 705177636Sdfr 706177636Sdfr /* 707177636Sdfr * Wait until the child has set its lock and then perform the 708177636Sdfr * test. 709177636Sdfr */ 710177636Sdfr if (read(pfd[0], &ch, 1) != 1) 711177636Sdfr err(1, "reading from pipe (child)"); 712177636Sdfr 713177636Sdfr /* 714177636Sdfr * fcntl should wait until the alarm and then return -1 with 715177636Sdfr * errno set to EINTR. 716177636Sdfr */ 717177636Sdfr printf("8 - F_SETLK shared lock on share locked region: "); 718177636Sdfr 719177636Sdfr fl.l_type = F_RDLCK; 720177636Sdfr res = fcntl(fd, F_SETLK, &fl); 721177636Sdfr 722177636Sdfr kill(pid, SIGTERM); 723177636Sdfr safe_waitpid(pid); 724177636Sdfr close(pfd[0]); 725177636Sdfr close(pfd[1]); 726177636Sdfr 727177636Sdfr fl.l_start = 0; 728177636Sdfr fl.l_len = 0; 729177636Sdfr fl.l_type = F_UNLCK; 730177636Sdfr if (fcntl(fd, F_SETLK, &fl) < 0) 731177636Sdfr err(1, "F_UNLCK"); 732177636Sdfr 733177636Sdfr FAIL(res != 0); 734177636Sdfr 735177636Sdfr SUCCEED; 736177636Sdfr} 737177636Sdfr 738177636Sdfr/* 739177636Sdfr * Test 9 - F_SETLK exclusive lock on share locked region 740177636Sdfr * 741177636Sdfr * If a shared or exclusive lock cannot be set, fcntl returns 742177636Sdfr * immediately with EACCES or EAGAIN. 743177636Sdfr */ 744177636Sdfrstatic int 745180025Sdfrtest9(int fd, __unused int argc, const __unused char **argv) 746177636Sdfr{ 747177636Sdfr /* 748177636Sdfr * We create a child process to hold the lock which we will 749177636Sdfr * test. We use a pipe to communicate with the child. 750177636Sdfr */ 751177636Sdfr int pid; 752177636Sdfr int pfd[2]; 753177636Sdfr struct flock fl; 754177636Sdfr char ch; 755177636Sdfr int res; 756177636Sdfr 757177636Sdfr if (pipe(pfd) < 0) 758177636Sdfr err(1, "pipe"); 759177636Sdfr 760177636Sdfr fl.l_start = 0; 761177636Sdfr fl.l_len = 0; 762177636Sdfr fl.l_type = F_RDLCK; 763177636Sdfr fl.l_whence = SEEK_SET; 764177636Sdfr 765177636Sdfr pid = fork(); 766177636Sdfr if (pid < 0) 767177636Sdfr err(1, "fork"); 768177636Sdfr 769177636Sdfr if (pid == 0) { 770177636Sdfr /* 771177636Sdfr * We are the child. We set a write lock and then 772177636Sdfr * write one byte back to the parent to tell it. The 773177636Sdfr * parent will kill us when its done. 774177636Sdfr */ 775177636Sdfr if (fcntl(fd, F_SETLK, &fl) < 0) 776177636Sdfr err(1, "F_SETLK (child)"); 777177636Sdfr if (write(pfd[1], "a", 1) < 0) 778177636Sdfr err(1, "writing to pipe (child)"); 779177636Sdfr pause(); 780177636Sdfr exit(0); 781177636Sdfr } 782177636Sdfr 783177636Sdfr /* 784177636Sdfr * Wait until the child has set its lock and then perform the 785177636Sdfr * test. 786177636Sdfr */ 787177636Sdfr if (read(pfd[0], &ch, 1) != 1) 788177636Sdfr err(1, "reading from pipe (child)"); 789177636Sdfr 790177636Sdfr /* 791177636Sdfr * fcntl should wait until the alarm and then return -1 with 792177636Sdfr * errno set to EINTR. 793177636Sdfr */ 794177636Sdfr printf("9 - F_SETLK exclusive lock on share locked region: "); 795177636Sdfr 796177636Sdfr fl.l_type = F_WRLCK; 797177636Sdfr res = fcntl(fd, F_SETLK, &fl); 798177636Sdfr kill(pid, SIGTERM); 799177636Sdfr safe_waitpid(pid); 800177636Sdfr close(pfd[0]); 801177636Sdfr close(pfd[1]); 802177636Sdfr 803177636Sdfr FAIL(res == 0); 804177636Sdfr FAIL(errno != EACCES && errno != EAGAIN); 805177636Sdfr 806177636Sdfr SUCCEED; 807177636Sdfr} 808177636Sdfr 809177636Sdfr/* 810177636Sdfr * Test 10 - trying to set bogus pid or sysid values 811177636Sdfr * 812177636Sdfr * The l_pid and l_sysid fields are only used with F_GETLK to return 813177636Sdfr * the process ID of the process holding a blocking lock and the 814177636Sdfr * system ID of the system that owns that process 815177636Sdfr */ 816177636Sdfrstatic int 817180025Sdfrtest10(int fd, __unused int argc, const __unused char **argv) 818177636Sdfr{ 819177636Sdfr /* 820177636Sdfr * We create a child process to hold the lock which we will 821177636Sdfr * test. We use a pipe to communicate with the child. 822177636Sdfr */ 823177636Sdfr int pid; 824177636Sdfr int pfd[2]; 825177636Sdfr struct flock fl; 826177636Sdfr char ch; 827177636Sdfr 828177636Sdfr if (pipe(pfd) < 0) 829177636Sdfr err(1, "pipe"); 830177636Sdfr 831177636Sdfr fl.l_start = 0; 832177636Sdfr fl.l_len = 0; 833177636Sdfr fl.l_type = F_WRLCK; 834177636Sdfr fl.l_whence = SEEK_SET; 835177636Sdfr fl.l_pid = 9999; 836177636Sdfr#ifdef HAVE_SYSID 837177636Sdfr fl.l_sysid = 9999; 838177636Sdfr#endif 839177636Sdfr 840177636Sdfr pid = fork(); 841177636Sdfr if (pid < 0) 842177636Sdfr err(1, "fork"); 843177636Sdfr 844177636Sdfr if (pid == 0) { 845177636Sdfr /* 846177636Sdfr * We are the child. We set a write lock and then 847177636Sdfr * write one byte back to the parent to tell it. The 848177636Sdfr * parent will kill us when its done. 849177636Sdfr */ 850177636Sdfr if (fcntl(fd, F_SETLK, &fl) < 0) 851177636Sdfr err(1, "F_SETLK (child)"); 852177636Sdfr if (write(pfd[1], "a", 1) < 0) 853177636Sdfr err(1, "writing to pipe (child)"); 854177636Sdfr pause(); 855177636Sdfr exit(0); 856177636Sdfr } 857177636Sdfr 858177636Sdfr /* 859177636Sdfr * Wait until the child has set its lock and then perform the 860177636Sdfr * test. 861177636Sdfr */ 862177636Sdfr if (read(pfd[0], &ch, 1) != 1) 863177636Sdfr err(1, "reading from pipe (child)"); 864177636Sdfr 865177636Sdfr printf("10 - trying to set bogus pid or sysid values: "); 866177636Sdfr 867177636Sdfr if (fcntl(fd, F_GETLK, &fl) < 0) 868177636Sdfr err(1, "F_GETLK"); 869177636Sdfr 870177636Sdfr kill(pid, SIGTERM); 871177636Sdfr safe_waitpid(pid); 872177636Sdfr close(pfd[0]); 873177636Sdfr close(pfd[1]); 874177636Sdfr 875177636Sdfr FAIL(fl.l_pid != pid); 876177636Sdfr#ifdef HAVE_SYSID 877177636Sdfr FAIL(fl.l_sysid != 0); 878177636Sdfr#endif 879177636Sdfr 880177636Sdfr SUCCEED; 881177636Sdfr} 882177636Sdfr 883177636Sdfr/* 884177636Sdfr * Test 11 - remote locks 885177636Sdfr * 886177636Sdfr * XXX temporary interface which will be removed when the kernel lockd 887177636Sdfr * is added. 888177636Sdfr */ 889177636Sdfrstatic int 890180025Sdfrtest11(int fd, __unused int argc, const __unused char **argv) 891177636Sdfr{ 892177636Sdfr#ifdef F_SETLK_REMOTE 893177636Sdfr struct flock fl; 894177636Sdfr int res; 895177636Sdfr 896177636Sdfr if (geteuid() != 0) 897177636Sdfr return 0; 898177636Sdfr 899177636Sdfr fl.l_start = 0; 900177636Sdfr fl.l_len = 0; 901177636Sdfr fl.l_type = F_WRLCK; 902177636Sdfr fl.l_whence = SEEK_SET; 903177636Sdfr fl.l_pid = 9999; 904177636Sdfr fl.l_sysid = 1001; 905177636Sdfr 906177636Sdfr printf("11 - remote locks: "); 907177636Sdfr 908177636Sdfr res = fcntl(fd, F_SETLK_REMOTE, &fl); 909177636Sdfr FAIL(res != 0); 910177636Sdfr 911177636Sdfr fl.l_sysid = 1002; 912177636Sdfr res = fcntl(fd, F_SETLK_REMOTE, &fl); 913177636Sdfr FAIL(res == 0); 914177636Sdfr FAIL(errno != EACCES && errno != EAGAIN); 915177636Sdfr 916177636Sdfr res = fcntl(fd, F_GETLK, &fl); 917177636Sdfr FAIL(res != 0); 918177636Sdfr FAIL(fl.l_pid != 9999); 919177636Sdfr FAIL(fl.l_sysid != 1001); 920177636Sdfr 921177636Sdfr fl.l_type = F_UNLCK; 922177636Sdfr fl.l_sysid = 1001; 923177636Sdfr fl.l_start = 0; 924177636Sdfr fl.l_len = 0; 925177636Sdfr res = fcntl(fd, F_SETLK_REMOTE, &fl); 926177636Sdfr FAIL(res != 0); 927177636Sdfr 928177636Sdfr fl.l_pid = 1234; 929177636Sdfr fl.l_sysid = 1001; 930177636Sdfr fl.l_start = 0; 931177636Sdfr fl.l_len = 1; 932177636Sdfr fl.l_whence = SEEK_SET; 933177636Sdfr fl.l_type = F_RDLCK; 934177636Sdfr res = fcntl(fd, F_SETLK_REMOTE, &fl); 935177636Sdfr FAIL(res != 0); 936177636Sdfr 937177636Sdfr fl.l_sysid = 1002; 938177636Sdfr res = fcntl(fd, F_SETLK_REMOTE, &fl); 939177636Sdfr FAIL(res != 0); 940177636Sdfr 941177636Sdfr fl.l_type = F_UNLCKSYS; 942177636Sdfr fl.l_sysid = 1001; 943177636Sdfr res = fcntl(fd, F_SETLK_REMOTE, &fl); 944177636Sdfr FAIL(res != 0); 945177636Sdfr 946177636Sdfr fl.l_type = F_WRLCK; 947177636Sdfr res = fcntl(fd, F_GETLK, &fl); 948177636Sdfr FAIL(res != 0); 949177636Sdfr FAIL(fl.l_pid != 1234); 950177636Sdfr FAIL(fl.l_sysid != 1002); 951177636Sdfr 952177636Sdfr fl.l_type = F_UNLCKSYS; 953177636Sdfr fl.l_sysid = 1002; 954177636Sdfr res = fcntl(fd, F_SETLK_REMOTE, &fl); 955177636Sdfr FAIL(res != 0); 956177636Sdfr 957177636Sdfr SUCCEED; 958177636Sdfr#else 959177636Sdfr return 0; 960177636Sdfr#endif 961177636Sdfr} 962177636Sdfr 963177636Sdfr/* 964177636Sdfr * Test 12 - F_SETLKW on locked region which is then unlocked 965177636Sdfr * 966177636Sdfr * If a shared or exclusive lock is blocked by other locks, the 967177636Sdfr * process waits until the request can be satisfied. 968177636Sdfr */ 969177636Sdfrstatic int 970180025Sdfrtest12(int fd, __unused int argc, const __unused char **argv) 971177636Sdfr{ 972177636Sdfr /* 973177636Sdfr * We create a child process to hold the lock which we will 974177636Sdfr * test. We use a pipe to communicate with the child. 975177636Sdfr */ 976177636Sdfr int pid; 977177636Sdfr int pfd[2]; 978177636Sdfr struct flock fl; 979177636Sdfr char ch; 980177636Sdfr int res; 981177636Sdfr 982177636Sdfr if (pipe(pfd) < 0) 983177636Sdfr err(1, "pipe"); 984177636Sdfr 985177636Sdfr fl.l_start = 0; 986177636Sdfr fl.l_len = 0; 987177636Sdfr fl.l_type = F_WRLCK; 988177636Sdfr fl.l_whence = SEEK_SET; 989177636Sdfr 990177636Sdfr pid = fork(); 991177636Sdfr if (pid < 0) 992177636Sdfr err(1, "fork"); 993177636Sdfr 994177636Sdfr if (pid == 0) { 995177636Sdfr /* 996177636Sdfr * We are the child. We set a write lock and then 997177636Sdfr * write one byte back to the parent to tell it. The 998177636Sdfr * parent will kill us when its done. 999177636Sdfr */ 1000177636Sdfr if (fcntl(fd, F_SETLK, &fl) < 0) 1001177636Sdfr err(1, "F_SETLK (child)"); 1002177636Sdfr if (write(pfd[1], "a", 1) < 0) 1003177636Sdfr err(1, "writing to pipe (child)"); 1004177636Sdfr 1005177636Sdfr sleep(1); 1006177636Sdfr exit(0); 1007177636Sdfr } 1008177636Sdfr 1009177636Sdfr /* 1010177636Sdfr * Wait until the child has set its lock and then perform the 1011177636Sdfr * test. 1012177636Sdfr */ 1013177636Sdfr if (read(pfd[0], &ch, 1) != 1) 1014177636Sdfr err(1, "reading from pipe (child)"); 1015177636Sdfr 1016177636Sdfr /* 1017177636Sdfr * fcntl should wait until the alarm and then return -1 with 1018177636Sdfr * errno set to EINTR. 1019177636Sdfr */ 1020177636Sdfr printf("12 - F_SETLKW on locked region which is then unlocked: "); 1021177636Sdfr 1022177636Sdfr //alarm(1); 1023177636Sdfr 1024177636Sdfr res = fcntl(fd, F_SETLKW, &fl); 1025177636Sdfr kill(pid, SIGTERM); 1026177636Sdfr safe_waitpid(pid); 1027177636Sdfr close(pfd[0]); 1028177636Sdfr close(pfd[1]); 1029177636Sdfr FAIL(res != 0); 1030177636Sdfr 1031177636Sdfr fl.l_start = 0; 1032177636Sdfr fl.l_len = 0; 1033177636Sdfr fl.l_type = F_UNLCK; 1034177636Sdfr if (fcntl(fd, F_SETLK, &fl) < 0) 1035177636Sdfr err(1, "F_UNLCK"); 1036177636Sdfr 1037177636Sdfr SUCCEED; 1038177636Sdfr} 1039177636Sdfr 1040177636Sdfr/* 1041177636Sdfr * Test 13 - F_SETLKW on locked region, race with owner 1042177636Sdfr * 1043177636Sdfr * If a shared or exclusive lock is blocked by other locks, the 1044177636Sdfr * process waits until the request can be satisfied. 1045177636Sdfr */ 1046177636Sdfrstatic int 1047180025Sdfrtest13(int fd, __unused int argc, const __unused char **argv) 1048177636Sdfr{ 1049177636Sdfr /* 1050177636Sdfr * We create a child process to hold the lock which we will 1051177636Sdfr * test. We use a pipe to communicate with the child. 1052177636Sdfr */ 1053177636Sdfr int i; 1054177636Sdfr int pid; 1055177636Sdfr int pfd[2]; 1056177636Sdfr struct flock fl; 1057177636Sdfr char ch; 1058177636Sdfr int res; 1059177636Sdfr struct itimerval itv; 1060177636Sdfr 1061177636Sdfr printf("13 - F_SETLKW on locked region, race with owner: "); 1062177636Sdfr fflush(stdout); 1063177636Sdfr 1064177636Sdfr for (i = 0; i < 100; i++) { 1065177636Sdfr if (pipe(pfd) < 0) 1066177636Sdfr err(1, "pipe"); 1067177636Sdfr 1068177636Sdfr fl.l_start = 0; 1069177636Sdfr fl.l_len = 0; 1070177636Sdfr fl.l_type = F_WRLCK; 1071177636Sdfr fl.l_whence = SEEK_SET; 1072177636Sdfr 1073177636Sdfr pid = fork(); 1074177636Sdfr if (pid < 0) 1075177636Sdfr err(1, "fork"); 1076177636Sdfr 1077177636Sdfr if (pid == 0) { 1078177636Sdfr /* 1079177636Sdfr * We are the child. We set a write lock and then 1080177636Sdfr * write one byte back to the parent to tell it. The 1081177636Sdfr * parent will kill us when its done. 1082177636Sdfr */ 1083177636Sdfr if (fcntl(fd, F_SETLK, &fl) < 0) 1084177636Sdfr err(1, "F_SETLK (child)"); 1085177636Sdfr if (write(pfd[1], "a", 1) < 0) 1086177636Sdfr err(1, "writing to pipe (child)"); 1087177636Sdfr 1088177636Sdfr usleep(1); 1089177636Sdfr exit(0); 1090177636Sdfr } 1091177636Sdfr 1092177636Sdfr /* 1093177636Sdfr * Wait until the child has set its lock and then perform the 1094177636Sdfr * test. 1095177636Sdfr */ 1096177636Sdfr while (read(pfd[0], &ch, 1) != 1) { 1097177636Sdfr if (errno == EINTR) 1098177636Sdfr continue; 1099177636Sdfr err(1, "reading from pipe (child)"); 1100177636Sdfr } 1101177636Sdfr 1102177636Sdfr /* 1103177636Sdfr * fcntl should wait until the alarm and then return -1 with 1104177636Sdfr * errno set to EINTR. 1105177636Sdfr */ 1106177636Sdfr itv.it_interval.tv_sec = 0; 1107177636Sdfr itv.it_interval.tv_usec = 0; 1108177636Sdfr itv.it_value.tv_sec = 0; 1109177636Sdfr itv.it_value.tv_usec = 2; 1110177636Sdfr setitimer(ITIMER_REAL, &itv, NULL); 1111177636Sdfr 1112177636Sdfr res = fcntl(fd, F_SETLKW, &fl); 1113177636Sdfr kill(pid, SIGTERM); 1114177636Sdfr safe_waitpid(pid); 1115177636Sdfr close(pfd[0]); 1116177636Sdfr close(pfd[1]); 1117177636Sdfr FAIL(!(res == 0 || (res == -1 && errno == EINTR))); 1118177636Sdfr 1119177636Sdfr fl.l_start = 0; 1120177636Sdfr fl.l_len = 0; 1121177636Sdfr fl.l_type = F_UNLCK; 1122177636Sdfr if (fcntl(fd, F_SETLK, &fl) < 0) 1123177636Sdfr err(1, "F_UNLCK"); 1124177636Sdfr } 1125177636Sdfr SUCCEED; 1126177636Sdfr} 1127177636Sdfr 1128177636Sdfr/* 1129177636Sdfr * Test 14 - soak test 1130177636Sdfr */ 1131177636Sdfrstatic int 1132180025Sdfrtest14(int fd, int argc, const char **argv) 1133177636Sdfr{ 1134177636Sdfr#define CHILD_COUNT 20 1135177636Sdfr /* 1136177636Sdfr * We create a set of child processes and let each one run 1137177636Sdfr * through a random sequence of locks and unlocks. 1138177636Sdfr */ 1139180025Sdfr int i, j, id, id_base; 1140177636Sdfr int pids[CHILD_COUNT], pid; 1141177636Sdfr char buf[128]; 1142177636Sdfr char tbuf[128]; 1143177636Sdfr int map[128]; 1144177636Sdfr char outbuf[512]; 1145177636Sdfr struct flock fl; 1146177636Sdfr struct itimerval itv; 1147177636Sdfr int status; 1148177636Sdfr 1149180025Sdfr id_base = 0; 1150180025Sdfr if (argc >= 2) 1151180025Sdfr id_base = strtol(argv[1], NULL, 0); 1152180025Sdfr 1153177636Sdfr printf("14 - soak test: "); 1154177636Sdfr fflush(stdout); 1155177636Sdfr 1156177636Sdfr for (i = 0; i < 128; i++) 1157177636Sdfr map[i] = F_UNLCK; 1158177636Sdfr 1159177636Sdfr for (i = 0; i < CHILD_COUNT; i++) { 1160177636Sdfr 1161177636Sdfr pid = fork(); 1162177636Sdfr if (pid < 0) 1163177636Sdfr err(1, "fork"); 1164177636Sdfr if (pid) { 1165177636Sdfr /* 1166177636Sdfr * Parent - record the pid and continue. 1167177636Sdfr */ 1168177636Sdfr pids[i] = pid; 1169177636Sdfr continue; 1170177636Sdfr } 1171177636Sdfr 1172177636Sdfr /* 1173177636Sdfr * Child - do some work and exit. 1174177636Sdfr */ 1175180025Sdfr id = id_base + i; 1176180025Sdfr srandom(getpid()); 1177177636Sdfr 1178177636Sdfr for (j = 0; j < 50; j++) { 1179177636Sdfr int start, end, len; 1180177636Sdfr int set, wrlock; 1181177636Sdfr 1182177636Sdfr do { 1183177636Sdfr start = random() & 127; 1184177636Sdfr end = random() & 127; 1185177636Sdfr } while (end <= start); 1186177636Sdfr 1187177636Sdfr set = random() & 1; 1188177636Sdfr wrlock = random() & 1; 1189177636Sdfr 1190177636Sdfr len = end - start; 1191177636Sdfr fl.l_start = start; 1192177636Sdfr fl.l_len = len; 1193177636Sdfr fl.l_whence = SEEK_SET; 1194177636Sdfr if (set) 1195177636Sdfr fl.l_type = wrlock ? F_WRLCK : F_RDLCK; 1196177636Sdfr else 1197177636Sdfr fl.l_type = F_UNLCK; 1198177636Sdfr 1199177636Sdfr itv.it_interval.tv_sec = 0; 1200177636Sdfr itv.it_interval.tv_usec = 0; 1201177636Sdfr itv.it_value.tv_sec = 0; 1202177636Sdfr itv.it_value.tv_usec = 3000; 1203177636Sdfr setitimer(ITIMER_REAL, &itv, NULL); 1204177636Sdfr 1205177636Sdfr if (fcntl(fd, F_SETLKW, &fl) < 0) { 1206177636Sdfr if (errno == EDEADLK || errno == EINTR) { 1207177636Sdfr if (verbose) { 1208177636Sdfr snprintf(outbuf, sizeof(outbuf), 1209177636Sdfr "%d[%d]: %s [%d .. %d] %s\n", 1210177636Sdfr id, j, 1211177636Sdfr set ? (wrlock ? "write lock" 1212177636Sdfr : "read lock") 1213177636Sdfr : "unlock", start, end, 1214177636Sdfr errno == EDEADLK 1215177636Sdfr ? "deadlock" 1216177636Sdfr : "interrupted"); 1217177636Sdfr write(1, outbuf, 1218177636Sdfr strlen(outbuf)); 1219177636Sdfr } 1220177636Sdfr continue; 1221177636Sdfr } else { 1222177636Sdfr perror("fcntl"); 1223177636Sdfr } 1224177636Sdfr } 1225177636Sdfr 1226177636Sdfr itv.it_interval.tv_sec = 0; 1227177636Sdfr itv.it_interval.tv_usec = 0; 1228177636Sdfr itv.it_value.tv_sec = 0; 1229177636Sdfr itv.it_value.tv_usec = 0; 1230177636Sdfr setitimer(ITIMER_REAL, &itv, NULL); 1231177636Sdfr 1232177636Sdfr if (verbose) { 1233177636Sdfr snprintf(outbuf, sizeof(outbuf), 1234177636Sdfr "%d[%d]: %s [%d .. %d] succeeded\n", 1235177636Sdfr id, j, 1236177636Sdfr set ? (wrlock ? "write lock" : "read lock") 1237177636Sdfr : "unlock", start, end); 1238177636Sdfr write(1, outbuf, strlen(outbuf)); 1239177636Sdfr } 1240177636Sdfr 1241177636Sdfr if (set) { 1242177636Sdfr if (wrlock) { 1243177636Sdfr /* 1244177636Sdfr * We got a write lock - write 1245177636Sdfr * our ID to each byte that we 1246177636Sdfr * managed to claim. 1247177636Sdfr */ 1248177636Sdfr for (i = start; i < end; i++) 1249177636Sdfr map[i] = F_WRLCK; 1250177636Sdfr memset(&buf[start], id, len); 1251177636Sdfr if (pwrite(fd, &buf[start], len, 1252177636Sdfr start) != len) { 1253177636Sdfr printf("%d: short write\n", id); 1254177636Sdfr exit(1); 1255177636Sdfr } 1256177636Sdfr } else { 1257177636Sdfr /* 1258177636Sdfr * We got a read lock - read 1259177636Sdfr * the bytes which we claimed 1260177636Sdfr * so that we can check that 1261177636Sdfr * they don't change 1262177636Sdfr * unexpectedly. 1263177636Sdfr */ 1264177636Sdfr for (i = start; i < end; i++) 1265177636Sdfr map[i] = F_RDLCK; 1266177636Sdfr if (pread(fd, &buf[start], len, 1267177636Sdfr start) != len) { 1268177636Sdfr printf("%d: short read\n", id); 1269177636Sdfr exit(1); 1270177636Sdfr } 1271177636Sdfr } 1272177636Sdfr } else { 1273177636Sdfr for (i = start; i < end; i++) 1274177636Sdfr map[i] = F_UNLCK; 1275177636Sdfr } 1276177636Sdfr 1277177636Sdfr usleep(1000); 1278177636Sdfr 1279177636Sdfr /* 1280177636Sdfr * Read back the whole region so that we can 1281177636Sdfr * check that all the bytes we have some kind 1282177636Sdfr * of claim to have the correct value. 1283177636Sdfr */ 1284177636Sdfr if (pread(fd, tbuf, sizeof(tbuf), 0) != sizeof(tbuf)) { 1285177636Sdfr printf("%d: short read\n", id); 1286177636Sdfr exit(1); 1287177636Sdfr } 1288177636Sdfr 1289177636Sdfr for (i = 0; i < 128; i++) { 1290177636Sdfr if (map[i] != F_UNLCK && buf[i] != tbuf[i]) { 1291177636Sdfr snprintf(outbuf, sizeof(outbuf), 1292177636Sdfr "%d: byte %d expected %d, " 1293177636Sdfr "got %d\n", id, i, buf[i], tbuf[i]); 1294177636Sdfr write(1, outbuf, strlen(outbuf)); 1295177636Sdfr exit(1); 1296177636Sdfr } 1297177636Sdfr } 1298177636Sdfr } 1299177636Sdfr if (verbose) 1300177636Sdfr printf("%d[%d]: done\n", id, j); 1301177636Sdfr 1302177636Sdfr exit(0); 1303177636Sdfr } 1304177636Sdfr 1305177636Sdfr status = 0; 1306177636Sdfr for (i = 0; i < CHILD_COUNT; i++) { 1307177636Sdfr status += safe_waitpid(pids[i]); 1308177636Sdfr } 1309177636Sdfr if (status) 1310177636Sdfr FAIL(status != 0); 1311177636Sdfr 1312177636Sdfr SUCCEED; 1313177636Sdfr} 1314177636Sdfr 1315180025Sdfr/* 1316180025Sdfr * Test 15 - flock(2) semantcs 1317180025Sdfr * 1318180025Sdfr * When a lock holder has a shared lock and attempts to upgrade that 1319180025Sdfr * shared lock to exclusive, it must drop the shared lock before 1320180025Sdfr * blocking on the exclusive lock. 1321180025Sdfr * 1322180025Sdfr * To test this, we first arrange for two shared locks on the file, 1323180025Sdfr * and then attempt to upgrade one of them to exclusive. This should 1324180025Sdfr * drop one of the shared locks and block. We interrupt the blocking 1325180025Sdfr * lock request and examine the lock state of the file after dropping 1326180025Sdfr * the other shared lock - there should be no active locks at this 1327180025Sdfr * point. 1328180025Sdfr */ 1329180025Sdfrstatic int 1330180025Sdfrtest15(int fd, __unused int argc, const __unused char **argv) 1331180025Sdfr{ 1332180025Sdfr#ifdef LOCK_EX 1333180025Sdfr /* 1334180025Sdfr * We create a child process to hold the lock which we will 1335180025Sdfr * test. We use a pipe to communicate with the child. 1336180025Sdfr * 1337180025Sdfr * Since we only have one file descriptors and lock ownership 1338180025Sdfr * for flock(2) goes with the file descriptor, we use fcntl to 1339180025Sdfr * set the child's shared lock. 1340180025Sdfr */ 1341180025Sdfr int pid; 1342180025Sdfr int pfd[2]; 1343180025Sdfr struct flock fl; 1344180025Sdfr char ch; 1345180025Sdfr int res; 1346180025Sdfr 1347180025Sdfr if (pipe(pfd) < 0) 1348180025Sdfr err(1, "pipe"); 1349180025Sdfr 1350180025Sdfr pid = fork(); 1351180025Sdfr if (pid < 0) 1352180025Sdfr err(1, "fork"); 1353180025Sdfr 1354180025Sdfr if (pid == 0) { 1355180025Sdfr /* 1356180025Sdfr * We are the child. We set a shared lock and then 1357180025Sdfr * write one byte back to the parent to tell it. The 1358180025Sdfr * parent will kill us when its done. 1359180025Sdfr */ 1360180025Sdfr fl.l_start = 0; 1361180025Sdfr fl.l_len = 0; 1362180025Sdfr fl.l_type = F_RDLCK; 1363180025Sdfr fl.l_whence = SEEK_SET; 1364180025Sdfr if (fcntl(fd, F_SETLK, &fl) < 0) 1365180025Sdfr err(1, "fcntl(F_SETLK) (child)"); 1366180025Sdfr if (write(pfd[1], "a", 1) < 0) 1367180025Sdfr err(1, "writing to pipe (child)"); 1368180025Sdfr pause(); 1369180025Sdfr exit(0); 1370180025Sdfr } 1371180025Sdfr 1372180025Sdfr /* 1373180025Sdfr * Wait until the child has set its lock and then perform the 1374180025Sdfr * test. 1375180025Sdfr */ 1376180025Sdfr if (read(pfd[0], &ch, 1) != 1) 1377180025Sdfr err(1, "reading from pipe (child)"); 1378180025Sdfr 1379268385Skib (void)dup(fd); 1380180025Sdfr if (flock(fd, LOCK_SH) < 0) 1381180025Sdfr err(1, "flock shared"); 1382180025Sdfr 1383180025Sdfr /* 1384180025Sdfr * flock should wait until the alarm and then return -1 with 1385180025Sdfr * errno set to EINTR. 1386180025Sdfr */ 1387180025Sdfr printf("15 - flock(2) semantics: "); 1388180025Sdfr 1389180025Sdfr alarm(1); 1390180025Sdfr flock(fd, LOCK_EX); 1391180025Sdfr 1392180025Sdfr /* 1393180025Sdfr * Kill the child to force it to drop its locks. 1394180025Sdfr */ 1395180025Sdfr kill(pid, SIGTERM); 1396180025Sdfr safe_waitpid(pid); 1397180025Sdfr 1398180025Sdfr fl.l_start = 0; 1399180025Sdfr fl.l_len = 0; 1400180025Sdfr fl.l_type = F_WRLCK; 1401180025Sdfr fl.l_whence = SEEK_SET; 1402180025Sdfr res = fcntl(fd, F_GETLK, &fl); 1403180025Sdfr 1404180025Sdfr close(pfd[0]); 1405180025Sdfr close(pfd[1]); 1406180025Sdfr FAIL(res != 0); 1407180025Sdfr FAIL(fl.l_type != F_UNLCK); 1408180025Sdfr 1409180025Sdfr SUCCEED; 1410180025Sdfr#else 1411180025Sdfr return 0; 1412180025Sdfr#endif 1413180025Sdfr} 1414180025Sdfr 1415192949Szmlstruct test_ctx { 1416192949Szml struct flock tc_fl; 1417192949Szml int tc_fd; 1418192949Szml}; 1419192949Szml 1420192949Szmlstatic void * 1421192949Szmltest16_func(void *tc_in) 1422192949Szml{ 1423192949Szml uintptr_t error; 1424192949Szml struct test_ctx *tc = tc_in; 1425192949Szml 1426192949Szml error = fcntl(tc->tc_fd, F_SETLKW, &tc->tc_fl); 1427192949Szml 1428192949Szml pthread_exit((void *)error); 1429192949Szml} 1430192949Szml 1431192949Szml#define THREADS 10 1432192949Szml 1433192949Szml/* 1434192949Szml * Test 16 - F_SETLKW from two threads 1435192949Szml * 1436192949Szml * If two threads within a process are blocked on a lock and the lock 1437192949Szml * is granted, make sure things are sane. 1438192949Szml */ 1439192949Szmlstatic int 1440192949Szmltest16(int fd, __unused int argc, const __unused char **argv) 1441192949Szml{ 1442192949Szml /* 1443192949Szml * We create a child process to hold the lock which we will 1444192949Szml * test. We use a pipe to communicate with the child. 1445192949Szml */ 1446192949Szml int pid; 1447192949Szml int pfd[2]; 1448192949Szml struct test_ctx tc = { .tc_fd = fd }; 1449192949Szml char ch; 1450192949Szml int i; 1451192949Szml int error; 1452192949Szml pthread_t thr[THREADS]; 1453192949Szml 1454192949Szml if (pipe(pfd) < 0) 1455192949Szml err(1, "pipe"); 1456192949Szml 1457192949Szml tc.tc_fl.l_start = 0; 1458192949Szml tc.tc_fl.l_len = 0; 1459192949Szml tc.tc_fl.l_type = F_WRLCK; 1460192949Szml tc.tc_fl.l_whence = SEEK_SET; 1461192949Szml 1462192949Szml pid = fork(); 1463192949Szml if (pid < 0) 1464192949Szml err(1, "fork"); 1465192949Szml 1466192949Szml if (pid == 0) { 1467192949Szml /* 1468192949Szml * We are the child. We set a write lock and then 1469192949Szml * write one byte back to the parent to tell it. The 1470192949Szml * parent will kill us when its done. 1471192949Szml */ 1472192949Szml if (fcntl(fd, F_SETLK, &tc.tc_fl) < 0) 1473192949Szml err(1, "F_SETLK (child)"); 1474192949Szml if (write(pfd[1], "a", 1) < 0) 1475192949Szml err(1, "writing to pipe (child)"); 1476192949Szml pause(); 1477192949Szml exit(0); 1478192949Szml } 1479192949Szml 1480192949Szml /* 1481192949Szml * Wait until the child has set its lock and then perform the 1482192949Szml * test. 1483192949Szml */ 1484192949Szml if (read(pfd[0], &ch, 1) != 1) 1485192949Szml err(1, "reading from pipe (child)"); 1486192949Szml 1487192949Szml /* 1488192949Szml * fcntl should wait until the alarm and then return -1 with 1489192949Szml * errno set to EINTR. 1490192949Szml */ 1491192949Szml printf("16 - F_SETLKW on locked region by two threads: "); 1492192949Szml 1493192949Szml for (i = 0; i < THREADS; i++) { 1494192949Szml error = pthread_create(&thr[i], NULL, test16_func, &tc); 1495192949Szml if (error) 1496192949Szml err(1, "pthread_create"); 1497192949Szml } 1498192949Szml 1499192949Szml /* 1500192949Szml * Sleep, then kill the child. This makes me a little sad, but it's 1501192949Szml * tricky to tell whether the threads are all really blocked by this 1502192949Szml * point. 1503192949Szml */ 1504192949Szml sleep(1); 1505192949Szml kill(pid, SIGTERM); 1506192949Szml safe_waitpid(pid); 1507192949Szml close(pfd[0]); 1508192949Szml close(pfd[1]); 1509192949Szml 1510192949Szml for (i = 0; i < THREADS; i++) { 1511192949Szml void *res; 1512192949Szml error = pthread_join(thr[i], &res); 1513192949Szml if (error) 1514192949Szml err(1, "pthread_join"); 1515192949Szml FAIL((uintptr_t)res != 0); 1516192949Szml } 1517192949Szml 1518192949Szml SUCCEED; 1519192949Szml} 1520192949Szml 1521177636Sdfrstruct test { 1522180025Sdfr int (*testfn)(int, int, const char **); /* function to perform the test */ 1523177636Sdfr int num; /* test number */ 1524177636Sdfr int intr; /* non-zero if the test interrupts a lock */ 1525177636Sdfr}; 1526177636Sdfr 1527277527Sngiestatic struct test tests[] = { 1528177636Sdfr { test1, 1, 0 }, 1529177636Sdfr { test2, 2, 0 }, 1530177636Sdfr { test3, 3, 1 }, 1531177636Sdfr { test4, 4, 0 }, 1532177636Sdfr { test5, 5, 1 }, 1533177636Sdfr { test6, 6, 1 }, 1534177636Sdfr { test7, 7, 0 }, 1535177636Sdfr { test8, 8, 0 }, 1536177636Sdfr { test9, 9, 0 }, 1537177636Sdfr { test10, 10, 0 }, 1538177636Sdfr { test11, 11, 1 }, 1539177636Sdfr { test12, 12, 0 }, 1540177636Sdfr { test13, 13, 1 }, 1541177636Sdfr { test14, 14, 0 }, 1542180025Sdfr { test15, 15, 1 }, 1543192949Szml { test16, 16, 1 }, 1544177636Sdfr}; 1545177636Sdfr 1546177636Sdfrint 1547177636Sdfrmain(int argc, const char *argv[]) 1548177636Sdfr{ 1549177636Sdfr int testnum; 1550177636Sdfr int fd; 1551177636Sdfr int nointr; 1552277527Sngie unsigned i; 1553177636Sdfr struct sigaction sa; 1554180025Sdfr int test_argc; 1555180025Sdfr const char **test_argv; 1556177636Sdfr 1557180025Sdfr if (argc < 2) { 1558180025Sdfr errx(1, "usage: flock <directory> [test number] ..."); 1559177636Sdfr } 1560177636Sdfr 1561177636Sdfr fd = make_file(argv[1], 1024); 1562180025Sdfr if (argc >= 3) { 1563177636Sdfr testnum = strtol(argv[2], NULL, 0); 1564180025Sdfr test_argc = argc - 2; 1565180025Sdfr test_argv = argv + 2; 1566180025Sdfr } else { 1567177636Sdfr testnum = 0; 1568180025Sdfr test_argc = 0; 1569298490Sngie test_argv = NULL; 1570180025Sdfr } 1571177636Sdfr 1572177636Sdfr sa.sa_handler = ignore_alarm; 1573177636Sdfr sigemptyset(&sa.sa_mask); 1574177636Sdfr sa.sa_flags = 0; 1575177636Sdfr sigaction(SIGALRM, &sa, 0); 1576177636Sdfr 1577177636Sdfr nointr = 0; 1578180025Sdfr#if defined(__FreeBSD__) && __FreeBSD_version < 800040 1579177636Sdfr { 1580177636Sdfr /* 1581180025Sdfr * FreeBSD with userland NLM can't interrupt a blocked 1582180025Sdfr * lock request on an NFS mounted filesystem. 1583177636Sdfr */ 1584177636Sdfr struct statfs st; 1585177636Sdfr fstatfs(fd, &st); 1586177636Sdfr nointr = !strcmp(st.f_fstypename, "nfs"); 1587177636Sdfr } 1588177636Sdfr#endif 1589177636Sdfr 1590277527Sngie for (i = 0; i < nitems(tests); i++) { 1591177636Sdfr if (tests[i].intr && nointr) 1592177636Sdfr continue; 1593177636Sdfr if (!testnum || tests[i].num == testnum) 1594180025Sdfr tests[i].testfn(fd, test_argc, test_argv); 1595177636Sdfr } 1596177636Sdfr 1597177636Sdfr return 0; 1598177636Sdfr} 1599