13cedbec3SEnji Cooper /*-
23cedbec3SEnji Cooper * Copyright (c) 2008 Isilon Inc http://www.isilon.com/
33cedbec3SEnji Cooper * Authors: Doug Rabson <dfr@rabson.org>
43cedbec3SEnji Cooper * Developed with Red Inc: Alfred Perlstein <alfred@freebsd.org>
53cedbec3SEnji Cooper *
63cedbec3SEnji Cooper * Redistribution and use in source and binary forms, with or without
73cedbec3SEnji Cooper * modification, are permitted provided that the following conditions
83cedbec3SEnji Cooper * are met:
93cedbec3SEnji Cooper * 1. Redistributions of source code must retain the above copyright
103cedbec3SEnji Cooper * notice, this list of conditions and the following disclaimer.
113cedbec3SEnji Cooper * 2. Redistributions in binary form must reproduce the above copyright
123cedbec3SEnji Cooper * notice, this list of conditions and the following disclaimer in the
133cedbec3SEnji Cooper * documentation and/or other materials provided with the distribution.
143cedbec3SEnji Cooper *
153cedbec3SEnji Cooper * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
163cedbec3SEnji Cooper * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
173cedbec3SEnji Cooper * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
183cedbec3SEnji Cooper * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
193cedbec3SEnji Cooper * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
203cedbec3SEnji Cooper * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
213cedbec3SEnji Cooper * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
223cedbec3SEnji Cooper * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
233cedbec3SEnji Cooper * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
243cedbec3SEnji Cooper * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
253cedbec3SEnji Cooper * SUCH DAMAGE.
263cedbec3SEnji Cooper */
273cedbec3SEnji Cooper
283cedbec3SEnji Cooper #include <sys/param.h>
293cedbec3SEnji Cooper #include <sys/file.h>
303cedbec3SEnji Cooper #include <sys/time.h>
313cedbec3SEnji Cooper #ifdef __FreeBSD__
323cedbec3SEnji Cooper #include <sys/mount.h>
333cedbec3SEnji Cooper #endif
343cedbec3SEnji Cooper #include <sys/stat.h>
353cedbec3SEnji Cooper #include <sys/wait.h>
363cedbec3SEnji Cooper
373cedbec3SEnji Cooper #include <err.h>
383cedbec3SEnji Cooper #include <errno.h>
393cedbec3SEnji Cooper #include <fcntl.h>
403cedbec3SEnji Cooper #include <pthread.h>
413cedbec3SEnji Cooper #include <signal.h>
423cedbec3SEnji Cooper #include <stdint.h>
433cedbec3SEnji Cooper #include <stdio.h>
443cedbec3SEnji Cooper #include <stdlib.h>
453cedbec3SEnji Cooper #include <string.h>
463cedbec3SEnji Cooper #include <unistd.h>
473cedbec3SEnji Cooper
483cedbec3SEnji Cooper #ifdef __FreeBSD__
493cedbec3SEnji Cooper #if __FreeBSD_version >= 800028
503cedbec3SEnji Cooper #define HAVE_SYSID
513cedbec3SEnji Cooper #endif
523cedbec3SEnji Cooper #include <sys/cdefs.h>
533cedbec3SEnji Cooper #else
543cedbec3SEnji Cooper #ifndef nitems
553cedbec3SEnji Cooper #define nitems(x) (sizeof((x)) / sizeof((x)[0]))
563cedbec3SEnji Cooper #endif
573cedbec3SEnji Cooper
583cedbec3SEnji Cooper #ifndef __unused
593cedbec3SEnji Cooper #ifdef __GNUC__
603cedbec3SEnji Cooper #define __unused __attribute__((__unused__))
613cedbec3SEnji Cooper #else
623cedbec3SEnji Cooper #define __unused
633cedbec3SEnji Cooper #endif
643cedbec3SEnji Cooper #endif
653cedbec3SEnji Cooper #endif
663cedbec3SEnji Cooper
673cedbec3SEnji Cooper static int verbose = 0;
683cedbec3SEnji Cooper
693cedbec3SEnji Cooper static int
make_file(const char * pathname,off_t sz)703cedbec3SEnji Cooper make_file(const char *pathname, off_t sz)
713cedbec3SEnji Cooper {
723cedbec3SEnji Cooper struct stat st;
733cedbec3SEnji Cooper const char *template = "/flocktempXXXXXX";
743cedbec3SEnji Cooper size_t len;
753cedbec3SEnji Cooper char *filename;
763cedbec3SEnji Cooper int fd;
773cedbec3SEnji Cooper
783cedbec3SEnji Cooper if (stat(pathname, &st) == 0) {
793cedbec3SEnji Cooper if (S_ISREG(st.st_mode)) {
803cedbec3SEnji Cooper fd = open(pathname, O_RDWR);
813cedbec3SEnji Cooper if (fd < 0)
823cedbec3SEnji Cooper err(1, "open(%s)", pathname);
833cedbec3SEnji Cooper if (ftruncate(fd, sz) < 0)
843cedbec3SEnji Cooper err(1, "ftruncate");
853cedbec3SEnji Cooper return (fd);
863cedbec3SEnji Cooper }
873cedbec3SEnji Cooper }
883cedbec3SEnji Cooper
893cedbec3SEnji Cooper len = strlen(pathname) + strlen(template) + 1;
903cedbec3SEnji Cooper filename = malloc(len);
913cedbec3SEnji Cooper strcpy(filename, pathname);
923cedbec3SEnji Cooper strcat(filename, template);
933cedbec3SEnji Cooper fd = mkstemp(filename);
943cedbec3SEnji Cooper if (fd < 0)
953cedbec3SEnji Cooper err(1, "mkstemp");
963cedbec3SEnji Cooper if (ftruncate(fd, sz) < 0)
973cedbec3SEnji Cooper err(1, "ftruncate");
983cedbec3SEnji Cooper if (unlink(filename) < 0)
993cedbec3SEnji Cooper err(1, "unlink");
1003cedbec3SEnji Cooper free(filename);
1013cedbec3SEnji Cooper
1023cedbec3SEnji Cooper return (fd);
1033cedbec3SEnji Cooper }
1043cedbec3SEnji Cooper
1053cedbec3SEnji Cooper static void
ignore_alarm(int __unused sig)1063cedbec3SEnji Cooper ignore_alarm(int __unused sig)
1073cedbec3SEnji Cooper {
1083cedbec3SEnji Cooper }
1093cedbec3SEnji Cooper
1103cedbec3SEnji Cooper static int
safe_waitpid(pid_t pid)1113cedbec3SEnji Cooper safe_waitpid(pid_t pid)
1123cedbec3SEnji Cooper {
1133cedbec3SEnji Cooper int save_errno;
1143cedbec3SEnji Cooper int status;
1153cedbec3SEnji Cooper
1163cedbec3SEnji Cooper save_errno = errno;
1173cedbec3SEnji Cooper errno = 0;
1183cedbec3SEnji Cooper while (waitpid(pid, &status, 0) != pid) {
1193cedbec3SEnji Cooper if (errno == EINTR)
1203cedbec3SEnji Cooper continue;
1213cedbec3SEnji Cooper err(1, "waitpid");
1223cedbec3SEnji Cooper }
1233cedbec3SEnji Cooper errno = save_errno;
1243cedbec3SEnji Cooper
1253cedbec3SEnji Cooper return (status);
1263cedbec3SEnji Cooper }
1273cedbec3SEnji Cooper
1283cedbec3SEnji Cooper #define FAIL(test) \
1293cedbec3SEnji Cooper do { \
1303cedbec3SEnji Cooper if (test) { \
1313cedbec3SEnji Cooper printf("FAIL (%s)\n", #test); \
1323cedbec3SEnji Cooper return -1; \
1333cedbec3SEnji Cooper } \
1343cedbec3SEnji Cooper } while (0)
1353cedbec3SEnji Cooper
1363cedbec3SEnji Cooper #define SUCCEED \
1373cedbec3SEnji Cooper do { printf("SUCCEED\n"); return 0; } while (0)
1383cedbec3SEnji Cooper
1393cedbec3SEnji Cooper /*
1403cedbec3SEnji Cooper * Test 1 - F_GETLK on unlocked region
1413cedbec3SEnji Cooper *
1423cedbec3SEnji Cooper * If no lock is found that would prevent this lock from being
1433cedbec3SEnji Cooper * created, the structure is left unchanged by this function call
1443cedbec3SEnji Cooper * except for the lock type which is set to F_UNLCK.
1453cedbec3SEnji Cooper */
1463cedbec3SEnji Cooper static int
test1(int fd,__unused int argc,const __unused char ** argv)1473cedbec3SEnji Cooper test1(int fd, __unused int argc, const __unused char **argv)
1483cedbec3SEnji Cooper {
1493cedbec3SEnji Cooper struct flock fl1, fl2;
1503cedbec3SEnji Cooper
1513cedbec3SEnji Cooper memset(&fl1, 1, sizeof(fl1));
1523cedbec3SEnji Cooper fl1.l_type = F_WRLCK;
1533cedbec3SEnji Cooper fl1.l_whence = SEEK_SET;
1543cedbec3SEnji Cooper fl2 = fl1;
1553cedbec3SEnji Cooper
1563cedbec3SEnji Cooper if (fcntl(fd, F_GETLK, &fl1) < 0)
1573cedbec3SEnji Cooper err(1, "F_GETLK");
1583cedbec3SEnji Cooper
1593cedbec3SEnji Cooper printf("1 - F_GETLK on unlocked region: ");
1603cedbec3SEnji Cooper FAIL(fl1.l_start != fl2.l_start);
1613cedbec3SEnji Cooper FAIL(fl1.l_len != fl2.l_len);
1623cedbec3SEnji Cooper FAIL(fl1.l_pid != fl2.l_pid);
1633cedbec3SEnji Cooper FAIL(fl1.l_type != F_UNLCK);
1643cedbec3SEnji Cooper FAIL(fl1.l_whence != fl2.l_whence);
1653cedbec3SEnji Cooper #ifdef HAVE_SYSID
1663cedbec3SEnji Cooper FAIL(fl1.l_sysid != fl2.l_sysid);
1673cedbec3SEnji Cooper #endif
1683cedbec3SEnji Cooper
1693cedbec3SEnji Cooper SUCCEED;
1703cedbec3SEnji Cooper }
1713cedbec3SEnji Cooper
1723cedbec3SEnji Cooper /*
1733cedbec3SEnji Cooper * Test 2 - F_SETLK on locked region
1743cedbec3SEnji Cooper *
1753cedbec3SEnji Cooper * If a shared or exclusive lock cannot be set, fcntl returns
1763cedbec3SEnji Cooper * immediately with EACCES or EAGAIN.
1773cedbec3SEnji Cooper */
1783cedbec3SEnji Cooper static int
test2(int fd,__unused int argc,const __unused char ** argv)1793cedbec3SEnji Cooper test2(int fd, __unused int argc, const __unused char **argv)
1803cedbec3SEnji Cooper {
1813cedbec3SEnji Cooper /*
1823cedbec3SEnji Cooper * We create a child process to hold the lock which we will
1833cedbec3SEnji Cooper * test. We use a pipe to communicate with the child.
1843cedbec3SEnji Cooper */
1853cedbec3SEnji Cooper int pid;
1863cedbec3SEnji Cooper int pfd[2];
1873cedbec3SEnji Cooper struct flock fl;
1883cedbec3SEnji Cooper char ch;
1893cedbec3SEnji Cooper int res;
1903cedbec3SEnji Cooper
1913cedbec3SEnji Cooper if (pipe(pfd) < 0)
1923cedbec3SEnji Cooper err(1, "pipe");
1933cedbec3SEnji Cooper
1943cedbec3SEnji Cooper fl.l_start = 0;
1953cedbec3SEnji Cooper fl.l_len = 0;
1963cedbec3SEnji Cooper fl.l_type = F_WRLCK;
1973cedbec3SEnji Cooper fl.l_whence = SEEK_SET;
1983cedbec3SEnji Cooper
1993cedbec3SEnji Cooper pid = fork();
2003cedbec3SEnji Cooper if (pid < 0)
2013cedbec3SEnji Cooper err(1, "fork");
2023cedbec3SEnji Cooper
2033cedbec3SEnji Cooper if (pid == 0) {
2043cedbec3SEnji Cooper /*
2053cedbec3SEnji Cooper * We are the child. We set a write lock and then
2063cedbec3SEnji Cooper * write one byte back to the parent to tell it. The
2073cedbec3SEnji Cooper * parent will kill us when its done.
2083cedbec3SEnji Cooper */
2093cedbec3SEnji Cooper if (fcntl(fd, F_SETLK, &fl) < 0)
2103cedbec3SEnji Cooper err(1, "F_SETLK (child)");
2113cedbec3SEnji Cooper if (write(pfd[1], "a", 1) < 0)
2123cedbec3SEnji Cooper err(1, "writing to pipe (child)");
2133cedbec3SEnji Cooper pause();
2143cedbec3SEnji Cooper exit(0);
2153cedbec3SEnji Cooper }
2163cedbec3SEnji Cooper
2173cedbec3SEnji Cooper /*
2183cedbec3SEnji Cooper * Wait until the child has set its lock and then perform the
2193cedbec3SEnji Cooper * test.
2203cedbec3SEnji Cooper */
2213cedbec3SEnji Cooper if (read(pfd[0], &ch, 1) != 1)
2223cedbec3SEnji Cooper err(1, "reading from pipe (child)");
2233cedbec3SEnji Cooper
2243cedbec3SEnji Cooper /*
2253cedbec3SEnji Cooper * fcntl should return -1 with errno set to either EACCES or
2263cedbec3SEnji Cooper * EAGAIN.
2273cedbec3SEnji Cooper */
2283cedbec3SEnji Cooper printf("2 - F_SETLK on locked region: ");
2293cedbec3SEnji Cooper res = fcntl(fd, F_SETLK, &fl);
2303cedbec3SEnji Cooper kill(pid, SIGTERM);
2313cedbec3SEnji Cooper safe_waitpid(pid);
2323cedbec3SEnji Cooper close(pfd[0]);
2333cedbec3SEnji Cooper close(pfd[1]);
2343cedbec3SEnji Cooper FAIL(res == 0);
2353cedbec3SEnji Cooper FAIL(errno != EACCES && errno != EAGAIN);
2363cedbec3SEnji Cooper
2373cedbec3SEnji Cooper SUCCEED;
2383cedbec3SEnji Cooper }
2393cedbec3SEnji Cooper
2403cedbec3SEnji Cooper /*
2413cedbec3SEnji Cooper * Test 3 - F_SETLKW on locked region
2423cedbec3SEnji Cooper *
2433cedbec3SEnji Cooper * If a shared or exclusive lock is blocked by other locks, the
2443cedbec3SEnji Cooper * process waits until the request can be satisfied.
2453cedbec3SEnji Cooper *
2463cedbec3SEnji Cooper * XXX this test hangs on FreeBSD NFS filesystems due to limitations
2473cedbec3SEnji Cooper * in FreeBSD's client (and server) lockd implementation.
2483cedbec3SEnji Cooper */
2493cedbec3SEnji Cooper static int
test3(int fd,__unused int argc,const __unused char ** argv)2503cedbec3SEnji Cooper test3(int fd, __unused int argc, const __unused char **argv)
2513cedbec3SEnji Cooper {
2523cedbec3SEnji Cooper /*
2533cedbec3SEnji Cooper * We create a child process to hold the lock which we will
2543cedbec3SEnji Cooper * test. We use a pipe to communicate with the child.
2553cedbec3SEnji Cooper */
2563cedbec3SEnji Cooper int pid;
2573cedbec3SEnji Cooper int pfd[2];
2583cedbec3SEnji Cooper struct flock fl;
2593cedbec3SEnji Cooper char ch;
2603cedbec3SEnji Cooper int res;
2613cedbec3SEnji Cooper
2623cedbec3SEnji Cooper if (pipe(pfd) < 0)
2633cedbec3SEnji Cooper err(1, "pipe");
2643cedbec3SEnji Cooper
2653cedbec3SEnji Cooper fl.l_start = 0;
2663cedbec3SEnji Cooper fl.l_len = 0;
2673cedbec3SEnji Cooper fl.l_type = F_WRLCK;
2683cedbec3SEnji Cooper fl.l_whence = SEEK_SET;
2693cedbec3SEnji Cooper
2703cedbec3SEnji Cooper pid = fork();
2713cedbec3SEnji Cooper if (pid < 0)
2723cedbec3SEnji Cooper err(1, "fork");
2733cedbec3SEnji Cooper
2743cedbec3SEnji Cooper if (pid == 0) {
2753cedbec3SEnji Cooper /*
2763cedbec3SEnji Cooper * We are the child. We set a write lock and then
2773cedbec3SEnji Cooper * write one byte back to the parent to tell it. The
2783cedbec3SEnji Cooper * parent will kill us when its done.
2793cedbec3SEnji Cooper */
2803cedbec3SEnji Cooper if (fcntl(fd, F_SETLK, &fl) < 0)
2813cedbec3SEnji Cooper err(1, "F_SETLK (child)");
2823cedbec3SEnji Cooper if (write(pfd[1], "a", 1) < 0)
2833cedbec3SEnji Cooper err(1, "writing to pipe (child)");
2843cedbec3SEnji Cooper pause();
2853cedbec3SEnji Cooper exit(0);
2863cedbec3SEnji Cooper }
2873cedbec3SEnji Cooper
2883cedbec3SEnji Cooper /*
2893cedbec3SEnji Cooper * Wait until the child has set its lock and then perform the
2903cedbec3SEnji Cooper * test.
2913cedbec3SEnji Cooper */
2923cedbec3SEnji Cooper if (read(pfd[0], &ch, 1) != 1)
2933cedbec3SEnji Cooper err(1, "reading from pipe (child)");
2943cedbec3SEnji Cooper
2953cedbec3SEnji Cooper /*
2963cedbec3SEnji Cooper * fcntl should wait until the alarm and then return -1 with
2973cedbec3SEnji Cooper * errno set to EINTR.
2983cedbec3SEnji Cooper */
2993cedbec3SEnji Cooper printf("3 - F_SETLKW on locked region: ");
3003cedbec3SEnji Cooper
3013cedbec3SEnji Cooper alarm(1);
3023cedbec3SEnji Cooper
3033cedbec3SEnji Cooper res = fcntl(fd, F_SETLKW, &fl);
3043cedbec3SEnji Cooper kill(pid, SIGTERM);
3053cedbec3SEnji Cooper safe_waitpid(pid);
3063cedbec3SEnji Cooper close(pfd[0]);
3073cedbec3SEnji Cooper close(pfd[1]);
3083cedbec3SEnji Cooper FAIL(res == 0);
3093cedbec3SEnji Cooper FAIL(errno != EINTR);
3103cedbec3SEnji Cooper
3113cedbec3SEnji Cooper SUCCEED;
3123cedbec3SEnji Cooper }
3133cedbec3SEnji Cooper
3143cedbec3SEnji Cooper /*
3153cedbec3SEnji Cooper * Test 4 - F_GETLK on locked region
3163cedbec3SEnji Cooper *
3173cedbec3SEnji Cooper * Get the first lock that blocks the lock.
3183cedbec3SEnji Cooper */
3193cedbec3SEnji Cooper static int
test4(int fd,__unused int argc,const __unused char ** argv)3203cedbec3SEnji Cooper test4(int fd, __unused int argc, const __unused char **argv)
3213cedbec3SEnji Cooper {
3223cedbec3SEnji Cooper /*
3233cedbec3SEnji Cooper * We create a child process to hold the lock which we will
3243cedbec3SEnji Cooper * test. We use a pipe to communicate with the child.
3253cedbec3SEnji Cooper */
3263cedbec3SEnji Cooper int pid;
3273cedbec3SEnji Cooper int pfd[2];
3283cedbec3SEnji Cooper struct flock fl;
3293cedbec3SEnji Cooper char ch;
3303cedbec3SEnji Cooper
3313cedbec3SEnji Cooper if (pipe(pfd) < 0)
3323cedbec3SEnji Cooper err(1, "pipe");
3333cedbec3SEnji Cooper
3343cedbec3SEnji Cooper fl.l_start = 0;
3353cedbec3SEnji Cooper fl.l_len = 99;
3363cedbec3SEnji Cooper fl.l_type = F_WRLCK;
3373cedbec3SEnji Cooper fl.l_whence = SEEK_SET;
3383cedbec3SEnji Cooper
3393cedbec3SEnji Cooper pid = fork();
3403cedbec3SEnji Cooper if (pid < 0)
3413cedbec3SEnji Cooper err(1, "fork");
3423cedbec3SEnji Cooper
3433cedbec3SEnji Cooper if (pid == 0) {
3443cedbec3SEnji Cooper /*
3453cedbec3SEnji Cooper * We are the child. We set a write lock and then
3463cedbec3SEnji Cooper * write one byte back to the parent to tell it. The
3473cedbec3SEnji Cooper * parent will kill us when its done.
3483cedbec3SEnji Cooper */
3493cedbec3SEnji Cooper if (fcntl(fd, F_SETLK, &fl) < 0)
3503cedbec3SEnji Cooper err(1, "F_SETLK (child)");
3513cedbec3SEnji Cooper if (write(pfd[1], "a", 1) < 0)
3523cedbec3SEnji Cooper err(1, "writing to pipe (child)");
3533cedbec3SEnji Cooper pause();
3543cedbec3SEnji Cooper exit(0);
3553cedbec3SEnji Cooper }
3563cedbec3SEnji Cooper
3573cedbec3SEnji Cooper /*
3583cedbec3SEnji Cooper * Wait until the child has set its lock and then perform the
3593cedbec3SEnji Cooper * test.
3603cedbec3SEnji Cooper */
3613cedbec3SEnji Cooper if (read(pfd[0], &ch, 1) != 1)
3623cedbec3SEnji Cooper err(1, "reading from pipe (child)");
3633cedbec3SEnji Cooper
3643cedbec3SEnji Cooper /*
3653cedbec3SEnji Cooper * fcntl should return a lock structure reflecting the lock we
3663cedbec3SEnji Cooper * made in the child process.
3673cedbec3SEnji Cooper */
3683cedbec3SEnji Cooper if (fcntl(fd, F_GETLK, &fl) < 0)
3693cedbec3SEnji Cooper err(1, "F_GETLK");
3703cedbec3SEnji Cooper
3713cedbec3SEnji Cooper printf("4 - F_GETLK on locked region: ");
3723cedbec3SEnji Cooper FAIL(fl.l_start != 0);
3733cedbec3SEnji Cooper FAIL(fl.l_len != 99);
3743cedbec3SEnji Cooper FAIL(fl.l_type != F_WRLCK);
3753cedbec3SEnji Cooper FAIL(fl.l_pid != pid);
3763cedbec3SEnji Cooper #ifdef HAVE_SYSID
3773cedbec3SEnji Cooper FAIL(fl.l_sysid != 0);
3783cedbec3SEnji Cooper #endif
3793cedbec3SEnji Cooper
3803cedbec3SEnji Cooper kill(pid, SIGTERM);
3813cedbec3SEnji Cooper safe_waitpid(pid);
3823cedbec3SEnji Cooper close(pfd[0]);
3833cedbec3SEnji Cooper close(pfd[1]);
3843cedbec3SEnji Cooper
3853cedbec3SEnji Cooper SUCCEED;
3863cedbec3SEnji Cooper }
3873cedbec3SEnji Cooper
3883cedbec3SEnji Cooper /*
3893cedbec3SEnji Cooper * Test 5 - F_SETLKW simple deadlock
3903cedbec3SEnji Cooper *
3913cedbec3SEnji Cooper * If a blocking shared lock request would cause a deadlock (i.e. the
3923cedbec3SEnji Cooper * lock request is blocked by a process which is itself blocked on a
3933cedbec3SEnji Cooper * lock currently owned by the process making the new request),
3943cedbec3SEnji Cooper * EDEADLK is returned.
3953cedbec3SEnji Cooper */
3963cedbec3SEnji Cooper static int
test5(int fd,__unused int argc,const __unused char ** argv)3973cedbec3SEnji Cooper test5(int fd, __unused int argc, const __unused char **argv)
3983cedbec3SEnji Cooper {
3993cedbec3SEnji Cooper /*
4003cedbec3SEnji Cooper * We create a child process to hold the lock which we will
4013cedbec3SEnji Cooper * test. Because our test relies on the child process being
4023cedbec3SEnji Cooper * blocked on the parent's lock, we can't easily use a pipe to
4033cedbec3SEnji Cooper * synchronize so we just sleep in the parent to given the
4043cedbec3SEnji Cooper * child a chance to setup.
4053cedbec3SEnji Cooper *
4063cedbec3SEnji Cooper * To create the deadlock condition, we arrange for the parent
4073cedbec3SEnji Cooper * to lock the first byte of the file and the child to lock
4083cedbec3SEnji Cooper * the second byte. After locking the second byte, the child
4093cedbec3SEnji Cooper * will attempt to lock the first byte of the file, and
4103cedbec3SEnji Cooper * block. The parent will then attempt to lock the second byte
4113cedbec3SEnji Cooper * (owned by the child) which should cause deadlock.
4123cedbec3SEnji Cooper */
4133cedbec3SEnji Cooper int pid;
4143cedbec3SEnji Cooper struct flock fl;
4153cedbec3SEnji Cooper int res;
4163cedbec3SEnji Cooper
4173cedbec3SEnji Cooper /*
4183cedbec3SEnji Cooper * Lock the first byte in the parent.
4193cedbec3SEnji Cooper */
4203cedbec3SEnji Cooper fl.l_start = 0;
4213cedbec3SEnji Cooper fl.l_len = 1;
4223cedbec3SEnji Cooper fl.l_type = F_WRLCK;
4233cedbec3SEnji Cooper fl.l_whence = SEEK_SET;
4243cedbec3SEnji Cooper if (fcntl(fd, F_SETLK, &fl) < 0)
4253cedbec3SEnji Cooper err(1, "F_SETLK 1 (parent)");
4263cedbec3SEnji Cooper
4273cedbec3SEnji Cooper pid = fork();
4283cedbec3SEnji Cooper if (pid < 0)
4293cedbec3SEnji Cooper err(1, "fork");
4303cedbec3SEnji Cooper
4313cedbec3SEnji Cooper if (pid == 0) {
4323cedbec3SEnji Cooper /*
4333cedbec3SEnji Cooper * Lock the second byte in the child and then block on
4343cedbec3SEnji Cooper * the parent's lock.
4353cedbec3SEnji Cooper */
4363cedbec3SEnji Cooper fl.l_start = 1;
4373cedbec3SEnji Cooper if (fcntl(fd, F_SETLK, &fl) < 0)
4383cedbec3SEnji Cooper err(1, "F_SETLK (child)");
4393cedbec3SEnji Cooper fl.l_start = 0;
4403cedbec3SEnji Cooper if (fcntl(fd, F_SETLKW, &fl) < 0)
4413cedbec3SEnji Cooper err(1, "F_SETLKW (child)");
4423cedbec3SEnji Cooper exit(0);
4433cedbec3SEnji Cooper }
4443cedbec3SEnji Cooper
4453cedbec3SEnji Cooper /*
4463cedbec3SEnji Cooper * Wait until the child has set its lock and then perform the
4473cedbec3SEnji Cooper * test.
4483cedbec3SEnji Cooper */
4493cedbec3SEnji Cooper sleep(1);
4503cedbec3SEnji Cooper
4513cedbec3SEnji Cooper /*
4523cedbec3SEnji Cooper * fcntl should immediately return -1 with errno set to
4533cedbec3SEnji Cooper * EDEADLK. If the alarm fires, we failed to detect the
4543cedbec3SEnji Cooper * deadlock.
4553cedbec3SEnji Cooper */
4563cedbec3SEnji Cooper alarm(1);
4573cedbec3SEnji Cooper printf("5 - F_SETLKW simple deadlock: ");
4583cedbec3SEnji Cooper
4593cedbec3SEnji Cooper fl.l_start = 1;
4603cedbec3SEnji Cooper res = fcntl(fd, F_SETLKW, &fl);
4613cedbec3SEnji Cooper kill(pid, SIGTERM);
4623cedbec3SEnji Cooper safe_waitpid(pid);
4633cedbec3SEnji Cooper
4643cedbec3SEnji Cooper FAIL(res == 0);
4653cedbec3SEnji Cooper FAIL(errno != EDEADLK);
4663cedbec3SEnji Cooper
4673cedbec3SEnji Cooper fl.l_start = 0;
4683cedbec3SEnji Cooper fl.l_len = 0;
4693cedbec3SEnji Cooper fl.l_type = F_UNLCK;
4703cedbec3SEnji Cooper if (fcntl(fd, F_SETLK, &fl) < 0)
4713cedbec3SEnji Cooper err(1, "F_UNLCK");
4723cedbec3SEnji Cooper
4733cedbec3SEnji Cooper /*
4743cedbec3SEnji Cooper * Cancel the alarm to avoid confusing later tests.
4753cedbec3SEnji Cooper */
4763cedbec3SEnji Cooper alarm(0);
4773cedbec3SEnji Cooper
4783cedbec3SEnji Cooper SUCCEED;
4793cedbec3SEnji Cooper }
4803cedbec3SEnji Cooper
4813cedbec3SEnji Cooper /*
4823cedbec3SEnji Cooper * Test 6 - F_SETLKW complex deadlock.
4833cedbec3SEnji Cooper *
4843cedbec3SEnji Cooper * This test involves three process, P, C1 and C2. We set things up so
4853cedbec3SEnji Cooper * that P locks byte zero, C1 locks byte 1 and C2 locks byte 2. We
4863cedbec3SEnji Cooper * also block C2 by attempting to lock byte zero. Lastly, P attempts
4873cedbec3SEnji Cooper * to lock a range including byte 1 and 2. This represents a deadlock
4883cedbec3SEnji Cooper * (due to C2's blocking attempt to lock byte zero).
4893cedbec3SEnji Cooper */
4903cedbec3SEnji Cooper static int
test6(int fd,__unused int argc,const __unused char ** argv)4913cedbec3SEnji Cooper test6(int fd, __unused int argc, const __unused char **argv)
4923cedbec3SEnji Cooper {
4933cedbec3SEnji Cooper /*
4943cedbec3SEnji Cooper * Because our test relies on the child process being blocked
4953cedbec3SEnji Cooper * on the parent's lock, we can't easily use a pipe to
4963cedbec3SEnji Cooper * synchronize so we just sleep in the parent to given the
4973cedbec3SEnji Cooper * children a chance to setup.
4983cedbec3SEnji Cooper */
4993cedbec3SEnji Cooper int pid1, pid2;
5003cedbec3SEnji Cooper struct flock fl;
5013cedbec3SEnji Cooper int res;
5023cedbec3SEnji Cooper
5033cedbec3SEnji Cooper /*
5043cedbec3SEnji Cooper * Lock the first byte in the parent.
5053cedbec3SEnji Cooper */
5063cedbec3SEnji Cooper fl.l_start = 0;
5073cedbec3SEnji Cooper fl.l_len = 1;
5083cedbec3SEnji Cooper fl.l_type = F_WRLCK;
5093cedbec3SEnji Cooper fl.l_whence = SEEK_SET;
5103cedbec3SEnji Cooper if (fcntl(fd, F_SETLK, &fl) < 0)
5113cedbec3SEnji Cooper err(1, "F_SETLK 1 (parent)");
5123cedbec3SEnji Cooper
5133cedbec3SEnji Cooper pid1 = fork();
5143cedbec3SEnji Cooper if (pid1 < 0)
5153cedbec3SEnji Cooper err(1, "fork");
5163cedbec3SEnji Cooper
5173cedbec3SEnji Cooper if (pid1 == 0) {
5183cedbec3SEnji Cooper /*
5193cedbec3SEnji Cooper * C1
5203cedbec3SEnji Cooper * Lock the second byte in the child and then sleep
5213cedbec3SEnji Cooper */
5223cedbec3SEnji Cooper fl.l_start = 1;
5233cedbec3SEnji Cooper if (fcntl(fd, F_SETLK, &fl) < 0)
5243cedbec3SEnji Cooper err(1, "F_SETLK (child1)");
5253cedbec3SEnji Cooper pause();
5263cedbec3SEnji Cooper exit(0);
5273cedbec3SEnji Cooper }
5283cedbec3SEnji Cooper
5293cedbec3SEnji Cooper pid2 = fork();
5303cedbec3SEnji Cooper if (pid2 < 0)
5313cedbec3SEnji Cooper err(1, "fork");
5323cedbec3SEnji Cooper
5333cedbec3SEnji Cooper if (pid2 == 0) {
5343cedbec3SEnji Cooper /*
5353cedbec3SEnji Cooper * C2
5363cedbec3SEnji Cooper * Lock the third byte in the child and then block on
5373cedbec3SEnji Cooper * the parent's lock.
5383cedbec3SEnji Cooper */
5393cedbec3SEnji Cooper fl.l_start = 2;
5403cedbec3SEnji Cooper if (fcntl(fd, F_SETLK, &fl) < 0)
5413cedbec3SEnji Cooper err(1, "F_SETLK (child2)");
5423cedbec3SEnji Cooper fl.l_start = 0;
5433cedbec3SEnji Cooper if (fcntl(fd, F_SETLKW, &fl) < 0)
5443cedbec3SEnji Cooper err(1, "F_SETLKW (child2)");
5453cedbec3SEnji Cooper exit(0);
5463cedbec3SEnji Cooper }
5473cedbec3SEnji Cooper
5483cedbec3SEnji Cooper /*
5493cedbec3SEnji Cooper * Wait until the children have set their locks and then
5503cedbec3SEnji Cooper * perform the test.
5513cedbec3SEnji Cooper */
5523cedbec3SEnji Cooper sleep(1);
5533cedbec3SEnji Cooper
5543cedbec3SEnji Cooper /*
5553cedbec3SEnji Cooper * fcntl should immediately return -1 with errno set to
5563cedbec3SEnji Cooper * EDEADLK. If the alarm fires, we failed to detect the
5573cedbec3SEnji Cooper * deadlock.
5583cedbec3SEnji Cooper */
5593cedbec3SEnji Cooper alarm(1);
5603cedbec3SEnji Cooper printf("6 - F_SETLKW complex deadlock: ");
5613cedbec3SEnji Cooper
5623cedbec3SEnji Cooper fl.l_start = 1;
5633cedbec3SEnji Cooper fl.l_len = 2;
5643cedbec3SEnji Cooper res = fcntl(fd, F_SETLKW, &fl);
5653cedbec3SEnji Cooper kill(pid1, SIGTERM);
5663cedbec3SEnji Cooper safe_waitpid(pid1);
5673cedbec3SEnji Cooper kill(pid2, SIGTERM);
5683cedbec3SEnji Cooper safe_waitpid(pid2);
5693cedbec3SEnji Cooper
5703cedbec3SEnji Cooper fl.l_start = 0;
5713cedbec3SEnji Cooper fl.l_len = 0;
5723cedbec3SEnji Cooper fl.l_type = F_UNLCK;
5733cedbec3SEnji Cooper if (fcntl(fd, F_SETLK, &fl) < 0)
5743cedbec3SEnji Cooper err(1, "F_UNLCK");
5753cedbec3SEnji Cooper
5763cedbec3SEnji Cooper FAIL(res == 0);
5773cedbec3SEnji Cooper FAIL(errno != EDEADLK);
5783cedbec3SEnji Cooper
5793cedbec3SEnji Cooper /*
5803cedbec3SEnji Cooper * Cancel the alarm to avoid confusing later tests.
5813cedbec3SEnji Cooper */
5823cedbec3SEnji Cooper alarm(0);
5833cedbec3SEnji Cooper
5843cedbec3SEnji Cooper SUCCEED;
5853cedbec3SEnji Cooper }
5863cedbec3SEnji Cooper
5873cedbec3SEnji Cooper /*
5883cedbec3SEnji Cooper * Test 7 - F_SETLK shared lock on exclusive locked region
5893cedbec3SEnji Cooper *
5903cedbec3SEnji Cooper * If a shared or exclusive lock cannot be set, fcntl returns
5913cedbec3SEnji Cooper * immediately with EACCES or EAGAIN.
5923cedbec3SEnji Cooper */
5933cedbec3SEnji Cooper static int
test7(int fd,__unused int argc,const __unused char ** argv)5943cedbec3SEnji Cooper test7(int fd, __unused int argc, const __unused char **argv)
5953cedbec3SEnji Cooper {
5963cedbec3SEnji Cooper /*
5973cedbec3SEnji Cooper * We create a child process to hold the lock which we will
5983cedbec3SEnji Cooper * test. We use a pipe to communicate with the child.
5993cedbec3SEnji Cooper */
6003cedbec3SEnji Cooper int pid;
6013cedbec3SEnji Cooper int pfd[2];
6023cedbec3SEnji Cooper struct flock fl;
6033cedbec3SEnji Cooper char ch;
6043cedbec3SEnji Cooper int res;
6053cedbec3SEnji Cooper
6063cedbec3SEnji Cooper if (pipe(pfd) < 0)
6073cedbec3SEnji Cooper err(1, "pipe");
6083cedbec3SEnji Cooper
6093cedbec3SEnji Cooper fl.l_start = 0;
6103cedbec3SEnji Cooper fl.l_len = 0;
6113cedbec3SEnji Cooper fl.l_type = F_WRLCK;
6123cedbec3SEnji Cooper fl.l_whence = SEEK_SET;
6133cedbec3SEnji Cooper
6143cedbec3SEnji Cooper pid = fork();
6153cedbec3SEnji Cooper if (pid < 0)
6163cedbec3SEnji Cooper err(1, "fork");
6173cedbec3SEnji Cooper
6183cedbec3SEnji Cooper if (pid == 0) {
6193cedbec3SEnji Cooper /*
6203cedbec3SEnji Cooper * We are the child. We set a write lock and then
6213cedbec3SEnji Cooper * write one byte back to the parent to tell it. The
6223cedbec3SEnji Cooper * parent will kill us when its done.
6233cedbec3SEnji Cooper */
6243cedbec3SEnji Cooper if (fcntl(fd, F_SETLK, &fl) < 0)
6253cedbec3SEnji Cooper err(1, "F_SETLK (child)");
6263cedbec3SEnji Cooper if (write(pfd[1], "a", 1) < 0)
6273cedbec3SEnji Cooper err(1, "writing to pipe (child)");
6283cedbec3SEnji Cooper pause();
6293cedbec3SEnji Cooper exit(0);
6303cedbec3SEnji Cooper }
6313cedbec3SEnji Cooper
6323cedbec3SEnji Cooper /*
6333cedbec3SEnji Cooper * Wait until the child has set its lock and then perform the
6343cedbec3SEnji Cooper * test.
6353cedbec3SEnji Cooper */
6363cedbec3SEnji Cooper if (read(pfd[0], &ch, 1) != 1)
6373cedbec3SEnji Cooper err(1, "reading from pipe (child)");
6383cedbec3SEnji Cooper
6393cedbec3SEnji Cooper /*
6403cedbec3SEnji Cooper * fcntl should wait until the alarm and then return -1 with
6413cedbec3SEnji Cooper * errno set to EINTR.
6423cedbec3SEnji Cooper */
6433cedbec3SEnji Cooper printf("7 - F_SETLK shared lock on exclusive locked region: ");
6443cedbec3SEnji Cooper
6453cedbec3SEnji Cooper fl.l_type = F_RDLCK;
6463cedbec3SEnji Cooper res = fcntl(fd, F_SETLK, &fl);
6473cedbec3SEnji Cooper kill(pid, SIGTERM);
6483cedbec3SEnji Cooper safe_waitpid(pid);
6493cedbec3SEnji Cooper close(pfd[0]);
6503cedbec3SEnji Cooper close(pfd[1]);
6513cedbec3SEnji Cooper
6523cedbec3SEnji Cooper FAIL(res == 0);
6533cedbec3SEnji Cooper FAIL(errno != EACCES && errno != EAGAIN);
6543cedbec3SEnji Cooper
6553cedbec3SEnji Cooper SUCCEED;
6563cedbec3SEnji Cooper }
6573cedbec3SEnji Cooper
6583cedbec3SEnji Cooper /*
6593cedbec3SEnji Cooper * Test 8 - F_SETLK shared lock on share locked region
6603cedbec3SEnji Cooper *
6613cedbec3SEnji Cooper * When a shared lock is set on a segment of a file, other processes
6623cedbec3SEnji Cooper * shall be able to set shared locks on that segment or a portion of
6633cedbec3SEnji Cooper * it.
6643cedbec3SEnji Cooper */
6653cedbec3SEnji Cooper static int
test8(int fd,__unused int argc,const __unused char ** argv)6663cedbec3SEnji Cooper test8(int fd, __unused int argc, const __unused char **argv)
6673cedbec3SEnji Cooper {
6683cedbec3SEnji Cooper /*
6693cedbec3SEnji Cooper * We create a child process to hold the lock which we will
6703cedbec3SEnji Cooper * test. We use a pipe to communicate with the child.
6713cedbec3SEnji Cooper */
6723cedbec3SEnji Cooper int pid;
6733cedbec3SEnji Cooper int pfd[2];
6743cedbec3SEnji Cooper struct flock fl;
6753cedbec3SEnji Cooper char ch;
6763cedbec3SEnji Cooper int res;
6773cedbec3SEnji Cooper
6783cedbec3SEnji Cooper if (pipe(pfd) < 0)
6793cedbec3SEnji Cooper err(1, "pipe");
6803cedbec3SEnji Cooper
6813cedbec3SEnji Cooper fl.l_start = 0;
6823cedbec3SEnji Cooper fl.l_len = 0;
6833cedbec3SEnji Cooper fl.l_type = F_RDLCK;
6843cedbec3SEnji Cooper fl.l_whence = SEEK_SET;
6853cedbec3SEnji Cooper
6863cedbec3SEnji Cooper pid = fork();
6873cedbec3SEnji Cooper if (pid < 0)
6883cedbec3SEnji Cooper err(1, "fork");
6893cedbec3SEnji Cooper
6903cedbec3SEnji Cooper if (pid == 0) {
6913cedbec3SEnji Cooper /*
6923cedbec3SEnji Cooper * We are the child. We set a write lock and then
6933cedbec3SEnji Cooper * write one byte back to the parent to tell it. The
6943cedbec3SEnji Cooper * parent will kill us when its done.
6953cedbec3SEnji Cooper */
6963cedbec3SEnji Cooper if (fcntl(fd, F_SETLK, &fl) < 0)
6973cedbec3SEnji Cooper err(1, "F_SETLK (child)");
6983cedbec3SEnji Cooper if (write(pfd[1], "a", 1) < 0)
6993cedbec3SEnji Cooper err(1, "writing to pipe (child)");
7003cedbec3SEnji Cooper pause();
7013cedbec3SEnji Cooper exit(0);
7023cedbec3SEnji Cooper }
7033cedbec3SEnji Cooper
7043cedbec3SEnji Cooper /*
7053cedbec3SEnji Cooper * Wait until the child has set its lock and then perform the
7063cedbec3SEnji Cooper * test.
7073cedbec3SEnji Cooper */
7083cedbec3SEnji Cooper if (read(pfd[0], &ch, 1) != 1)
7093cedbec3SEnji Cooper err(1, "reading from pipe (child)");
7103cedbec3SEnji Cooper
7113cedbec3SEnji Cooper /*
7123cedbec3SEnji Cooper * fcntl should wait until the alarm and then return -1 with
7133cedbec3SEnji Cooper * errno set to EINTR.
7143cedbec3SEnji Cooper */
7153cedbec3SEnji Cooper printf("8 - F_SETLK shared lock on share locked region: ");
7163cedbec3SEnji Cooper
7173cedbec3SEnji Cooper fl.l_type = F_RDLCK;
7183cedbec3SEnji Cooper res = fcntl(fd, F_SETLK, &fl);
7193cedbec3SEnji Cooper
7203cedbec3SEnji Cooper kill(pid, SIGTERM);
7213cedbec3SEnji Cooper safe_waitpid(pid);
7223cedbec3SEnji Cooper close(pfd[0]);
7233cedbec3SEnji Cooper close(pfd[1]);
7243cedbec3SEnji Cooper
7253cedbec3SEnji Cooper fl.l_start = 0;
7263cedbec3SEnji Cooper fl.l_len = 0;
7273cedbec3SEnji Cooper fl.l_type = F_UNLCK;
7283cedbec3SEnji Cooper if (fcntl(fd, F_SETLK, &fl) < 0)
7293cedbec3SEnji Cooper err(1, "F_UNLCK");
7303cedbec3SEnji Cooper
7313cedbec3SEnji Cooper FAIL(res != 0);
7323cedbec3SEnji Cooper
7333cedbec3SEnji Cooper SUCCEED;
7343cedbec3SEnji Cooper }
7353cedbec3SEnji Cooper
7363cedbec3SEnji Cooper /*
7373cedbec3SEnji Cooper * Test 9 - F_SETLK exclusive lock on share locked region
7383cedbec3SEnji Cooper *
7393cedbec3SEnji Cooper * If a shared or exclusive lock cannot be set, fcntl returns
7403cedbec3SEnji Cooper * immediately with EACCES or EAGAIN.
7413cedbec3SEnji Cooper */
7423cedbec3SEnji Cooper static int
test9(int fd,__unused int argc,const __unused char ** argv)7433cedbec3SEnji Cooper test9(int fd, __unused int argc, const __unused char **argv)
7443cedbec3SEnji Cooper {
7453cedbec3SEnji Cooper /*
7463cedbec3SEnji Cooper * We create a child process to hold the lock which we will
7473cedbec3SEnji Cooper * test. We use a pipe to communicate with the child.
7483cedbec3SEnji Cooper */
7493cedbec3SEnji Cooper int pid;
7503cedbec3SEnji Cooper int pfd[2];
7513cedbec3SEnji Cooper struct flock fl;
7523cedbec3SEnji Cooper char ch;
7533cedbec3SEnji Cooper int res;
7543cedbec3SEnji Cooper
7553cedbec3SEnji Cooper if (pipe(pfd) < 0)
7563cedbec3SEnji Cooper err(1, "pipe");
7573cedbec3SEnji Cooper
7583cedbec3SEnji Cooper fl.l_start = 0;
7593cedbec3SEnji Cooper fl.l_len = 0;
7603cedbec3SEnji Cooper fl.l_type = F_RDLCK;
7613cedbec3SEnji Cooper fl.l_whence = SEEK_SET;
7623cedbec3SEnji Cooper
7633cedbec3SEnji Cooper pid = fork();
7643cedbec3SEnji Cooper if (pid < 0)
7653cedbec3SEnji Cooper err(1, "fork");
7663cedbec3SEnji Cooper
7673cedbec3SEnji Cooper if (pid == 0) {
7683cedbec3SEnji Cooper /*
7693cedbec3SEnji Cooper * We are the child. We set a write lock and then
7703cedbec3SEnji Cooper * write one byte back to the parent to tell it. The
7713cedbec3SEnji Cooper * parent will kill us when its done.
7723cedbec3SEnji Cooper */
7733cedbec3SEnji Cooper if (fcntl(fd, F_SETLK, &fl) < 0)
7743cedbec3SEnji Cooper err(1, "F_SETLK (child)");
7753cedbec3SEnji Cooper if (write(pfd[1], "a", 1) < 0)
7763cedbec3SEnji Cooper err(1, "writing to pipe (child)");
7773cedbec3SEnji Cooper pause();
7783cedbec3SEnji Cooper exit(0);
7793cedbec3SEnji Cooper }
7803cedbec3SEnji Cooper
7813cedbec3SEnji Cooper /*
7823cedbec3SEnji Cooper * Wait until the child has set its lock and then perform the
7833cedbec3SEnji Cooper * test.
7843cedbec3SEnji Cooper */
7853cedbec3SEnji Cooper if (read(pfd[0], &ch, 1) != 1)
7863cedbec3SEnji Cooper err(1, "reading from pipe (child)");
7873cedbec3SEnji Cooper
7883cedbec3SEnji Cooper /*
7893cedbec3SEnji Cooper * fcntl should wait until the alarm and then return -1 with
7903cedbec3SEnji Cooper * errno set to EINTR.
7913cedbec3SEnji Cooper */
7923cedbec3SEnji Cooper printf("9 - F_SETLK exclusive lock on share locked region: ");
7933cedbec3SEnji Cooper
7943cedbec3SEnji Cooper fl.l_type = F_WRLCK;
7953cedbec3SEnji Cooper res = fcntl(fd, F_SETLK, &fl);
7963cedbec3SEnji Cooper kill(pid, SIGTERM);
7973cedbec3SEnji Cooper safe_waitpid(pid);
7983cedbec3SEnji Cooper close(pfd[0]);
7993cedbec3SEnji Cooper close(pfd[1]);
8003cedbec3SEnji Cooper
8013cedbec3SEnji Cooper FAIL(res == 0);
8023cedbec3SEnji Cooper FAIL(errno != EACCES && errno != EAGAIN);
8033cedbec3SEnji Cooper
8043cedbec3SEnji Cooper SUCCEED;
8053cedbec3SEnji Cooper }
8063cedbec3SEnji Cooper
8073cedbec3SEnji Cooper /*
8083cedbec3SEnji Cooper * Test 10 - trying to set bogus pid or sysid values
8093cedbec3SEnji Cooper *
8103cedbec3SEnji Cooper * The l_pid and l_sysid fields are only used with F_GETLK to return
8113cedbec3SEnji Cooper * the process ID of the process holding a blocking lock and the
8123cedbec3SEnji Cooper * system ID of the system that owns that process
8133cedbec3SEnji Cooper */
8143cedbec3SEnji Cooper static int
test10(int fd,__unused int argc,const __unused char ** argv)8153cedbec3SEnji Cooper test10(int fd, __unused int argc, const __unused char **argv)
8163cedbec3SEnji Cooper {
8173cedbec3SEnji Cooper /*
8183cedbec3SEnji Cooper * We create a child process to hold the lock which we will
8193cedbec3SEnji Cooper * test. We use a pipe to communicate with the child.
8203cedbec3SEnji Cooper */
8213cedbec3SEnji Cooper int pid;
8223cedbec3SEnji Cooper int pfd[2];
8233cedbec3SEnji Cooper struct flock fl;
8243cedbec3SEnji Cooper char ch;
8253cedbec3SEnji Cooper
8263cedbec3SEnji Cooper if (pipe(pfd) < 0)
8273cedbec3SEnji Cooper err(1, "pipe");
8283cedbec3SEnji Cooper
8293cedbec3SEnji Cooper fl.l_start = 0;
8303cedbec3SEnji Cooper fl.l_len = 0;
8313cedbec3SEnji Cooper fl.l_type = F_WRLCK;
8323cedbec3SEnji Cooper fl.l_whence = SEEK_SET;
8333cedbec3SEnji Cooper fl.l_pid = 9999;
8343cedbec3SEnji Cooper #ifdef HAVE_SYSID
8353cedbec3SEnji Cooper fl.l_sysid = 9999;
8363cedbec3SEnji Cooper #endif
8373cedbec3SEnji Cooper
8383cedbec3SEnji Cooper pid = fork();
8393cedbec3SEnji Cooper if (pid < 0)
8403cedbec3SEnji Cooper err(1, "fork");
8413cedbec3SEnji Cooper
8423cedbec3SEnji Cooper if (pid == 0) {
8433cedbec3SEnji Cooper /*
8443cedbec3SEnji Cooper * We are the child. We set a write lock and then
8453cedbec3SEnji Cooper * write one byte back to the parent to tell it. The
8463cedbec3SEnji Cooper * parent will kill us when its done.
8473cedbec3SEnji Cooper */
8483cedbec3SEnji Cooper if (fcntl(fd, F_SETLK, &fl) < 0)
8493cedbec3SEnji Cooper err(1, "F_SETLK (child)");
8503cedbec3SEnji Cooper if (write(pfd[1], "a", 1) < 0)
8513cedbec3SEnji Cooper err(1, "writing to pipe (child)");
8523cedbec3SEnji Cooper pause();
8533cedbec3SEnji Cooper exit(0);
8543cedbec3SEnji Cooper }
8553cedbec3SEnji Cooper
8563cedbec3SEnji Cooper /*
8573cedbec3SEnji Cooper * Wait until the child has set its lock and then perform the
8583cedbec3SEnji Cooper * test.
8593cedbec3SEnji Cooper */
8603cedbec3SEnji Cooper if (read(pfd[0], &ch, 1) != 1)
8613cedbec3SEnji Cooper err(1, "reading from pipe (child)");
8623cedbec3SEnji Cooper
8633cedbec3SEnji Cooper printf("10 - trying to set bogus pid or sysid values: ");
8643cedbec3SEnji Cooper
8653cedbec3SEnji Cooper if (fcntl(fd, F_GETLK, &fl) < 0)
8663cedbec3SEnji Cooper err(1, "F_GETLK");
8673cedbec3SEnji Cooper
8683cedbec3SEnji Cooper kill(pid, SIGTERM);
8693cedbec3SEnji Cooper safe_waitpid(pid);
8703cedbec3SEnji Cooper close(pfd[0]);
8713cedbec3SEnji Cooper close(pfd[1]);
8723cedbec3SEnji Cooper
8733cedbec3SEnji Cooper FAIL(fl.l_pid != pid);
8743cedbec3SEnji Cooper #ifdef HAVE_SYSID
8753cedbec3SEnji Cooper FAIL(fl.l_sysid != 0);
8763cedbec3SEnji Cooper #endif
8773cedbec3SEnji Cooper
8783cedbec3SEnji Cooper SUCCEED;
8793cedbec3SEnji Cooper }
8803cedbec3SEnji Cooper
8813cedbec3SEnji Cooper /*
8823cedbec3SEnji Cooper * Test 11 - remote locks
8833cedbec3SEnji Cooper *
8843cedbec3SEnji Cooper * XXX temporary interface which will be removed when the kernel lockd
8853cedbec3SEnji Cooper * is added.
8863cedbec3SEnji Cooper */
8873cedbec3SEnji Cooper static int
test11(int fd,__unused int argc,const __unused char ** argv)8883cedbec3SEnji Cooper test11(int fd, __unused int argc, const __unused char **argv)
8893cedbec3SEnji Cooper {
8903cedbec3SEnji Cooper #ifdef F_SETLK_REMOTE
8913cedbec3SEnji Cooper struct flock fl;
8923cedbec3SEnji Cooper int res;
8933cedbec3SEnji Cooper
8943cedbec3SEnji Cooper if (geteuid() != 0)
8953cedbec3SEnji Cooper return 0;
8963cedbec3SEnji Cooper
8973cedbec3SEnji Cooper fl.l_start = 0;
8983cedbec3SEnji Cooper fl.l_len = 0;
8993cedbec3SEnji Cooper fl.l_type = F_WRLCK;
9003cedbec3SEnji Cooper fl.l_whence = SEEK_SET;
9013cedbec3SEnji Cooper fl.l_pid = 9999;
9023cedbec3SEnji Cooper fl.l_sysid = 1001;
9033cedbec3SEnji Cooper
9043cedbec3SEnji Cooper printf("11 - remote locks: ");
9053cedbec3SEnji Cooper
9063cedbec3SEnji Cooper res = fcntl(fd, F_SETLK_REMOTE, &fl);
9073cedbec3SEnji Cooper FAIL(res != 0);
9083cedbec3SEnji Cooper
9093cedbec3SEnji Cooper fl.l_sysid = 1002;
9103cedbec3SEnji Cooper res = fcntl(fd, F_SETLK_REMOTE, &fl);
9113cedbec3SEnji Cooper FAIL(res == 0);
9123cedbec3SEnji Cooper FAIL(errno != EACCES && errno != EAGAIN);
9133cedbec3SEnji Cooper
9143cedbec3SEnji Cooper res = fcntl(fd, F_GETLK, &fl);
9153cedbec3SEnji Cooper FAIL(res != 0);
9163cedbec3SEnji Cooper FAIL(fl.l_pid != 9999);
9173cedbec3SEnji Cooper FAIL(fl.l_sysid != 1001);
9183cedbec3SEnji Cooper
9193cedbec3SEnji Cooper fl.l_type = F_UNLCK;
9203cedbec3SEnji Cooper fl.l_sysid = 1001;
9213cedbec3SEnji Cooper fl.l_start = 0;
9223cedbec3SEnji Cooper fl.l_len = 0;
9233cedbec3SEnji Cooper res = fcntl(fd, F_SETLK_REMOTE, &fl);
9243cedbec3SEnji Cooper FAIL(res != 0);
9253cedbec3SEnji Cooper
9263cedbec3SEnji Cooper fl.l_pid = 1234;
9273cedbec3SEnji Cooper fl.l_sysid = 1001;
9283cedbec3SEnji Cooper fl.l_start = 0;
9293cedbec3SEnji Cooper fl.l_len = 1;
9303cedbec3SEnji Cooper fl.l_whence = SEEK_SET;
9313cedbec3SEnji Cooper fl.l_type = F_RDLCK;
9323cedbec3SEnji Cooper res = fcntl(fd, F_SETLK_REMOTE, &fl);
9333cedbec3SEnji Cooper FAIL(res != 0);
9343cedbec3SEnji Cooper
9353cedbec3SEnji Cooper fl.l_sysid = 1002;
9363cedbec3SEnji Cooper res = fcntl(fd, F_SETLK_REMOTE, &fl);
9373cedbec3SEnji Cooper FAIL(res != 0);
9383cedbec3SEnji Cooper
9393cedbec3SEnji Cooper fl.l_type = F_UNLCKSYS;
9403cedbec3SEnji Cooper fl.l_sysid = 1001;
9413cedbec3SEnji Cooper res = fcntl(fd, F_SETLK_REMOTE, &fl);
9423cedbec3SEnji Cooper FAIL(res != 0);
9433cedbec3SEnji Cooper
9443cedbec3SEnji Cooper fl.l_type = F_WRLCK;
9453cedbec3SEnji Cooper res = fcntl(fd, F_GETLK, &fl);
9463cedbec3SEnji Cooper FAIL(res != 0);
9473cedbec3SEnji Cooper FAIL(fl.l_pid != 1234);
9483cedbec3SEnji Cooper FAIL(fl.l_sysid != 1002);
9493cedbec3SEnji Cooper
9503cedbec3SEnji Cooper fl.l_type = F_UNLCKSYS;
9513cedbec3SEnji Cooper fl.l_sysid = 1002;
9523cedbec3SEnji Cooper res = fcntl(fd, F_SETLK_REMOTE, &fl);
9533cedbec3SEnji Cooper FAIL(res != 0);
9543cedbec3SEnji Cooper
9553cedbec3SEnji Cooper SUCCEED;
9563cedbec3SEnji Cooper #else
9573cedbec3SEnji Cooper return 0;
9583cedbec3SEnji Cooper #endif
9593cedbec3SEnji Cooper }
9603cedbec3SEnji Cooper
9613cedbec3SEnji Cooper /*
9623cedbec3SEnji Cooper * Test 12 - F_SETLKW on locked region which is then unlocked
9633cedbec3SEnji Cooper *
9643cedbec3SEnji Cooper * If a shared or exclusive lock is blocked by other locks, the
9653cedbec3SEnji Cooper * process waits until the request can be satisfied.
9663cedbec3SEnji Cooper */
9673cedbec3SEnji Cooper static int
test12(int fd,__unused int argc,const __unused char ** argv)9683cedbec3SEnji Cooper test12(int fd, __unused int argc, const __unused char **argv)
9693cedbec3SEnji Cooper {
9703cedbec3SEnji Cooper /*
9713cedbec3SEnji Cooper * We create a child process to hold the lock which we will
9723cedbec3SEnji Cooper * test. We use a pipe to communicate with the child.
9733cedbec3SEnji Cooper */
9743cedbec3SEnji Cooper int pid;
9753cedbec3SEnji Cooper int pfd[2];
9763cedbec3SEnji Cooper struct flock fl;
9773cedbec3SEnji Cooper char ch;
9783cedbec3SEnji Cooper int res;
9793cedbec3SEnji Cooper
9803cedbec3SEnji Cooper if (pipe(pfd) < 0)
9813cedbec3SEnji Cooper err(1, "pipe");
9823cedbec3SEnji Cooper
9833cedbec3SEnji Cooper fl.l_start = 0;
9843cedbec3SEnji Cooper fl.l_len = 0;
9853cedbec3SEnji Cooper fl.l_type = F_WRLCK;
9863cedbec3SEnji Cooper fl.l_whence = SEEK_SET;
9873cedbec3SEnji Cooper
9883cedbec3SEnji Cooper pid = fork();
9893cedbec3SEnji Cooper if (pid < 0)
9903cedbec3SEnji Cooper err(1, "fork");
9913cedbec3SEnji Cooper
9923cedbec3SEnji Cooper if (pid == 0) {
9933cedbec3SEnji Cooper /*
9943cedbec3SEnji Cooper * We are the child. We set a write lock and then
9953cedbec3SEnji Cooper * write one byte back to the parent to tell it. The
9963cedbec3SEnji Cooper * parent will kill us when its done.
9973cedbec3SEnji Cooper */
9983cedbec3SEnji Cooper if (fcntl(fd, F_SETLK, &fl) < 0)
9993cedbec3SEnji Cooper err(1, "F_SETLK (child)");
10003cedbec3SEnji Cooper if (write(pfd[1], "a", 1) < 0)
10013cedbec3SEnji Cooper err(1, "writing to pipe (child)");
10023cedbec3SEnji Cooper
10033cedbec3SEnji Cooper sleep(1);
10043cedbec3SEnji Cooper exit(0);
10053cedbec3SEnji Cooper }
10063cedbec3SEnji Cooper
10073cedbec3SEnji Cooper /*
10083cedbec3SEnji Cooper * Wait until the child has set its lock and then perform the
10093cedbec3SEnji Cooper * test.
10103cedbec3SEnji Cooper */
10113cedbec3SEnji Cooper if (read(pfd[0], &ch, 1) != 1)
10123cedbec3SEnji Cooper err(1, "reading from pipe (child)");
10133cedbec3SEnji Cooper
10143cedbec3SEnji Cooper /*
10153cedbec3SEnji Cooper * fcntl should wait until the alarm and then return -1 with
10163cedbec3SEnji Cooper * errno set to EINTR.
10173cedbec3SEnji Cooper */
10183cedbec3SEnji Cooper printf("12 - F_SETLKW on locked region which is then unlocked: ");
10193cedbec3SEnji Cooper
10203cedbec3SEnji Cooper //alarm(1);
10213cedbec3SEnji Cooper
10223cedbec3SEnji Cooper res = fcntl(fd, F_SETLKW, &fl);
10233cedbec3SEnji Cooper kill(pid, SIGTERM);
10243cedbec3SEnji Cooper safe_waitpid(pid);
10253cedbec3SEnji Cooper close(pfd[0]);
10263cedbec3SEnji Cooper close(pfd[1]);
10273cedbec3SEnji Cooper FAIL(res != 0);
10283cedbec3SEnji Cooper
10293cedbec3SEnji Cooper fl.l_start = 0;
10303cedbec3SEnji Cooper fl.l_len = 0;
10313cedbec3SEnji Cooper fl.l_type = F_UNLCK;
10323cedbec3SEnji Cooper if (fcntl(fd, F_SETLK, &fl) < 0)
10333cedbec3SEnji Cooper err(1, "F_UNLCK");
10343cedbec3SEnji Cooper
10353cedbec3SEnji Cooper SUCCEED;
10363cedbec3SEnji Cooper }
10373cedbec3SEnji Cooper
10383cedbec3SEnji Cooper /*
10393cedbec3SEnji Cooper * Test 13 - F_SETLKW on locked region, race with owner
10403cedbec3SEnji Cooper *
10413cedbec3SEnji Cooper * If a shared or exclusive lock is blocked by other locks, the
10423cedbec3SEnji Cooper * process waits until the request can be satisfied.
10433cedbec3SEnji Cooper */
10443cedbec3SEnji Cooper static int
test13(int fd,__unused int argc,const __unused char ** argv)10453cedbec3SEnji Cooper test13(int fd, __unused int argc, const __unused char **argv)
10463cedbec3SEnji Cooper {
10473cedbec3SEnji Cooper /*
10483cedbec3SEnji Cooper * We create a child process to hold the lock which we will
10493cedbec3SEnji Cooper * test. We use a pipe to communicate with the child.
10503cedbec3SEnji Cooper */
10513cedbec3SEnji Cooper int i;
10523cedbec3SEnji Cooper int pid;
10533cedbec3SEnji Cooper int pfd[2];
10543cedbec3SEnji Cooper struct flock fl;
10553cedbec3SEnji Cooper char ch;
10563cedbec3SEnji Cooper int res;
10573cedbec3SEnji Cooper struct itimerval itv;
10583cedbec3SEnji Cooper
10593cedbec3SEnji Cooper printf("13 - F_SETLKW on locked region, race with owner: ");
10603cedbec3SEnji Cooper fflush(stdout);
10613cedbec3SEnji Cooper
10623cedbec3SEnji Cooper for (i = 0; i < 100; i++) {
10633cedbec3SEnji Cooper if (pipe(pfd) < 0)
10643cedbec3SEnji Cooper err(1, "pipe");
10653cedbec3SEnji Cooper
10663cedbec3SEnji Cooper fl.l_start = 0;
10673cedbec3SEnji Cooper fl.l_len = 0;
10683cedbec3SEnji Cooper fl.l_type = F_WRLCK;
10693cedbec3SEnji Cooper fl.l_whence = SEEK_SET;
10703cedbec3SEnji Cooper
10713cedbec3SEnji Cooper pid = fork();
10723cedbec3SEnji Cooper if (pid < 0)
10733cedbec3SEnji Cooper err(1, "fork");
10743cedbec3SEnji Cooper
10753cedbec3SEnji Cooper if (pid == 0) {
10763cedbec3SEnji Cooper /*
10773cedbec3SEnji Cooper * We are the child. We set a write lock and then
10783cedbec3SEnji Cooper * write one byte back to the parent to tell it. The
10793cedbec3SEnji Cooper * parent will kill us when its done.
10803cedbec3SEnji Cooper */
10813cedbec3SEnji Cooper if (fcntl(fd, F_SETLK, &fl) < 0)
10823cedbec3SEnji Cooper err(1, "F_SETLK (child)");
10833cedbec3SEnji Cooper if (write(pfd[1], "a", 1) < 0)
10843cedbec3SEnji Cooper err(1, "writing to pipe (child)");
10853cedbec3SEnji Cooper
10863cedbec3SEnji Cooper usleep(1);
10873cedbec3SEnji Cooper exit(0);
10883cedbec3SEnji Cooper }
10893cedbec3SEnji Cooper
10903cedbec3SEnji Cooper /*
10913cedbec3SEnji Cooper * Wait until the child has set its lock and then perform the
10923cedbec3SEnji Cooper * test.
10933cedbec3SEnji Cooper */
10943cedbec3SEnji Cooper while (read(pfd[0], &ch, 1) != 1) {
10953cedbec3SEnji Cooper if (errno == EINTR)
10963cedbec3SEnji Cooper continue;
10973cedbec3SEnji Cooper err(1, "reading from pipe (child)");
10983cedbec3SEnji Cooper }
10993cedbec3SEnji Cooper
11003cedbec3SEnji Cooper /*
11013cedbec3SEnji Cooper * fcntl should wait until the alarm and then return -1 with
11023cedbec3SEnji Cooper * errno set to EINTR.
11033cedbec3SEnji Cooper */
11043cedbec3SEnji Cooper itv.it_interval.tv_sec = 0;
11053cedbec3SEnji Cooper itv.it_interval.tv_usec = 0;
11063cedbec3SEnji Cooper itv.it_value.tv_sec = 0;
11073cedbec3SEnji Cooper itv.it_value.tv_usec = 2;
11083cedbec3SEnji Cooper setitimer(ITIMER_REAL, &itv, NULL);
11093cedbec3SEnji Cooper
11103cedbec3SEnji Cooper res = fcntl(fd, F_SETLKW, &fl);
11113cedbec3SEnji Cooper kill(pid, SIGTERM);
11123cedbec3SEnji Cooper safe_waitpid(pid);
11133cedbec3SEnji Cooper close(pfd[0]);
11143cedbec3SEnji Cooper close(pfd[1]);
11153cedbec3SEnji Cooper FAIL(!(res == 0 || (res == -1 && errno == EINTR)));
11163cedbec3SEnji Cooper
11173cedbec3SEnji Cooper fl.l_start = 0;
11183cedbec3SEnji Cooper fl.l_len = 0;
11193cedbec3SEnji Cooper fl.l_type = F_UNLCK;
11203cedbec3SEnji Cooper if (fcntl(fd, F_SETLK, &fl) < 0)
11213cedbec3SEnji Cooper err(1, "F_UNLCK");
11223cedbec3SEnji Cooper }
11233cedbec3SEnji Cooper SUCCEED;
11243cedbec3SEnji Cooper }
11253cedbec3SEnji Cooper
11263cedbec3SEnji Cooper /*
11273cedbec3SEnji Cooper * Test 14 - soak test
11283cedbec3SEnji Cooper */
11293cedbec3SEnji Cooper static int
test14(int fd,int argc,const char ** argv)11303cedbec3SEnji Cooper test14(int fd, int argc, const char **argv)
11313cedbec3SEnji Cooper {
11323cedbec3SEnji Cooper #define CHILD_COUNT 20
11333cedbec3SEnji Cooper /*
11343cedbec3SEnji Cooper * We create a set of child processes and let each one run
11353cedbec3SEnji Cooper * through a random sequence of locks and unlocks.
11363cedbec3SEnji Cooper */
11373cedbec3SEnji Cooper int i, j, id, id_base;
11383cedbec3SEnji Cooper int pids[CHILD_COUNT], pid;
11393cedbec3SEnji Cooper char buf[128];
11403cedbec3SEnji Cooper char tbuf[128];
11413cedbec3SEnji Cooper int map[128];
11423cedbec3SEnji Cooper char outbuf[512];
11433cedbec3SEnji Cooper struct flock fl;
11443cedbec3SEnji Cooper struct itimerval itv;
11453cedbec3SEnji Cooper int status;
11463cedbec3SEnji Cooper
11473cedbec3SEnji Cooper id_base = 0;
11483cedbec3SEnji Cooper if (argc >= 2)
11493cedbec3SEnji Cooper id_base = strtol(argv[1], NULL, 0);
11503cedbec3SEnji Cooper
11513cedbec3SEnji Cooper printf("14 - soak test: ");
11523cedbec3SEnji Cooper fflush(stdout);
11533cedbec3SEnji Cooper
11543cedbec3SEnji Cooper for (i = 0; i < 128; i++)
11553cedbec3SEnji Cooper map[i] = F_UNLCK;
11563cedbec3SEnji Cooper
11573cedbec3SEnji Cooper for (i = 0; i < CHILD_COUNT; i++) {
11583cedbec3SEnji Cooper
11593cedbec3SEnji Cooper pid = fork();
11603cedbec3SEnji Cooper if (pid < 0)
11613cedbec3SEnji Cooper err(1, "fork");
11623cedbec3SEnji Cooper if (pid) {
11633cedbec3SEnji Cooper /*
11643cedbec3SEnji Cooper * Parent - record the pid and continue.
11653cedbec3SEnji Cooper */
11663cedbec3SEnji Cooper pids[i] = pid;
11673cedbec3SEnji Cooper continue;
11683cedbec3SEnji Cooper }
11693cedbec3SEnji Cooper
11703cedbec3SEnji Cooper /*
11713cedbec3SEnji Cooper * Child - do some work and exit.
11723cedbec3SEnji Cooper */
11733cedbec3SEnji Cooper id = id_base + i;
11743cedbec3SEnji Cooper srandom(getpid());
11753cedbec3SEnji Cooper
11763cedbec3SEnji Cooper for (j = 0; j < 50; j++) {
11773cedbec3SEnji Cooper int start, end, len;
11783cedbec3SEnji Cooper int set, wrlock;
11793cedbec3SEnji Cooper
11803cedbec3SEnji Cooper do {
11813cedbec3SEnji Cooper start = random() & 127;
11823cedbec3SEnji Cooper end = random() & 127;
11833cedbec3SEnji Cooper } while (end <= start);
11843cedbec3SEnji Cooper
11853cedbec3SEnji Cooper set = random() & 1;
11863cedbec3SEnji Cooper wrlock = random() & 1;
11873cedbec3SEnji Cooper
11883cedbec3SEnji Cooper len = end - start;
11893cedbec3SEnji Cooper fl.l_start = start;
11903cedbec3SEnji Cooper fl.l_len = len;
11913cedbec3SEnji Cooper fl.l_whence = SEEK_SET;
11923cedbec3SEnji Cooper if (set)
11933cedbec3SEnji Cooper fl.l_type = wrlock ? F_WRLCK : F_RDLCK;
11943cedbec3SEnji Cooper else
11953cedbec3SEnji Cooper fl.l_type = F_UNLCK;
11963cedbec3SEnji Cooper
11973cedbec3SEnji Cooper itv.it_interval.tv_sec = 0;
11983cedbec3SEnji Cooper itv.it_interval.tv_usec = 0;
11993cedbec3SEnji Cooper itv.it_value.tv_sec = 0;
12003cedbec3SEnji Cooper itv.it_value.tv_usec = 3000;
12013cedbec3SEnji Cooper setitimer(ITIMER_REAL, &itv, NULL);
12023cedbec3SEnji Cooper
12033cedbec3SEnji Cooper if (fcntl(fd, F_SETLKW, &fl) < 0) {
12043cedbec3SEnji Cooper if (errno == EDEADLK || errno == EINTR) {
12053cedbec3SEnji Cooper if (verbose) {
12063cedbec3SEnji Cooper snprintf(outbuf, sizeof(outbuf),
12073cedbec3SEnji Cooper "%d[%d]: %s [%d .. %d] %s\n",
12083cedbec3SEnji Cooper id, j,
12093cedbec3SEnji Cooper set ? (wrlock ? "write lock"
12103cedbec3SEnji Cooper : "read lock")
12113cedbec3SEnji Cooper : "unlock", start, end,
12123cedbec3SEnji Cooper errno == EDEADLK
12133cedbec3SEnji Cooper ? "deadlock"
12143cedbec3SEnji Cooper : "interrupted");
12153cedbec3SEnji Cooper write(1, outbuf,
12163cedbec3SEnji Cooper strlen(outbuf));
12173cedbec3SEnji Cooper }
12183cedbec3SEnji Cooper continue;
12193cedbec3SEnji Cooper } else {
12203cedbec3SEnji Cooper perror("fcntl");
12213cedbec3SEnji Cooper }
12223cedbec3SEnji Cooper }
12233cedbec3SEnji Cooper
12243cedbec3SEnji Cooper itv.it_interval.tv_sec = 0;
12253cedbec3SEnji Cooper itv.it_interval.tv_usec = 0;
12263cedbec3SEnji Cooper itv.it_value.tv_sec = 0;
12273cedbec3SEnji Cooper itv.it_value.tv_usec = 0;
12283cedbec3SEnji Cooper setitimer(ITIMER_REAL, &itv, NULL);
12293cedbec3SEnji Cooper
12303cedbec3SEnji Cooper if (verbose) {
12313cedbec3SEnji Cooper snprintf(outbuf, sizeof(outbuf),
12323cedbec3SEnji Cooper "%d[%d]: %s [%d .. %d] succeeded\n",
12333cedbec3SEnji Cooper id, j,
12343cedbec3SEnji Cooper set ? (wrlock ? "write lock" : "read lock")
12353cedbec3SEnji Cooper : "unlock", start, end);
12363cedbec3SEnji Cooper write(1, outbuf, strlen(outbuf));
12373cedbec3SEnji Cooper }
12383cedbec3SEnji Cooper
12393cedbec3SEnji Cooper if (set) {
12403cedbec3SEnji Cooper if (wrlock) {
12413cedbec3SEnji Cooper /*
12423cedbec3SEnji Cooper * We got a write lock - write
12433cedbec3SEnji Cooper * our ID to each byte that we
12443cedbec3SEnji Cooper * managed to claim.
12453cedbec3SEnji Cooper */
12463cedbec3SEnji Cooper for (i = start; i < end; i++)
12473cedbec3SEnji Cooper map[i] = F_WRLCK;
12483cedbec3SEnji Cooper memset(&buf[start], id, len);
12493cedbec3SEnji Cooper if (pwrite(fd, &buf[start], len,
12503cedbec3SEnji Cooper start) != len) {
12513cedbec3SEnji Cooper printf("%d: short write\n", id);
12523cedbec3SEnji Cooper exit(1);
12533cedbec3SEnji Cooper }
12543cedbec3SEnji Cooper } else {
12553cedbec3SEnji Cooper /*
12563cedbec3SEnji Cooper * We got a read lock - read
12573cedbec3SEnji Cooper * the bytes which we claimed
12583cedbec3SEnji Cooper * so that we can check that
12593cedbec3SEnji Cooper * they don't change
12603cedbec3SEnji Cooper * unexpectedly.
12613cedbec3SEnji Cooper */
12623cedbec3SEnji Cooper for (i = start; i < end; i++)
12633cedbec3SEnji Cooper map[i] = F_RDLCK;
12643cedbec3SEnji Cooper if (pread(fd, &buf[start], len,
12653cedbec3SEnji Cooper start) != len) {
12663cedbec3SEnji Cooper printf("%d: short read\n", id);
12673cedbec3SEnji Cooper exit(1);
12683cedbec3SEnji Cooper }
12693cedbec3SEnji Cooper }
12703cedbec3SEnji Cooper } else {
12713cedbec3SEnji Cooper for (i = start; i < end; i++)
12723cedbec3SEnji Cooper map[i] = F_UNLCK;
12733cedbec3SEnji Cooper }
12743cedbec3SEnji Cooper
12753cedbec3SEnji Cooper usleep(1000);
12763cedbec3SEnji Cooper
12773cedbec3SEnji Cooper /*
12783cedbec3SEnji Cooper * Read back the whole region so that we can
12793cedbec3SEnji Cooper * check that all the bytes we have some kind
12803cedbec3SEnji Cooper * of claim to have the correct value.
12813cedbec3SEnji Cooper */
12823cedbec3SEnji Cooper if (pread(fd, tbuf, sizeof(tbuf), 0) != sizeof(tbuf)) {
12833cedbec3SEnji Cooper printf("%d: short read\n", id);
12843cedbec3SEnji Cooper exit(1);
12853cedbec3SEnji Cooper }
12863cedbec3SEnji Cooper
12873cedbec3SEnji Cooper for (i = 0; i < 128; i++) {
12883cedbec3SEnji Cooper if (map[i] != F_UNLCK && buf[i] != tbuf[i]) {
12893cedbec3SEnji Cooper snprintf(outbuf, sizeof(outbuf),
12903cedbec3SEnji Cooper "%d: byte %d expected %d, "
12913cedbec3SEnji Cooper "got %d\n", id, i, buf[i], tbuf[i]);
12923cedbec3SEnji Cooper write(1, outbuf, strlen(outbuf));
12933cedbec3SEnji Cooper exit(1);
12943cedbec3SEnji Cooper }
12953cedbec3SEnji Cooper }
12963cedbec3SEnji Cooper }
12973cedbec3SEnji Cooper if (verbose)
12983cedbec3SEnji Cooper printf("%d[%d]: done\n", id, j);
12993cedbec3SEnji Cooper
13003cedbec3SEnji Cooper exit(0);
13013cedbec3SEnji Cooper }
13023cedbec3SEnji Cooper
13033cedbec3SEnji Cooper status = 0;
13043cedbec3SEnji Cooper for (i = 0; i < CHILD_COUNT; i++) {
13053cedbec3SEnji Cooper status += safe_waitpid(pids[i]);
13063cedbec3SEnji Cooper }
13073cedbec3SEnji Cooper if (status)
13083cedbec3SEnji Cooper FAIL(status != 0);
13093cedbec3SEnji Cooper
13103cedbec3SEnji Cooper SUCCEED;
13113cedbec3SEnji Cooper }
13123cedbec3SEnji Cooper
13133cedbec3SEnji Cooper /*
13143cedbec3SEnji Cooper * Test 15 - flock(2) semantcs
13153cedbec3SEnji Cooper *
13163cedbec3SEnji Cooper * When a lock holder has a shared lock and attempts to upgrade that
13173cedbec3SEnji Cooper * shared lock to exclusive, it must drop the shared lock before
13183cedbec3SEnji Cooper * blocking on the exclusive lock.
13193cedbec3SEnji Cooper *
13203cedbec3SEnji Cooper * To test this, we first arrange for two shared locks on the file,
13213cedbec3SEnji Cooper * and then attempt to upgrade one of them to exclusive. This should
13223cedbec3SEnji Cooper * drop one of the shared locks and block. We interrupt the blocking
13233cedbec3SEnji Cooper * lock request and examine the lock state of the file after dropping
13243cedbec3SEnji Cooper * the other shared lock - there should be no active locks at this
13253cedbec3SEnji Cooper * point.
13263cedbec3SEnji Cooper */
13273cedbec3SEnji Cooper static int
test15(int fd,__unused int argc,const __unused char ** argv)13283cedbec3SEnji Cooper test15(int fd, __unused int argc, const __unused char **argv)
13293cedbec3SEnji Cooper {
13303cedbec3SEnji Cooper #ifdef LOCK_EX
13313cedbec3SEnji Cooper /*
13323cedbec3SEnji Cooper * We create a child process to hold the lock which we will
13333cedbec3SEnji Cooper * test. We use a pipe to communicate with the child.
13343cedbec3SEnji Cooper *
13353cedbec3SEnji Cooper * Since we only have one file descriptors and lock ownership
13363cedbec3SEnji Cooper * for flock(2) goes with the file descriptor, we use fcntl to
13373cedbec3SEnji Cooper * set the child's shared lock.
13383cedbec3SEnji Cooper */
13393cedbec3SEnji Cooper int pid;
13403cedbec3SEnji Cooper int pfd[2];
13413cedbec3SEnji Cooper struct flock fl;
13423cedbec3SEnji Cooper char ch;
13433cedbec3SEnji Cooper int res;
13443cedbec3SEnji Cooper
13453cedbec3SEnji Cooper if (pipe(pfd) < 0)
13463cedbec3SEnji Cooper err(1, "pipe");
13473cedbec3SEnji Cooper
13483cedbec3SEnji Cooper pid = fork();
13493cedbec3SEnji Cooper if (pid < 0)
13503cedbec3SEnji Cooper err(1, "fork");
13513cedbec3SEnji Cooper
13523cedbec3SEnji Cooper if (pid == 0) {
13533cedbec3SEnji Cooper /*
13543cedbec3SEnji Cooper * We are the child. We set a shared lock and then
13553cedbec3SEnji Cooper * write one byte back to the parent to tell it. The
13563cedbec3SEnji Cooper * parent will kill us when its done.
13573cedbec3SEnji Cooper */
13583cedbec3SEnji Cooper fl.l_start = 0;
13593cedbec3SEnji Cooper fl.l_len = 0;
13603cedbec3SEnji Cooper fl.l_type = F_RDLCK;
13613cedbec3SEnji Cooper fl.l_whence = SEEK_SET;
13623cedbec3SEnji Cooper if (fcntl(fd, F_SETLK, &fl) < 0)
13633cedbec3SEnji Cooper err(1, "fcntl(F_SETLK) (child)");
13643cedbec3SEnji Cooper if (write(pfd[1], "a", 1) < 0)
13653cedbec3SEnji Cooper err(1, "writing to pipe (child)");
13663cedbec3SEnji Cooper pause();
13673cedbec3SEnji Cooper exit(0);
13683cedbec3SEnji Cooper }
13693cedbec3SEnji Cooper
13703cedbec3SEnji Cooper /*
13713cedbec3SEnji Cooper * Wait until the child has set its lock and then perform the
13723cedbec3SEnji Cooper * test.
13733cedbec3SEnji Cooper */
13743cedbec3SEnji Cooper if (read(pfd[0], &ch, 1) != 1)
13753cedbec3SEnji Cooper err(1, "reading from pipe (child)");
13763cedbec3SEnji Cooper
13773cedbec3SEnji Cooper (void)dup(fd);
13783cedbec3SEnji Cooper if (flock(fd, LOCK_SH) < 0)
13793cedbec3SEnji Cooper err(1, "flock shared");
13803cedbec3SEnji Cooper
13813cedbec3SEnji Cooper /*
13823cedbec3SEnji Cooper * flock should wait until the alarm and then return -1 with
13833cedbec3SEnji Cooper * errno set to EINTR.
13843cedbec3SEnji Cooper */
13853cedbec3SEnji Cooper printf("15 - flock(2) semantics: ");
13863cedbec3SEnji Cooper
13873cedbec3SEnji Cooper alarm(1);
13883cedbec3SEnji Cooper flock(fd, LOCK_EX);
13893cedbec3SEnji Cooper
13903cedbec3SEnji Cooper /*
13913cedbec3SEnji Cooper * Kill the child to force it to drop its locks.
13923cedbec3SEnji Cooper */
13933cedbec3SEnji Cooper kill(pid, SIGTERM);
13943cedbec3SEnji Cooper safe_waitpid(pid);
13953cedbec3SEnji Cooper
13963cedbec3SEnji Cooper fl.l_start = 0;
13973cedbec3SEnji Cooper fl.l_len = 0;
13983cedbec3SEnji Cooper fl.l_type = F_WRLCK;
13993cedbec3SEnji Cooper fl.l_whence = SEEK_SET;
14003cedbec3SEnji Cooper res = fcntl(fd, F_GETLK, &fl);
14013cedbec3SEnji Cooper
14023cedbec3SEnji Cooper close(pfd[0]);
14033cedbec3SEnji Cooper close(pfd[1]);
14043cedbec3SEnji Cooper FAIL(res != 0);
14053cedbec3SEnji Cooper FAIL(fl.l_type != F_UNLCK);
14063cedbec3SEnji Cooper
14073cedbec3SEnji Cooper SUCCEED;
14083cedbec3SEnji Cooper #else
14093cedbec3SEnji Cooper return 0;
14103cedbec3SEnji Cooper #endif
14113cedbec3SEnji Cooper }
14123cedbec3SEnji Cooper
14133cedbec3SEnji Cooper struct test_ctx {
14143cedbec3SEnji Cooper struct flock tc_fl;
14153cedbec3SEnji Cooper int tc_fd;
14163cedbec3SEnji Cooper };
14173cedbec3SEnji Cooper
14183cedbec3SEnji Cooper static void *
test16_func(void * tc_in)14193cedbec3SEnji Cooper test16_func(void *tc_in)
14203cedbec3SEnji Cooper {
14213cedbec3SEnji Cooper uintptr_t error;
14223cedbec3SEnji Cooper struct test_ctx *tc = tc_in;
14233cedbec3SEnji Cooper
14243cedbec3SEnji Cooper error = fcntl(tc->tc_fd, F_SETLKW, &tc->tc_fl);
14253cedbec3SEnji Cooper
14263cedbec3SEnji Cooper pthread_exit((void *)error);
14273cedbec3SEnji Cooper }
14283cedbec3SEnji Cooper
14293cedbec3SEnji Cooper #define THREADS 10
14303cedbec3SEnji Cooper
14313cedbec3SEnji Cooper /*
14323cedbec3SEnji Cooper * Test 16 - F_SETLKW from two threads
14333cedbec3SEnji Cooper *
14343cedbec3SEnji Cooper * If two threads within a process are blocked on a lock and the lock
14353cedbec3SEnji Cooper * is granted, make sure things are sane.
14363cedbec3SEnji Cooper */
14373cedbec3SEnji Cooper static int
test16(int fd,__unused int argc,const __unused char ** argv)14383cedbec3SEnji Cooper test16(int fd, __unused int argc, const __unused char **argv)
14393cedbec3SEnji Cooper {
14403cedbec3SEnji Cooper /*
14413cedbec3SEnji Cooper * We create a child process to hold the lock which we will
14423cedbec3SEnji Cooper * test. We use a pipe to communicate with the child.
14433cedbec3SEnji Cooper */
14443cedbec3SEnji Cooper int pid;
14453cedbec3SEnji Cooper int pfd[2];
14463cedbec3SEnji Cooper struct test_ctx tc = { .tc_fd = fd };
14473cedbec3SEnji Cooper char ch;
14483cedbec3SEnji Cooper int i;
14493cedbec3SEnji Cooper int error;
14503cedbec3SEnji Cooper pthread_t thr[THREADS];
14513cedbec3SEnji Cooper
14523cedbec3SEnji Cooper if (pipe(pfd) < 0)
14533cedbec3SEnji Cooper err(1, "pipe");
14543cedbec3SEnji Cooper
14553cedbec3SEnji Cooper tc.tc_fl.l_start = 0;
14563cedbec3SEnji Cooper tc.tc_fl.l_len = 0;
14573cedbec3SEnji Cooper tc.tc_fl.l_type = F_WRLCK;
14583cedbec3SEnji Cooper tc.tc_fl.l_whence = SEEK_SET;
14593cedbec3SEnji Cooper
14603cedbec3SEnji Cooper pid = fork();
14613cedbec3SEnji Cooper if (pid < 0)
14623cedbec3SEnji Cooper err(1, "fork");
14633cedbec3SEnji Cooper
14643cedbec3SEnji Cooper if (pid == 0) {
14653cedbec3SEnji Cooper /*
14663cedbec3SEnji Cooper * We are the child. We set a write lock and then
14673cedbec3SEnji Cooper * write one byte back to the parent to tell it. The
14683cedbec3SEnji Cooper * parent will kill us when its done.
14693cedbec3SEnji Cooper */
14703cedbec3SEnji Cooper if (fcntl(fd, F_SETLK, &tc.tc_fl) < 0)
14713cedbec3SEnji Cooper err(1, "F_SETLK (child)");
14723cedbec3SEnji Cooper if (write(pfd[1], "a", 1) < 0)
14733cedbec3SEnji Cooper err(1, "writing to pipe (child)");
14743cedbec3SEnji Cooper pause();
14753cedbec3SEnji Cooper exit(0);
14763cedbec3SEnji Cooper }
14773cedbec3SEnji Cooper
14783cedbec3SEnji Cooper /*
14793cedbec3SEnji Cooper * Wait until the child has set its lock and then perform the
14803cedbec3SEnji Cooper * test.
14813cedbec3SEnji Cooper */
14823cedbec3SEnji Cooper if (read(pfd[0], &ch, 1) != 1)
14833cedbec3SEnji Cooper err(1, "reading from pipe (child)");
14843cedbec3SEnji Cooper
14853cedbec3SEnji Cooper /*
14863cedbec3SEnji Cooper * fcntl should wait until the alarm and then return -1 with
14873cedbec3SEnji Cooper * errno set to EINTR.
14883cedbec3SEnji Cooper */
14893cedbec3SEnji Cooper printf("16 - F_SETLKW on locked region by two threads: ");
14903cedbec3SEnji Cooper
14913cedbec3SEnji Cooper for (i = 0; i < THREADS; i++) {
14923cedbec3SEnji Cooper error = pthread_create(&thr[i], NULL, test16_func, &tc);
14933cedbec3SEnji Cooper if (error)
14943cedbec3SEnji Cooper err(1, "pthread_create");
14953cedbec3SEnji Cooper }
14963cedbec3SEnji Cooper
14973cedbec3SEnji Cooper /*
14983cedbec3SEnji Cooper * Sleep, then kill the child. This makes me a little sad, but it's
14993cedbec3SEnji Cooper * tricky to tell whether the threads are all really blocked by this
15003cedbec3SEnji Cooper * point.
15013cedbec3SEnji Cooper */
15023cedbec3SEnji Cooper sleep(1);
15033cedbec3SEnji Cooper kill(pid, SIGTERM);
15043cedbec3SEnji Cooper safe_waitpid(pid);
15053cedbec3SEnji Cooper close(pfd[0]);
15063cedbec3SEnji Cooper close(pfd[1]);
15073cedbec3SEnji Cooper
15083cedbec3SEnji Cooper for (i = 0; i < THREADS; i++) {
15093cedbec3SEnji Cooper void *res;
15103cedbec3SEnji Cooper error = pthread_join(thr[i], &res);
15113cedbec3SEnji Cooper if (error)
15123cedbec3SEnji Cooper err(1, "pthread_join");
15133cedbec3SEnji Cooper FAIL((uintptr_t)res != 0);
15143cedbec3SEnji Cooper }
15153cedbec3SEnji Cooper
15163cedbec3SEnji Cooper SUCCEED;
15173cedbec3SEnji Cooper }
15183cedbec3SEnji Cooper
15193cedbec3SEnji Cooper struct test {
15203cedbec3SEnji Cooper int (*testfn)(int, int, const char **); /* function to perform the test */
15213cedbec3SEnji Cooper int num; /* test number */
15223cedbec3SEnji Cooper int intr; /* non-zero if the test interrupts a lock */
15233cedbec3SEnji Cooper };
15243cedbec3SEnji Cooper
15253cedbec3SEnji Cooper static struct test tests[] = {
15263cedbec3SEnji Cooper { test1, 1, 0 },
15273cedbec3SEnji Cooper { test2, 2, 0 },
15283cedbec3SEnji Cooper { test3, 3, 1 },
15293cedbec3SEnji Cooper { test4, 4, 0 },
15303cedbec3SEnji Cooper { test5, 5, 1 },
15313cedbec3SEnji Cooper { test6, 6, 1 },
15323cedbec3SEnji Cooper { test7, 7, 0 },
15333cedbec3SEnji Cooper { test8, 8, 0 },
15343cedbec3SEnji Cooper { test9, 9, 0 },
15353cedbec3SEnji Cooper { test10, 10, 0 },
15363cedbec3SEnji Cooper { test11, 11, 1 },
15373cedbec3SEnji Cooper { test12, 12, 0 },
15383cedbec3SEnji Cooper { test13, 13, 1 },
15393cedbec3SEnji Cooper { test14, 14, 0 },
15403cedbec3SEnji Cooper { test15, 15, 1 },
15413cedbec3SEnji Cooper { test16, 16, 1 },
15423cedbec3SEnji Cooper };
15433cedbec3SEnji Cooper
15443cedbec3SEnji Cooper int
main(int argc,const char * argv[])15453cedbec3SEnji Cooper main(int argc, const char *argv[])
15463cedbec3SEnji Cooper {
15473cedbec3SEnji Cooper int testnum;
15483cedbec3SEnji Cooper int fd;
15493cedbec3SEnji Cooper int nointr;
15503cedbec3SEnji Cooper unsigned i;
15513cedbec3SEnji Cooper struct sigaction sa;
15523cedbec3SEnji Cooper int test_argc;
15533cedbec3SEnji Cooper const char **test_argv;
15543cedbec3SEnji Cooper
15553cedbec3SEnji Cooper if (argc < 2) {
15563cedbec3SEnji Cooper errx(1, "usage: flock <directory> [test number] ...");
15573cedbec3SEnji Cooper }
15583cedbec3SEnji Cooper
15593cedbec3SEnji Cooper fd = make_file(argv[1], 1024);
15603cedbec3SEnji Cooper if (argc >= 3) {
15613cedbec3SEnji Cooper testnum = strtol(argv[2], NULL, 0);
15623cedbec3SEnji Cooper test_argc = argc - 2;
15633cedbec3SEnji Cooper test_argv = argv + 2;
15643cedbec3SEnji Cooper } else {
15653cedbec3SEnji Cooper testnum = 0;
15663cedbec3SEnji Cooper test_argc = 0;
1567*abea2d5aSEnji Cooper test_argv = NULL;
15683cedbec3SEnji Cooper }
15693cedbec3SEnji Cooper
15703cedbec3SEnji Cooper sa.sa_handler = ignore_alarm;
15713cedbec3SEnji Cooper sigemptyset(&sa.sa_mask);
15723cedbec3SEnji Cooper sa.sa_flags = 0;
15733cedbec3SEnji Cooper sigaction(SIGALRM, &sa, 0);
15743cedbec3SEnji Cooper
15753cedbec3SEnji Cooper nointr = 0;
15763cedbec3SEnji Cooper #if defined(__FreeBSD__) && __FreeBSD_version < 800040
15773cedbec3SEnji Cooper {
15783cedbec3SEnji Cooper /*
15793cedbec3SEnji Cooper * FreeBSD with userland NLM can't interrupt a blocked
15803cedbec3SEnji Cooper * lock request on an NFS mounted filesystem.
15813cedbec3SEnji Cooper */
15823cedbec3SEnji Cooper struct statfs st;
15833cedbec3SEnji Cooper fstatfs(fd, &st);
15843cedbec3SEnji Cooper nointr = !strcmp(st.f_fstypename, "nfs");
15853cedbec3SEnji Cooper }
15863cedbec3SEnji Cooper #endif
15873cedbec3SEnji Cooper
15883cedbec3SEnji Cooper for (i = 0; i < nitems(tests); i++) {
15893cedbec3SEnji Cooper if (tests[i].intr && nointr)
15903cedbec3SEnji Cooper continue;
15913cedbec3SEnji Cooper if (!testnum || tests[i].num == testnum)
15923cedbec3SEnji Cooper tests[i].testfn(fd, test_argc, test_argv);
15933cedbec3SEnji Cooper }
15943cedbec3SEnji Cooper
15953cedbec3SEnji Cooper return 0;
15963cedbec3SEnji Cooper }
1597