Whamcloud - gitweb
LU-16138 kernel: preserve RHEL8.x server kABI for block integrity
[fs/lustre-release.git] / lustre / tests / functions.sh
1 #!/bin/bash
2
3 # Simple function used by run_*.sh scripts
4
5 assert_env() {
6         local failed=""
7
8         for name in "$@"; do
9         if [ -z "${!name}" ]; then
10                 echo "$0: $name must be set"
11                 failed=1
12         fi
13         done
14         [ $failed ] && exit 1 || true
15 }
16
17 # lrepl - Lustre test Read-Eval-Print Loop.
18 #
19 # This function implements a REPL for the Lustre test framework.  It
20 # doesn't exec an actual shell because the user may want to inspect
21 # variables and use functions from the test framework.
22 lrepl() {
23         local line
24         local rawline
25         local prompt
26
27         cat <<EOF
28         This is an interactive read-eval-print loop interactive shell
29         simulation that you can use to debug failing tests.  You can
30         enter most bash command lines (see notes below).
31
32         Use this REPL to inspect variables, set them, call test
33         framework shell functions, etcetera.
34
35         'exit' or EOF to exit this shell.
36
37         set \$retcode to 0 to cause the assertion failure that
38         triggered this REPL to be ignored.
39
40         Examples:
41             do_facet ost1 lctl get_param ost.*.ost.threads_*
42             do_rpc_nodes \$OSTNODES unload_modules
43
44         NOTES:
45             All but the last line of multi-line statements or blocks
46             must end in a backslash.
47
48             "Here documents" are not supported.
49
50             History is not supported, but command-line editing is.
51
52 EOF
53
54         # Prompt escapes don't work in read -p, sadly.
55         prompt=":${TESTNAME:-UNKNOWN}:$(uname -n):$(basename $PWD)% "
56
57         # We use read -r to get close to a shell experience
58         while read -e -r -p "$prompt" rawline; do
59         line=
60         case "$rawline" in
61         # Don't want to exit-exit, just exit the REPL
62         exit) break;;
63         # We need to handle continuations, and read -r doesn't do
64         # that for us.  Yet we need read -r.
65         #
66         # We also use case/esac to compare lines read to "*\\"
67         # because [ "$line" = *\\ ] and variants of that don't work.
68         *\\) line="$rawline"
69                 while read -e -r -p '> ' rawline
70                 do
71                         line="$line"$'\n'"$rawline"
72                         case "$rawline" in
73                         # We could check for here documents by matching
74                         # against *<<*, but who cares.
75                         *\\) continue;;
76                         *) break;;
77                         esac
78                 done
79                 ;;
80         *) line=$rawline
81         esac
82
83         case "$line" in
84         *\\) break;;
85         esac
86
87         # Finally!  Time to eval.
88         eval "$line"
89         done
90
91         echo $'\n\tExiting interactive shell...\n'
92         return 0
93 }
94
95 # lassert - Lustre test framework assert
96 #
97 # Arguments: failure code, failure message, expression/statement
98 #
99 # lassert evaluates the expression given, and, if false, calls
100 # error() to trigger test failure.  If REPL_ON_LASSERT is true then
101 # lassert will call lrepl() to give the user an interactive shell.
102 # If the REPL sets retcode=0 then the assertion failure will be
103 # ignored.
104 lassert() {
105         local retcode=$1
106         local msg=$2
107         shift 2
108
109         echo "checking $* ($(eval echo \""$*"\"))..."
110         eval "$@" && return 0;
111
112         if ${REPL_ON_LASSERT:-false}; then
113                 echo "Assertion $retcode failed: $*
114                         (expanded: $(eval echo \""$*"\")) $msg"
115                 lrepl
116         fi
117
118         error "Assertion $retcode failed: $*
119                 (expanded: $(eval echo \""$*"\")) $msg"
120         return $retcode
121 }
122
123 # setmodopts- set module options for subsequent calls to load_modules
124 #
125 # Usage: setmodopts module_name new_value [var_in_which_to_save_old_value]
126 #        setmodopts -a module_name new_value [var_in_which_to_save_old_value]
127 #
128 # In the second usage the new value is appended to the old.
129 setmodopts() {
130         local _append=false
131
132         if [ "$1" = -a ]; then
133                 _append=true
134                 shift
135         fi
136
137         local _var=MODOPTS_$1
138         local _newvalue=$2
139         local _savevar=$3
140         local _oldvalue
141
142         # Dynamic naming of variables is a pain in bash.  In ksh93 we could
143         # write "nameref opts_var=${modname}_MODOPTS" then assign directly
144         # to opts_var.  Associative arrays would also help, alternatively.
145         # Alas, we're stuck with eval until all distros move to a more recent
146         # version of bash.  Fortunately we don't need to eval unset and export.
147
148         if [ -z "$_newvalue" ]; then
149                 unset $_var
150                 return 0
151         fi
152
153         _oldvalue=${!_var}
154         $_append && _newvalue="$_oldvalue $_newvalue"
155         export $_var="$_newvalue"
156         echo setmodopts: ${_var}=${_newvalue}
157
158         [ -n "$_savevar" ] && eval $_savevar=\""$_oldvalue"\"
159 }
160
161 echoerr () { echo "$@" 1>&2 ; }
162
163 signaled() {
164         echoerr "$(date +'%F %H:%M:%S'): client load was signaled to terminate"
165
166         local PGID=$(ps -eo "%c %p %r" | awk "/ $PPID / {print \$3}")
167         kill -TERM -$PGID
168         sleep 5
169         kill -KILL -$PGID
170 }
171
172 mpi_run () {
173         local mpirun="$MPIRUN $MPIRUN_OPTIONS"
174         local command="$mpirun $@"
175         local mpilog=$TMP/mpi.log
176         local rc
177
178         if [ -n "$MPI_USER" -a "$MPI_USER" != root -a -n "$mpirun" ]; then
179                 echo "+ chmod 0777 $MOUNT"
180                 chmod 0777 $MOUNT
181                 command="su $MPI_USER bash -c \"$command \""
182         fi
183
184         ls -ald $MOUNT
185         echo "+ $command"
186         eval $command 2>&1 | tee $mpilog || true
187
188         rc=${PIPESTATUS[0]}
189         if [ $rc -eq 0 ] && grep -q "p4_error:" $mpilog ; then
190                 rc=1
191         fi
192         return $rc
193 }
194
195 nids_list () {
196         local list
197         local escape="$2"
198         for i in ${1//,/ }; do
199                 if [ "$list" = "" ]; then
200                         list="$i@$NETTYPE"
201                 else
202                         list="$list$escape $i@$NETTYPE"
203                 fi
204         done
205         echo $list
206 }
207
208 # FIXME: all setup/cleanup can be done without rpc.sh
209 lst_end_session () {
210         local verbose=false
211         [ x$1 = x--verbose ] && verbose=true
212
213         export LST_SESSION=`$LST show_session 2>/dev/null | awk '{print $5}'`
214         [ "$LST_SESSION" == "" ] && return
215
216         $LST stop b
217         if $verbose; then
218                 $LST show_error c s
219         fi
220         $LST end_session
221 }
222
223 lst_session_cleanup_all () {
224         local list=$(comma_list $(nodes_list))
225         do_rpc_nodes $list lst_end_session
226 }
227
228 lst_cleanup () {
229         lsmod | grep -q lnet_selftest && \
230                 rmmod lnet_selftest > /dev/null 2>&1 || true
231 }
232
233 lst_cleanup_all () {
234         local list=$(comma_list $(nodes_list))
235
236         # lst end_session needs to be executed only locally
237         # i.e. on node where lst new_session was called
238         lst_end_session --verbose
239         do_rpc_nodes $list lst_cleanup
240 }
241
242 lst_setup () {
243         load_module lnet_selftest
244 }
245
246 lst_setup_all () {
247         local list=$(comma_list $(nodes_list))
248         do_rpc_nodes $list lst_setup
249 }
250
251 ###
252 # short_hostname
253 #
254 # Passed a single argument, strips everything off following
255 # and includes the first period.
256 # client-20.lab.whamcloud.com becomes client-20
257 short_hostname() {
258         echo $(sed 's/\..*//' <<< $1)
259 }
260
261 ###
262 # short_nodename
263 #
264 # Find remote nodename, stripped of any domain, etc.
265 # 'hostname -s' is easy, but not implemented on all systems
266 short_nodename() {
267         local rname=$(do_node $1 "uname -n" || echo -1)
268         if [[ "$rname" = "-1" ]]; then
269                 rname=$1
270         fi
271         echo $(short_hostname $rname)
272 }
273
274 print_opts () {
275         local var
276
277         echo OPTIONS:
278
279         for i in "$@"; do
280                 var=$i
281                 echo "${var}=${!var}"
282         done
283         [ -e $MACHINEFILE ] && cat $MACHINEFILE
284 }
285
286 is_lustre () {
287         [ "$(stat -f -c %T $1)" = "lustre" ]
288 }
289
290 setstripe_getstripe () {
291         local file=$1
292         shift
293         local params=$@
294
295         is_lustre $file || return 0
296
297         if [ -n "$params" ]; then
298                 $LFS setstripe $params $file ||
299                         error "setstripe $params failed"
300         fi
301         $LFS getstripe $file ||
302                 error "getstripe $file failed"
303 }
304
305 run_compilebench() {
306         local dir=${1:-$DIR}
307         local cbench_DIR=${cbench_DIR:-""}
308         local cbench_IDIRS=${cbench_IDIRS:-2}
309         local cbench_RUNS=${cbench_RUNS:-2}
310
311         print_opts cbench_DIR cbench_IDIRS cbench_RUNS
312
313         [ x$cbench_DIR = x ] &&
314                 skip_env "compilebench not found"
315
316         [ -e $cbench_DIR/compilebench ] ||
317                 skip_env "No compilebench build"
318
319         # Space estimation:
320         # compile dir kernel-0  ~1GB
321         # required space        ~1GB * cbench_IDIRS
322         local space=$(df -P $dir | tail -n 1 | awk '{ print $4 }')
323         if [[ $space -le $((1024 * 1024 * cbench_IDIRS)) ]]; then
324                 cbench_IDIRS=$((space / 1024 / 1024))
325                 [[ $cbench_IDIRS -eq 0 ]] &&
326                         skip_env "Need free space at least 1GB, have $space"
327
328                 echo "reducing initial dirs to $cbench_IDIRS"
329         fi
330         echo "free space = $space KB"
331
332         # FIXME:
333         # t-f _base needs to be modifyed to set properly tdir
334         # for new "test_foo" functions names
335         # local testdir=$DIR/$tdir
336         local testdir=$dir/d0.compilebench.$$
337         test_mkdir -p $testdir
338         setstripe_getstripe $testdir $cbench_STRIPEPARAMS
339
340         local savePWD=$PWD
341         cd $cbench_DIR
342         local cmd="./compilebench -D $testdir -i $cbench_IDIRS \
343                 -r $cbench_RUNS --makej"
344
345         log "$cmd"
346
347         local rc=0
348         eval $cmd
349         rc=$?
350
351         cd $savePWD
352         [ $rc = 0 ] || error "compilebench failed: $rc"
353         rm -rf $testdir
354 }
355
356 run_metabench() {
357         local dir=${1:-$DIR}
358         local mntpt=${2:-$MOUNT}
359         METABENCH=${METABENCH:-$(which metabench 2> /dev/null || true)}
360         mbench_NFILES=${mbench_NFILES:-30400}
361         # threads per client
362         mbench_THREADS=${mbench_THREADS:-4}
363         mbench_OPTIONS=${mbench_OPTIONS:-}
364         mbench_CLEANUP=${mbench_CLEANUP:-true}
365
366         [ x$METABENCH = x ] && skip_env "metabench not found"
367
368         print_opts METABENCH clients mbench_NFILES mbench_THREADS
369
370         local testdir=$dir/d0.metabench
371         test_mkdir -p $testdir
372         setstripe_getstripe $testdir $mbench_STRIPEPARAMS
373
374         # mpi_run uses mpiuser
375         chmod 0777 $testdir
376
377         # -C             Run the file creation tests. Creates zero byte files.
378         # -S             Run the file stat tests.
379         # -c nfile       Number of files to be used in each test.
380         # -k             Cleanup files when finished.
381         local cmd="$METABENCH -w $testdir -c $mbench_NFILES -C -S $mbench_OPTIONS"
382         echo "+ $cmd"
383
384         # find out if we need to use srun by checking $SRUN_PARTITION
385         if [ "$SRUN_PARTITION" ]; then
386                 $SRUN $SRUN_OPTIONS -D $testdir -w $clients -N $num_clients \
387                         -n $((num_clients * mbench_THREADS)) \
388                         -p $SRUN_PARTITION -- $cmd
389         else
390                 mpi_run ${MACHINEFILE_OPTION} ${MACHINEFILE} \
391                         -np $((num_clients * $mbench_THREADS)) $cmd
392         fi
393
394         local rc=$?
395         if [ $rc != 0 ] ; then
396                 error "metabench failed! $rc"
397         fi
398
399         if $mbench_CLEANUP; then
400                 rm -rf $testdir
401         else
402                 mv $dir/d0.metabench $mntpt/_xxx.$(date +%s).d0.metabench
403         fi
404 }
405
406 run_simul() {
407         SIMUL=${SIMUL:=$(which simul 2> /dev/null || true)}
408         [ x$SIMUL = x ] && skip_env "simul not found"
409         [ "$NFSCLIENT" ] && skip "skipped for NFSCLIENT mode"
410
411         # threads per client
412         simul_THREADS=${simul_THREADS:-2}
413         simul_REP=${simul_REP:-20}
414
415         # FIXME
416         # Need space estimation here.
417
418         print_opts SIMUL clients simul_REP simul_THREADS
419
420         local testdir=$DIR/d0.simul
421         test_mkdir $testdir
422         setstripe_getstripe $testdir $simul_STRIPEPARAMS
423
424         # mpi_run uses mpiuser
425         chmod 0777 $testdir
426
427         # -n # : repeat each test # times
428         # -N # : repeat the entire set of tests # times
429
430         local cmd="$SIMUL -d $testdir -n $simul_REP -N $simul_REP"
431
432         echo "+ $cmd"
433         # find out if we need to use srun by checking $SRUN_PARTITION
434         if [ "$SRUN_PARTITION" ]; then
435                 $SRUN $SRUN_OPTIONS -D $testdir -w $clients -N $num_clients \
436                         -n $((num_clients * simul_THREADS)) -p $SRUN_PARTITION \
437                         -- $cmd
438         else
439                 mpi_run ${MACHINEFILE_OPTION} ${MACHINEFILE} \
440                         -np $((num_clients * simul_THREADS)) $cmd
441         fi
442
443         local rc=$?
444
445         if [ $rc != 0 ] ; then
446                 error "simul failed! $rc"
447         fi
448         rm -rf $testdir
449 }
450
451 run_mdtest() {
452         MDTEST=${MDTEST:=$(which mdtest 2> /dev/null || true)}
453         [ x$MDTEST = x ] && skip_env "mdtest not found"
454         [ "$NFSCLIENT" ] && skip "skipped for NFSCLIENT mode"
455
456         # threads per client
457         mdtest_THREADS=${mdtest_THREADS:-2}
458         mdtest_nFiles=${mdtest_nFiles:-"100000"}
459         # We devide the files by number of core
460         mdtest_nFiles=$((mdtest_nFiles/mdtest_THREADS/num_clients))
461         mdtest_iteration=${mdtest_iteration:-1}
462         local mdtest_custom_params=${mdtest_custom_params:-""}
463         local type=${1:-"ssf"}
464
465         local mdtest_Nmntp=${mdtest_Nmntp:-1}
466
467         if [ $type = "ssf" ] && [ $mdtest_Nmntp -ne 1 ]; then
468                 skip "shared directory mode is not compatible" \
469                         "with multiple directory paths"
470         fi
471
472         # FIXME
473         # Need space estimation here.
474
475         print_opts MDTEST mdtest_iteration mdtest_THREADS mdtest_nFiles
476
477         local testdir=$DIR/d0.mdtest
478         test_mkdir $testdir
479         setstripe_getstripe $testdir $mdtest_STRIPEPARAMS
480         chmod 0777 $testdir
481
482         for ((i=1; i<mdtest_Nmntp; i++)); do
483                 zconf_mount_clients $clients $MOUNT$i "$mntopts" ||
484                         error_exit "Failed $clients on $MOUNT$i"
485                 local dir=$DIR$i/d0.mdtest$i
486                 test_mkdir $dir
487                 setstripe_getstripe $dir $mdtest_SETSTRIPEPARAMS
488                 chmod 0777 $dir
489                 testdir="$testdir@$dir"
490         done
491         # mpi_run uses mpiuser
492
493         # -i # : repeat each test # times
494         # -d   : test dir
495         # -n # : number of file/dir to create/stat/remove
496         # -u   : each process create/stat/remove individually
497
498         local cmd="$MDTEST -d $testdir -i $mdtest_iteration \
499                 -n $mdtest_nFiles $mdtest_custom_params"
500
501         [ $type = "fpp" ] && cmd="$cmd -u"
502
503         echo "+ $cmd"
504         # find out if we need to use srun by checking $SRUN_PARTITION
505         if [ "$SRUN_PARTITION" ]; then
506                 $SRUN $SRUN_OPTIONS -D $testdir -w $clients -N $num_clients \
507                         -n $((num_clients * mdtest_THREADS)) \
508                         -p $SRUN_PARTITION -- $cmd
509         else
510                 mpi_run ${MACHINEFILE_OPTION} ${MACHINEFILE} \
511                         -np $((num_clients * mdtest_THREADS)) $cmd
512         fi
513
514         local rc=$?
515
516         if [ $rc != 0 ] ; then
517                 error "mdtest failed! $rc"
518         fi
519         rm -rf $testdir
520         for ((i=1; i<mdtest_Nmntp; i++)); do
521                 local dir=$DIR$i/d0.mdtest$i
522                 rm -rf $dir
523                 zconf_umount_clients $clients $MOUNT$i ||
524                         error_exit "Failed umount $MOUNT$i on $clients"
525         done
526 }
527
528 run_connectathon() {
529         local dir=${1:-$DIR}
530         cnt_DIR=${cnt_DIR:-""}
531         cnt_NRUN=${cnt_NRUN:-10}
532
533         print_opts cnt_DIR cnt_NRUN
534
535         [ x$cnt_DIR = x ] && skip_env "connectathon dir not found"
536         [ -e $cnt_DIR/runtests ] || skip_env "No connectathon runtests found"
537
538         # Space estimation:
539         # "special" tests create a 30 MB file + misc. small files
540         # required space ~40 MB
541         local space=$(df -P $dir | tail -n 1 | awk '{ print $4 }')
542         if [[ $space -le $((1024 * 40)) ]]; then
543                 skip_env "Need free space at least 40MB, have $space KB"
544         fi
545         echo "free space = $space KB"
546
547         local testdir=$dir/d0.connectathon
548         test_mkdir -p $testdir
549         setstripe_getstripe $testdir $cnt_STRIPEPARAMS
550
551         local savePWD=$PWD
552         cd $cnt_DIR
553
554         #
555         # To run connectathon:
556         # runtests [-a|-b|-g|-s|-l] [-f|-n|-t] [-N numpasses] [test-directory]
557         #
558         # One of the following test types
559         #    -b  basic
560         #    -g  general
561         #    -s  special
562         #    -l  lock
563         #    -a  all of the above
564         #
565         # -f  a quick functional test
566         # -n  suppress directory operations (mkdir and rmdir)
567         # -t  run with time statistics (default for basic tests)
568         #
569         # -N numpasses - specifies the number of times to run
570         #                the tests. Optional.
571
572         tests="-b -g -s"
573         # Include lock tests unless we're running on nfsv4
574         local fstype=$(df -TP $testdir | awk 'NR==2  {print $2}')
575         echo "$testdir: $fstype"
576         if [[ $fstype != "nfs4" ]]; then
577                 tests="$tests -l"
578         fi
579         echo "tests: $tests"
580         for test in $tests; do
581                 local cmd="sh ./runtests -N $cnt_NRUN $test -f $testdir"
582                 local rc=0
583
584                 log "$cmd"
585                 eval $cmd
586                 rc=$?
587                 [ $rc = 0 ] || error "connectathon failed: $rc"
588         done
589
590         cd $savePWD
591         rm -rf $testdir
592 }
593
594 run_ior() {
595         local type=${1:="ssf"}
596         local dir=${2:-$DIR}
597         local testdir=$dir/d0.ior.$type
598         local nfs_srvmntpt=$3
599
600         if [ "$NFSCLIENT" ]; then
601                 [[ -n $nfs_srvmntpt ]] ||
602                         { error "NFSCLIENT mode, but nfs exported dir"\
603                                 "is not set!" && return 1; }
604         fi
605
606         IOR=${IOR:-$(which IOR 2> /dev/null || true)}
607         [ x$IOR = x ] && skip_env "IOR not found"
608
609         # threads per client
610         ior_THREADS=${ior_THREADS:-2}
611         ior_iteration=${ior_iteration:-1}
612         ior_blockSize=${ior_blockSize:-6}
613         ior_blockUnit=${ior_blockUnit:-M}   # K, M, G
614         ior_xferSize=${ior_xferSize:-1M}
615         ior_type=${ior_type:-POSIX}
616         ior_DURATION=${ior_DURATION:-30}        # minutes
617         ior_CLEANUP=${ior_CLEANUP:-true}
618         local multiplier=1
619         case ${ior_blockUnit} in
620                 [G])
621                         multiplier=$((1024 * 1024 * 1024))
622                         ;;
623                 [M])
624                         multiplier=$((1024 * 1024))
625                         ;;
626                 [K])
627                         multiplier=1024
628                         ;;
629                 *)      error "Incorrect block unit should be one of [KMG]"
630                         ;;
631         esac
632
633         # calculate the space in bytes
634         local space=$(df -B 1 -P $dir | tail -n 1 | awk '{ print $4 }')
635         local total_threads=$((num_clients * ior_THREADS))
636         echo "+ $ior_blockSize * $multiplier * $total_threads "
637         if [ $((space / 2)) -le \
638              $((ior_blockSize * multiplier * total_threads)) ]; then
639                 ior_blockSize=$((space / 2 / multiplier / total_threads))
640                 [ $ior_blockSize -eq 0 ] &&
641                 skip_env "Need free space more than $((2 * total_threads)) \
642                          ${ior_blockUnit}: have $((space / multiplier))"
643
644                 echo "(reduced blockSize to $ior_blockSize \
645                      ${ior_blockUnit} bytes)"
646         fi
647
648         print_opts IOR ior_THREADS ior_DURATION MACHINEFILE
649
650         test_mkdir -p $testdir
651
652         # mpi_run uses mpiuser
653         chmod 0777 $testdir
654         [[ "$ior_stripe_params" && -z "$ior_STRIPEPARAMS" ]] &&
655                 ior_STRIPEPARAMS="$ior_stripe_params" &&
656                 echo "got deprecated ior_stripe_params,"\
657                         "use ior_STRIPEPARAMS instead"
658         setstripe_getstripe $testdir $ior_STRIPEPARAMS
659
660         #
661         # -b N  blockSize --
662         #       contiguous bytes to write per task (e.g.: 8, 4K, 2M, 1G)"
663         # -o S  testFileName
664         # -t N  transferSize -- size of transfer in bytes (e.g.: 8, 4K, 2M, 1G)"
665         # -w    writeFile -- write file"
666         # -r    readFile -- read existing file"
667         # -W    checkWrite -- check read after write"
668         # -C    reorderTasks -- changes task ordering to n+1 ordering for readback
669         # -T    maxTimeDuration -- max time in minutes to run tests"
670         # -k    keepFile -- keep testFile(s) on program exit
671
672         local cmd
673         if [ -n "$ior_custom_params" ]; then
674                 cmd="$IOR -o $testdir/iorData $ior_custom_params"
675         else
676                 cmd="$IOR -a $ior_type -b ${ior_blockSize}${ior_blockUnit} \
677                 -o $testdir/iorData -t $ior_xferSize -v -C -w -r -W \
678                 -i $ior_iteration -T $ior_DURATION -k"
679         fi
680
681         [ $type = "fpp" ] && cmd="$cmd -F"
682
683         echo "+ $cmd"
684         # find out if we need to use srun by checking $SRUN_PARTITION
685         if [ "$SRUN_PARTITION" ]; then
686                 $SRUN $SRUN_OPTIONS -D $testdir -w $clients -N $num_clients \
687                         -n $((num_clients * ior_THREADS)) -p $SRUN_PARTITION \
688                         -- $cmd
689         else
690                 mpi_ior_custom_threads=${mpi_ior_custom_threads:-"$((num_clients * ior_THREADS))"}
691                 mpi_run ${MACHINEFILE_OPTION} ${MACHINEFILE} \
692                         -np $mpi_ior_custom_threads $cmd
693         fi
694
695         local rc=$?
696
697         if [ $rc != 0 ] ; then
698                 error "ior failed! $rc"
699         fi
700         $ior_CLEANUP && rm -rf $testdir || true
701 }
702
703 run_mib() {
704         MIB=${MIB:=$(which mib 2> /dev/null || true)}
705         [ "$NFSCLIENT" ] && skip "skipped for NFSCLIENT mode"
706         [ x$MIB = x ] && skip_env "MIB not found"
707
708         # threads per client
709         mib_THREADS=${mib_THREADS:-2}
710         mib_xferSize=${mib_xferSize:-1m}
711         mib_xferLimit=${mib_xferLimit:-5000}
712         mib_timeLimit=${mib_timeLimit:-300}
713         mib_STRIPEPARAMS=${mib_STRIPEPARAMS:-"-c -1"}
714
715         print_opts MIB mib_THREADS mib_xferSize mib_xferLimit mib_timeLimit \
716                 MACHINEFILE
717
718         local testdir=$DIR/d0.mib
719         test_mkdir $testdir
720         setstripe_getstripe $testdir $mib_STRIPEPARAMS
721
722         # mpi_run uses mpiuser
723         chmod 0777 $testdir
724
725         #
726         # -I    Show intermediate values in output
727         # -H    Show headers in output
728         # -L    Do not issue new system calls after this many seconds
729         # -s    Use system calls of this size
730         # -t    test dir
731         # -l    Issue no more than this many system calls
732         local cmd="$MIB -t $testdir -s $mib_xferSize -l $mib_xferLimit \
733                 -L $mib_timeLimit -HI -p mib.$(date +%Y%m%d%H%M%S)"
734
735         echo "+ $cmd"
736         # find out if we need to use srun by checking $SRUN_PARTITION
737         if [ "$SRUN_PARTITION" ]; then
738                 $SRUN $SRUN_OPTIONS -D $testdir -w $clients -N $num_clients \
739                         -n $((num_clients * mib_THREADS)) -p $SRUN_PARTITION \
740                         -- $cmd
741         else
742                 mpi_run ${MACHINEFILE_OPTION} ${MACHINEFILE} \
743                         -np $((num_clients * mib_THREADS)) $cmd
744         fi
745
746         local rc=$?
747
748         if [ $rc != 0 ] ; then
749                 error "mib failed! $rc"
750         fi
751         rm -rf $testdir
752 }
753
754 run_cascading_rw() {
755         CASC_RW=${CASC_RW:-$(which cascading_rw 2> /dev/null || true)}
756         [ x$CASC_RW = x ] && skip_env "cascading_rw not found"
757         [ "$NFSCLIENT" ] && skip "skipped for NFSCLIENT mode"
758
759         # threads per client
760         casc_THREADS=${casc_THREADS:-2}
761         casc_REP=${casc_REP:-300}
762
763         # FIXME
764         # Need space estimation here.
765
766         print_opts CASC_RW clients casc_THREADS casc_REP MACHINEFILE
767
768         local testdir=$DIR/d0.cascading_rw
769         test_mkdir $testdir
770         setstripe_getstripe $testdir $casc_STRIPEPARAMS
771
772         # mpi_run uses mpiuser
773         chmod 0777 $testdir
774
775         # -g: debug mode
776         # -n: repeat test # times
777
778         local cmd="$CASC_RW -g -d $testdir -n $casc_REP"
779
780         echo "+ $cmd"
781         mpi_run ${MACHINEFILE_OPTION} ${MACHINEFILE} \
782                 -np $((num_clients * $casc_THREADS)) $cmd
783
784         local rc=$?
785
786         if [ $rc != 0 ] ; then
787                 error "cascading_rw failed! $rc"
788         fi
789         rm -rf $testdir
790 }
791
792 run_write_append_truncate() {
793         [ "$NFSCLIENT" ] && skip "skipped for NFSCLIENT mode"
794         # location is lustre/tests dir
795         if ! which write_append_truncate > /dev/null 2>&1 ; then
796                 skip_env "write_append_truncate not found"
797         fi
798
799         # threads per client
800         write_THREADS=${write_THREADS:-8}
801         write_REP=${write_REP:-10000}
802
803         # FIXME
804         # Need space estimation here.
805
806         local testdir=$DIR/d0.write_append_truncate
807         local file=$testdir/f0.wat
808
809         print_opts clients write_REP write_THREADS MACHINEFILE
810
811         test_mkdir $testdir
812         # mpi_run uses mpiuser
813         setstripe_getstripe $testdir $write_STRIPEPARAMS
814
815         chmod 0777 $testdir
816
817         local cmd="write_append_truncate -n $write_REP $file"
818
819         echo "+ $cmd"
820         mpi_run ${MACHINEFILE_OPTION} ${MACHINEFILE} \
821                 -np $((num_clients * $write_THREADS)) $cmd
822
823         local rc=$?
824
825         if [ $rc != 0 ] ; then
826         error "write_append_truncate failed! $rc"
827         return $rc
828         fi
829         rm -rf $testdir
830 }
831
832 run_write_disjoint() {
833         WRITE_DISJOINT=${WRITE_DISJOINT:-$(which write_disjoint 2> /dev/null ||
834                                            true)}
835         [ x$WRITE_DISJOINT = x ] && skip_env "write_disjoint not found"
836         [ "$NFSCLIENT" ] && skip "skipped for NFSCLIENT mode"
837
838         # threads per client
839         wdisjoint_THREADS=${wdisjoint_THREADS:-4}
840         wdisjoint_REP=${wdisjoint_REP:-10000}
841         chunk_size_limit=$1
842
843         # FIXME
844         # Need space estimation here.
845
846         print_opts WRITE_DISJOINT clients wdisjoint_THREADS wdisjoint_REP \
847                 MACHINEFILE
848         local testdir=$DIR/d0.write_disjoint
849         test_mkdir $testdir
850         setstripe_getstripe $testdir $wdisjoint_STRIPEPARAMS
851
852         # mpi_run uses mpiuser
853         chmod 0777 $testdir
854
855         local cmd="$WRITE_DISJOINT -f $testdir/file -n $wdisjoint_REP -m \
856                         $chunk_size_limit"
857
858         echo "+ $cmd"
859         mpi_run ${MACHINEFILE_OPTION} ${MACHINEFILE} \
860                 -np $((num_clients * $wdisjoint_THREADS)) $cmd
861
862         local rc=$?
863
864         if [ $rc != 0 ] ; then
865                 error "write_disjoint failed! $rc"
866         fi
867         rm -rf $testdir
868 }
869
870 run_parallel_grouplock() {
871         PARALLEL_GROUPLOCK=${PARALLEL_GROUPLOCK:-$(which parallel_grouplock \
872             2> /dev/null || true)}
873
874         [ x$PARALLEL_GROUPLOCK = x ] && skip "PARALLEL_GROUPLOCK not found"
875         [ "$NFSCLIENT" ] && skip "skipped for NFSCLIENT mode"
876
877         parallel_grouplock_MINTASKS=${parallel_grouplock_MINTASKS:-5}
878
879         print_opts clients parallel_grouplock_MINTASKS MACHINEFILE
880
881         local testdir=$DIR/d0.parallel_grouplock
882         test_mkdir $testdir
883         setstripe_getstripe $testdir $parallel_grouplock_STRIPEPARAMS
884
885         # mpi_run uses mpiuser
886         chmod 0777 $testdir
887
888         local cmd
889         local status=0
890         local subtest
891         for i in $(seq 12); do
892                 subtest="-t $i"
893                 local cmd="$PARALLEL_GROUPLOCK -g -v -d $testdir $subtest"
894                 echo "+ $cmd"
895
896                 mpi_run ${MACHINEFILE_OPTION} ${MACHINEFILE} \
897                         -np $parallel_grouplock_MINTASKS $cmd
898                 local rc=$?
899                 if [ $rc != 0 ] ; then
900                         error_noexit "parallel_grouplock subtests $subtest " \
901                                      "failed! $rc"
902                 else
903                         echo "parallel_grouplock subtests $subtest PASS"
904                 fi
905                 let status=$((status + rc))
906                 # clear debug to collect one log per one test
907                 do_nodes $(comma_list $(nodes_list)) lctl clear
908         done
909         [ $status -eq 0 ] || error "parallel_grouplock status: $status"
910         rm -rf $testdir
911 }
912
913 cleanup_statahead () {
914         trap 0
915
916         local clients=$1
917         local mntpt_root=$2
918         local num_mntpts=$3
919
920         for i in $(seq 0 $num_mntpts);do
921         zconf_umount_clients $clients ${mntpt_root}$i ||
922                 error_exit "Failed to umount lustre on ${mntpt_root}$i"
923         done
924 }
925
926 run_statahead () {
927         if [[ -n $NFSCLIENT ]]; then
928                 skip "Statahead testing is not supported on NFS clients."
929         fi
930         [ x$MDSRATE = x ] && skip_env "mdsrate not found"
931
932         statahead_NUMMNTPTS=${statahead_NUMMNTPTS:-5}
933         statahead_NUMFILES=${statahead_NUMFILES:-500000}
934
935         print_opts MDSRATE clients statahead_NUMMNTPTS statahead_NUMFILES
936
937         # create large dir
938
939         # do not use default "d[0-9]*" dir name
940         # to avoid of rm $statahead_NUMFILES (500k) files in t-f cleanup
941         local dir=dstatahead
942         local testdir=$DIR/$dir
943
944         # cleanup only if dir exists
945         # cleanup only $statahead_NUMFILES number of files
946         # ignore the other files created by someone else
947         [ -d $testdir ] &&
948         mdsrate_cleanup $((num_clients * 32)) $MACHINEFILE \
949                 $statahead_NUMFILES $testdir 'f%%d' --ignore
950
951         test_mkdir $testdir
952         setstripe_getstripe $testdir $statahead_STRIPEPARAMS
953
954         # mpi_run uses mpiuser
955         chmod 0777 $testdir
956
957         local num_files=$statahead_NUMFILES
958
959         local IFree=$(inodes_available)
960         if [ $IFree -lt $num_files ]; then
961                 num_files=$IFree
962         fi
963
964         cancel_lru_locks mdc
965
966         local cmd1="${MDSRATE} ${MDSRATE_DEBUG} --mknod --dir $testdir"
967         local cmd2="--nfiles $num_files --filefmt 'f%%d'"
968         local cmd="$cmd1 $cmd2"
969         echo "+ $cmd"
970
971         mpi_run ${MACHINEFILE_OPTION} ${MACHINEFILE} \
972                 -np $((num_clients * 32)) $cmd
973
974         local rc=$?
975
976         if [ $rc != 0 ] ; then
977                 error "mdsrate failed to create $rc"
978                 return $rc
979         fi
980
981         local num_mntpts=$statahead_NUMMNTPTS
982         local mntpt_root=$TMP/mntpt/lustre
983         local mntopts=$MNTOPTSTATAHEAD
984
985         echo "Mounting $num_mntpts lustre clients starts on $clients"
986         trap "cleanup_statahead $clients $mntpt_root $num_mntpts" EXIT ERR
987         for i in $(seq 0 $num_mntpts); do
988         zconf_mount_clients $clients ${mntpt_root}$i "$mntopts" ||
989                 error_exit "Failed to mount lustre on ${mntpt_root}$i on $clients"
990         done
991
992         do_rpc_nodes $clients cancel_lru_locks mdc
993
994         do_rpc_nodes $clients do_ls $mntpt_root $num_mntpts $dir
995
996         mdsrate_cleanup $((num_clients * 32)) $MACHINEFILE \
997                 $num_files $testdir 'f%%d' --ignore
998
999         # use rm instead of rmdir because of
1000         # testdir could contain the files created by someone else,
1001         # or by previous run where is num_files prev > num_files current
1002         rm -rf $testdir
1003         cleanup_statahead $clients $mntpt_root $num_mntpts
1004 }
1005
1006 cleanup_rr_alloc () {
1007         trap 0
1008         local clients="$1"
1009         local mntpt_root="$2"
1010         local rr_alloc_MNTPTS="$3"
1011         local mntpt_dir=$(dirname ${mntpt_root})
1012
1013         for i in $(seq 0 $((rr_alloc_MNTPTS - 1))); do
1014                 zconf_umount_clients $clients ${mntpt_root}$i ||
1015                 error_exit "Failed to umount lustre on ${mntpt_root}$i"
1016         done
1017         do_nodes $clients "rm -rf $mntpt_dir"
1018 }
1019
1020 run_rr_alloc() {
1021         remote_mds_nodsh && skip "remote MDS with nodsh"
1022         echo "===Test gives more reproduction percentage if number of "\
1023                 "client and ost are more. Test with 44 or more clients "\
1024                 "and 73 or more OSTs gives 100% reproduction rate=="
1025
1026         RR_ALLOC=${RR_ALLOC:-$(which rr_alloc 2> /dev/null || true)}
1027         [ x$RR_ALLOC = x ] && skip_env "rr_alloc not found"
1028         declare -a diff_max_min_arr
1029         # foeo = file on each ost. calc = calculated.
1030         local ost_idx
1031         local foeo_calc
1032         local qos_prec_objs="${TMP}/qos_and_precreated_objects"
1033         local rr_alloc_NFILES=${rr_alloc_NFILES:-555}
1034         local rr_alloc_MNTPTS=${rr_alloc_MNTPTS:-11}
1035         local total_MNTPTS=$((rr_alloc_MNTPTS * num_clients))
1036         local mntpt_root="${TMP}/rr_alloc_mntpt/lustre"
1037         test_mkdir $DIR/$tdir
1038         setstripe_getstripe $DIR/$tdir $rr_alloc_STRIPEPARAMS
1039
1040         chmod 0777 $DIR/$tdir
1041
1042         trap "cleanup_rr_alloc $clients $mntpt_root $rr_alloc_MNTPTS" EXIT ERR
1043         for i in $(seq 0 $((rr_alloc_MNTPTS - 1))); do
1044                 zconf_mount_clients $clients ${mntpt_root}$i $MOUNT_OPTS ||
1045                 error_exit "Failed to mount lustre on ${mntpt_root}$i $clients"
1046         done
1047
1048         local cmd="$RR_ALLOC $mntpt_root/$tdir/ash $rr_alloc_NFILES \
1049                 $num_clients"
1050
1051         # Save mdt values, set threshold to 100% i.e always Round Robin,
1052         # restore the saved values again after creating files...
1053         save_lustre_params mds1 \
1054                 "lod.$FSNAME-MDT0000*.qos_threshold_rr" > $qos_prec_objs
1055         save_lustre_params mds1 \
1056                 "osp.$FSNAME-OST*-osc-MDT0000.create_count" >> $qos_prec_objs
1057
1058         local old_create_count=$(grep -e "create_count" $qos_prec_objs |
1059                 cut -d'=' -f 2 | sort -nr | head -n1)
1060
1061         # Make sure that every osp has enough precreated objects for the file
1062         # creation app
1063
1064         # create_count is always set to the power of 2 only, so if the files
1065         # per OST are not multiple of that then it will be set to nearest
1066         # lower power of 2. So set 'create_count' to the upper power of 2.
1067
1068         foeo_calc=$((rr_alloc_NFILES * total_MNTPTS / OSTCOUNT))
1069         local create_count=$((2 * foeo_calc))
1070
1071         # create_count accepted values:
1072         #   [OST_MIN_PRECREATE=32, OST_MAX_PRECREATE=20000]
1073         # values exceeding OST_MAX_PRECREATE are lowered to the maximum.
1074         [[ $create_count -lt 32 ]] && create_count=32
1075         local i
1076         for i in $(seq $MDSCOUNT); do
1077                 do_facet mds$i "$LCTL set_param -n \
1078                         lod.$FSNAME-MDT*.qos_threshold_rr=100 \
1079                         osp.$FSNAME-OST*-osc-MDT*.create_count=$create_count"
1080         done
1081
1082         # Create few temporary files in order to increase the precreated objects
1083         # to a desired value, before starting 'rr_alloc' app. Due to default
1084         # value 32 of precreation count (OST_MIN_PRECREATE=32), precreated
1085         # objects available are 32 initially, these gets exhausted very soon,
1086         # which causes skip of some osps when very large number of files
1087         # is created per OSTs.
1088         createmany -o $DIR/$tdir/foo- $(((old_create_count + 1) * OSTCOUNT)) \
1089                 > /dev/null
1090         rm -f /$DIR/$tdir/foo*
1091
1092         # Check for enough precreated objects... We should not
1093         # fail here because code(osp_precreate.c) also takes care of it.
1094         # So we have good chances of passing test even if this check fails.
1095         local mdt_idx=0
1096         for ost_idx in $(seq 0 $((OSTCOUNT - 1))); do
1097                 [[ $(precreated_ost_obj_count $mdt_idx $ost_idx) -ge \
1098                         $foeo_calc ]] || echo "Warning: test may fail because" \
1099                         "of lack of precreated objects on OST${ost_idx}"
1100         done
1101
1102         if [[ $total_MNTPTS -ne 0 ]]; then
1103                 # Now start the actual file creation app.
1104                 mpi_run "-np $total_MNTPTS" $cmd || return
1105         else
1106                 error "No mount point"
1107         fi
1108
1109         restore_lustre_params < $qos_prec_objs
1110         rm -f $qos_prec_objs
1111
1112         diff_max_min_arr=($($LFS getstripe -r $DIR/$tdir/ |
1113                 grep "lmm_stripe_offset:" | awk '{print $2}' | sort -n |
1114                 uniq -c | awk 'NR==1 {min=max=$1} \
1115                 { $1<min ? min=$1 : min; $1>max ? max=$1 : max} \
1116                 END {print max-min, max, min}'))
1117
1118         rm -rf $DIR/$tdir
1119
1120         # In-case of fairly large number of file creation using RR (round-robin)
1121         # there can be two cases in which deviation will occur than the regular
1122         # RR algo behaviour-
1123         # 1- When rr_alloc does not start right with 'lqr_start_count' reseeded,
1124         # 2- When rr_alloc does not finish with 'lqr_start_count == 0'.
1125         # So the difference of files b/w any 2 OST should not be more than 2.
1126         [[ ${diff_max_min_arr[0]} -le 2 ]] ||
1127                 error "Uneven distribution detected: difference between" \
1128                 "maximum files per OST (${diff_max_min_arr[1]}) and" \
1129                 "minimum files per OST (${diff_max_min_arr[2]}) must not be" \
1130                 "greater than 2"
1131 }
1132
1133 run_fs_test() {
1134         # fs_test.x is the default name for exe
1135         FS_TEST=${FS_TEST:=$(which fs_test.x 2> /dev/null || true)}
1136
1137         local clients=${CLIENTS:-$(hostname)}
1138         local testdir=$DIR/d0.fs_test
1139         local file=${testdir}/fs_test
1140         fs_test_threads=${fs_test_threads:-2}
1141         fs_test_type=${fs_test_type:-1}
1142         fs_test_nobj=${fs_test_nobj:-10}
1143         fs_test_check=${fs_test_check:-3}
1144         fs_test_strided=${fs_test_strided:-1}
1145         fs_test_touch=${fs_test_touch:-3}
1146         fs_test_supersize=${fs_test_supersize:-1}
1147         fs_test_op=${fs_test_op:-write}
1148         fs_test_barriers=${fs_test_barriers:-bopen,bwrite,bclose}
1149         fs_test_io=${fs_test_io:-mpi}
1150         fs_test_objsize=${fs_test_objsize:-100}
1151         fs_test_objunit=${fs_test_objunit:-1048576} # 1 mb
1152         fs_test_ndirs=${fs_test_ndirs:-80000}
1153
1154         [ x$FS_TEST = x ] && skip "FS_TEST not found"
1155
1156         # Space estimation  in bytes
1157         local space=$(df -B 1 -P $dir | tail -n 1 | awk '{ print $4 }')
1158         local total_threads=$((num_clients * fs_test_threads))
1159         echo "+ $fs_test_objsize * $fs_test_objunit * $total_threads "
1160         if [ $((space / 2)) -le \
1161                 $((fs_test_objsize * fs_test_objunit * total_threads)) ]; then
1162                         fs_test_objsize=$((space / 2 / fs_test_objunit /
1163                                 total_threads))
1164                         [ $fs_test_objsize -eq 0 ] &&
1165                         skip_env "Need free space more than \
1166                                 $((2 * total_threads * fs_test_objunit)) \
1167                                 : have $((space / fs_test_objunit))"
1168
1169                         echo "(reduced objsize to \
1170                                 $((fs_test_objsize * fs_test_objunit)) bytes)"
1171         fi
1172
1173         print_opts FS_TEST clients fs_test_threads fs_test_objsize MACHINEFILE
1174
1175         test_mkdir $testdir
1176         setstripe_getstripe $testdir $fs_test_STRIPEPARAMS
1177
1178         # mpi_run uses mpiuser
1179         chmod 0777 $testdir
1180
1181         # --nodb          Turn off the database code at runtime
1182         # -g --target     The path to the data file
1183         # -t --type       Whether to do N-N (1) or N-1 (2)
1184         # -n --nobj       The number of objects written/read by each proc
1185         # -z --size       The size of each object
1186         # -d ---num_nn_dirs Number of subdirectories for files
1187         # -C --check      Check every byte using argument 3.
1188         # --collective    Whether to use collective I/O (for N-1, mpi-io only)
1189         # -s --strided    Whether to use a strided pattern (for N-1 only)
1190         # -T --touch      Touch every byte using argument 3
1191         # -o --op         Whether to read only (read) or write only (write)
1192         # -b --barriers   When to barrier.
1193         # -i --io         Use POSIX, MPI, or PLFS IO routines (mpi|posix|plfs)
1194         # -S --supersize  Specify how many objects per superblock
1195
1196         local cmd="$FS_TEST -nodb -g $file -t $fs_test_type -n $fs_test_nobj \
1197                 -z $((fs_test_objsize * fs_test_objunit)) -d $fs_test_ndirs \
1198                 -C $fs_test_check -collective -s $fs_test_strided \
1199                 -T $fs_test_touch -o $fs_test_op -b $fs_test_barriers \
1200                 -i $fs_test_io -S $fs_test_supersize"
1201
1202         echo "+ $cmd"
1203         mpi_run "-np $((num_clients * fs_test_threads))" $cmd
1204
1205         local rc=$?
1206         if [ $rc != 0 ] ; then
1207                 error "fs_test failed! $rc"
1208         fi
1209
1210         rm -rf $testdir
1211 }
1212
1213 ior_mdtest_parallel() {
1214         local rc1=0
1215         local rc2=0
1216         local type=$1
1217
1218         run_ior $type &
1219         local pids=$!
1220
1221         run_mdtest $type || rc2=$?
1222         [[ $rc2 -ne 0 ]] && echo "mdtest failed with error $rc2"
1223
1224         wait $pids || rc1=$?
1225         [[ $rc1 -ne 0 ]] && echo "ior failed with error $rc1"
1226
1227         [[ $rc1 -ne 0 || $rc2 -ne 0 ]] && return 1
1228         return 0
1229 }
1230
1231 run_fio() {
1232         FIO=${FIO:=$(which fio 2> /dev/null || true)}
1233
1234         local clients=${CLIENTS:-$(hostname)}
1235         local fio_jobNum=${fio_jobNum:-4}
1236         local fio_jobFile=${fio_jobFile:-$TMP/fiojobfile.$(date +%s)}
1237         local fio_bs=${fio_bs:-1}
1238         local testdir=$DIR/d0.fio
1239         local file=${testdir}/fio
1240         local runtime=60
1241         local propagate=false
1242
1243         [ "$SLOW" = "no" ] || runtime=600
1244
1245         [ x$FIO = x ] && skip_env "FIO not found"
1246
1247         test_mkdir $testdir
1248         setstripe_getstripe $testdir $fio_STRIPEPARAMS
1249
1250         # use fio job file if exists,
1251         # create a simple one if missing
1252         if ! [ -f $fio_jobFile ]; then
1253                 cat >> $fio_jobFile <<EOF
1254 [global]
1255 rw=randwrite
1256 size=128m
1257 time_based=1
1258 runtime=$runtime
1259 filename=${file}_\$(hostname)
1260 EOF
1261                 # bs size increased by $i for each job
1262                 for ((i=1; i<=fio_jobNum; i++)); do
1263                         cat >> $fio_jobFile <<EOF
1264
1265 [job$i]
1266 bs=$(( fio_bs * i ))m
1267 EOF
1268                 done
1269                 # job file is created, should be propagated to all clients
1270                 propagate=true
1271         fi
1272
1273
1274         # propagate the job file if not all clients have it yet or
1275         # if the job file was created during the test run
1276         if ! do_nodesv $clients " [ -f $fio_jobFile ] " ||
1277            $propagate; then
1278                 local cfg=$(cat $fio_jobFile)
1279                 do_nodes $clients "echo \\\"$cfg\\\" > ${fio_jobFile}" ||
1280                         error "job file $fio_jobFile is not propagated"
1281                 do_nodesv $clients "cat ${fio_jobFile}"
1282         fi
1283
1284         cmd="$FIO $fio_jobFile"
1285         echo "+ $cmd"
1286
1287         log "clients: $clients $cmd"
1288
1289         local rc=0
1290         do_nodesv $clients "$cmd "
1291         rc=$?
1292
1293         [ $rc = 0 ] || error "fio failed: $rc"
1294         rm -rf $testdir
1295 }
1296
1297 run_xdd() {
1298         XDD=${XDD:=$(which xdd 2> /dev/null || true)}
1299
1300         local clients=${CLIENTS:-$(hostname)}
1301         local testdir=$DIR/d0.xdd
1302         xdd_queuedepth=${xdd_queuedepth:-4}
1303         xdd_blocksize=${xdd_blocksize:-512}
1304         xdd_reqsize=${xdd_reqsize:-128}
1305         xdd_mbytes=${xdd_mbytes:-100}
1306         xdd_passes=${xdd_passes:-40}
1307         xdd_rwratio=${xdd_rwratio:-0}
1308         xdd_ntargets=${xdd_ntargets:-6}
1309         local xdd_custom_params=${xdd_custom_params:-"-dio -stoponerror \
1310                 -maxpri -minall -noproclock -nomemlock"}
1311
1312         [ x$XDD = x ] && skip "XDD not found"
1313
1314         print_opts XDD clients xdd_queuedepth xdd_blocksize xdd_reqsize \
1315                 xdd_mbytes xdd_passes xdd_rwratio
1316
1317         test_mkdir $testdir
1318         setstripe_getstripe $testdir $xdd_STRIPEPARAMS
1319
1320         local files=""
1321         # Target files creates based on the given number of targets
1322         for (( i=0; i < $xdd_ntargets; i++ ))
1323         do
1324                 files+="${testdir}/xdd"$i" "
1325         done
1326
1327         # -targets      specifies the devices or files to perform operation
1328         # -reqsize      number of 'blocks' per operation
1329         # -mbytes       number of 1024*1024-byte blocks to transfer
1330         # -blocksize    size of a single 'block'
1331         # -passes       number of times to read mbytes
1332         # -queuedepth   number of commands to queue on the target
1333         # -rwratio      percentage of read to write operations
1334         # -verbose      will print out statistics on each pass
1335
1336         local cmd="$XDD -targets $xdd_ntargets $files -reqsize $xdd_reqsize \
1337                 -mbytes $xdd_mbytes -blocksize $xdd_blocksize \
1338                 -passes $xdd_passes -queuedepth $xdd_queuedepth \
1339                 -rwratio $xdd_rwratio -verbose $xdd_custom_params"
1340         echo "+ $cmd"
1341
1342         local rc=0
1343         do_nodesv $clients "$cmd "
1344         rc=$?
1345
1346         [ $rc = 0 ] || error "xdd failed: $rc"
1347
1348         rm -rf $testdir
1349 }