generic: add OFD lock tests
authorXiong Zhou <xzhou@redhat.com>
Tue, 13 Feb 2018 14:10:26 +0000 (22:10 +0800)
committerEryu Guan <eguan@redhat.com>
Thu, 15 Feb 2018 17:28:32 +0000 (01:28 +0800)
Test OFD locks. Use fcntl F_OFD_SETLK/F_OFD_GETLK, to verify we are
being given correct advices through getlk by kernel.

The basic idea is one setlk routine setting locks via fcntl *_SETLK,
followed by operations like clone, dup then close fd; another
routine getlk getting locks via fcntl *_GETLK.

Firstly in setlk routine process P0, place a lock L0 on an opened
testfile, then do clone or dup and close relative fd.

In getlk process P2, do fcntl *_GETLK with lock L1 after get
notified by setlk routine.

In the end, getlk routine check the returned struct flock.l_type to
see if the lock mechanism works fine.

Test combainations of:
- shared or exclusive lock
- these locks are conflicting or not
- one OFD lock and one POSIX lock
- that open testfile RDONLY or RDWR
- clone with CLONE_FILES or not
- dup and close newfd

[eguan: made some minor non-functional changes]

Signed-off-by: Xiong Zhou <xzhou@redhat.com>
Reviewed-by: Eryu Guan <eguan@redhat.com>
Signed-off-by: Eryu Guan <eguan@redhat.com>
.gitignore
common/rc
src/Makefile
src/t_ofd_locks.c [new file with mode: 0644]
tests/generic/478 [new file with mode: 0755]
tests/generic/478.out [new file with mode: 0644]
tests/generic/group

index ee7eaed02f932bf89280b06a5b9316f9100973fd..368d11c84a663bba9d70dbc961b01a7d37c35ef0 100644 (file)
 /src/t_mmap_write_ro
 /src/t_mmap_writev
 /src/t_mtab
+/src/t_ofd_locks
 /src/t_readdir_1
 /src/t_readdir_2
 /src/t_rename_overwrite
index 4ad59b1da92bfdd25b5e2d52580dc1c529838091..a6caca96c888dfb17b8422de2b59dd2d95c29cd2 100644 (file)
--- a/common/rc
+++ b/common/rc
@@ -3308,6 +3308,17 @@ _require_test_fcntl_advisory_locks()
                _notrun "Require fcntl advisory locks support"
 }
 
+_require_ofd_locks()
+{
+       # Give a test run by getlk wrlck on testfile.
+       # If the running kernel does not support OFD locks,
+       # EINVAL will be returned.
+       _require_test_program "t_ofd_locks"
+       touch $TEST_DIR/ofd_testfile
+       src/t_ofd_locks -t $TEST_DIR/ofd_testfile > /dev/null 2>&1
+       [ $? -eq 22 ] && _notrun "Require OFD locks support"
+}
+
 _require_test_lsattr()
 {
        testio=$(lsattr -d $TEST_DIR 2>&1)
index b96b8cf255629d1d65a69e8ce30f09026f95a189..0d3feae1eeb2d0c29d40a100d0257f78ac60d260 100644 (file)
@@ -14,7 +14,8 @@ TARGETS = dirstress fill fill2 getpagesize holes lstat64 \
        t_mmap_writev t_truncate_cmtime dirhash_collide t_rename_overwrite \
        holetest t_truncate_self t_mmap_dio af_unix t_mmap_stale_pmd \
        t_mmap_cow_race t_mmap_fallocate fsync-err t_mmap_write_ro \
-       t_ext4_dax_journal_corruption t_ext4_dax_inline_corruption
+       t_ext4_dax_journal_corruption t_ext4_dax_inline_corruption \
+       t_ofd_locks
 
 LINUX_TARGETS = xfsctl bstat t_mtab getdevicesize preallo_rw_pattern_reader \
        preallo_rw_pattern_writer ftrunc trunc fs_perms testx looptest \
diff --git a/src/t_ofd_locks.c b/src/t_ofd_locks.c
new file mode 100644 (file)
index 0000000..d578cd7
--- /dev/null
@@ -0,0 +1,444 @@
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sched.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/ipc.h>
+#include <sys/sem.h>
+
+/*
+ * In distributions that do not have these macros ready in glibc-headers,
+ * compilation fails. Adding them here to avoid build errors, relevant tests
+ * would fail at the helper which requires OFD locks support and notrun if the
+ * kernel does not support OFD locks. If the kernel does support OFD locks, we
+ * are good to go.
+ */
+#ifndef F_OFD_GETLK
+#define F_OFD_GETLK    36
+#endif
+
+#ifndef F_OFD_SETLK
+#define F_OFD_SETLK    37
+#endif
+
+#ifndef F_OFD_SETLKW
+#define F_OFD_SETLKW   38
+#endif
+
+/*
+ * Usually we run getlk routine after running setlk routine
+ * in background. However, getlk could be executed before setlk
+ * sometimes, which is invalid for our tests. So we use semaphore
+ * to synchronize between getlk and setlk.
+ *
+ * setlk routine:                               * getlk routine:
+ *                                              *
+ *   start                                      *   start
+ *     |                                        *     |
+ *  open file                                   *  open file
+ *     |                                        *     |
+ *  init sem                                    *     |
+ *     |                                        *     |
+ * wait init sem done                           * wait init sem done
+ *     |                                        *     |
+ *   setlk                                      *     |
+ *     |                                        *     |
+ *     |------------clone()--------|            *     |
+ *     |                           |            *     |
+ *     |(parent)            (child)|            *     |
+ *     |                           |            *     |
+ *     |                      close fd          *     |
+ *     |                           |            *     |
+ *     |                     set sem0=0          * wait sem0==0
+ *     |                           |            *     |
+ *     |                           |            *   getlk
+ *     |                           |            *     |
+ *  wait sem1==0                   |            *  set sem1=0
+ *     |                           |            *     |
+ *   wait child                    |            *     |
+ *     |                           |            *  check result
+ *     |                           |            *     |
+ *    exit                       exit           *    exit
+ */
+
+static int fd;
+static int semid;
+
+/* This is required by semctl to set semaphore value */
+union semun {
+       int              val;    /* Value for SETVAL */
+       struct semid_ds *buf;    /* Buffer for IPC_STAT, IPC_SET */
+       unsigned short  *array;  /* Array for GETALL, SETALL */
+       struct seminfo  *__buf;  /* Buffer for IPC_INFO
+                                   (Linux-specific) */
+};
+
+static void err_exit(char *op, int errn)
+{
+       fprintf(stderr, "%s: %s\n", op, strerror(errn));
+       if (fd > 0)
+               close(fd);
+       if (semid > 0 && semctl(semid, 2, IPC_RMID) == -1)
+               perror("exit rmid");
+       exit(errn);
+}
+
+/*
+ * Flags that used to specify operation details.
+ * They can be specified via command line options.
+ *
+ * option: -P
+ * posix : 1 <--> test posix lock
+ *        0 <--> test OFD lock (default)
+ *
+ * option: -s/-g
+ * lock_cmd : 1 <--> setlk (default)
+ *           0 <--> getlk
+ *
+ * option: -r/-w
+ * lock_rw : 1 <--> set/get wrlck (default)
+ *          0 <--> set/get rdlck
+ *
+ * option: -o num
+ * lock_start : l_start to getlk
+ *
+ * option: -F
+ * clone_fs : clone with CLONE_FILES
+ *
+ * option: -d
+ * use_dup : dup and close to setup condition in setlk
+ *
+ * option: -R/-W
+ * open_rw : 1 <--> open file RDWR (default)
+ *          0 <--> open file RDONLY
+ *
+ * This option is for _require_ofd_locks helper, just do
+ * fcntl setlk then return errno.
+ * option: -t
+ * testrun : 1 <--> this is a testrun, return after setlk
+ *          0 <--> this is not a testrun, run as usual
+ */
+
+static void usage(char *arg0)
+{
+       printf("Usage: %s [-sgrwo:l:RWPtFd] filename\n", arg0);
+       printf("\t-s/-g : to setlk or to getlk\n");
+       printf("\t-P : POSIX locks\n");
+       printf("\t-F : clone with CLONE_FILES in setlk to setup test condition\n");
+       printf("\t-d : dup and close in setlk\n");
+       printf("\twithout both -F/d, use clone without CLONE_FILES\n");
+       printf("\t-r/-w : set/get rdlck/wrlck\n");
+       printf("\t-o num : offset start to lock, default 0\n");
+       printf("\t-l num : lock length, default 10\n");
+       printf("\t-R/-W : open file RDONLY/RDWR\n\n");
+       printf("\tUsually we run a setlk routine in background and then\n");
+       printf("\trun a getlk routine to check. They must be paired, or\n");
+       printf("\ttest will hang.\n\n");
+       exit(0);
+}
+
+#define STACK_SIZE (1024 * 1024)
+static char child_stack[STACK_SIZE] __attribute__((aligned));
+
+static int child_fn(void* p)
+{
+       union semun semu;
+       int cfd = *(int *)p;
+
+       /* close relative fd */
+       if (cfd > 0 && close(cfd) == -1)
+               perror("close in child");
+
+       /* set sem0 = 0 (setlk and close fd done) */
+       semu.val = 0;
+       if (semctl(semid, 0, SETVAL, semu) == -1)
+               err_exit("set sem0 0", errno);
+
+       return 0;
+}
+
+int main(int argc, char **argv)
+{
+       int posix = 0;
+       int lock_cmd = 1;
+       int lock_rw = 1;
+       int lock_start = 0;
+       int lock_l = 10;
+       int open_rw = 1;
+       int clone_fs = 0;
+       int use_dup = 0;
+       int testrun = 0;
+       int setlk_macro = F_OFD_SETLKW;
+       int getlk_macro = F_OFD_GETLK;
+       struct timespec ts;
+       key_t semkey;
+       unsigned short vals[2];
+       union semun semu;
+       struct semid_ds sem_ds;
+       struct sembuf sop;
+       int opt, ret, retry;
+
+       while((opt = getopt(argc, argv, "sgrwo:l:PRWtFd")) != -1) {
+               switch(opt) {
+               case 's':
+                       lock_cmd = 1;
+                       break;
+               case 'g':
+                       lock_cmd = 0;
+                       break;
+               case 'r':
+                       lock_rw = 0;
+                       break;
+               case 'w':
+                       lock_rw = 1;
+                       break;
+               case 'o':
+                       lock_start = atoi(optarg);
+                       break;
+               case 'l':
+                       lock_l = atoi(optarg);
+                       break;
+               case 'P':
+                       posix = 1;
+                       break;
+               case 'R':
+                       open_rw = 0;
+                       break;
+               case 'W':
+                       open_rw = 1;
+                       break;
+               case 't':
+                       testrun = 1;
+                       break;
+               case 'F':
+                       clone_fs = 1;
+                       break;
+               case 'd':
+                       use_dup = 1;
+                       break;
+               default:
+                       usage(argv[0]);
+                       return -1;
+               }
+       }
+
+       if (optind >= argc) {
+               usage(argv[0]);
+               return -1;
+       }
+
+       struct flock flk = {
+               .l_whence = SEEK_SET,
+               .l_start = lock_start,
+               .l_len = lock_l,
+               .l_type = F_RDLCK,
+       };
+
+       if (posix == 0) {
+               /* OFD lock requires l_pid to be zero */
+               flk.l_pid = 0;
+               setlk_macro = F_OFD_SETLKW;
+               getlk_macro = F_OFD_GETLK;
+       } else {
+               setlk_macro = F_SETLKW;
+               getlk_macro = F_GETLK;
+       }
+
+       if (lock_rw == 1)
+               flk.l_type = F_WRLCK;
+       else
+               flk.l_type = F_RDLCK;
+
+       if (open_rw == 0)
+               fd = open(argv[optind], O_RDONLY);
+       else
+               fd = open(argv[optind], O_RDWR);
+       if (fd == -1)
+               err_exit("open", errno);
+
+       /*
+        * In a testun, we do a fcntl getlk call and exit
+        * immediately no matter it succeeds or not.
+        */
+       if (testrun == 1) {
+               fcntl(fd, F_OFD_GETLK, &flk);
+               err_exit("test_ofd_getlk", errno);
+       }
+
+       if((semkey = ftok(argv[optind], 255)) == -1)
+               err_exit("ftok", errno);
+
+       /* setlk, and always init the semaphore at setlk time */
+       if (lock_cmd == 1) {
+               /*
+                * Init the semaphore, with a key related to the testfile.
+                * getlk routine will wait untill this sem has been created and
+                * iniialized.
+                *
+                * We must make sure the semaphore set is newly created, rather
+                * then the one left from last run. In which case getlk will
+                * exit immediately and left setlk routine waiting forever.
+                * Also because newly created semaphore has zero sem_otime,
+                * which is used here to sync with getlk routine.
+                */
+               retry = 0;
+               do {
+                       semid = semget(semkey, 2, IPC_CREAT|IPC_EXCL);
+                       if (semid < 0 && errno == EEXIST) {
+                               /* remove sem set after one round of test */
+                               if (semctl(semid, 2, IPC_RMID, semu) == -1)
+                                       err_exit("rmid 0", errno);
+                               retry++;
+                       } else if (semid < 0)
+                               err_exit("semget", errno);
+                       else
+                               retry = 10;
+               } while (retry < 5);
+               /* We can't create a new semaphore set in 5 tries */
+               if (retry == 5)
+                       err_exit("semget", errno);
+
+               /* Init both new sem to 1 */
+               vals[0] = 1;
+               vals[1] = 1;
+               semu.array = vals;
+               if (semctl(semid, 2, SETALL, semu) == -1)
+                       err_exit("init sem", errno);
+               /* Inc both new sem to 2 */
+               sop.sem_num = 0;
+               sop.sem_op = 1;
+               sop.sem_flg = 0;
+               ts.tv_sec = 15;
+               ts.tv_nsec = 0;
+               if (semtimedop(semid, &sop, 1, &ts) == -1)
+                       err_exit("inc sem0 2", errno);
+               sop.sem_num = 1;
+               sop.sem_op = 1;
+               sop.sem_flg = 0;
+               ts.tv_sec = 15;
+               ts.tv_nsec = 0;
+               if (semtimedop(semid, &sop, 1, &ts) == -1)
+                       err_exit("inc sem1 2", errno);
+
+               /*
+                * Wait initialization complete. semctl(2) only update
+                * sem_ctime, semop(2) will update sem_otime.
+                */
+               ret = -1;
+               do {
+                       memset(&sem_ds, 0, sizeof(sem_ds));
+                       semu.buf = &sem_ds;
+                       ret = semctl(semid, 0, IPC_STAT, semu);
+               } while (!(ret == 0 && sem_ds.sem_otime != 0));
+
+               /* place the lock */
+               if (fcntl(fd, setlk_macro, &flk) < 0)
+                       err_exit("setlkw", errno);
+
+               if (use_dup == 1) {
+                       /* dup fd and close the newfd */
+                       int dfd = dup(fd);
+                       if (dfd == -1)
+                               err_exit("dup", errno);
+                       close(dfd);
+                       /* set sem0 = 0 (setlk and close fd done) */
+                       semu.val = 0;
+                       if (semctl(semid, 0, SETVAL, semu) == -1)
+                               err_exit("set sem0 0", errno);
+               } else {
+                       /*
+                        * clone a child to close the fd then tell getlk to go;
+                        * in parent we keep holding the lock till getlk done.
+                        */
+                       pid_t child_pid = 0;
+                       if (clone_fs)
+                               child_pid = clone(child_fn, child_stack+STACK_SIZE,
+                                       CLONE_FILES|CLONE_SYSVSEM|SIGCHLD, &fd);
+                       else
+                               child_pid = clone(child_fn, child_stack+STACK_SIZE,
+                                       CLONE_SYSVSEM|SIGCHLD, &fd);
+                       if (child_pid == -1)
+                               err_exit("clone", errno);
+                       /* wait child done */
+                       waitpid(child_pid, NULL, 0);
+               }
+
+               /* "hold" lock and wait sem1 == 0 (getlk done) */
+               sop.sem_num = 1;
+               sop.sem_op = 0;
+               sop.sem_flg = 0;
+               ts.tv_sec = 15;
+               ts.tv_nsec = 0;
+               if (semtimedop(semid, &sop, 1, &ts) == -1)
+                       err_exit("wait sem1 0", errno);
+
+               /* remove sem set after one round of test */
+               if (semctl(semid, 2, IPC_RMID, semu) == -1)
+                       err_exit("rmid", errno);
+               close(fd);
+               exit(0);
+       }
+
+       /* getlck */
+       if (lock_cmd == 0) {
+               /* wait sem created and initialized */
+               do {
+                       semid = semget(semkey, 2, 0);
+                       if (semid != -1)
+                               break;
+                       if (errno == ENOENT)
+                               continue;
+                       else
+                               err_exit("getlk_semget", errno);
+               } while (1);
+               do {
+                       memset(&sem_ds, 0, sizeof(sem_ds));
+                       semu.buf = &sem_ds;
+                       ret = semctl(semid, 0, IPC_STAT, semu);
+               } while (!(ret == 0 && sem_ds.sem_otime != 0));
+
+               /* wait sem0 == 0 (setlk and close fd done) */
+               sop.sem_num = 0;
+               sop.sem_op = 0;
+               sop.sem_flg = 0;
+               ts.tv_sec = 15;
+               ts.tv_nsec = 0;
+               if (semtimedop(semid, &sop, 1, &ts) == -1)
+                       err_exit("wait sem0 0", errno);
+
+               if (fcntl(fd, getlk_macro, &flk) < 0)
+                       err_exit("getlk", errno);
+
+               /* set sem1 = 0 (getlk done) */
+               semu.val = 0;
+               if (semctl(semid, 1, SETVAL, semu) == -1)
+                       err_exit("set sem1 0", errno);
+
+               /* check result */
+               switch (flk.l_type) {
+               case F_UNLCK:
+                       printf("lock could be placed\n");
+                       break;
+               case F_RDLCK:
+                       printf("get rdlck\n");
+                       break;
+               case F_WRLCK:
+                       printf("get wrlck\n");
+                       break;
+               default:
+                       printf("unknown lock type\n");
+                       break;
+               }
+               close(fd);
+       }
+       return 0;
+}
diff --git a/tests/generic/478 b/tests/generic/478
new file mode 100755 (executable)
index 0000000..6d5da8d
--- /dev/null
@@ -0,0 +1,250 @@
+#! /bin/bash
+# FS QA Test 478
+#
+# Test OFD lock. fcntl F_OFD_SETLK to set lock, then F_OFD_GETLK
+# to verify we are being given correct advice by kernel.
+#
+# OFD lock combines POSIX lock and BSD flock:
+#   + does not share between threads
+#   + byte granularity
+#            (both tested by LTP/fcntl3{4,6})
+#   + only release automatically after all open fd closed
+#
+# This test target the third one and expand a little bit.
+#
+# The basic idea is one setlk routine setting locks via fcntl
+# *_SETLK, followed by operations like clone, dup then close fd;
+# another routine getlk getting locks via fcntl *_GETLK.
+#
+# Firstly in setlk routine process P0, place a lock L0 on an
+# opened testfile, then
+#
+#   + clone() a child P1 to close the fd then tell getlk to go,
+#     parent P0 wait getlk done then close fd.
+# or
+#   + dup() fd to a newfd then close newfd then tell getlk to go,
+#     then wait getlk done then close fd.
+#
+# In getlk process P2, do fcntl *_GETLK with lock L1 after get
+# notified by setlk routine.
+#
+# In the end, getlk routine check the returned struct flock.l_type
+# to see if the lock mechanism works fine.
+#
+# When testing with clone,
+#    + CLONE_FILES set, close releases all locks;
+#    + CLONE_FILES not set, locks remain in P0;
+#
+# If L0 is a POSIX lock,
+#   + it is not inherited into P1
+#   + it is released after dup & close
+#
+# If L0 is a OFD lock,
+#   + it is inherited into P1
+#   + it is not released after dup & close
+#
+#  setlk routine:                       * getlk routine:
+#    start                              *   start
+#      |                                *     |
+#   open file                           *  open file
+#      |                                *     |
+#   init sem                            *     |
+#      |                                *     |
+#  wait init sem done                   * wait init sem done
+#      |                                *     |
+#    setlk L0                            *     |
+#      |                                *     |
+#      |---------clone()--------|       *     |
+#      |                        |       *     |
+#      |(child P1)   (parent P0)|       *     | (P2)
+#      |                        |       *     |
+#      |                   close fd     *     |
+#      |                        |       *     |
+#      |                 set sem0=0     *  wait sem0==0
+#      |                        |       *     |
+#      |                        |       *   getlk L1
+#      |                        |       *     |
+#   wait sem1==0                |       *  set sem1=0
+#      |                        |       *     |
+#     exit                wait child    *     |
+#                               |       *  check result
+#                           cleanup     *     |
+#                               |       *     |
+#                             exit      *    exit
+#
+# We can test combainations of:
+#      + shared or exclusive lock
+#      + these locks are conflicting or not
+#      + one OFD lock and one POSIX lock
+#      + that open testfile RDONLY or RDWR
+#      + clone with CLONE_FILES or not
+#      + dup and close newfd
+#
+#-----------------------------------------------------------------------
+# Copyright (c) 2018 Red Hat Inc.  All Rights Reserved.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it would be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write the Free Software Foundation,
+# Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+#-----------------------------------------------------------------------
+#
+
+seq=`basename $0`
+seqres=$RESULT_DIR/$seq
+echo "QA output created by $seq"
+
+here=`pwd`
+tmp=/tmp/$$
+status=1       # failure is the default!
+trap "_cleanup; exit \$status" 0 1 2 3 15
+
+_cleanup()
+{
+       cd /
+       rm -f $tmp.*
+}
+
+# get standard environment, filters and checks
+. ./common/rc
+. ./common/filter
+
+# remove previous $seqres.full before test
+rm -f $seqres.full
+
+# Modify as appropriate.
+_supported_fs generic
+_supported_os Linux
+_require_test
+_require_ofd_locks
+
+# real QA test starts here
+# prepare a 4k testfile in TEST_DIR
+$XFS_IO_PROG -f -c "pwrite -S 0xFF 0 4096" \
+       $TEST_DIR/testfile >> $seqres.full 2>&1
+
+do_test()
+{
+       local soptions="$1"
+       local goptions="$2"
+       # print options and getlk output for debug
+       echo $* >> $seqres.full 2>&1
+       # -s : do setlk
+       $here/src/t_ofd_locks $soptions $TEST_DIR/testfile &
+       # -g : do getlk
+       $here/src/t_ofd_locks $goptions $TEST_DIR/testfile | \
+               tee -a $seqres.full
+       wait $!
+
+       # add -F to clone with CLONE_FILES
+       soptions="$1 -F"
+       # with -F, new locks are always file to place
+       $here/src/t_ofd_locks $soptions $TEST_DIR/testfile &
+       $here/src/t_ofd_locks $goptions $TEST_DIR/testfile | \
+               tee -a $seqres.full
+       wait $!
+
+       # add -d to dup and close
+       soptions="$1 -d"
+       $here/src/t_ofd_locks $soptions $TEST_DIR/testfile &
+       $here/src/t_ofd_locks $goptions $TEST_DIR/testfile | \
+               tee -a $seqres.full
+       wait $!
+}
+
+# Always setlk at range [0,9], getlk at range [0,9] [5,24] or [20,29].
+# To open file RDONLY or RDWR should not break the locks.
+# POSIX locks should be released after closed fd, so it wont conflict
+# with other locks in tests
+
+# -P : operate posix lock
+# -w : operate on F_WRLCK
+# -r : operate on F_RDLCK
+# -R : open file RDONLY
+# -W : open file RDWR
+# -o : file offset where the lock starts
+# -l : lock length
+# -F : clone with CLONE_FILES in setlk
+# -d : dup and close in setlk
+
+# setlk wrlck [0,9], getlk wrlck [0,9], expect
+#    + wrlck when CLONE_FILES not set
+#    + unlck when CLONE_FILES set
+#    + wrlck when dup & close
+do_test "-s -w -o 0 -l 10 -W" "-g -w -o 0 -l 10 -W" "wrlck" "unlck" "wrlck"
+# setlk wrlck [0,9], getlk posix wrlck [5,24]
+do_test "-s -w -o 0 -l 10 -W" "-g -w -o 5 -l 20 -W -P" "wrlck" "unlck" "wrlck"
+# setlk wrlck [0,9], getlk wrlck [20,29]
+do_test "-s -w -o 0 -l 10 -W" "-g -w -o 20 -l 10 -W" "unlck" "unlck" "unlck"
+# setlk posix wrlck [0,9], getlk wrlck [5,24]
+do_test "-s -w -o 0 -l 10 -W -P" "-g -w -o 5 -l 20 -W" "wrlck" "unlck" "unlck"
+# setlk posix wrlck [0,9], getlk wrlck [20,29]
+do_test "-s -w -o 0 -l 10 -W -P" "-g -w -o 20 -l 10 -W" "unlck" "unlck" "unlck"
+
+# setlk wrlck [0,9], getlk rdlck [0,9]
+do_test "-s -w -o 0 -l 10 -W" "-g -r -o 0 -l 10 -W" "wrlck" "unlck" "wrlck"
+# setlk wrlck [0,9], getlk posix rdlck [5,24]
+do_test "-s -w -o 0 -l 10" "-g -r -o 5 -l 20 -P" "wrlck" "unlck" "wrlck"
+# setlk wrlck [0,9], getlk rdlck [20,29]
+do_test "-s -w -o 0 -l 10" "-g -r -o 20 -l 10" "unlck" "unlck" "unlck"
+# setlk posix wrlck [0,9], getlk rdlck [5,24]
+do_test "-s -w -o 0 -l 10 -P" "-g -r -o 5 -l 20" "wrlck" "unlck" "unlck"
+# setlk posix wrlck [0,9], getlk rdlck [20,29]
+do_test "-s -w -o 0 -l 10 -P" "-g -r -o 20 -l 10" "unlck" "unlck" "unlck"
+
+# setlk rdlck [0,9], getlk wrlck [0,9], open RDONLY
+do_test "-s -r -o 0 -l 10 -R" "-g -w -o 0 -l 10 -R" "rdlck" "unlck" "rdlck"
+# setlk rdlck [0,9], getlk wrlck [5,24], open RDONLY
+do_test "-s -r -o 0 -l 10 -R" "-g -w -o 5 -l 20 -R -P" "rdlck" "unlck" "rdlck"
+# setlk posix rdlck [0,9], getlk wrlck [5,24], open RDONLY
+do_test "-s -r -o 0 -l 10 -R -P" "-g -w -o 5 -l 20 -R" "rdlck" "unlck" "unlck"
+
+# setlk rdlck [0,9], getlk wrlck [0,9]
+do_test "-s -r -o 0 -l 10" "-g -w -o 0 -l 10" "rdlck" "unlck" "rdlck"
+# setlk rdlck [0,9], getlk posix wrlck [5,24]
+do_test "-s -r -o 0 -l 10" "-g -w -o 5 -l 20 -P" "rdlck" "unlck" "rdlck"
+# setlk posix rdlck [0,9], getlk wrlck [5,24]
+do_test "-s -r -o 0 -l 10 -P" "-g -w -o 5 -l 20" "rdlck" "unlck" "unlck"
+
+# setlk rdlck [0,9], getlk wrlck [20,29], open RDONLY
+do_test "-s -r -o 0 -l 10 -R" "-g -w -o 20 -l 10 -R" "unlck" "unlck" "unlck"
+# setlk posix rdlck [0,9], getlk wrlck [20,29], open RDONLY
+do_test "-s -r -o 0 -l 10 -R -P" "-g -w -o 20 -l 10 -R" "unlck" "unlck" "unlck"
+# setlk rdlck [0,9], getlk wrlck [20,29]
+do_test "-s -r -o 0 -l 10" "-g -w -o 20 -l 10" "unlck" "unlck" "unlck"
+# setlk posix rdlck [0,9], getlk wrlck [20,29]
+do_test "-s -r -o 0 -l 10 -P" "-g -w -o 20 -l 10" "unlck" "unlck" "unlck"
+
+# setlk rdlck [0,9], getlk rdlck [0,9], open RDONLY
+do_test "-s -r -o 0 -l 10 -R" "-g -r -o 0 -l 10 -R" "unlck" "unlck" "unlck"
+# setlk rdlck [0,9], getlk posix rdlck [0,9], open RDONLY
+do_test "-s -r -o 0 -l 10 -R" "-g -r -o 0 -l 10 -R -P" "unlck" "unlck" "unlck"
+# setlk posix rdlck [0,9], getlk rdlck [0,9], open RDONLY
+do_test "-s -r -o 0 -l 10 -R -P" "-g -r -o 0 -l 10 -R" "unlck" "unlck" "unlck"
+# setlk rdlck [0,9], getlk rdlck [0,9]
+do_test "-s -r -o 0 -l 10" "-g -r -o 0 -l 10" "unlck" "unlck" "unlck"
+# setlk posix rdlck [0,9], getlk rdlck [0,9]
+do_test "-s -r -o 0 -l 10 -P" "-g -r -o 0 -l 10" "unlck" "unlck" "unlck"
+
+# setlk rdlck [0,9], getlk rdlck [20,29], open RDONLY
+do_test "-s -r -o 0 -l 10 -R" "-g -r -o 20 -l 10 -R" "unlck" "unlck" "unlck"
+# setlk rdlck [0,9], getlk posix rdlck [20,29], open RDONLY
+do_test "-s -r -o 0 -l 10 -R" "-g -r -o 20 -l 10 -R -P" "unlck" "unlck" "unlck"
+# setlk posix rdlck [0,9], getlk rdlck [20,29], open RDONLY
+do_test "-s -r -o 0 -l 10 -R -P" "-g -r -o 20 -l 10 -R" "unlck" "unlck" "unlck"
+# setlk rdlck [0,9], getlk rdlck [20,29]
+do_test "-s -r -o 0 -l 10" "-g -r -o 20 -l 10" "unlck" "unlck" "unlck"
+# setlk posix rdlck [0,9], getlk rdlck [20,29]
+do_test "-s -r -o 0 -l 10 -P" "-g -r -o 20 -l 10" "unlck" "unlck" "unlck"
+
+# success, all done
+status=0
+exit
diff --git a/tests/generic/478.out b/tests/generic/478.out
new file mode 100644 (file)
index 0000000..0b4b344
--- /dev/null
@@ -0,0 +1,91 @@
+QA output created by 478
+get wrlck
+lock could be placed
+get wrlck
+get wrlck
+lock could be placed
+get wrlck
+lock could be placed
+lock could be placed
+lock could be placed
+get wrlck
+lock could be placed
+lock could be placed
+lock could be placed
+lock could be placed
+lock could be placed
+get wrlck
+lock could be placed
+get wrlck
+get wrlck
+lock could be placed
+get wrlck
+lock could be placed
+lock could be placed
+lock could be placed
+get wrlck
+lock could be placed
+lock could be placed
+lock could be placed
+lock could be placed
+lock could be placed
+get rdlck
+lock could be placed
+get rdlck
+get rdlck
+lock could be placed
+get rdlck
+get rdlck
+lock could be placed
+lock could be placed
+get rdlck
+lock could be placed
+get rdlck
+get rdlck
+lock could be placed
+get rdlck
+get rdlck
+lock could be placed
+lock could be placed
+lock could be placed
+lock could be placed
+lock could be placed
+lock could be placed
+lock could be placed
+lock could be placed
+lock could be placed
+lock could be placed
+lock could be placed
+lock could be placed
+lock could be placed
+lock could be placed
+lock could be placed
+lock could be placed
+lock could be placed
+lock could be placed
+lock could be placed
+lock could be placed
+lock could be placed
+lock could be placed
+lock could be placed
+lock could be placed
+lock could be placed
+lock could be placed
+lock could be placed
+lock could be placed
+lock could be placed
+lock could be placed
+lock could be placed
+lock could be placed
+lock could be placed
+lock could be placed
+lock could be placed
+lock could be placed
+lock could be placed
+lock could be placed
+lock could be placed
+lock could be placed
+lock could be placed
+lock could be placed
+lock could be placed
+lock could be placed
index cce03e99d921f4d5089d0d66d71f9ccdf78d98ac..b2ce7a66ce81c16cbe42a283cb9ed783556c826f 100644 (file)
 475 shutdown auto log metadata
 476 auto rw
 477 auto quick exportfs
+478 auto quick