1272343Sngie/* $NetBSD: t_lockf.c,v 1.9 2013/10/19 17:45:00 christos Exp $ */ 2272343Sngie 3272343Sngie/*- 4272343Sngie * Copyright (c) 2000 The NetBSD Foundation, Inc. 5272343Sngie * All rights reserved. 6272343Sngie * 7272343Sngie * Redistribution and use in source and binary forms, with or without 8272343Sngie * modification, are permitted provided that the following conditions 9272343Sngie * are met: 10272343Sngie * 1. Redistributions of source code must retain the above copyright 11272343Sngie * notice, this list of conditions and the following disclaimer. 12272343Sngie * 2. Redistributions in binary form must reproduce the above copyright 13272343Sngie * notice, this list of conditions and the following disclaimer in the 14272343Sngie * documentation and/or other materials provided with the distribution. 15272343Sngie * 16272343Sngie * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 17272343Sngie * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 18272343Sngie * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19272343Sngie * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 20272343Sngie * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21272343Sngie * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22272343Sngie * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23272343Sngie * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24272343Sngie * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25272343Sngie * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26272343Sngie * POSSIBILITY OF SUCH DAMAGE. 27272343Sngie */ 28272343Sngie 29272343Sngie#include <atf-c.h> 30272343Sngie#include <err.h> 31272343Sngie#include <errno.h> 32272343Sngie#include <fcntl.h> 33272343Sngie#include <signal.h> 34272343Sngie#include <stdio.h> 35272343Sngie#include <stdlib.h> 36272343Sngie#include <string.h> 37272343Sngie#include <unistd.h> 38272343Sngie 39272343Sngie#include <sys/types.h> 40272343Sngie#include <sys/wait.h> 41272343Sngie#include <sys/ptrace.h> 42272343Sngie 43272343Sngie/* 44272343Sngie * lockf1 regression test: 45272343Sngie * 46272343Sngie * Tests: 47272343Sngie * Fork N child processes, each of which gets M random byte range locks 48272343Sngie * on a common file. We ignore all lock errors (practically speaking, 49272343Sngie * this means EDEADLK or ENOLOCK), but we make numerous passes over all 50272343Sngie * the children to make sure that they are still awake. (We do this by 51272343Sngie * verifying that we can ptrace(ATTACH/DETACH) to the children and get 52272343Sngie * their status via waitpid().) 53272343Sngie * When finished, reap all the children. 54272343Sngie */ 55272343Sngie 56272343Sngie#define nlocks 500 /* number of locks per thread */ 57272343Sngie#define nprocs 10 /* number of processes to spawn */ 58272343Sngie#define npasses 50 /* number of passes to make over the children */ 59272343Sngie#define sleeptime 150000 /* sleep time between locks, usec */ 60272343Sngie#define filesize 8192 /* size of file to lock */ 61272343Sngie 62272343Sngieconst char *lockfile = "lockf_test"; 63272343Sngie 64272343Sngiestatic u_int32_t 65272343Sngierandom_uint32(void) 66272343Sngie{ 67272343Sngie return lrand48(); 68272343Sngie} 69272343Sngie 70272343Sngiestatic void 71272343Sngietrylocks(int id) 72272343Sngie{ 73272343Sngie int i, fd; 74272343Sngie 75272343Sngie srand48(getpid()); 76272343Sngie 77272343Sngie fd = open (lockfile, O_RDWR, 0); 78272343Sngie 79272343Sngie if (fd < 0) 80272343Sngie err(1, "%s", lockfile); 81272343Sngie 82272343Sngie printf("%d: start\n", id); 83272343Sngie 84272343Sngie for (i = 0; i < nlocks; i++) { 85272343Sngie struct flock fl; 86272343Sngie 87272343Sngie fl.l_start = random_uint32() % filesize; 88272343Sngie fl.l_len = random_uint32() % filesize; 89272343Sngie switch (random_uint32() % 3) { 90272343Sngie case 0: 91272343Sngie fl.l_type = F_RDLCK; 92272343Sngie break; 93272343Sngie case 1: 94272343Sngie fl.l_type = F_WRLCK; 95272343Sngie break; 96272343Sngie case 2: 97272343Sngie fl.l_type = F_UNLCK; 98272343Sngie break; 99272343Sngie } 100272343Sngie fl.l_whence = SEEK_SET; 101272343Sngie 102272343Sngie (void)fcntl(fd, F_SETLKW, &fl); 103272343Sngie 104272343Sngie if (usleep(sleeptime) < 0) 105291179Sngie#if defined(__FreeBSD__) 106291179Sngie if (errno != EINTR) 107291179Sngie#endif 108272343Sngie err(1, "usleep"); 109272343Sngie } 110272343Sngie printf("%d: done\n", id); 111272343Sngie close (fd); 112272343Sngie} 113272343Sngie 114272343SngieATF_TC(randlock); 115272343SngieATF_TC_HEAD(randlock, tc) 116272343Sngie{ 117272343Sngie 118272343Sngie atf_tc_set_md_var(tc, "timeout", "300"); 119272343Sngie atf_tc_set_md_var(tc, "descr", "Checks fcntl(2) locking"); 120272343Sngie} 121272343Sngie 122272343SngieATF_TC_BODY(randlock, tc) 123272343Sngie{ 124272343Sngie int i, j, fd; 125272343Sngie int pipe_fd[2]; 126272343Sngie pid_t *pid; 127272343Sngie int status; 128272343Sngie char pipe_in, pipe_out; 129272343Sngie const char pipe_errmsg[] = "child: pipe write failed\n"; 130272343Sngie 131272343Sngie (void)unlink(lockfile); 132272343Sngie 133272343Sngie fd = open (lockfile, O_RDWR|O_CREAT|O_EXCL|O_TRUNC, 0666); 134272343Sngie ATF_REQUIRE_MSG(fd >= 0, "open(%s): %s", lockfile, strerror(errno)); 135272343Sngie 136272343Sngie ATF_REQUIRE_MSG(ftruncate(fd, filesize) >= 0, 137272343Sngie "ftruncate(%s): %s", lockfile, strerror(errno)); 138272343Sngie 139272343Sngie ATF_REQUIRE_MSG(pipe(pipe_fd) == 0, "pipe: %s", strerror(errno)); 140272343Sngie 141272343Sngie fsync(fd); 142272343Sngie close(fd); 143272343Sngie 144272343Sngie pid = malloc(nprocs * sizeof(pid_t)); 145272343Sngie 146272343Sngie for (i = 0; i < nprocs; i++) { 147272343Sngie pipe_out = (char)('A' + i); 148272343Sngie pid[i] = fork(); 149272343Sngie switch (pid[i]) { 150272343Sngie case 0: 151272343Sngie if (write(pipe_fd[1], &pipe_out, 1) != 1) 152272343Sngie write(STDERR_FILENO, pipe_errmsg, 153272343Sngie __arraycount(pipe_errmsg) - 1); 154272343Sngie else 155272343Sngie trylocks(i); 156272343Sngie _exit(0); 157272343Sngie break; 158272343Sngie case -1: 159272343Sngie atf_tc_fail("fork %d failed", i); 160272343Sngie break; 161272343Sngie default: 162272343Sngie ATF_REQUIRE_MSG(read(pipe_fd[0], &pipe_in, 1) == 1, 163272343Sngie "parent: read_pipe(%i): %s", i, strerror(errno)); 164272343Sngie ATF_REQUIRE_MSG(pipe_in == pipe_out, 165272343Sngie "parent: pipe does not match"); 166272343Sngie break; 167272343Sngie } 168272343Sngie } 169272343Sngie for (j = 0; j < npasses; j++) { 170272343Sngie printf("parent: run %i\n", j+1); 171272343Sngie for (i = 0; i < nprocs; i++) { 172272343Sngie ATF_REQUIRE_MSG(ptrace(PT_ATTACH, pid[i], 0, 0) >= 0, 173272343Sngie "ptrace attach %d", pid[i]); 174272343Sngie ATF_REQUIRE_MSG(waitpid(pid[i], &status, WUNTRACED) >= 0, 175272343Sngie "waitpid(ptrace)"); 176272343Sngie usleep(sleeptime / 3); 177272343Sngie ATF_REQUIRE_MSG(ptrace(PT_DETACH, pid[i], (caddr_t)1, 178272343Sngie 0) >= 0, 179272343Sngie "ptrace detach %d", pid[i]); 180272343Sngie usleep(sleeptime / 3); 181272343Sngie } 182272343Sngie } 183272343Sngie for (i = 0; i < nprocs; i++) { 184272343Sngie printf("reap %d: ", i); 185272343Sngie fflush(stdout); 186272343Sngie kill(pid[i], SIGINT); 187272343Sngie waitpid(pid[i], &status, 0); 188272343Sngie printf(" status %d\n", status); 189272343Sngie } 190272343Sngie atf_tc_pass(); 191272343Sngie} 192272343Sngie 193272343Sngiestatic int 194272343Sngiedolock(int fd, int op, off_t lk_off, off_t lk_size) 195272343Sngie{ 196272343Sngie off_t result; 197272343Sngie int ret; 198272343Sngie 199272343Sngie result = lseek(fd, lk_off, SEEK_SET); 200272343Sngie if (result == -1) { 201272343Sngie return errno; 202272343Sngie } 203272343Sngie ATF_REQUIRE_MSG(result == lk_off, "lseek to wrong offset"); 204272343Sngie ret = lockf(fd, op, lk_size); 205272343Sngie if (ret == -1) { 206272343Sngie return errno; 207272343Sngie } 208272343Sngie return 0; 209272343Sngie} 210272343Sngie 211272343SngieATF_TC(deadlock); 212272343SngieATF_TC_HEAD(deadlock, tc) 213272343Sngie{ 214272343Sngie 215272343Sngie atf_tc_set_md_var(tc, "timeout", "30"); 216272343Sngie atf_tc_set_md_var(tc, "descr", "Checks fcntl(2) deadlock detection"); 217272343Sngie} 218272343Sngie 219272343SngieATF_TC_BODY(deadlock, tc) 220272343Sngie{ 221272343Sngie int fd; 222272343Sngie int error; 223272343Sngie int ret; 224272343Sngie pid_t pid; 225272343Sngie 226272343Sngie (void)unlink(lockfile); 227272343Sngie 228272343Sngie fd = open (lockfile, O_RDWR|O_CREAT|O_EXCL|O_TRUNC, 0666); 229272343Sngie ATF_REQUIRE_MSG(fd >= 0, "open(%s): %s", lockfile, strerror(errno)); 230272343Sngie 231272343Sngie ATF_REQUIRE_MSG(ftruncate(fd, filesize) >= 0, 232272343Sngie "ftruncate(%s): %s", lockfile, strerror(errno)); 233272343Sngie 234272343Sngie fsync(fd); 235272343Sngie 236272343Sngie error = dolock(fd, F_LOCK, 0, 1); 237272343Sngie ATF_REQUIRE_MSG(error == 0, "initial dolock: %s", strerror(errno)); 238272343Sngie 239272343Sngie pid = fork(); 240272343Sngie ATF_REQUIRE_MSG(pid != -1, "fork failed: %s", strerror(errno)); 241272343Sngie if (pid == 0) { 242272343Sngie error = dolock(fd, F_LOCK, 1, 1); 243272343Sngie ATF_REQUIRE_MSG(error == 0, "child dolock: %s", 244272343Sngie strerror(errno)); 245272343Sngie dolock(fd, F_LOCK, 0, 1); /* will block */ 246272343Sngie atf_tc_fail("child did not block"); 247272343Sngie } 248272343Sngie sleep(1); /* give child time to grab its lock then block */ 249272343Sngie 250272343Sngie error = dolock(fd, F_LOCK, 1, 1); 251272343Sngie ATF_REQUIRE_MSG(error == EDEADLK, "parent did not detect deadlock: %s", 252272343Sngie strerror(errno)); 253272343Sngie ret = kill(pid, SIGKILL); 254272343Sngie ATF_REQUIRE_MSG(ret != -1, "failed to kill child: %s", strerror(errno)); 255272343Sngie 256272343Sngie atf_tc_pass(); 257272343Sngie} 258272343Sngie 259272343SngieATF_TP_ADD_TCS(tp) 260272343Sngie{ 261272343Sngie ATF_TP_ADD_TC(tp, randlock); 262272343Sngie ATF_TP_ADD_TC(tp, deadlock); 263272343Sngie 264272343Sngie return atf_no_error(); 265272343Sngie} 266