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