summaryrefslogtreecommitdiff
path: root/tests/generic/478
blob: 419acc945bb47071209c50f327dc141672878968 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
#! /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