mirror of
https://github.com/linux-apfs/apfstests.git
synced 2026-05-01 15:01:44 -07:00
generic: add OFD lock tests
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>
This commit is contained in:
@@ -128,6 +128,7 @@
|
||||
/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
|
||||
|
||||
@@ -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)
|
||||
|
||||
+2
-1
@@ -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 \
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
Executable
+250
@@ -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
|
||||
@@ -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
|
||||
@@ -480,3 +480,4 @@
|
||||
475 shutdown auto log metadata
|
||||
476 auto rw
|
||||
477 auto quick exportfs
|
||||
478 auto quick
|
||||
|
||||
Reference in New Issue
Block a user