Whamcloud - gitweb
LU-5668 test: enable ior data consistency check
[fs/lustre-release.git] / lustre / tests / functions.sh
1 #!/bin/bash
2 # -*- mode: Bash; tab-width: 4; indent-tabs-mode: t; -*-
3 # vim:shiftwidth=4:softtabstop=4:tabstop=4:
4
5 # Simple function used by run_*.sh scripts
6
7 assert_env() {
8     local failed=""
9     for name in $@; do
10         if [ -z "${!name}" ]; then
11             echo "$0: $name must be set"
12             failed=1
13         fi
14     done
15     [ $failed ] && exit 1 || true
16 }
17
18 # lrepl - Lustre test Read-Eval-Print Loop.
19 #
20 # This function implements a REPL for the Lustre test framework.  It
21 # doesn't exec an actual shell because the user may want to inspect
22 # variables and use functions from the test framework.
23 lrepl() {
24     local line
25     local rawline
26     local prompt
27
28     cat <<EOF
29         This is an interactive read-eval-print loop interactive shell
30         simulation that you can use to debug failing tests.  You can
31         enter most bash command lines (see notes below).
32
33         Use this REPL to inspect variables, set them, call test
34         framework shell functions, etcetera.
35
36         'exit' or EOF to exit this shell.
37
38         set \$retcode to 0 to cause the assertion failure that
39         triggered this REPL to be ignored.
40
41         Examples:
42             do_facet ost1 lctl get_param ost.*.ost.threads_*
43             do_rpc_nodes \$OSTNODES unload_modules
44
45         NOTES:
46             All but the last line of multi-line statements or blocks
47             must end in a backslash.
48
49             "Here documents" are not supported.
50
51             History is not supported, but command-line editing is.
52
53 EOF
54
55     # Prompt escapes don't work in read -p, sadly.
56     prompt=":test_${testnum:-UNKNOWN}:$(uname -n):$(basename $PWD)% "
57
58     # We use read -r to get close to a shell experience
59     while read -e -r -p "$prompt" rawline; do
60         line=
61         case "$rawline" in
62         # Don't want to exit-exit, just exit the REPL
63         exit) break;;
64         # We need to handle continuations, and read -r doesn't do
65         # that for us.  Yet we need read -r.
66         #
67         # We also use case/esac to compare lines read to "*\\"
68         # because [ "$line" = *\\ ] and variants of that don't work.
69         *\\) line="$rawline"
70             while read -e -r -p '> ' rawline
71             do
72                 line="$line"$'\n'"$rawline"
73                 case "$rawline" in
74                 # We could check for here documents by matching
75                 # against *<<*, but who cares.
76                 *\\) continue;;
77                 *) break;;
78                 esac
79             done
80             ;;
81         *) line=$rawline
82         esac
83
84         case "$line" in
85         *\\) break;;
86         esac
87
88         # Finally!  Time to eval.
89         eval "$line"
90     done
91
92     echo $'\n\tExiting interactive shell...\n'
93     return 0
94 }
95
96 # lassert - Lustre test framework assert
97 #
98 # Arguments: failure code, failure message, expression/statement
99 #
100 # lassert evaluates the expression given, and, if false, calls
101 # error() to trigger test failure.  If REPL_ON_LASSERT is true then
102 # lassert will call lrepl() to give the user an interactive shell.
103 # If the REPL sets retcode=0 then the assertion failure will be
104 # ignored.
105 lassert() {
106     local retcode=$1
107     local msg=$2
108     shift 2
109
110     echo "checking $* ($(eval echo \""$*"\"))..."
111     eval "$@" && return 0;
112
113     if ${REPL_ON_LASSERT:-false}; then
114         echo "Assertion $retcode failed: $* (expanded: $(eval echo \""$*"\"))
115 $msg"
116         lrepl
117     fi
118
119     error "Assertion $retcode failed: $* (expanded: $(eval echo \""$*"\"))
120 $msg"
121     return $retcode
122 }
123
124 # setmodopts- set module options for subsequent calls to load_modules
125 #
126 # Usage: setmodopts module_name new_value [var_in_which_to_save_old_value]
127 #        setmodopts -a module_name new_value [var_in_which_to_save_old_value]
128 #
129 # In the second usage the new value is appended to the old.
130 setmodopts() {
131         local _append=false
132
133         if [ "$1" = -a ]; then
134             _append=true
135             shift
136         fi
137
138         local _var=MODOPTS_$1
139         local _newvalue=$2
140         local _savevar=$3
141         local _oldvalue
142
143         # Dynamic naming of variables is a pain in bash.  In ksh93 we could
144         # write "nameref opts_var=${modname}_MODOPTS" then assign directly
145         # to opts_var.  Associative arrays would also help, alternatively.
146         # Alas, we're stuck with eval until all distros move to a more recent
147         # version of bash.  Fortunately we don't need to eval unset and export.
148
149         if [ -z "$_newvalue" ]; then
150             unset $_var
151             return 0
152         fi
153
154         _oldvalue=${!var}
155         $_append && _newvalue="$_oldvalue $_newvalue"
156         export $_var="$_newvalue"
157         echo setmodopts: ${_var}=${_newvalue}
158
159         [ -n "$_savevar" ] && eval $_savevar=\""$_oldvalue"\"
160 }
161
162 echoerr () { echo "$@" 1>&2 ; }
163
164 signaled() {
165     echoerr "$(date +'%F %H:%M:%S'): client load was signaled to terminate"
166
167     local PGID=$(ps -eo "%c %p %r" | awk "/ $PPID / {print \$3}")
168     kill -TERM -$PGID
169     sleep 5
170     kill -KILL -$PGID
171 }
172
173 mpi_run () {
174     local mpirun="$MPIRUN $MPIRUN_OPTIONS"
175     local command="$mpirun $@"
176     local mpilog=$TMP/mpi.log
177     local rc
178
179     if [ -n "$MPI_USER" -a "$MPI_USER" != root -a -n "$mpirun" ]; then
180         echo "+ chmod 0777 $MOUNT"
181         chmod 0777 $MOUNT
182         command="su $MPI_USER sh -c \"$command \""
183     fi
184
185     ls -ald $MOUNT
186     echo "+ $command"
187     eval $command 2>&1 | tee $mpilog || true
188
189     rc=${PIPESTATUS[0]}
190     if [ $rc -eq 0 ] && grep -q "p4_error:" $mpilog ; then
191        rc=1
192     fi
193     return $rc
194 }
195
196 nids_list () {
197    local list
198    for i in ${1//,/ }; do
199        list="$list $i@$NETTYPE"
200    done
201    echo $list
202 }
203
204 # FIXME: all setup/cleanup can be done without rpc.sh
205 lst_end_session () {
206     local verbose=false
207     [ x$1 = x--verbose ] && verbose=true
208
209     export LST_SESSION=`$LST show_session 2>/dev/null | awk -F " " '{print $5}'`
210     [ "$LST_SESSION" == "" ] && return
211
212     if $verbose; then
213         $LST show_error c s
214     fi
215     $LST stop b
216     $LST end_session
217 }
218
219 lst_session_cleanup_all () {
220     local list=$(comma_list $(nodes_list))
221     do_rpc_nodes $list lst_end_session
222 }
223
224 lst_cleanup () {
225     lsmod | grep -q lnet_selftest && \
226         rmmod lnet_selftest > /dev/null 2>&1 || true
227 }
228
229 lst_cleanup_all () {
230    local list=$(comma_list $(nodes_list))
231
232    # lst end_session needs to be executed only locally
233    # i.e. on node where lst new_session was called
234    lst_end_session --verbose
235    do_rpc_nodes $list lst_cleanup
236 }
237
238 lst_setup () {
239     load_module lnet_selftest
240 }
241
242 lst_setup_all () {
243     local list=$(comma_list $(nodes_list))
244     do_rpc_nodes $list lst_setup
245 }
246
247 ###
248 # short_hostname
249 #
250 # Passed a single argument, strips everything off following
251 # and includes the first period.
252 # client-20.lab.whamcloud.com becomes client-20
253 short_hostname() {
254   echo $(sed 's/\..*//' <<< $1)
255 }
256
257 ###
258 # short_nodename
259 #
260 # Find remote nodename, stripped of any domain, etc.
261 # 'hostname -s' is easy, but not implemented on all systems
262 short_nodename() {
263         local rname=$(do_node $1 "uname -n" || echo -1)
264         if [[ "$rname" = "-1" ]]; then
265                 rname=$1
266         fi
267         echo $(short_hostname $rname)
268 }
269
270 print_opts () {
271     local var
272
273     echo OPTIONS:
274
275     for i in $@; do
276         var=$i
277         echo "${var}=${!var}"
278     done
279     [ -e $MACHINEFILE ] && cat $MACHINEFILE
280 }
281
282 run_compilebench() {
283         # Space estimation:
284         # compile dir kernel-0  ~1GB
285         # required space        ~1GB * cbench_IDIRS
286
287     cbench_DIR=${cbench_DIR:-""}
288     cbench_IDIRS=${cbench_IDIRS:-2}
289     cbench_RUNS=${cbench_RUNS:-2}
290
291     print_opts cbench_DIR cbench_IDIRS cbench_RUNS
292
293     [ x$cbench_DIR = x ] &&
294         { skip_env "compilebench not found" && return; }
295
296     [ -e $cbench_DIR/compilebench ] || \
297         { skip_env "No compilebench build" && return; }
298
299         local space=$(df -P $DIR | tail -n 1 | awk '{ print $4 }')
300         if [[ $space -le $((1024 * 1024 * cbench_IDIRS)) ]]; then
301                 cbench_IDIRS=$((space / 1024 / 1024))
302                 [[ $cbench_IDIRS -eq 0 ]] &&
303                         skip_env "Need free space at least 1GB, have $space" &&
304                         return
305
306                 echo "free space=$space, reducing initial dirs to $cbench_IDIRS"
307         fi
308
309     # FIXME:
310     # t-f _base needs to be modifyed to set properly tdir
311     # for new "test_foo" functions names
312     # local testdir=$DIR/$tdir
313     local testdir=$DIR/d0.compilebench
314     mkdir -p $testdir
315
316     local savePWD=$PWD
317     cd $cbench_DIR
318     local cmd="./compilebench -D $testdir -i $cbench_IDIRS \
319         -r $cbench_RUNS --makej"
320
321     log "$cmd"
322
323     local rc=0
324     eval $cmd
325     rc=$?
326
327     cd $savePWD
328     [ $rc = 0 ] || error "compilebench failed: $rc"
329     rm -rf $testdir
330 }
331
332 run_metabench() {
333
334     METABENCH=${METABENCH:-$(which metabench 2> /dev/null || true)}
335     mbench_NFILES=${mbench_NFILES:-30400}
336     # threads per client
337     mbench_THREADS=${mbench_THREADS:-4}
338
339     [ x$METABENCH = x ] &&
340         { skip_env "metabench not found" && return; }
341
342     # FIXME
343     # Need space estimation here.
344
345     print_opts METABENCH clients mbench_NFILES mbench_THREADS
346
347     local testdir=$DIR/d0.metabench
348     mkdir -p $testdir
349     # mpi_run uses mpiuser
350     chmod 0777 $testdir
351
352     # -C             Run the file creation tests.
353     # -S             Run the file stat tests.
354     # -c nfile       Number of files to be used in each test.
355     # -k             Cleanup.  Remove the test directories.
356     local cmd="$METABENCH -w $testdir -c $mbench_NFILES -C -S -k"
357     echo "+ $cmd"
358
359         # find out if we need to use srun by checking $SRUN_PARTITION
360         if [ "$SRUN_PARTITION" ]; then
361                 $SRUN $SRUN_OPTIONS -D $testdir -w $clients -N $num_clients \
362                         -n $((num_clients * mbench_THREADS)) \
363                         -p $SRUN_PARTITION -- $cmd
364         else
365                 mpi_run ${MACHINEFILE_OPTION} ${MACHINEFILE} \
366                         -np $((num_clients * $mbench_THREADS)) $cmd
367         fi
368
369     local rc=$?
370     if [ $rc != 0 ] ; then
371         error "metabench failed! $rc"
372     fi
373     rm -rf $testdir
374 }
375
376 run_simul() {
377
378     SIMUL=${SIMUL:=$(which simul 2> /dev/null || true)}
379     # threads per client
380     simul_THREADS=${simul_THREADS:-2}
381     simul_REP=${simul_REP:-20}
382
383     if [ "$NFSCLIENT" ]; then
384         skip "skipped for NFSCLIENT mode"
385         return
386     fi
387
388     [ x$SIMUL = x ] &&
389         { skip_env "simul not found" && return; }
390
391     # FIXME
392     # Need space estimation here.
393
394     print_opts SIMUL clients simul_REP simul_THREADS
395
396     local testdir=$DIR/d0.simul
397     mkdir -p $testdir
398     # mpi_run uses mpiuser
399     chmod 0777 $testdir
400
401     # -n # : repeat each test # times
402     # -N # : repeat the entire set of tests # times
403
404     local cmd="$SIMUL -d $testdir -n $simul_REP -N $simul_REP"
405
406         echo "+ $cmd"
407         # find out if we need to use srun by checking $SRUN_PARTITION
408         if [ "$SRUN_PARTITION" ]; then
409                 $SRUN $SRUN_OPTIONS -D $testdir -w $clients -N $num_clients \
410                         -n $((num_clients * simul_THREADS)) -p $SRUN_PARTITION \
411                         -- $cmd
412         else
413                 mpi_run ${MACHINEFILE_OPTION} ${MACHINEFILE} \
414                         -np $((num_clients * simul_THREADS)) $cmd
415         fi
416
417     local rc=$?
418     if [ $rc != 0 ] ; then
419         error "simul failed! $rc"
420     fi
421     rm -rf $testdir
422 }
423
424 run_mdtest() {
425
426     MDTEST=${MDTEST:=$(which mdtest 2> /dev/null || true)}
427     # threads per client
428     mdtest_THREADS=${mdtest_THREADS:-2}
429     mdtest_nFiles=${mdtest_nFiles:-"100000"}
430     # We devide the files by number of core
431     mdtest_nFiles=$((mdtest_nFiles/mdtest_THREADS/num_clients))
432     mdtest_iteration=${mdtest_iteration:-1}
433
434     local type=${1:-"ssf"}
435
436     if [ "$NFSCLIENT" ]; then
437         skip "skipped for NFSCLIENT mode"
438         return
439     fi
440
441     [ x$MDTEST = x ] &&
442         { skip_env "mdtest not found" && return; }
443
444     # FIXME
445     # Need space estimation here.
446
447     print_opts MDTEST mdtest_iteration mdtest_THREADS mdtest_nFiles
448
449     local testdir=$DIR/d0.mdtest
450     mkdir -p $testdir
451     # mpi_run uses mpiuser
452     chmod 0777 $testdir
453
454     # -i # : repeat each test # times
455     # -d   : test dir
456     # -n # : number of file/dir to create/stat/remove
457     # -u   : each process create/stat/remove individually
458
459     local cmd="$MDTEST -d $testdir -i $mdtest_iteration -n $mdtest_nFiles"
460     [ $type = "fpp" ] && cmd="$cmd -u"
461
462         echo "+ $cmd"
463         # find out if we need to use srun by checking $SRUN_PARTITION
464         if [ "$SRUN_PARTITION" ]; then
465                 $SRUN $SRUN_OPTIONS -D $testdir -w $clients -N $num_clients \
466                         -n $((num_clients * mdtest_THREADS)) \
467                         -p $SRUN_PARTITION -- $cmd
468         else
469                 mpi_run ${MACHINEFILE_OPTION} ${MACHINEFILE} \
470                         -np $((num_clients * mdtest_THREADS)) $cmd
471         fi
472
473     local rc=$?
474     if [ $rc != 0 ] ; then
475         error "mdtest failed! $rc"
476     fi
477     rm -rf $testdir
478 }
479
480 run_connectathon() {
481
482     cnt_DIR=${cnt_DIR:-""}
483     cnt_NRUN=${cnt_NRUN:-10}
484
485     print_opts cnt_DIR cnt_NRUN
486
487     [ x$cnt_DIR = x ] &&
488         { skip_env "connectathon dir not found" && return; }
489
490     [ -e $cnt_DIR/runtests ] || \
491         { skip_env "No connectathon runtests found" && return; }
492
493     local testdir=$DIR/d0.connectathon
494     mkdir -p $testdir
495
496     local savePWD=$PWD
497     cd $cnt_DIR
498
499     #
500     # cthon options (must be in this order)
501     #
502     # -N numpasses - will be passed to the runtests script.  This argument
503     #         is optional.  It specifies the number of times to run
504     #         through the tests.
505     #
506     # One of these test types
507     #    -b  basic
508     #    -g  general
509     #    -s  special
510     #    -l  lock
511     #    -a  all of the above
512     #
513     # -f      a quick functionality test
514     #
515
516     tests="-b -g -s"
517     # Include lock tests unless we're running on nfsv4
518     local fstype=$(df -TP $testdir | awk 'NR==2  {print $2}')
519     echo "$testdir: $fstype"
520     if [[ $fstype != "nfs4" ]]; then
521         tests="$tests -l"
522     fi
523     echo "tests: $tests"
524     for test in $tests; do
525         local cmd="./runtests -N $cnt_NRUN $test -f $testdir"
526         local rc=0
527
528         log "$cmd"
529         eval $cmd
530         rc=$?
531         [ $rc = 0 ] || error "connectathon failed: $rc"
532     done
533
534     cd $savePWD
535     rm -rf $testdir
536 }
537
538 run_ior() {
539     local type=${1:="ssf"}
540
541     IOR=${IOR:-$(which IOR 2> /dev/null || true)}
542     # threads per client
543     ior_THREADS=${ior_THREADS:-2}
544     ior_iteration=${ior_iteration:-1}
545     ior_blockSize=${ior_blockSize:-6}   # GB
546     ior_xferSize=${ior_xferSize:-2m}
547     ior_type=${ior_type:-POSIX}
548     ior_DURATION=${ior_DURATION:-30}    # minutes
549
550     [ x$IOR = x ] &&
551         { skip_env "IOR not found" && return; }
552
553     local space=$(df -P $DIR | tail -n 1 | awk '{ print $4 }')
554     local total_threads=$(( num_clients * ior_THREADS ))
555     echo "+ $ior_blockSize * 1024 * 1024 * $total_threads "
556     if [ $((space / 2)) -le \
557         $(( ior_blockSize * 1024 * 1024 * total_threads)) ]; then
558         echo "+ $space * 9/10 / 1024 / 1024 / $num_clients / $ior_THREADS"
559         ior_blockSize=$(( space /2 /1024 /1024 / num_clients / ior_THREADS ))
560         [ $ior_blockSize = 0 ] && \
561             skip_env "Need free space more than $((2 * total_threads))GB: \
562                 $((total_threads *1024 *1024*2)), have $space" && return
563
564         local reduced_size="$num_clients x $ior_THREADS x $ior_blockSize"
565         echo "free space=$space, Need: $reduced_size GB"
566         echo "(blockSize reduced to $ior_blockSize Gb)"
567     fi
568
569     print_opts IOR ior_THREADS ior_DURATION MACHINEFILE
570
571     local testdir=$DIR/d0.ior.$type
572     mkdir -p $testdir
573     # mpi_run uses mpiuser
574     chmod 0777 $testdir
575     if [ "$NFSCLIENT" ]; then
576         setstripe_nfsserver $testdir -c -1 ||
577             { error "setstripe on nfsserver failed" && return 1; }
578     else
579         $LFS setstripe $testdir -c -1 ||
580             { error "setstripe failed" && return 2; }
581     fi
582     #
583     # -b N  blockSize --
584     #       contiguous bytes to write per task (e.g.: 8, 4k, 2m, 1g)"
585     # -o S  testFileName
586     # -t N  transferSize -- size of transfer in bytes (e.g.: 8, 4k, 2m, 1g)"
587     # -w    writeFile -- write file"
588     # -r    readFile -- read existing file"
589     # -W    checkWrite -- check read after write"
590     # -C    reorderTasks -- changes task ordering to n+1 ordering for readback
591     # -T    maxTimeDuration -- max time in minutes to run tests"
592     # -k    keepFile -- keep testFile(s) on program exit
593
594     local cmd="$IOR -a $ior_type -b ${ior_blockSize}g -o $testdir/iorData \
595          -t $ior_xferSize -v -C -w -r -W -i $ior_iteration -T $ior_DURATION -k"
596     [ $type = "fpp" ] && cmd="$cmd -F"
597
598         echo "+ $cmd"
599         # find out if we need to use srun by checking $SRUN_PARTITION
600         if [ "$SRUN_PARTITION" ]; then
601                 $SRUN $SRUN_OPTIONS -D $testdir -w $clients -N $num_clients \
602                         -n $((num_clients * ior_THREADS)) -p $SRUN_PARTITION \
603                         -- $cmd
604         else
605                 mpi_run ${MACHINEFILE_OPTION} ${MACHINEFILE} \
606                         -np $((num_clients * $ior_THREADS)) $cmd
607         fi
608
609     local rc=$?
610     if [ $rc != 0 ] ; then
611         error "ior failed! $rc"
612     fi
613     rm -rf $testdir
614 }
615
616 run_mib() {
617
618     MIB=${MIB:=$(which mib 2> /dev/null || true)}
619     # threads per client
620     mib_THREADS=${mib_THREADS:-2}
621     mib_xferSize=${mib_xferSize:-1m}
622     mib_xferLimit=${mib_xferLimit:-5000}
623     mib_timeLimit=${mib_timeLimit:-300}
624
625     if [ "$NFSCLIENT" ]; then
626         skip "skipped for NFSCLIENT mode"
627         return
628     fi
629
630     [ x$MIB = x ] &&
631         { skip_env "MIB not found" && return; }
632
633     print_opts MIB mib_THREADS mib_xferSize mib_xferLimit mib_timeLimit \
634         MACHINEFILE
635
636     local testdir=$DIR/d0.mib
637     mkdir -p $testdir
638     # mpi_run uses mpiuser
639     chmod 0777 $testdir
640     $LFS setstripe $testdir -c -1 ||
641         { error "setstripe failed" && return 2; }
642     #
643     # -I    Show intermediate values in output
644     # -H    Show headers in output
645     # -L    Do not issue new system calls after this many seconds
646     # -s    Use system calls of this size
647     # -t    test dir
648     # -l    Issue no more than this many system calls
649     local cmd="$MIB -t $testdir -s $mib_xferSize -l $mib_xferLimit \
650         -L $mib_timeLimit -HI -p mib.$(date +%Y%m%d%H%M%S)"
651
652         echo "+ $cmd"
653         # find out if we need to use srun by checking $SRUN_PARTITION
654         if [ "$SRUN_PARTITION" ]; then
655                 $SRUN $SRUN_OPTIONS -D $testdir -w $clients -N $num_clients \
656                         -n $((num_clients * mib_THREADS)) -p $SRUN_PARTITION \
657                         -- $cmd
658         else
659                 mpi_run ${MACHINEFILE_OPTION} ${MACHINEFILE} \
660                         -np $((num_clients * mib_THREADS)) $cmd
661         fi
662
663     local rc=$?
664     if [ $rc != 0 ] ; then
665         error "mib failed! $rc"
666     fi
667     rm -rf $testdir
668 }
669
670 run_cascading_rw() {
671
672     CASC_RW=${CASC_RW:-$(which cascading_rw 2> /dev/null || true)}
673     # threads per client
674     casc_THREADS=${casc_THREADS:-2}
675     casc_REP=${casc_REP:-300}
676
677     if [ "$NFSCLIENT" ]; then
678         skip "skipped for NFSCLIENT mode"
679         return
680     fi
681
682     [ x$CASC_RW = x ] &&
683         { skip_env "cascading_rw not found" && return; }
684
685     # FIXME
686     # Need space estimation here.
687
688     print_opts CASC_RW clients casc_THREADS casc_REP MACHINEFILE
689
690     local testdir=$DIR/d0.cascading_rw
691     mkdir -p $testdir
692     # mpi_run uses mpiuser
693     chmod 0777 $testdir
694
695     # -g: debug mode
696     # -n: repeat test # times
697
698     local cmd="$CASC_RW -g -d $testdir -n $casc_REP"
699
700         echo "+ $cmd"
701         mpi_run ${MACHINEFILE_OPTION} ${MACHINEFILE} \
702                 -np $((num_clients * $casc_THREADS)) $cmd
703
704     local rc=$?
705     if [ $rc != 0 ] ; then
706         error "cascading_rw failed! $rc"
707     fi
708     rm -rf $testdir
709 }
710
711 run_write_append_truncate() {
712
713     # threads per client
714     write_THREADS=${write_THREADS:-8}
715     write_REP=${write_REP:-10000}
716
717     if [ "$NFSCLIENT" ]; then
718         skip "skipped for NFSCLIENT mode"
719         return
720     fi
721
722     # location is lustre/tests dir
723     if ! which write_append_truncate > /dev/null 2>&1 ; then
724         skip_env "write_append_truncate not found"
725         return
726     fi
727
728     # FIXME
729     # Need space estimation here.
730
731     local testdir=$DIR/d0.write_append_truncate
732     local file=$testdir/f0.wat
733
734     print_opts clients write_REP write_THREADS MACHINEFILE
735
736     mkdir -p $testdir
737     # mpi_run uses mpiuser
738     chmod 0777 $testdir
739
740     local cmd="write_append_truncate -n $write_REP $file"
741
742         echo "+ $cmd"
743         mpi_run ${MACHINEFILE_OPTION} ${MACHINEFILE} \
744                 -np $((num_clients * $write_THREADS)) $cmd
745
746     local rc=$?
747     if [ $rc != 0 ] ; then
748         error "write_append_truncate failed! $rc"
749         return $rc
750     fi
751     rm -rf $testdir
752 }
753
754 run_write_disjoint() {
755
756     WRITE_DISJOINT=${WRITE_DISJOINT:-$(which write_disjoint \
757         2> /dev/null || true)}
758     # threads per client
759     wdisjoint_THREADS=${wdisjoint_THREADS:-4}
760     wdisjoint_REP=${wdisjoint_REP:-10000}
761
762     if [ "$NFSCLIENT" ]; then
763         skip "skipped for NFSCLIENT mode"
764         return
765     fi
766
767     [ x$WRITE_DISJOINT = x ] &&
768         { skip_env "write_disjoint not found" && return; }
769
770     # FIXME
771     # Need space estimation here.
772
773     print_opts WRITE_DISJOINT clients wdisjoint_THREADS wdisjoint_REP \
774         MACHINEFILE
775     local testdir=$DIR/d0.write_disjoint
776     mkdir -p $testdir
777     # mpi_run uses mpiuser
778     chmod 0777 $testdir
779
780     local cmd="$WRITE_DISJOINT -f $testdir/file -n $wdisjoint_REP"
781
782         echo "+ $cmd"
783         mpi_run ${MACHINEFILE_OPTION} ${MACHINEFILE} \
784                 -np $((num_clients * $wdisjoint_THREADS)) $cmd
785
786     local rc=$?
787     if [ $rc != 0 ] ; then
788         error "write_disjoint failed! $rc"
789     fi
790     rm -rf $testdir
791 }
792
793 run_parallel_grouplock() {
794
795     PARALLEL_GROUPLOCK=${PARALLEL_GROUPLOCK:-$(which parallel_grouplock \
796         2> /dev/null || true)}
797     parallel_grouplock_MINTASKS=${parallel_grouplock_MINTASKS:-5}
798
799     if [ "$NFSCLIENT" ]; then
800         skip "skipped for NFSCLIENT mode"
801         return
802     fi
803
804     [ x$PARALLEL_GROUPLOCK = x ] &&
805         { skip "PARALLEL_GROUPLOCK not found" && return; }
806
807     print_opts clients parallel_grouplock_MINTASKS MACHINEFILE
808
809     local testdir=$DIR/d0.parallel_grouplock
810     mkdir -p $testdir
811     # mpi_run uses mpiuser
812     chmod 0777 $testdir
813
814     do_nodes $clients "lctl set_param llite.*.max_rw_chunk=0" ||
815         error "set_param max_rw_chunk=0 failed "
816
817     local cmd
818     local status=0
819     local subtest
820         for i in $(seq 12); do
821                 subtest="-t $i"
822                 local cmd="$PARALLEL_GROUPLOCK -g -v -d $testdir $subtest"
823                 echo "+ $cmd"
824
825                 mpi_run ${MACHINEFILE_OPTION} ${MACHINEFILE} \
826                         -np $parallel_grouplock_MINTASKS $cmd
827                 local rc=$?
828                 if [ $rc != 0 ] ; then
829                         error_noexit "parallel_grouplock subtests $subtest " \
830                                      "failed! $rc"
831                 else
832                         echo "parallel_grouplock subtests $subtest PASS"
833                 fi
834                 let status=$((status + rc))
835                 # clear debug to collect one log per one test
836                 do_nodes $(comma_list $(nodes_list)) lctl clear
837         done
838         [ $status -eq 0 ] || error "parallel_grouplock status: $status"
839         rm -rf $testdir
840 }
841
842 cleanup_statahead () {
843     trap 0
844
845     local clients=$1
846     local mntpt_root=$2
847     local num_mntpts=$3
848
849     for i in $(seq 0 $num_mntpts);do
850         zconf_umount_clients $clients ${mntpt_root}$i ||
851             error_exit "Failed to umount lustre on ${mntpt_root}$i"
852     done
853 }
854
855 run_statahead () {
856
857     statahead_NUMMNTPTS=${statahead_NUMMNTPTS:-5}
858     statahead_NUMFILES=${statahead_NUMFILES:-500000}
859
860     if [[ -n $NFSCLIENT ]]; then
861         skip "Statahead testing is not supported on NFS clients."
862         return 0
863     fi
864
865     [ x$MDSRATE = x ] &&
866         { skip_env "mdsrate not found" && return; }
867
868     print_opts MDSRATE clients statahead_NUMMNTPTS statahead_NUMFILES
869
870     # create large dir
871
872     # do not use default "d[0-9]*" dir name
873     # to avoid of rm $statahead_NUMFILES (500k) files in t-f cleanup
874     local dir=dstatahead
875     local testdir=$DIR/$dir
876
877     # cleanup only if dir exists
878     # cleanup only $statahead_NUMFILES number of files
879     # ignore the other files created by someone else
880     [ -d $testdir ] &&
881         mdsrate_cleanup $((num_clients * 32)) $MACHINEFILE \
882             $statahead_NUMFILES $testdir 'f%%d' --ignore
883
884     mkdir -p $testdir
885     # mpi_run uses mpiuser
886     chmod 0777 $testdir
887
888     local num_files=$statahead_NUMFILES
889
890     local IFree=$(inodes_available)
891     if [ $IFree -lt $num_files ]; then
892       num_files=$IFree
893     fi
894
895     cancel_lru_locks mdc
896
897     local cmd1="${MDSRATE} ${MDSRATE_DEBUG} --mknod --dir $testdir"
898     local cmd2="--nfiles $num_files --filefmt 'f%%d'"
899     local cmd="$cmd1 $cmd2"
900     echo "+ $cmd"
901
902         mpi_run ${MACHINEFILE_OPTION} ${MACHINEFILE} \
903                 -np $((num_clients * 32)) $cmd
904
905     local rc=$?
906     if [ $rc != 0 ] ; then
907         error "mdsrate failed to create $rc"
908         return $rc
909     fi
910
911     local num_mntpts=$statahead_NUMMNTPTS
912     local mntpt_root=$TMP/mntpt/lustre
913     local mntopts=$MNTOPTSTATAHEAD
914
915     echo "Mounting $num_mntpts lustre clients starts on $clients"
916     trap "cleanup_statahead $clients $mntpt_root $num_mntpts" EXIT ERR
917     for i in $(seq 0 $num_mntpts); do
918         zconf_mount_clients $clients ${mntpt_root}$i "$mntopts" ||
919             error_exit "Failed to mount lustre on ${mntpt_root}$i on $clients"
920     done
921
922     do_rpc_nodes $clients cancel_lru_locks mdc
923
924     do_rpc_nodes $clients do_ls $mntpt_root $num_mntpts $dir
925
926     mdsrate_cleanup $((num_clients * 32)) $MACHINEFILE \
927         $num_files $testdir 'f%%d' --ignore
928
929     # use rm instead of rmdir because of
930     # testdir could contain the files created by someone else,
931     # or by previous run where is num_files prev > num_files current
932     rm -rf $testdir
933     cleanup_statahead $clients $mntpt_root $num_mntpts
934 }