Whamcloud - gitweb
LU-9771 flr: lfs mirror create and extend commands
[fs/lustre-release.git] / lustre / tests / sanity-flr.sh
1 #!/bin/bash
2 #
3 # Run select tests by setting ONLY, or as arguments to the script.
4 # Skip specific tests by setting EXCEPT.
5 set -e
6 set +o posix
7
8 SRCDIR=$(dirname $0)
9 export PATH=$PWD/$SRCDIR:$SRCDIR:$PWD/$SRCDIR/../utils:$PATH:/sbin
10
11 ONLY=${ONLY:-"$*"}
12 # Bug number for skipped test:
13 ALWAYS_EXCEPT="$SANITY_FLR_EXCEPT 201"
14 # UPDATE THE COMMENT ABOVE WITH BUG NUMBERS WHEN CHANGING ALWAYS_EXCEPT!
15
16 LUSTRE=${LUSTRE:-$(cd $(dirname $0)/..; echo $PWD)}
17 . $LUSTRE/tests/test-framework.sh
18 init_test_env $@
19 . ${CONFIG:=$LUSTRE/tests/cfg/$NAME.sh}
20 init_logging
21
22 if [[ $(lustre_version_code $SINGLEMDS) -lt $(version_code 2.10.53) ]]; then
23         skip_env "Need MDS version at least 2.10.53" && exit
24 fi
25
26 [ $UID -eq 0 -a $RUNAS_ID -eq 0 ] &&
27         error "\$RUNAS_ID set to 0, but \$UID is also 0!"
28 check_runas_id $RUNAS_ID $RUNAS_GID $RUNAS
29
30 check_and_setup_lustre
31 DIR=${DIR:-$MOUNT}
32 assert_DIR
33
34 build_test_filter
35
36 # global array to store mirror IDs
37 declare -a mirror_array
38 get_mirror_ids() {
39         local tf=$1
40         local id
41         local array
42
43         array=()
44         for id in $($LFS getstripe $tf | awk '/lcme_id/{print $2}'); do
45                 array[${#array[@]}]=$((id >> 16))
46         done
47
48         mirror_array=($(printf "%s\n" "${array[@]}" | sort -u))
49
50         echo ${#mirror_array[@]}
51 }
52
53 drop_client_cache() {
54         echo 3 > /proc/sys/vm/drop_caches
55 }
56
57 stop_osts() {
58         local idx
59
60         for idx in "$@"; do
61                 stop ost$idx
62         done
63
64         for idx in "$@"; do
65                 wait_osc_import_state client ost$idx DISCONN
66         done
67 }
68
69 start_osts() {
70         local idx
71
72         for idx in "$@"; do
73                 start ost$idx $(ostdevname $idx) $OST_MOUNT_OPTS ||
74                         error "start ost$idx failed"
75         done
76
77         for idx in "$@"; do
78                 wait_osc_import_state client ost$idx FULL
79         done
80 }
81
82 # command line test cases
83 test_1() {
84         local tf=$DIR/$tfile
85         local mirror_count=16 # LUSTRE_MIRROR_COUNT_MAX
86         local mirror_create_cmd="$LFS mirror create"
87         local stripes[0]=$OSTCOUNT
88
89         mirror_create_cmd+=" -N -c ${stripes[0]}"
90         for ((i = 1; i < $mirror_count; i++)); do
91                 # add mirrors with different stripes to the file
92                 stripes[$i]=$((RANDOM % OSTCOUNT))
93                 [ ${stripes[$i]} -eq 0 ] && stripes[$i]=1
94
95                 mirror_create_cmd+=" -N -c ${stripes[$i]}"
96         done
97
98         eval $mirror_create_cmd $tf || error "creating mirrored file $tf failed"
99
100         [ $(get_mirror_ids $tf) -ne $mirror_count ] &&
101                 error "mirror count error"
102
103         # can't create mirrors exceeding LUSTRE_MIRROR_COUNT_MAX
104         $LFS mirror extend -N $tf &&
105                 error "Creating the $((mirror_count+1))th mirror succeeded"
106
107         local ids=($($LFS getstripe $tf | awk '/lcme_id/{print $2}' |
108                         tr '\n' ' '))
109
110         # verify the range of components and stripe counts
111         for ((i = 0; i < $mirror_count; i++)); do
112                 local sc=$($LFS getstripe -I${ids[$i]} -c $tf)
113                 local start=$($LFS getstripe -I${ids[$i]} --component-start $tf)
114                 local end=$($LFS getstripe -I${ids[$i]} --component-end $tf)
115
116                 [[ ${stripes[$i]} = $sc ]] || {
117                         $LFS getstripe -v $tf;
118                         error "$i: sc error: id: ${ids[$i]}, ${stripes[$i]}";
119                 }
120                 [ $start -eq 0 ] || {
121                         $LFS getstripe -v $tf;
122                         error "$i: start error id: ${ids[$i]}";
123                 }
124                 [ $end = "EOF" ] || {
125                         $LFS getstripe -v $tf;
126                         error "$i: end error id: ${ids[$i]}";
127                 }
128         done
129 }
130 run_test 1 "create components with setstripe options"
131
132 test_2() {
133         local tf=$DIR/$tfile
134         local tf2=$DIR/$tfile-2
135
136         $LFS setstripe -E 1M -E EOF -c 1 $tf
137         $LFS setstripe -E 2M -E EOF -c -1 $tf2
138
139         local layout=$($LFS getstripe $tf2 | grep -A 4 lmm_objects)
140
141         $LFS mirror extend -N -f $tf2 $tf ||
142                 error "merging $tf2 into $tf failed"
143
144         [ $(get_mirror_ids $tf) -ne 2 ] && error "mirror count should be 2"
145         [[ ! -e $tf2 ]] || error "$tf2 was not unlinked"
146 }
147 run_test 2 "create components from existing files"
148
149 test_3() {
150         [[ $MDSCOUNT -lt 2 ]] && skip "need >= 2 MDTs" && return
151
152         for ((i = 0; i < 2; i++)); do
153                 $LFS mkdir -i $i $DIR/$tdir-$i
154                 $LFS setstripe -E -1 $DIR/$tdir-$i/$tfile
155         done
156
157         $LFS mirror extend -N -f $DIR/$tdir-1/$tfile \
158                 $DIR/$tdir-0/$tfile || error "creating mirrors"
159
160         # mdt doesn't support to cancel layout lock for remote objects, do
161         # it here manually.
162         cancel_lru_locks mdc
163
164         # make sure the mirrorted file was created successfully
165         [[ $($LFS getstripe --component-count $DIR/$tdir-0/$tfile) -eq 2 ]] ||
166                 { $LFS getstripe $DIR/$tdir-0/$tfile;
167                         error "expected 2 components"; }
168
169         # cleanup
170         rm -rf $DIR/$tdir-*
171 }
172 run_test 3 "create components from files located on different MDTs"
173
174 test_21() {
175         local tf=$DIR/$tfile
176         local tf2=$DIR/$tfile-2
177
178         [[ $OSTCOUNT -lt 2 ]] && skip "need >= 2 OSTs" && return
179
180         $LFS setstripe -E EOF -o 0 $tf
181         $LFS setstripe -E EOF -o 1 $tf2
182
183         local dd_count=$((RANDOM % 20 + 1))
184         dd if=/dev/zero of=$tf bs=1M count=$dd_count
185         dd if=/dev/zero of=$tf2 bs=1M count=1 seek=$((dd_count - 1))
186         cancel_lru_locks osc
187
188         local blocks=$(du -kc $tf $tf2 | awk '/total/{print $1}')
189
190         # add component
191         $LFS mirror extend -N -f $tf2 $tf ||
192                 error "merging $tf2 into $tf failed"
193
194         # cancel layout lock
195         cancel_lru_locks mdc
196
197         local new_blocks=$(du -k $tf | awk '{print $1}')
198         [ $new_blocks -eq $blocks ] ||
199         error "i_blocks error expected: $blocks, actual: $new_blocks"
200 }
201 run_test 21 "glimpse should report accurate i_blocks"
202
203 get_osc_lock_count() {
204         local lock_count=0
205
206         for idx in "$@"; do
207                 local osc_name
208                 local count
209
210                 osc_name=${FSNAME}-OST$(printf "%04x" $((idx-1)))-osc-'ffff*'
211                 count=$($LCTL get_param -n ldlm.namespaces.$osc_name.lock_count)
212                 lock_count=$((lock_count + count))
213         done
214         echo $lock_count
215 }
216
217 test_22() {
218         local tf=$DIR/$tfile
219
220         $LFS setstripe -E EOF -o 0 $tf
221         dd if=/dev/zero of=$tf bs=1M count=$((RANDOM % 20 + 1))
222
223         # add component, two mirrors located on the same OST ;-)
224         $LFS mirror extend -N -o 0 $tf ||
225                 error "extending mirrored file $tf failed"
226
227         size_blocks=$(stat --format="%b %s" $tf)
228
229         cancel_lru_locks mdc
230         cancel_lru_locks osc
231
232         local new_size_blocks=$(stat --format="%b %s" $tf)
233
234         # make sure there is no lock cached
235         [ $(get_osc_lock_count 1) -eq 0 ] || error "glimpse requests were sent"
236
237         [ "$new_size_blocks" = "$size_blocks" ] ||
238                 echo "size expected: $size_blocks, actual: $new_size_blocks"
239
240         rm -f $tmpfile
241 }
242 run_test 22 "no glimpse to OSTs for READ_ONLY files"
243
244 test_31() {
245         local tf=$DIR/$tfile
246
247         $LFS mirror create -N -o 0 -N -o 1 $tf ||
248                 error "creating mirrored file $tf failed"
249
250         #define OBD_FAIL_GLIMPSE_IMMUTABLE 0x1A00
251         $LCTL set_param fail_loc=0x1A00
252
253         local ost_idx
254         for ((ost_idx = 1; ost_idx <= 2; ost_idx++)); do
255                 cancel_lru_locks osc
256                 stop_osts $ost_idx
257
258                 local tmpfile=$(mktemp)
259                 stat --format="%b %s" $tf > $tmpfile  &
260                 local pid=$!
261
262                 local cnt=0
263                 while [ $cnt -le 5 ]; do
264                         kill -0 $pid > /dev/null 2>&1 || break
265                         sleep 1
266                         ((cnt += 1))
267                 done
268                 kill -0 $pid > /dev/null 2>&1 &&
269                         error "stat process stuck due to unavailable OSTs"
270
271                 # make sure glimpse request has been sent
272                 [ $(get_osc_lock_count 1 2) -ne 0 ] ||
273                         error "OST $ost_idx: no glimpse request was sent"
274
275                 start_osts $ost_idx
276         done
277 }
278 run_test 31 "make sure glimpse request can be retried"
279
280 test_32() {
281         [[ $OSTCOUNT -lt 2 ]] && skip "need >= 2 OSTs" && return
282         rm -f $DIR/$tfile $DIR/$tfile-2
283
284         $LFS setstripe -E EOF -o 0 $DIR/$tfile
285         dd if=/dev/urandom of=$DIR/$tfile bs=1M count=$((RANDOM % 10 + 2))
286
287         local fsize=$(stat -c %s $DIR/$tfile)
288         [[ $fsize -ne 0 ]] || error "file size is (wrongly) zero"
289
290         local cksum=$(md5sum $DIR/$tfile)
291
292         # create a new mirror in sync mode
293         $LFS mirror extend -N -o 1 $DIR/$tfile ||
294                 error "extending mirrored file $DIR/$tfile failed"
295
296         # make sure the mirrored file was created successfully
297         [ $(get_mirror_ids $DIR/$tfile) -eq 2 ] ||
298                 { $LFS getstripe $DIR/$tfile; error "expected 2 mirrors"; }
299
300         drop_client_cache
301         stop_osts 1
302
303         # check size is correct, glimpse request should go to the 2nd mirror
304         $CHECKSTAT -t file -s $fsize $DIR/$tfile ||
305                 error "file size error $fsize vs. $(stat -c %s $DIR/$tfile)"
306
307         echo "reading file from the 2nd mirror and verify checksum"
308         [[ "$cksum" == "$(md5sum $DIR/$tfile)" ]] ||
309                 error "checksum error: expected $cksum"
310
311         start_osts 1
312 }
313 run_test 32 "data should be mirrored to newly created mirror"
314
315 test_33() {
316         [[ $OSTCOUNT -lt 2 ]] && skip "need >= 2 OSTs" && return
317
318         rm -f $DIR/$tfile $DIR/$tfile-2
319
320         # create a file with two mirrors
321         $LFS setstripe -E EOF -o 0 $DIR/$tfile
322         local max_count=100
323         local count=0
324         while [ $count -lt $max_count ]; do
325                 echo "ost1" >> $DIR/$tfile
326                 count=$((count + 1));
327         done
328
329         # tmp file that will be used as mirror
330         $LFS setstripe -E EOF -o 1 $DIR/$tfile-2
331         count=0
332         while [ $count -lt $max_count ]; do
333                 echo "ost2" >> $DIR/$tfile-2
334                 count=$((count + 1));
335         done
336
337         # create a mirrored file
338         $LFS mirror extend -N -f $DIR/$tfile-2 $DIR/$tfile &&
339                 error "merging $DIR/$tfile-2 into $DIR/$tfile" \
340                       "with verification should fail"
341         $LFS mirror extend --no-verify -N -f $DIR/$tfile-2 $DIR/$tfile ||
342                 error "merging $DIR/$tfile-2 into $DIR/$tfile" \
343                       "without verification failed"
344
345         # make sure that $tfile has two mirrors and $tfile-2 does not exist
346         [ $(get_mirror_ids $DIR/$tfile) -eq 2 ] ||
347                 { $LFS getstripe $DIR/$tfile; error "expected count 2"; }
348
349         [[ ! -e $DIR/$tfile-2 ]] || error "$DIR/$tfile-2 was not unlinked"
350
351         # execpted file size
352         local fsize=$((5 * max_count))
353         $CHECKSTAT -t file -s $fsize $DIR/$tfile ||
354                 error "mirrored file size is not $fsize"
355
356         # read file - all OSTs are available
357         echo "reading file (data should be provided by ost1)... "
358         local rs=$(cat $DIR/$tfile | head -1)
359         [[ "$rs" == "ost1" ]] ||
360                 error "file content error: expected: \"ost1\", actual: \"$rs\""
361
362         # read file again with ost1 failed
363         stop_osts 1
364         drop_client_cache
365
366         echo "reading file (data should be provided by ost2)..."
367         local rs=$(cat $DIR/$tfile | head -1)
368         [[ "$rs" == "ost2" ]] ||
369                 error "file content error: expected: \"ost2\", actual: \"$rs\""
370
371         # remount ost1
372         start_osts 1
373
374         # read file again with ost2 failed
375         $LCTL set_param ldlm.namespaces.lustre-*-osc-ffff*.lru_size=clear
376
377         fail ost2 &
378         sleep 1
379
380         # check size, glimpse should work
381         $CHECKSTAT -t file -s $fsize $DIR/$tfile ||
382                 error "mirrored file size is not $fsize"
383
384         echo "reading file (data should be provided by ost1)..."
385         local rs=$(cat $DIR/$tfile | head -1)
386         [[ "$rs" == "ost1" ]] ||
387                 error "file content error: expected: \"ost1\", actual: \"$rs\""
388
389         wait_osc_import_state client ost2 FULL
390 }
391 run_test 33 "read can choose available mirror to read"
392
393 test_34a() {
394         [[ $OSTCOUNT -lt 4 ]] && skip "need >= 4 OSTs" && return
395
396         rm -f $DIR/$tfile $DIR/$tfile-2 $DIR/$tfile-ref
397
398         # reference file
399         $LFS setstripe -o 0 $DIR/$tfile-ref
400         dd if=/dev/urandom of=$DIR/$tfile-ref bs=1M count=3
401
402         # create a file with two mirrors
403         $LFS setstripe -E -1 -o 0,1 -S 1M $DIR/$tfile
404         dd if=$DIR/$tfile-ref of=$DIR/$tfile bs=1M
405
406         $LFS setstripe -E -1 -o 2,3 -S 1M $DIR/$tfile-2
407         dd if=$DIR/$tfile-ref of=$DIR/$tfile-2 bs=1M
408
409         $CHECKSTAT -t file -s $((3 * 1024 * 1024)) $DIR/$tfile ||
410                 error "mirrored file size is not 3M"
411
412         # merge a mirrored file
413         $LFS mirror extend -N -f $DIR/$tfile-2 $DIR/$tfile ||
414                 error "merging $DIR/$tfile-2 into $DIR/$tfile failed"
415
416         cancel_lru_locks osc
417
418         # stop two OSTs, so the 2nd stripe of the 1st mirror and
419         # the 1st stripe of the 2nd mirror will be inaccessible, ...
420         stop_osts 2 3
421
422         echo "comparing files ... "
423
424         # however, read can still return the correct data. It should return
425         # the 1st stripe from mirror 1 and 2st stripe from mirror 2.
426         cmp -n 2097152 <(rwv -f $DIR/$tfile -r -o -n 1 2097152) \
427                 $DIR/$tfile-ref || error "file reading error"
428
429         start_osts 2 3
430 }
431 run_test 34a "read mirrored file with multiple stripes"
432
433 test_34b() {
434         [[ $OSTCOUNT -lt 4 ]] && skip "need >= 4 OSTs" && return
435
436         rm -f $DIR/$tfile $DIR/$tfile-2 $DIR/$tfile-ref
437
438         # reference file
439         $LFS setstripe -o 0 $DIR/$tfile-ref
440         dd if=/dev/urandom of=$DIR/$tfile-ref bs=1M count=3
441
442         $LFS setstripe -E 1M -S 1M -o 0 -E eof -o 1 $DIR/$tfile
443         dd if=$DIR/$tfile-ref of=$DIR/$tfile bs=1M
444
445         $LFS setstripe -E 1M -S 1M -o 2 -E eof -o 3 $DIR/$tfile-2
446         dd if=$DIR/$tfile-ref of=$DIR/$tfile-2 bs=1M
447
448         $CHECKSTAT -t file -s $((3 * 1024 * 1024)) $DIR/$tfile ||
449                 error "mirrored file size is not 3M"
450
451         # merge a mirrored file
452         $LFS mirror extend -N -f $DIR/$tfile-2 $DIR/$tfile ||
453                 error "merging $DIR/$tfile-2 into $DIR/$tfile failed"
454
455         cancel_lru_locks osc
456
457         # stop two OSTs, so the 2nd component of the 1st mirror and
458         # the 1st component of the 2nd mirror will be inaccessible, ...
459         stop_osts 2 3
460
461         echo "comparing files ... "
462
463         # however, read can still return the correct data. It should return
464         # the 1st stripe from mirror 1 and 2st stripe from mirror 2.
465         cmp -n 2097152 <(rwv -f $DIR/$tfile -r -o -n 1 2097152) \
466                 $DIR/$tfile-ref || error "file reading error"
467
468         start_osts 2 3
469 }
470 run_test 34b "read mirrored file with multiple components"
471
472 test_35() {
473         local tf=$DIR/$tfile
474
475         $LFS setstripe -E eof $tf
476
477         # add an out-of-sync mirror to the file
478         $LFS mirror extend -N -c 2 $tf ||
479                 error "extending mirrored file $tf failed"
480
481         $MULTIOP $tf oO_WRONLY:c ||
482                 error "write open a mirrored file failed"
483
484         # truncate file should return error
485         $TRUNCATE $tf 100 || error "error truncating a mirrored file"
486 }
487 run_test 35 "allow to write to mirrored files"
488
489 verify_ost_layout_version() {
490         local tf=$1
491
492         # get file layout version
493         local flv=$($LFS getstripe $tf | awk '/lcm_layout_gen/{print $2}')
494
495         # layout version from OST objects
496         local olv=$($MULTIOP $tf oXc | awk '/ostlayoutversion/{print $2}')
497
498         [ $flv -eq $olv ] || error "layout version mismatch: $flv vs. $olv"
499 }
500
501 create_file_36() {
502         local tf
503
504         for tf in "$@"; do
505                 $LFS setstripe -E 1M -E 2M -E 4M -E eof -c -1 $tf
506                 $LFS setstripe -E 3M -E 6M -E eof -c -1 $tf-tmp
507
508                 $LFS mirror extend -N -f $tf-tmp $tf ||
509                         error "merging $tf-tmp into $tf failed"
510         done
511 }
512
513 test_36() {
514         local tf=$DIR/$tfile
515
516         create_file_36 $tf $tf-2 $tf-3
517
518         [ $(get_mirror_ids $tf) -gt 1 ] || error "wrong mirror count"
519
520         # test case 1 - check file write and verify layout version
521         $MULTIOP $tf oO_WRONLY:c ||
522                 error "write open a mirrored file failed"
523
524         # write open file should not return error
525         $MULTIOP $tf oO_WRONLY:w1024Yc || error "write mirrored file error"
526
527         # instantiate components should work
528         dd if=/dev/zero of=$tf bs=1M count=12 || error "write file error"
529
530         # verify OST layout version
531         verify_ost_layout_version $tf
532
533         # test case 2
534         local mds_idx=mds$(($($LFS getstripe -M $tf-2) + 1))
535
536         local delay_sec=10
537         do_facet $mds_idx $LCTL set_param fail_val=$delay_sec
538
539         #define OBD_FAIL_FLR_LV_DELAY 0x1A01
540         do_facet $mds_idx $LCTL set_param fail_loc=0x1A01
541
542         # write should take at least $fail_loc seconds and succeed
543         local st=$(date +%s)
544         $MULTIOP $tf-2 oO_WRONLY:w1024Yc || error "write mirrored file error"
545
546         [ $(date +%s) -ge $((st+delay_sec)) ] ||
547                 error "write finished before layout version is transmitted"
548
549         # verify OST layout version
550         verify_ost_layout_version $tf
551
552         do_facet $mds_idx $LCTL set_param fail_loc=0
553
554         # test case 3
555         mds_idx=mds$(($($LFS getstripe -M $tf-3) + 1))
556
557         #define OBD_FAIL_FLR_LV_INC 0x1A02
558         do_facet $mds_idx $LCTL set_param fail_loc=0x1A02
559
560         # write open file should return error
561         $MULTIOP $tf-3 oO_WRONLY:O_SYNC:w1024c &&
562                 error "write a mirrored file succeeded" || true
563
564         do_facet $mds_idx $LCTL set_param fail_loc=0
565 }
566 run_test 36 "write to mirrored files"
567
568 create_files_37() {
569         local tf
570         local fsize=$1
571
572         echo "create test files with size $fsize .."
573
574         shift
575         for tf in "$@"; do
576                 $LFS setstripe -E 1M -c 1 -E eof -c -1 $tf
577
578                 dd if=/dev/urandom of=$tf bs=1M count=16 &> /dev/null
579                 $TRUNCATE $tf $fsize
580         done
581 }
582
583 test_37()
584 {
585         local tf=$DIR/$tfile
586         local tf2=$DIR/$tfile-2
587         local tf3=$DIR/$tfile-3
588
589         create_files_37 $((RANDOM + 15 * 1048576)) $tf $tf2 $tf3
590
591         # assume the mirror id will be 1, 2, and 3
592         declare -A checksums
593         checksums[1]=$(md5sum $tf | cut -f 1 -d' ')
594         checksums[2]=$(md5sum $tf2 | cut -f 1 -d' ')
595         checksums[3]=$(md5sum $tf3 | cut -f 1 -d' ')
596
597         printf '%s\n' "${checksums[@]}"
598
599         # merge these files into a mirrored file
600         $LFS mirror extend --no-verify -N -f $tf2 $tf ||
601                 error "merging $tf2 into $tf failed"
602         $LFS mirror extend --no-verify -N -f $tf3 $tf ||
603                 error "merging $tf3 into $tf failed"
604
605         get_mirror_ids $tf
606
607         # verify mirror read, checksums should equal to the original files'
608         echo "Verifying mirror read .."
609
610         local sum
611         for i in ${mirror_array[@]}; do
612                 sum=$(mirror_io dump -i $i $tf | md5sum | cut -f 1 -d' ')
613                 [ "$sum" = "${checksums[$i]}" ] ||
614                         error "$i: mismatch: \'${checksums[$i]}\' vs. \'$sum\'"
615         done
616
617         # verify mirror copy, write to this mirrored file will invalidate
618         # the other two mirrors
619         echo "Verifying mirror copy .."
620
621         local osts=$(comma_list $(osts_nodes))
622
623         # define OBD_FAIL_OST_SKIP_LV_CHECK     0x241
624         do_nodes $osts lctl set_param fail_loc=0x241
625
626         mirror_io copy -i ${mirror_array[0]} \
627                 -t $(echo ${mirror_array[@]:1} | tr ' ' ',') $tf ||
628                         error "mirror copy error"
629
630         do_nodes $osts lctl set_param fail_loc=0
631
632         # verify copying is successful by checking checksums
633         remount_client $MOUNT
634         for i in ${mirror_array[@]}; do
635                 sum=$(mirror_io dump -i $i $tf | md5sum | cut -f 1 -d' ')
636                 [ "$sum" = "${checksums[1]}" ] ||
637                         error "$i: mismatch checksum after copy"
638         done
639
640         rm -f $tf
641 }
642 run_test 37 "mirror I/O API verification"
643
644 verify_flr_state()
645 {
646         local tf=$1
647         local expected_state=$2
648         local state_strings=("not_flr" "read_only" "write_pending" \
649                 "sync_pending")
650
651         local state=$($LFS getstripe -v $tf | awk '/lcm_flags/{ print $2 }')
652         [ $expected_state = ${state_strings[$state]} ] ||
653                 error "expected: $expected_state, " \
654                         "actual ${state_strings[$state]}($state)"
655 }
656
657 test_38() {
658         local tf=$DIR/$tfile
659         local ref=$DIR/${tfile}-ref
660
661         $LFS setstripe -E 1M -c 1 -E 4M -c 2 -E eof -c -1 $tf
662         $LFS setstripe -E 2M -c 1 -E 6M -c 2 -E 8M -c -1 -E eof -c -1 $tf-2
663         $LFS setstripe -E 4M -c 1 -E 8M -c 2 -E eof -c -1 $tf-3
664
665         # instantiate all components
666         $LFS mirror extend -N -f $tf-2 $tf ||
667                 error "merging $tf-2 into $tf failed"
668         $LFS mirror extend -N -f $tf-3 $tf ||
669                 error "merging $tf-3 into $tf failed"
670         $LFS mirror extend -N -c 1 $tf ||
671                 error "extending mirrored file $tf failed"
672
673         verify_flr_state $tf "read_only"
674
675         dd if=/dev/urandom of=$ref  bs=1M count=16 &> /dev/null
676
677         local fsize=$((RANDOM << 8 + 1048576))
678         $TRUNCATE $ref $fsize
679
680         local ref_cksum=$(md5sum $ref | cut -f 1 -d' ')
681
682         # case 1: verify write to mirrored file & resync work
683         cp $ref $tf || error "copy from $ref to $f error"
684         verify_flr_state $tf "write_pending"
685
686         local file_cksum=$(md5sum $tf | cut -f 1 -d' ')
687         [ "$file_cksum" = "$ref_cksum" ] || error "write failed, cksum mismatch"
688
689         get_mirror_ids $tf
690         echo "mirror IDs: ${mirror_array[@]}"
691
692         local valid_mirror stale_mirror id mirror_cksum
693         for id in "${mirror_array[@]}"; do
694                 mirror_cksum=$(mirror_io dump -i $id $tf |
695                                 md5sum | cut -f 1 -d' ')
696                 [ "$ref_cksum" == "$mirror_cksum" ] &&
697                         { valid_mirror=$id; continue; }
698
699                 stale_mirror=$id
700         done
701
702         [ -z "$stale_mirror" ] && error "stale mirror doesn't exist"
703         [ -z "$valid_mirror" ] && error "valid mirror doesn't exist"
704
705         mirror_io resync $tf || error "resync failed"
706         verify_flr_state $tf "read_only"
707
708         mirror_cksum=$(mirror_io dump -i $stale_mirror $tf |
709                         md5sum | cut -f 1 -d' ')
710         [ "$file_cksum" = "$ref_cksum" ] || error "resync failed"
711
712         # case 2: inject an error to make mirror_io exit after changing
713         # the file state to sync_pending so that we can start a concurrent
714         # write.
715         $MULTIOP $tf oO_WRONLY:w$((RANDOM % 1048576 + 1024))c
716         verify_flr_state $tf "write_pending"
717
718         mirror_io resync -e resync_start $tf && error "resync succeeded"
719         verify_flr_state $tf "sync_pending"
720
721         # from sync_pending to write_pending
722         $MULTIOP $tf oO_WRONLY:w$((RANDOM % 1048576 + 1024))c
723         verify_flr_state $tf "write_pending"
724
725         mirror_io resync -e resync_start $tf && error "resync succeeded"
726         verify_flr_state $tf "sync_pending"
727
728         # from sync_pending to read_only
729         mirror_io resync $tf || error "resync failed"
730         verify_flr_state $tf "read_only"
731 }
732 run_test 38 "resync"
733
734 ctrl_file=$(mktemp /tmp/CTRL.XXXXXX)
735 lock_file=$(mktemp /var/lock/FLR.XXXXXX)
736
737 write_file_200() {
738         local tf=$1
739
740         local fsize=$(stat --printf=%s $tf)
741
742         while [ -f $ctrl_file ]; do
743                 local off=$((RANDOM << 8))
744                 local len=$((RANDOM << 5 + 131072))
745
746                 [ $((off + len)) -gt $fsize ] && {
747                         fsize=$((off + len))
748                         echo "Extending file size to $fsize .."
749                 }
750
751                 flock -s $lock_file -c \
752                         "$MULTIOP $tf oO_WRONLY:z${off}w${len}c" ||
753                                 { rm -f $ctrl_file;
754                                   error "failed writing to $off:$len"; }
755                 sleep 0.$((RANDOM % 2 + 1))
756         done
757 }
758
759 read_file_200() {
760         local tf=$1
761
762         while [ -f $ctrl_file ]; do
763                 flock -s $lock_file -c "cat $tf &> /dev/null" ||
764                         { rm -f $ctrl_file; error "read failed"; }
765                 sleep 0.$((RANDOM % 2 + 1))
766         done
767 }
768
769 resync_file_200() {
770         local tf=$1
771
772         options=("" "-e resync_start" "-e delay_before_copy -d 1" "" "")
773
774         exec 200<>$lock_file
775         while [ -f $ctrl_file ]; do
776                 local index=$((RANDOM % ${#options[@]}))
777                 local lock_taken=false
778
779                 [ $((RANDOM % 4)) -eq 0 ] && {
780                         index=0
781                         lock_taken=true
782                         echo -n "lock to "
783                 }
784
785                 echo -n "resync file $tf with '${options[$index]}' .."
786
787                 $lock_taken && flock -x 200
788                 mirror_io resync ${options[$index]} $tf &> /dev/null &&
789                         echo "done" || echo "failed"
790
791                 $lock_taken && flock -u 200
792
793                 sleep 0.$((RANDOM % 8 + 1))
794         done
795 }
796
797 test_200() {
798         local tf=$DIR/$tfile
799         local tf2=$DIR2/$tfile
800         local tf3=$DIR3/$tfile
801
802         $LFS setstripe -E 1M -E 2M -c 2 -E 4M -E 16M -E eof $tf
803         $LFS setstripe -E 2M -E 6M -c 2 -E 8M -E 32M -E eof $tf-2
804         $LFS setstripe -E 4M -c 2 -E 8M -E 64M -E eof $tf-3
805
806         $LFS mirror extend -N -f $tf-2 $tf ||
807                 error "merging $tf-2 into $tf failed"
808         $LFS mirror extend -N -f $tf-3 $tf ||
809                 error "merging $tf-3 into $tf failed"
810
811         mkdir -p $MOUNT2 && mount_client $MOUNT2
812
813         mkdir -p $MOUNT3 && mount_client $MOUNT3
814
815         verify_flr_state $tf3 "read_only"
816
817         #define OBD_FAIL_FLR_RANDOM_PICK_MIRROR 0x1A03
818         $LCTL set_param fail_loc=0x1A03
819
820         local mds_idx=mds$(($($LFS getstripe -M $tf) + 1))
821         do_facet $mds_idx $LCTL set_param fail_loc=0x1A03
822
823         declare -a pids
824
825         write_file_200 $tf &
826         pids+=($!)
827
828         read_file_200 $tf &
829         pids+=($!)
830
831         write_file_200 $tf2 &
832         pids+=($!)
833
834         read_file_200 $tf2 &
835         pids+=($!)
836
837         resync_file_200 $tf3 &
838         pids+=($!)
839
840         local sleep_time=60
841         [ "$SLOW" = "yes" ] && sleep_time=360
842         while [ $sleep_time -gt 0 -a -f $ctrl_file ]; do
843                 sleep 1
844                 ((--sleep_time))
845         done
846
847         rm -f $ctrl_file
848
849         echo "Waiting ${pids[@]}"
850         wait ${pids[@]}
851
852         umount_client $MOUNT2
853         umount_client $MOUNT3
854
855         rm -f $lock_file
856
857         # resync and verify mirrors
858         mirror_io resync $tf
859         get_mirror_ids $tf
860
861         local csum=$(mirror_io dump -i ${mirror_array[0]} $tf | md5sum)
862         for id in ${mirror_array[@]:1}; do
863                 [ "$(mirror_io dump -i $id $tf | md5sum)" = "$csum" ] ||
864                         error "checksum error for mirror $id"
865         done
866
867         true
868 }
869 run_test 200 "stress test"
870
871 cleanup_test_201() {
872         trap 0
873         do_facet $SINGLEMDS $LCTL --device $MDT0 changelog_deregister $CL_USER
874
875         umount_client $MOUNT2
876 }
877
878 test_201() {
879         local delay=${RESYNC_DELAY:-5}
880
881         MDT0=$($LCTL get_param -n mdc.*.mds_server_uuid |
882                awk '{ gsub(/_UUID/,""); print $1 }' | head -n1)
883
884         trap cleanup_test_201 EXIT
885
886         CL_USER=$(do_facet $SINGLEMDS $LCTL --device $MDT0 \
887                         changelog_register -n)
888
889         mkdir -p $MOUNT2 && mount_client $MOUNT2
890
891         local index=0
892         while :; do
893                 local log=$($LFS changelog $MDT0 $index | grep FLRW)
894                 [ -z "$log" ] && { sleep 1; continue; }
895
896                 index=$(echo $log | awk '{print $1}')
897                 local ts=$(date -d "$(echo $log | awk '{print $3}')" "+%s" -u)
898                 local fid=$(echo $log | awk '{print $6}' | sed -e 's/t=//')
899                 local file=$($LFS fid2path $MOUNT2 $fid 2> /dev/null)
900
901                 ((++index))
902                 [ -z "$file" ] && continue
903
904                 local now=$(date +%s)
905
906                 echo "file: $file $fid was modified at $ts, now: $now, " \
907                      "will be resynced at $((ts+delay))"
908
909                 [ $now -lt $((ts + delay)) ] && sleep $((ts + delay - now))
910
911                 mirror_io resync $file
912                 echo "$file resync done"
913         done
914
915         cleanup_test_201
916 }
917 run_test 201 "FLR data mover"
918
919 complete $SECONDS
920 check_and_cleanup_lustre
921 exit_status