#! /bin/bash # SPDX-License-Identifier: GPL-2.0 # Copyright (c) 2018 Red Hat Inc. All Rights Reserved. # # 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 # . ./common/preamble _begin_fstest auto quick # Import common functions. . ./common/filter # Modify as appropriate. _supported_fs generic _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 mk_sem() { SEMID=$(ipcmk -S 2 | cut -d ":" -f 2 | tr -d '[:space:]') if [ -z "$SEMID" ]; then echo "ipcmk failed" exit 1 fi SEMKEY=$(ipcs -s | grep $SEMID | cut -d " " -f 1) if [ -z "$SEMKEY" ]; then echo "ipcs failed" exit 1 fi } rm_sem() { ipcrm -s $SEMID 2>/dev/null } do_test() { local soptions local goptions # print options and getlk output for debug echo $* >> $seqres.full 2>&1 mk_sem soptions="$1 -K $SEMKEY" goptions="$2 -K $SEMKEY" # -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 $! rm_sem mk_sem # add -F to clone with CLONE_FILES soptions="$1 -F -K $SEMKEY" goptions="$2 -K $SEMKEY" # 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 $! rm_sem mk_sem # add -d to dup and close soptions="$1 -d -K $SEMKEY" goptions="$2 -K $SEMKEY" $here/src/t_ofd_locks $soptions $TEST_DIR/testfile & $here/src/t_ofd_locks $goptions $TEST_DIR/testfile | \ tee -a $seqres.full wait $! rm_sem } # 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