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