Whamcloud - gitweb
LU-3738 tests: improve posix.sh to support BASELINE_FS=zfs
[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 print_opts () {
258     local var
259
260     echo OPTIONS:
261
262     for i in $@; do
263         var=$i
264         echo "${var}=${!var}"
265     done
266     [ -e $MACHINEFILE ] && cat $MACHINEFILE
267 }
268
269 run_compilebench() {
270         # Space estimation:
271         # compile dir kernel-0  ~1GB
272         # required space        ~1GB * cbench_IDIRS
273
274     cbench_DIR=${cbench_DIR:-""}
275     cbench_IDIRS=${cbench_IDIRS:-2}
276     cbench_RUNS=${cbench_RUNS:-2}
277
278     print_opts cbench_DIR cbench_IDIRS cbench_RUNS
279
280     [ x$cbench_DIR = x ] &&
281         { skip_env "compilebench not found" && return; }
282
283     [ -e $cbench_DIR/compilebench ] || \
284         { skip_env "No compilebench build" && return; }
285
286         local space=$(lfs_df $DIR | awk '/^filesystem/{ print $4 }')
287         if [[ $space -le $((1024 * 1024 * cbench_IDIRS)) ]]; then
288                 cbench_IDIRS=$((space / 1024 / 1024))
289                 [[ $cbench_IDIRS -eq 0 ]] &&
290                         skip_env "Need free space at least 1GB, have $space" &&
291                         return
292
293                 echo "free space=$space, reducing initial dirs to $cbench_IDIRS"
294         fi
295
296     # FIXME:
297     # t-f _base needs to be modifyed to set properly tdir
298     # for new "test_foo" functions names
299     # local testdir=$DIR/$tdir
300     local testdir=$DIR/d0.compilebench
301     mkdir -p $testdir
302
303     local savePWD=$PWD
304     cd $cbench_DIR
305     local cmd="./compilebench -D $testdir -i $cbench_IDIRS \
306         -r $cbench_RUNS --makej"
307
308     log "$cmd"
309
310     local rc=0
311     eval $cmd
312     rc=$?
313
314     cd $savePWD
315     [ $rc = 0 ] || error "compilebench failed: $rc"
316     rm -rf $testdir
317 }
318
319 run_metabench() {
320
321     METABENCH=${METABENCH:-$(which metabench 2> /dev/null || true)}
322     mbench_NFILES=${mbench_NFILES:-30400}
323     # threads per client
324     mbench_THREADS=${mbench_THREADS:-4}
325
326     [ x$METABENCH = x ] &&
327         { skip_env "metabench not found" && return; }
328
329     # FIXME
330     # Need space estimation here.
331
332     print_opts METABENCH clients mbench_NFILES mbench_THREADS
333
334     local testdir=$DIR/d0.metabench
335     mkdir -p $testdir
336     # mpi_run uses mpiuser
337     chmod 0777 $testdir
338
339     # -C             Run the file creation tests.
340     # -S             Run the file stat tests.
341     # -c nfile       Number of files to be used in each test.
342     # -k             Cleanup.  Remove the test directories.
343     local cmd="$METABENCH -w $testdir -c $mbench_NFILES -C -S -k"
344     echo "+ $cmd"
345
346         # find out if we need to use srun by checking $SRUN_PARTITION
347         if [ "$SRUN_PARTITION" ]; then
348                 $SRUN $SRUN_OPTIONS -D $testdir -w $clients -N $num_clients \
349                         -n $((num_clients * mbench_THREADS)) \
350                         -p $SRUN_PARTITION -- $cmd
351         else
352                 mpi_run -np $((num_clients * $mbench_THREADS)) \
353                         ${MACHINEFILE_OPTION} ${MACHINEFILE} $cmd
354         fi
355
356     local rc=$?
357     if [ $rc != 0 ] ; then
358         error "metabench failed! $rc"
359     fi
360     rm -rf $testdir
361 }
362
363 run_simul() {
364
365     SIMUL=${SIMUL:=$(which simul 2> /dev/null || true)}
366     # threads per client
367     simul_THREADS=${simul_THREADS:-2}
368     simul_REP=${simul_REP:-20}
369
370     if [ "$NFSCLIENT" ]; then
371         skip "skipped for NFSCLIENT mode"
372         return
373     fi
374
375     [ x$SIMUL = x ] &&
376         { skip_env "simul not found" && return; }
377
378     # FIXME
379     # Need space estimation here.
380
381     print_opts SIMUL clients simul_REP simul_THREADS
382
383     local testdir=$DIR/d0.simul
384     mkdir -p $testdir
385     # mpi_run uses mpiuser
386     chmod 0777 $testdir
387
388     # -n # : repeat each test # times
389     # -N # : repeat the entire set of tests # times
390
391     local cmd="$SIMUL -d $testdir -n $simul_REP -N $simul_REP"
392
393         echo "+ $cmd"
394         # find out if we need to use srun by checking $SRUN_PARTITION
395         if [ "$SRUN_PARTITION" ]; then
396                 $SRUN $SRUN_OPTIONS -D $testdir -w $clients -N $num_clients \
397                         -n $((num_clients * simul_THREADS)) -p $SRUN_PARTITION \
398                         -- $cmd
399         else
400                 mpi_run -np $((num_clients * simul_THREADS)) \
401                         ${MACHINEFILE_OPTION} ${MACHINEFILE} $cmd
402         fi
403
404     local rc=$?
405     if [ $rc != 0 ] ; then
406         error "simul failed! $rc"
407     fi
408     rm -rf $testdir
409 }
410
411 run_mdtest() {
412
413     MDTEST=${MDTEST:=$(which mdtest 2> /dev/null || true)}
414     # threads per client
415     mdtest_THREADS=${mdtest_THREADS:-2}
416     mdtest_nFiles=${mdtest_nFiles:-"100000"}
417     # We devide the files by number of core
418     mdtest_nFiles=$((mdtest_nFiles/mdtest_THREADS/num_clients))
419     mdtest_iteration=${mdtest_iteration:-1}
420
421     local type=${1:-"ssf"}
422
423     if [ "$NFSCLIENT" ]; then
424         skip "skipped for NFSCLIENT mode"
425         return
426     fi
427
428     [ x$MDTEST = x ] &&
429         { skip_env "mdtest not found" && return; }
430
431     # FIXME
432     # Need space estimation here.
433
434     print_opts MDTEST mdtest_iteration mdtest_THREADS mdtest_nFiles
435
436     local testdir=$DIR/d0.mdtest
437     mkdir -p $testdir
438     # mpi_run uses mpiuser
439     chmod 0777 $testdir
440
441     # -i # : repeat each test # times
442     # -d   : test dir
443     # -n # : number of file/dir to create/stat/remove
444     # -u   : each process create/stat/remove individually
445
446     local cmd="$MDTEST -d $testdir -i $mdtest_iteration -n $mdtest_nFiles"
447     [ $type = "fpp" ] && cmd="$cmd -u"
448
449         echo "+ $cmd"
450         # find out if we need to use srun by checking $SRUN_PARTITION
451         if [ "$SRUN_PARTITION" ]; then
452                 $SRUN $SRUN_OPTIONS -D $testdir -w $clients -N $num_clients \
453                         -n $((num_clients * mdtest_THREADS)) \
454                         -p $SRUN_PARTITION -- $cmd
455         else
456                 mpi_run -np $((num_clients * mdtest_THREADS)) \
457                         ${MACHINEFILE_OPTION} ${MACHINEFILE} $cmd
458         fi
459
460     local rc=$?
461     if [ $rc != 0 ] ; then
462         error "mdtest failed! $rc"
463     fi
464     rm -rf $testdir
465 }
466
467 run_connectathon() {
468
469     cnt_DIR=${cnt_DIR:-""}
470     cnt_NRUN=${cnt_NRUN:-10}
471
472     print_opts cnt_DIR cnt_NRUN
473
474     [ x$cnt_DIR = x ] &&
475         { skip_env "connectathon dir not found" && return; }
476
477     [ -e $cnt_DIR/runtests ] || \
478         { skip_env "No connectathon runtests found" && return; }
479
480     local testdir=$DIR/d0.connectathon
481     mkdir -p $testdir
482
483     local savePWD=$PWD
484     cd $cnt_DIR
485
486     #
487     # cthon options (must be in this order)
488     #
489     # -N numpasses - will be passed to the runtests script.  This argument
490     #         is optional.  It specifies the number of times to run
491     #         through the tests.
492     #
493     # One of these test types
494     #    -b  basic
495     #    -g  general
496     #    -s  special
497     #    -l  lock
498     #    -a  all of the above
499     #
500     # -f      a quick functionality test
501     #
502
503     tests="-b -g -s"
504     # Include lock tests unless we're running on nfsv4
505     local fstype=$(df -TP $testdir | awk 'NR==2  {print $2}')
506     echo "$testdir: $fstype"
507     if [[ $fstype != "nfs4" ]]; then
508         tests="$tests -l"
509     fi
510     echo "tests: $tests"
511     for test in $tests; do
512         local cmd="./runtests -N $cnt_NRUN $test -f $testdir"
513         local rc=0
514
515         log "$cmd"
516         eval $cmd
517         rc=$?
518         [ $rc = 0 ] || error "connectathon failed: $rc"
519     done
520
521     cd $savePWD
522     rm -rf $testdir
523 }
524
525 run_ior() {
526     local type=${1:="ssf"}
527
528     IOR=${IOR:-$(which IOR 2> /dev/null || true)}
529     # threads per client
530     ior_THREADS=${ior_THREADS:-2}
531     ior_iteration=${ior_iteration:-1}
532     ior_blockSize=${ior_blockSize:-6}   # GB
533     ior_xferSize=${ior_xferSize:-2m}
534     ior_type=${ior_type:-POSIX}
535     ior_DURATION=${ior_DURATION:-30}    # minutes
536
537     [ x$IOR = x ] &&
538         { skip_env "IOR not found" && return; }
539
540     local space=$(df -P $DIR | tail -n 1 | awk '{ print $4 }')
541     local total_threads=$(( num_clients * ior_THREADS ))
542     echo "+ $ior_blockSize * 1024 * 1024 * $total_threads "
543     if [ $((space / 2)) -le \
544         $(( ior_blockSize * 1024 * 1024 * total_threads)) ]; then
545         echo "+ $space * 9/10 / 1024 / 1024 / $num_clients / $ior_THREADS"
546         ior_blockSize=$(( space /2 /1024 /1024 / num_clients / ior_THREADS ))
547         [ $ior_blockSize = 0 ] && \
548             skip_env "Need free space more than $((2 * total_threads))GB: \
549                 $((total_threads *1024 *1024*2)), have $space" && return
550
551         local reduced_size="$num_clients x $ior_THREADS x $ior_blockSize"
552         echo "free space=$space, Need: $reduced_size GB"
553         echo "(blockSize reduced to $ior_blockSize Gb)"
554     fi
555
556     print_opts IOR ior_THREADS ior_DURATION MACHINEFILE
557
558     local testdir=$DIR/d0.ior.$type
559     mkdir -p $testdir
560     # mpi_run uses mpiuser
561     chmod 0777 $testdir
562     if [ "$NFSCLIENT" ]; then
563         setstripe_nfsserver $testdir -c -1 ||
564             { error "setstripe on nfsserver failed" && return 1; }
565     else
566         $LFS setstripe $testdir -c -1 ||
567             { error "setstripe failed" && return 2; }
568     fi
569     #
570     # -b N  blockSize --
571     #       contiguous bytes to write per task (e.g.: 8, 4k, 2m, 1g)"
572     # -o S  testFileName
573     # -t N  transferSize -- size of transfer in bytes (e.g.: 8, 4k, 2m, 1g)"
574     # -w    writeFile -- write file"
575     # -r    readFile -- read existing file"
576     # -T    maxTimeDuration -- max time in minutes to run tests"
577     # -k    keepFile -- keep testFile(s) on program exit
578
579     local cmd="$IOR -a $ior_type -b ${ior_blockSize}g -o $testdir/iorData \
580          -t $ior_xferSize -v -w -r -i $ior_iteration -T $ior_DURATION -k"
581     [ $type = "fpp" ] && cmd="$cmd -F"
582
583         echo "+ $cmd"
584         # find out if we need to use srun by checking $SRUN_PARTITION
585         if [ "$SRUN_PARTITION" ]; then
586                 $SRUN $SRUN_OPTIONS -D $testdir -w $clients -N $num_clients \
587                         -n $((num_clients * ior_THREADS)) -p $SRUN_PARTITION \
588                         -- $cmd
589         else
590                 mpi_run -np $((num_clients * $ior_THREADS)) \
591                         ${MACHINEFILE_OPTION} ${MACHINEFILE} $cmd
592         fi
593
594     local rc=$?
595     if [ $rc != 0 ] ; then
596         error "ior failed! $rc"
597     fi
598     rm -rf $testdir
599 }
600
601 run_mib() {
602
603     MIB=${MIB:=$(which mib 2> /dev/null || true)}
604     # threads per client
605     mib_THREADS=${mib_THREADS:-2}
606     mib_xferSize=${mib_xferSize:-1m}
607     mib_xferLimit=${mib_xferLimit:-5000}
608     mib_timeLimit=${mib_timeLimit:-300}
609
610     if [ "$NFSCLIENT" ]; then
611         skip "skipped for NFSCLIENT mode"
612         return
613     fi
614
615     [ x$MIB = x ] &&
616         { skip_env "MIB not found" && return; }
617
618     print_opts MIB mib_THREADS mib_xferSize mib_xferLimit mib_timeLimit \
619         MACHINEFILE
620
621     local testdir=$DIR/d0.mib
622     mkdir -p $testdir
623     # mpi_run uses mpiuser
624     chmod 0777 $testdir
625     $LFS setstripe $testdir -c -1 ||
626         { error "setstripe failed" && return 2; }
627     #
628     # -I    Show intermediate values in output
629     # -H    Show headers in output
630     # -L    Do not issue new system calls after this many seconds
631     # -s    Use system calls of this size
632     # -t    test dir
633     # -l    Issue no more than this many system calls
634     local cmd="$MIB -t $testdir -s $mib_xferSize -l $mib_xferLimit \
635         -L $mib_timeLimit -HI -p mib.$(date +%Y%m%d%H%M%S)"
636
637         echo "+ $cmd"
638         # find out if we need to use srun by checking $SRUN_PARTITION
639         if [ "$SRUN_PARTITION" ]; then
640                 $SRUN $SRUN_OPTIONS -D $testdir -w $clients -N $num_clients \
641                         -n $((num_clients * mib_THREADS)) -p $SRUN_PARTITION \
642                         -- $cmd
643         else
644                 mpi_run -np $((num_clients * mib_THREADS)) \
645                         ${MACHINEFILE_OPTION} ${MACHINEFILE} $cmd
646         fi
647
648     local rc=$?
649     if [ $rc != 0 ] ; then
650         error "mib failed! $rc"
651     fi
652     rm -rf $testdir
653 }
654
655 run_cascading_rw() {
656
657     CASC_RW=${CASC_RW:-$(which cascading_rw 2> /dev/null || true)}
658     # threads per client
659     casc_THREADS=${casc_THREADS:-2}
660     casc_REP=${casc_REP:-300}
661
662     if [ "$NFSCLIENT" ]; then
663         skip "skipped for NFSCLIENT mode"
664         return
665     fi
666
667     [ x$CASC_RW = x ] &&
668         { skip_env "cascading_rw not found" && return; }
669
670     # FIXME
671     # Need space estimation here.
672
673     print_opts CASC_RW clients casc_THREADS casc_REP MACHINEFILE
674
675     local testdir=$DIR/d0.cascading_rw
676     mkdir -p $testdir
677     # mpi_run uses mpiuser
678     chmod 0777 $testdir
679
680     # -g: debug mode
681     # -n: repeat test # times
682
683     local cmd="$CASC_RW -g -d $testdir -n $casc_REP"
684
685         echo "+ $cmd"
686         mpi_run -np $((num_clients * $casc_THREADS)) ${MACHINEFILE_OPTION} \
687                 ${MACHINEFILE} $cmd
688
689     local rc=$?
690     if [ $rc != 0 ] ; then
691         error "cascading_rw failed! $rc"
692     fi
693     rm -rf $testdir
694 }
695
696 run_write_append_truncate() {
697
698     # threads per client
699     write_THREADS=${write_THREADS:-8}
700     write_REP=${write_REP:-10000}
701
702     if [ "$NFSCLIENT" ]; then
703         skip "skipped for NFSCLIENT mode"
704         return
705     fi
706
707     # location is lustre/tests dir
708     if ! which write_append_truncate > /dev/null 2>&1 ; then
709         skip_env "write_append_truncate not found"
710         return
711     fi
712
713     # FIXME
714     # Need space estimation here.
715
716     local testdir=$DIR/d0.write_append_truncate
717     local file=$testdir/f0.wat
718
719     print_opts clients write_REP write_THREADS MACHINEFILE
720
721     mkdir -p $testdir
722     # mpi_run uses mpiuser
723     chmod 0777 $testdir
724
725     local cmd="write_append_truncate -n $write_REP $file"
726
727         echo "+ $cmd"
728         mpi_run -np $((num_clients * $write_THREADS)) ${MACHINEFILE_OPTION} \
729                 ${MACHINEFILE} $cmd
730
731     local rc=$?
732     if [ $rc != 0 ] ; then
733         error "write_append_truncate failed! $rc"
734         return $rc
735     fi
736     rm -rf $testdir
737 }
738
739 run_write_disjoint() {
740
741     WRITE_DISJOINT=${WRITE_DISJOINT:-$(which write_disjoint \
742         2> /dev/null || true)}
743     # threads per client
744     wdisjoint_THREADS=${wdisjoint_THREADS:-4}
745     wdisjoint_REP=${wdisjoint_REP:-10000}
746
747     if [ "$NFSCLIENT" ]; then
748         skip "skipped for NFSCLIENT mode"
749         return
750     fi
751
752     [ x$WRITE_DISJOINT = x ] &&
753         { skip_env "write_disjoint not found" && return; }
754
755     # FIXME
756     # Need space estimation here.
757
758     print_opts WRITE_DISJOINT clients wdisjoint_THREADS wdisjoint_REP \
759         MACHINEFILE
760     local testdir=$DIR/d0.write_disjoint
761     mkdir -p $testdir
762     # mpi_run uses mpiuser
763     chmod 0777 $testdir
764
765     local cmd="$WRITE_DISJOINT -f $testdir/file -n $wdisjoint_REP"
766
767         echo "+ $cmd"
768         mpi_run -np $((num_clients * $wdisjoint_THREADS)) \
769                 ${MACHINEFILE_OPTION} ${MACHINEFILE} $cmd
770
771     local rc=$?
772     if [ $rc != 0 ] ; then
773         error "write_disjoint failed! $rc"
774     fi
775     rm -rf $testdir
776 }
777
778 run_parallel_grouplock() {
779
780     PARALLEL_GROUPLOCK=${PARALLEL_GROUPLOCK:-$(which parallel_grouplock \
781         2> /dev/null || true)}
782     parallel_grouplock_MINTASKS=${parallel_grouplock_MINTASKS:-5}
783
784     if [ "$NFSCLIENT" ]; then
785         skip "skipped for NFSCLIENT mode"
786         return
787     fi
788
789     [ x$PARALLEL_GROUPLOCK = x ] &&
790         { skip "PARALLEL_GROUPLOCK not found" && return; }
791
792     print_opts clients parallel_grouplock_MINTASKS MACHINEFILE
793
794     local testdir=$DIR/d0.parallel_grouplock
795     mkdir -p $testdir
796     # mpi_run uses mpiuser
797     chmod 0777 $testdir
798
799     do_nodes $clients "lctl set_param llite.*.max_rw_chunk=0" ||
800         error "set_param max_rw_chunk=0 failed "
801
802     local cmd
803     local status=0
804     local subtest
805         for i in $(seq 12); do
806                 subtest="-t $i"
807                 local cmd="$PARALLEL_GROUPLOCK -g -v -d $testdir $subtest"
808                 echo "+ $cmd"
809
810                 mpi_run -np $parallel_grouplock_MINTASKS ${MACHINEFILE_OPTION} \
811                         ${MACHINEFILE} $cmd
812                 local rc=$?
813                 if [ $rc != 0 ] ; then
814                         error_noexit "parallel_grouplock subtests $subtest " \
815                                      "failed! $rc"
816                 else
817                         echo "parallel_grouplock subtests $subtest PASS"
818                 fi
819                 let status=$((status + rc))
820                 # clear debug to collect one log per one test
821                 do_nodes $(comma_list $(nodes_list)) lctl clear
822         done
823         [ $status -eq 0 ] || error "parallel_grouplock status: $status"
824         rm -rf $testdir
825 }
826
827 cleanup_statahead () {
828     trap 0
829
830     local clients=$1
831     local mntpt_root=$2
832     local num_mntpts=$3
833
834     for i in $(seq 0 $num_mntpts);do
835         zconf_umount_clients $clients ${mntpt_root}$i ||
836             error_exit "Failed to umount lustre on ${mntpt_root}$i"
837     done
838 }
839
840 run_statahead () {
841
842     statahead_NUMMNTPTS=${statahead_NUMMNTPTS:-5}
843     statahead_NUMFILES=${statahead_NUMFILES:-500000}
844
845     if [[ -n $NFSCLIENT ]]; then
846         skip "Statahead testing is not supported on NFS clients."
847         return 0
848     fi
849
850     [ x$MDSRATE = x ] &&
851         { skip_env "mdsrate not found" && return; }
852
853     print_opts MDSRATE clients statahead_NUMMNTPTS statahead_NUMFILES
854
855     # create large dir
856
857     # do not use default "d[0-9]*" dir name
858     # to avoid of rm $statahead_NUMFILES (500k) files in t-f cleanup
859     local dir=dstatahead
860     local testdir=$DIR/$dir
861
862     # cleanup only if dir exists
863     # cleanup only $statahead_NUMFILES number of files
864     # ignore the other files created by someone else
865     [ -d $testdir ] &&
866         mdsrate_cleanup $((num_clients * 32)) $MACHINEFILE \
867             $statahead_NUMFILES $testdir 'f%%d' --ignore
868
869     mkdir -p $testdir
870     # mpi_run uses mpiuser
871     chmod 0777 $testdir
872
873     local num_files=$statahead_NUMFILES
874
875     local IFree=$(inodes_available)
876     if [ $IFree -lt $num_files ]; then
877       num_files=$IFree
878     fi
879
880     cancel_lru_locks mdc
881
882     local cmd1="${MDSRATE} ${MDSRATE_DEBUG} --mknod --dir $testdir"
883     local cmd2="--nfiles $num_files --filefmt 'f%%d'"
884     local cmd="$cmd1 $cmd2"
885     echo "+ $cmd"
886
887         mpi_run -np $((num_clients * 32)) ${MACHINEFILE_OPTION} ${MACHINEFILE} \
888                 $cmd
889
890     local rc=$?
891     if [ $rc != 0 ] ; then
892         error "mdsrate failed to create $rc"
893         return $rc
894     fi
895
896     local num_mntpts=$statahead_NUMMNTPTS
897     local mntpt_root=$TMP/mntpt/lustre
898     local mntopts=${MNTOPTSTATAHEAD:-$MOUNTOPT}
899
900     echo "Mounting $num_mntpts lustre clients starts on $clients"
901     trap "cleanup_statahead $clients $mntpt_root $num_mntpts" EXIT ERR
902     for i in $(seq 0 $num_mntpts); do
903         zconf_mount_clients $clients ${mntpt_root}$i "$mntopts" ||
904             error_exit "Failed to mount lustre on ${mntpt_root}$i on $clients"
905     done
906
907     do_rpc_nodes $clients cancel_lru_locks mdc
908
909     do_rpc_nodes $clients do_ls $mntpt_root $num_mntpts $dir
910
911     mdsrate_cleanup $((num_clients * 32)) $MACHINEFILE \
912         $num_files $testdir 'f%%d' --ignore
913
914     # use rm instead of rmdir because of
915     # testdir could contain the files created by someone else,
916     # or by previous run where is num_files prev > num_files current
917     rm -rf $testdir
918     cleanup_statahead $clients $mntpt_root $num_mntpts
919 }