generic: test deadlock on O_DIRECT|O_DSYNC
[xfstests-dev.git] / tests / generic / 001
1 #! /bin/bash
2 # SPDX-License-Identifier: GPL-2.0
3 # Copyright (c) 2000-2001 Silicon Graphics, Inc.  All Rights Reserved.
4 #
5 # FS QA Test No. 001
6 #
7 # Random file copier to produce chains of identical files so the head
8 # and the tail can be diff'd at the end of each iteration.
9 #
10 # Exercises creat, write and unlink for a variety of directory sizes, and
11 # checks for data corruption.
12 #
13 # run [config]
14 #
15 # config has one line per file with filename and byte size, else use
16 # the default one below.
17 #
18 seq=`basename $0`
19 seqres=$RESULT_DIR/$seq
20 echo "QA output created by $seq"
21
22 # get standard environment, filters and checks
23 . ./common/rc
24 . ./common/filter
25
26 tmp=/tmp/$$
27 here=`pwd`
28 status=1
29 done_cleanup=false
30 trap "_cleanup; rm -f $tmp.*; exit \$status" 0 1 2 3 15
31
32 # real QA test starts here
33 _supported_fs generic
34 _supported_os Linux
35 _require_test
36
37 verbose=true
38 verify=$here/verify_fill
39
40 if [ $# -eq 0 ]
41 then
42     # use the default config
43     #
44     cat <<End-of-File >$tmp.config
45 # pathname      size in bytes
46 #
47 small           10
48 big             102400
49 sub/small       10
50 sub/big         102400
51 #
52 sub/a           1
53 sub/b           2
54 sub/c           4
55 sub/d           8
56 sub/e           16
57 sub/f           32
58 sub/g           64
59 sub/h           128
60 sub/i           256
61 sub/j           512
62 sub/k           1024
63 sub/l           2048
64 sub/m           4096
65 sub/n           8192
66 #
67 sub/a00         100
68 sub/b00         200
69 sub/c00         400
70 sub/d00         800
71 sub/e00         1600
72 sub/f00         3200
73 sub/g00         6400
74 sub/h00         12800
75 sub/i00         25600
76 sub/j00         51200
77 sub/k00         102400
78 sub/l00         204800
79 sub/m00         409600
80 sub/n00         819200
81 #
82 sub/a000        1000
83 sub/e000        16000
84 sub/h000        128000
85 sub/k000        1024000
86 End-of-File
87 elif [ $# -eq 1 ]
88 then
89     if [ -f $1 ]
90     then
91         cp $1 $tmp.config
92     else
93         echo "Error: cannot open config \"$1\""
94         exit 1
95     fi
96 else
97     echo "Usage: run [config]"
98     exit 1
99 fi
100
101 ncopy=200               # number of file copies in the chain step
102 udf_fsize=20240         # number of sectors for UDF
103
104 _setup()
105 {
106     if mkdir -p $TEST_DIR/$$
107     then
108         :
109     else
110         echo "Error: cannot mkdir \"$TEST_DIR/$$\""
111         exit 1
112     fi
113     cd $TEST_DIR/$$
114
115     $verbose && echo -n "setup "
116     sed -e '/^#/d' $tmp.config \
117     | while read file nbytes
118     do
119         dir=`dirname $file`
120         if [ "$dir" != "." ]
121         then
122             if [ ! -d $dir ]
123             then
124                 if mkdir $dir
125                 then
126                     :
127                 else
128                     $verbose && echo
129                     echo "Error: cannot mkdir \"$dir\""
130                     exit 1
131                 fi
132             fi
133         fi
134         rm -f $file
135         if $here/src/fill $file $file $nbytes
136         then
137             :
138         else
139             $verbose && echo
140             echo "Error: cannot create \"$file\""
141             exit 1
142         fi
143         $verbose && echo -n "."
144     done
145     $verbose && echo
146 }
147
148 _mark_iteration()
149 {
150     $verbose && echo -n "mark_iteration "
151     sed -e '/^#/d' $tmp.config \
152     | while read file nbytes
153     do
154         if [ ! -f $file ]
155         then
156             $verbose && echo
157             echo "Error: $file vanished!"
158             touch $tmp.bad
159             continue
160         fi
161         sed -e "s/ [0-9][0-9]* / $1 /" <$file >$file.tmp
162         mv $file.tmp $file
163         $verbose && echo -n "."
164     done
165     $verbose && echo
166 }
167
168 # for each file, make a number of copies forming a chain like foo.0,
169 # foo.1, foo.2, ... foo.N
170 #
171 # files are chosen at random, so the lengths of the chains are different
172 #
173 # then rename foo.N to foo.last and remove all of the other files in
174 # the chain
175 #
176 _chain()
177 {
178     $AWK_PROG -v full_file=$seqres.full -v verify=$verify <$tmp.config '
179 BEGIN   { nfile = 0 }
180 /^#/    { next }
181         { file[nfile] = $1
182           size[nfile] = $2
183           link[nfile] = 0
184           nfile++
185           total_size += $2
186         }
187 END     { srand('$iter')
188           for (i=0; i < '$ncopy'; i++) {
189             # choose a file at random, and add one copy to that chain
190             j = -1
191             while (j < 0 || j >= nfile)
192                 j = int(rand() * nfile)
193             if (link[j] == 0) {
194                 # previous should already exist and next one should not exist
195                 printf "if [ ! -f %s ]; then echo \"%s missing!\"; exit; fi\n",file[j],file[j]
196                 printf "if [ -f %s.0 ]; then echo \"%s.0 already present!\"; exit; fi\n",file[j],file[j]
197                 printf "cp %s %s.0 || exit 1\n",file[j],file[j]
198                 printf "ls -i %s.0\n", file[j] >full_file;
199                 total_size += size[j]
200                 printf "# total size = %d\n", total_size 
201             }
202             else {
203                 # previous should already exist and next one should not exist
204                 printf "if [ ! -f %s.%d ]; then echo \"%s.%d missing!\"; exit; fi\n",file[j],link[j]-1,file[j],link[j]-1
205                 printf "if [ -f %s.%d ]; then echo \"%s.%d already present!\"; exit; fi\n",file[j],link[j],file[j],link[j]
206                 printf "cp %s.%d %s.%d || exit 1\n",file[j],link[j]-1,file[j],link[j]
207                 printf "ls -i %s.%d\n", file[j], link[j] >full_file;
208                 total_size += size[j]
209                 printf "# total size = %d\n", total_size 
210             }
211             link[j]++
212           }
213           # close all the chains, 
214           # if have at least one copy then move the last copy to "file[j].last"
215           # and remove all of the other files except the head of the chain
216           for (j=0; j<nfile; j++) {
217             if (link[j] > 0) {
218                 printf "mv %s.%d %s.last\n",file[j],link[j]-1,file[j]
219                 printf "ls -i %s.last\n", file[j] >full_file;
220             }
221             for (i=0; i<link[j]-1; i++) {
222                 printf "rm -f %s.%d\n",file[j],i
223             }
224           }
225         }' \
226         | tee -a $seqres.full | sh
227 }
228
229 _check()
230 {
231     rm -f $tmp.bad
232     $verbose && echo -n "check "
233     sed -e '/^#/d' $tmp.config \
234     | while read file nbytes
235     do
236         # the file is never removed so it should exist
237         if [ ! -f $file ]
238         then
239             $verbose && echo
240             echo "Error: $file vanished!"
241             touch $tmp.bad
242             continue
243         fi
244         # checks that the file and its last copy are the same
245         if [ -f $file.last ]
246         then
247             if cmp $file $file.last >/dev/null 2>&1
248             then
249                 $verbose && echo -n "."
250             else
251                 $verbose && echo
252                 echo "Error: corruption for $file ..."
253                 diff -c $file $file.last
254                 touch $tmp.bad
255             fi
256         else
257             $verbose && echo -n "."
258         fi
259     done
260     $verbose && echo
261 }
262
263 _cleanup()
264 {
265     # cleanup
266     #
267     if $done_cleanup
268     then
269         :
270     elif [ $status -eq 0 ]
271     then
272         $verbose && echo "cleanup"
273         cd /
274         rm -rf $TEST_DIR/$$
275         done_cleanup=true
276     fi
277 }
278
279 rm -f $seqres.full
280 status=0
281 _cleanup
282 status=1
283 done_cleanup=false
284
285 _setup
286
287 # do the test
288 #
289 for iter in 1 2 3 4 5
290 do
291     echo -n "iter $iter chain ... "
292     echo "iter $iter" >> $seqres.full
293     _chain
294     _check
295     if [ -f $tmp.bad ]
296     then
297         echo "Fatal error: test abandoned without changes"
298         exit 1
299     fi
300 done
301
302 status=0
303 exit