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