3 # functions used by other scripts
9 if [ -z "${!name}" ]; then
10 echo "$0: $name must be set"
14 [ $failed ] && exit 1 || true
17 # lrepl - Lustre test Read-Eval-Print Loop.
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.
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).
32 Use this REPL to inspect variables, set them, call test
33 framework shell functions, etcetera.
35 'exit' or EOF to exit this shell.
37 set \$retcode to 0 to cause the assertion failure that
38 triggered this REPL to be ignored.
41 do_facet ost1 lctl get_param ost.*.ost.threads_*
42 do_rpc_nodes \$OSTNODES unload_modules
45 All but the last line of multi-line statements or blocks
46 must end in a backslash.
48 "Here documents" are not supported.
50 History is not supported, but command-line editing is.
54 # Prompt escapes don't work in read -p, sadly.
55 prompt=":${TESTNAME:-UNKNOWN}:$(uname -n):$(basename $PWD)% "
57 # We use read -r to get close to a shell experience
58 while read -e -r -p "$prompt" rawline; do
61 # Don't want to exit-exit, just exit the REPL
63 # We need to handle continuations, and read -r doesn't do
64 # that for us. Yet we need read -r.
66 # We also use case/esac to compare lines read to "*\\"
67 # because [ "$line" = *\\ ] and variants of that don't work.
69 while read -e -r -p '> ' rawline
71 line="$line"$'\n'"$rawline"
73 # We could check for here documents by matching
74 # against *<<*, but who cares.
87 # Finally! Time to eval.
91 echo $'\n\tExiting interactive shell...\n'
95 # lassert - Lustre test framework assert
97 # Arguments: failure code, failure message, expression/statement
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
109 echo "checking $* ($(eval echo \""$*"\"))..."
110 eval "$@" && return 0;
112 if ${REPL_ON_LASSERT:-false}; then
113 echo "Assertion $retcode failed: $*
114 (expanded: $(eval echo \""$*"\")) $msg"
118 error "Assertion $retcode failed: $*
119 (expanded: $(eval echo \""$*"\")) $msg"
123 # setmodopts- set module options for subsequent calls to load_modules
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]
128 # In the second usage the new value is appended to the old.
132 if [ "$1" = -a ]; then
137 local _var=MODOPTS_$1
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.
148 if [ -z "$_newvalue" ]; then
154 $_append && _newvalue="$_oldvalue $_newvalue"
155 export $_var="$_newvalue"
156 echo setmodopts: ${_var}=${_newvalue}
158 [ -n "$_savevar" ] && eval $_savevar=\""$_oldvalue"\"
161 echoerr () { echo "$@" 1>&2 ; }
164 echoerr "$(date +'%F %H:%M:%S'): client load was signaled to terminate"
166 local PGID=$(ps -eo "%c %p %r" | awk "/ $PPID / {print \$3}")
173 local mpirun="$MPIRUN $MPIRUN_OPTIONS"
174 local command="$mpirun $@"
175 local mpilog=$TMP/mpi.log
178 if [ -n "$MPI_USER" -a "$MPI_USER" != root -a -n "$mpirun" ]; then
179 echo "+ chmod 0777 $MOUNT"
181 command="su $MPI_USER bash -c \"$command \""
186 eval $command 2>&1 | tee $mpilog || true
189 if [ $rc -eq 0 ] && grep -q "p4_error:" $mpilog ; then
198 for i in ${1//,/ }; do
199 if [ "$list" = "" ]; then
202 list="$list$escape $i@$NETTYPE"
208 # FIXME: all setup/cleanup can be done without rpc.sh
211 [ x$1 = x--verbose ] && verbose=true
213 export LST_SESSION=`$LST show_session 2>/dev/null | awk '{print $5}'`
214 [ "$LST_SESSION" == "" ] && return
223 lst_session_cleanup_all () {
224 local list=$(comma_list $(nodes_list))
225 do_rpc_nodes $list lst_end_session
229 lsmod | grep -q lnet_selftest && \
230 rmmod lnet_selftest > /dev/null 2>&1 || true
234 local list=$(comma_list $(nodes_list))
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
243 load_module lnet_selftest
247 local list=$(comma_list $(nodes_list))
248 do_rpc_nodes $list lst_setup
254 # Passed a single argument, strips everything off following
255 # and includes the first period.
256 # client-20.lab.whamcloud.com becomes client-20
258 echo $(sed 's/\..*//' <<< $1)
264 # Find remote nodename, stripped of any domain, etc.
265 # 'hostname -s' is easy, but not implemented on all systems
267 local rname=$(do_node $1 "uname -n" || echo -1)
268 if [[ "$rname" = "-1" ]]; then
271 echo $(short_hostname $rname)
281 echo "${var}=${!var}"
283 [ -e $MACHINEFILE ] && cat $MACHINEFILE
287 [ "$(stat -f -c %T $1)" = "lustre" ]
290 setstripe_getstripe () {
295 is_lustre $file || return 0
297 if [ -n "$params" ]; then
298 echo "setstripe option: $params"
299 $LFS setstripe $params $file ||
300 error "setstripe $params failed"
302 $LFS getstripe -d $file ||
303 error "getstripe $file failed"
308 local cbench_DIR=${cbench_DIR:-""}
309 local cbench_IDIRS=${cbench_IDIRS:-2}
310 local cbench_RUNS=${cbench_RUNS:-2}
312 print_opts cbench_DIR cbench_IDIRS cbench_RUNS
314 [ x$cbench_DIR = x ] &&
315 skip_env "compilebench not found"
317 [ -e $cbench_DIR/compilebench ] ||
318 skip_env "No compilebench build"
321 # compile dir kernel-0 ~1GB
322 # required space ~1GB * cbench_IDIRS
323 local space=$(df -P $dir | tail -n 1 | awk '{ print $4 }')
324 if [[ $space -le $((1024 * 1024 * cbench_IDIRS)) ]]; then
325 cbench_IDIRS=$((space / 1024 / 1024))
326 [[ $cbench_IDIRS -eq 0 ]] &&
327 skip_env "Need free space at least 1GB, have $space"
329 echo "reducing initial dirs to $cbench_IDIRS"
331 echo "free space = $space KB"
334 # t-f _base needs to be modifyed to set properly tdir
335 # for new "test_foo" functions names
336 # local testdir=$DIR/$tdir
337 local testdir=$dir/d0.compilebench.$$
338 test_mkdir -p $testdir
339 setstripe_getstripe $testdir $cbench_STRIPEPARAMS
343 local cmd="./compilebench -D $testdir -i $cbench_IDIRS \
344 -r $cbench_RUNS --makej"
353 [ $rc = 0 ] || error "compilebench failed: $rc"
357 # try to understand why a test is running out of space/quota
360 local tmpfile=$(mktemp)
362 $LFS df $dir || df $dir
363 $LFS df -i $dir || df -i $dir
364 $LFS quota -u mpiuser $dir
365 $LFS quota -u root $dir
367 du -skx $dir/../* | sort -nr | tee $tmpfile
368 local topdir=$(awk '{ print $2; exit; }' $tmpfile)
369 du -skx $topdir/* | sort -nr | tee $tmpfile
370 topdir=$(awk '{ print $2; exit; }' $tmpfile)
371 du -skx $topdir/* | sort -nr
377 local mntpt=${2:-$MOUNT}
378 METABENCH=${METABENCH:-$(which metabench 2> /dev/null || true)}
379 mbench_NFILES=${mbench_NFILES:-30400}
381 mbench_THREADS=${mbench_THREADS:-4}
382 mbench_OPTIONS=${mbench_OPTIONS:-}
383 mbench_CLEANUP=${mbench_CLEANUP:-true}
385 [ x$METABENCH = x ] && skip_env "metabench not found"
387 print_opts METABENCH clients mbench_NFILES mbench_THREADS
389 local testdir=$dir/d0.metabench
390 test_mkdir -p $testdir
391 setstripe_getstripe $testdir $mbench_STRIPEPARAMS
393 # mpi_run uses mpiuser
396 # try to understand why this test is running out of space/quota
397 find_space_usage $dir
399 # -C Run the file creation tests. Creates zero byte files.
400 # -S Run the file stat tests.
401 # -c nfile Number of files to be used in each test.
402 # -k Cleanup files when finished.
403 local cmd="$METABENCH -w $testdir -c $mbench_NFILES -C -S $mbench_OPTIONS"
406 # find out if we need to use srun by checking $SRUN_PARTITION
407 if [ "$SRUN_PARTITION" ]; then
408 $SRUN $SRUN_OPTIONS -D $testdir -w $clients -N $num_clients \
409 -n $((num_clients * mbench_THREADS)) \
410 -p $SRUN_PARTITION -- $cmd
412 mpi_run ${MACHINEFILE_OPTION} ${MACHINEFILE} \
413 -np $((num_clients * $mbench_THREADS)) $cmd
417 if [ $rc != 0 ] ; then
418 find_space_usage $dir
419 error "metabench failed! $rc"
422 if $mbench_CLEANUP; then
425 mv $dir/d0.metabench $mntpt/_xxx.$(date +%s).d0.metabench
430 SIMUL=${SIMUL:=$(which simul 2> /dev/null || true)}
431 [ x$SIMUL = x ] && skip_env "simul not found"
432 [ "$NFSCLIENT" ] && skip "skipped for NFSCLIENT mode"
435 simul_THREADS=${simul_THREADS:-2}
436 simul_REP=${simul_REP:-20}
439 # Need space estimation here.
441 print_opts SIMUL clients simul_REP simul_THREADS
443 local testdir=$DIR/d0.simul
445 setstripe_getstripe $testdir $simul_STRIPEPARAMS
447 # mpi_run uses mpiuser
450 # -n # : repeat each test # times
451 # -N # : repeat the entire set of tests # times
453 local cmd="$SIMUL -d $testdir -n $simul_REP -N $simul_REP"
456 # find out if we need to use srun by checking $SRUN_PARTITION
457 if [ "$SRUN_PARTITION" ]; then
458 $SRUN $SRUN_OPTIONS -D $testdir -w $clients -N $num_clients \
459 -n $((num_clients * simul_THREADS)) -p $SRUN_PARTITION \
462 mpi_run ${MACHINEFILE_OPTION} ${MACHINEFILE} \
463 -np $((num_clients * simul_THREADS)) $cmd
468 if [ $rc != 0 ] ; then
469 error "simul failed! $rc"
475 MDTEST=${MDTEST:=$(which mdtest 2> /dev/null || true)}
476 [ x$MDTEST = x ] && skip_env "mdtest not found"
477 [ "$NFSCLIENT" ] && skip "skipped for NFSCLIENT mode"
480 mdtest_THREADS=${mdtest_THREADS:-2}
481 mdtest_nFiles=${mdtest_nFiles:-"100000"}
482 # We devide the files by number of core
483 mdtest_nFiles=$((mdtest_nFiles/mdtest_THREADS/num_clients))
484 mdtest_iteration=${mdtest_iteration:-1}
485 local mdtest_custom_params=${mdtest_custom_params:-""}
486 local type=${1:-"ssf"}
488 local mdtest_Nmntp=${mdtest_Nmntp:-1}
490 if [ $type = "ssf" ] && [ $mdtest_Nmntp -ne 1 ]; then
491 skip "shared directory mode is not compatible" \
492 "with multiple directory paths"
496 # Need space estimation here.
498 print_opts MDTEST mdtest_iteration mdtest_THREADS mdtest_nFiles
500 local testdir=$DIR/d0.mdtest
502 setstripe_getstripe $testdir $mdtest_STRIPEPARAMS
505 for ((i=1; i<mdtest_Nmntp; i++)); do
506 zconf_mount_clients $clients $MOUNT$i "$mntopts" ||
507 error_exit "Failed $clients on $MOUNT$i"
508 local dir=$DIR$i/d0.mdtest$i
510 setstripe_getstripe $dir $mdtest_SETSTRIPEPARAMS
512 testdir="$testdir@$dir"
514 # mpi_run uses mpiuser
516 # -i # : repeat each test # times
518 # -n # : number of file/dir to create/stat/remove
519 # -u : each process create/stat/remove individually
521 local cmd="$MDTEST -d $testdir -i $mdtest_iteration \
522 -n $mdtest_nFiles $mdtest_custom_params"
524 [ $type = "fpp" ] && cmd="$cmd -u"
527 # find out if we need to use srun by checking $SRUN_PARTITION
528 if [ "$SRUN_PARTITION" ]; then
529 $SRUN $SRUN_OPTIONS -D $testdir -w $clients -N $num_clients \
530 -n $((num_clients * mdtest_THREADS)) \
531 -p $SRUN_PARTITION -- $cmd
533 mpi_run ${MACHINEFILE_OPTION} ${MACHINEFILE} \
534 -np $((num_clients * mdtest_THREADS)) $cmd
539 if [ $rc != 0 ] ; then
540 error "mdtest failed! $rc"
543 for ((i=1; i<mdtest_Nmntp; i++)); do
544 local dir=$DIR$i/d0.mdtest$i
546 zconf_umount_clients $clients $MOUNT$i ||
547 error_exit "Failed umount $MOUNT$i on $clients"
553 cnt_DIR=${cnt_DIR:-""}
554 cnt_NRUN=${cnt_NRUN:-10}
556 print_opts cnt_DIR cnt_NRUN
558 [ x$cnt_DIR = x ] && skip_env "connectathon dir not found"
559 [ -e $cnt_DIR/runtests ] || skip_env "No connectathon runtests found"
562 # "special" tests create a 30 MB file + misc. small files
563 # required space ~40 MB
564 local space=$(df -P $dir | tail -n 1 | awk '{ print $4 }')
565 if [[ $space -le $((1024 * 40)) ]]; then
566 skip_env "Need free space at least 40MB, have $space KB"
568 echo "free space = $space KB"
570 local testdir=$dir/d0.connectathon
571 test_mkdir -p $testdir
572 setstripe_getstripe $testdir $cnt_STRIPEPARAMS
578 # To run connectathon:
579 # runtests [-a|-b|-g|-s|-l] [-f|-n|-t] [-N numpasses] [test-directory]
581 # One of the following test types
586 # -a all of the above
588 # -f a quick functional test
589 # -n suppress directory operations (mkdir and rmdir)
590 # -t run with time statistics (default for basic tests)
592 # -N numpasses - specifies the number of times to run
593 # the tests. Optional.
596 # Include lock tests unless we're running on nfsv4
597 local fstype=$(df -TP $testdir | awk 'NR==2 {print $2}')
598 echo "$testdir: $fstype"
599 if [[ $fstype != "nfs4" ]]; then
603 for test in $tests; do
604 local cmd="bash ./runtests -N $cnt_NRUN $test -f $testdir"
610 [ $rc = 0 ] || error "connectathon failed: $rc"
618 local type=${1:="ssf"}
620 local testdir=$dir/d0.ior.$type
621 local nfs_srvmntpt=$3
623 if [ "$NFSCLIENT" ]; then
624 [[ -n $nfs_srvmntpt ]] ||
625 { error "NFSCLIENT mode, but nfs exported dir"\
626 "is not set!" && return 1; }
629 IOR=${IOR:-$(which ior 2> /dev/null)}
630 [[ -z "$IOR" ]] && IOR=$(which IOR 2> /dev/null)
631 [[ -n "$IOR" ]] || skip_env "IOR/ior not found"
634 ior_THREADS=${ior_THREADS:-2}
635 ior_iteration=${ior_iteration:-1}
636 ior_blockSize=${ior_blockSize:-6}
637 ior_blockUnit=${ior_blockUnit:-M} # K, M, G
638 ior_xferSize=${ior_xferSize:-1M}
639 ior_type=${ior_type:-POSIX}
640 ior_DURATION=${ior_DURATION:-30} # minutes
641 ior_CLEANUP=${ior_CLEANUP:-true}
643 case ${ior_blockUnit} in
645 multiplier=$((1024 * 1024 * 1024))
648 multiplier=$((1024 * 1024))
653 *) error "Incorrect block unit should be one of [KMG]"
657 # calculate the space in bytes
658 local space=$(df -B 1 -P $dir | tail -n 1 | awk '{ print $4 }')
659 local total_threads=$((num_clients * ior_THREADS))
660 echo "+ $ior_blockSize * $multiplier * $total_threads "
661 if [ $((space / 2)) -le \
662 $((ior_blockSize * multiplier * total_threads)) ]; then
663 ior_blockSize=$((space / 2 / multiplier / total_threads))
664 [ $ior_blockSize -eq 0 ] &&
665 skip_env "Need free space more than $((2 * total_threads)) \
666 ${ior_blockUnit}: have $((space / multiplier))"
668 echo "(reduced blockSize to $ior_blockSize \
669 ${ior_blockUnit} bytes)"
672 print_opts IOR ior_THREADS ior_DURATION MACHINEFILE
674 client_load_mkdir $testdir
676 # mpi_run uses mpiuser
678 [[ "$ior_stripe_params" && -z "$ior_STRIPEPARAMS" ]] &&
679 ior_STRIPEPARAMS="$ior_stripe_params" &&
680 echo "got deprecated ior_stripe_params,"\
681 "use ior_STRIPEPARAMS instead"
682 setstripe_getstripe $testdir $ior_STRIPEPARAMS
686 # contiguous bytes to write per task (e.g.: 8, 4K, 2M, 1G)"
688 # -t N transferSize -- size of transfer in bytes (e.g.: 8, 4K, 2M, 1G)"
689 # -w writeFile -- write file"
690 # -r readFile -- read existing file"
691 # -W checkWrite -- check read after write"
692 # -C reorderTasks -- changes task ordering to n+1 ordering for readback
693 # -T maxTimeDuration -- max time in minutes to run tests"
694 # -k keepFile -- keep testFile(s) on program exit
697 if [ -n "$ior_custom_params" ]; then
698 cmd="$IOR -o $testdir/iorData $ior_custom_params"
700 cmd="$IOR -a $ior_type -b ${ior_blockSize}${ior_blockUnit} \
701 -o $testdir/iorData -t $ior_xferSize -v -C -w -r -W \
702 -i $ior_iteration -T $ior_DURATION -k"
705 [ $type = "fpp" ] && cmd="$cmd -F"
708 # find out if we need to use srun by checking $SRUN_PARTITION
709 if [ "$SRUN_PARTITION" ]; then
710 $SRUN $SRUN_OPTIONS -D $testdir -w $clients -N $num_clients \
711 -n $((num_clients * ior_THREADS)) -p $SRUN_PARTITION \
714 mpi_ior_custom_threads=${mpi_ior_custom_threads:-"$((num_clients * ior_THREADS))"}
715 mpi_run ${MACHINEFILE_OPTION} ${MACHINEFILE} \
716 -np $mpi_ior_custom_threads $cmd
721 if [ $rc != 0 ] ; then
722 error "ior failed! $rc"
724 $ior_CLEANUP && rm -rf $testdir || true
728 MIB=${MIB:=$(which mib 2> /dev/null || true)}
729 [ "$NFSCLIENT" ] && skip "skipped for NFSCLIENT mode"
730 [ x$MIB = x ] && skip_env "MIB not found"
733 mib_THREADS=${mib_THREADS:-2}
734 mib_xferSize=${mib_xferSize:-1m}
735 mib_xferLimit=${mib_xferLimit:-5000}
736 mib_timeLimit=${mib_timeLimit:-300}
737 mib_STRIPEPARAMS=${mib_STRIPEPARAMS:-"-c -1"}
739 print_opts MIB mib_THREADS mib_xferSize mib_xferLimit mib_timeLimit \
742 local testdir=$DIR/d0.mib
744 setstripe_getstripe $testdir $mib_STRIPEPARAMS
746 # mpi_run uses mpiuser
750 # -I Show intermediate values in output
751 # -H Show headers in output
752 # -L Do not issue new system calls after this many seconds
753 # -s Use system calls of this size
755 # -l Issue no more than this many system calls
756 local cmd="$MIB -t $testdir -s $mib_xferSize -l $mib_xferLimit \
757 -L $mib_timeLimit -HI -p mib.$(date +%Y%m%d%H%M%S)"
760 # find out if we need to use srun by checking $SRUN_PARTITION
761 if [ "$SRUN_PARTITION" ]; then
762 $SRUN $SRUN_OPTIONS -D $testdir -w $clients -N $num_clients \
763 -n $((num_clients * mib_THREADS)) -p $SRUN_PARTITION \
766 mpi_run ${MACHINEFILE_OPTION} ${MACHINEFILE} \
767 -np $((num_clients * mib_THREADS)) $cmd
772 if [ $rc != 0 ] ; then
773 error "mib failed! $rc"
779 CASC_RW=${CASC_RW:-$(which cascading_rw 2> /dev/null || true)}
780 [ x$CASC_RW = x ] && skip_env "cascading_rw not found"
781 [ "$NFSCLIENT" ] && skip "skipped for NFSCLIENT mode"
784 casc_THREADS=${casc_THREADS:-2}
785 casc_REP=${casc_REP:-300}
788 # Need space estimation here.
790 print_opts CASC_RW clients casc_THREADS casc_REP MACHINEFILE
792 local testdir=$DIR/d0.cascading_rw
794 setstripe_getstripe $testdir $casc_STRIPEPARAMS
796 # mpi_run uses mpiuser
800 # -n: repeat test # times
802 local cmd="$CASC_RW -g -d $testdir -n $casc_REP"
805 mpi_run ${MACHINEFILE_OPTION} ${MACHINEFILE} \
806 -np $((num_clients * $casc_THREADS)) $cmd
810 if [ $rc != 0 ] ; then
811 error "cascading_rw failed! $rc"
816 run_write_append_truncate() {
817 [ "$NFSCLIENT" ] && skip "skipped for NFSCLIENT mode"
818 # location is lustre/tests dir
819 WRITE_APPEND_TRUNCATE=${WRITE_APPEND_TRUNCATE:-$(which \
820 write_append_truncate 2> /dev/null || true)}
821 [[ -n "$WRITE_APPEND_TRUNCATE" ]] ||
822 skip_env "write_append_truncate not found"
825 write_THREADS=${write_THREADS:-8}
826 write_REP=${write_REP:-10000}
829 # Need space estimation here.
831 local testdir=$DIR/d0.write_append_truncate
832 local file=$testdir/f0.wat
834 print_opts clients write_REP write_THREADS MACHINEFILE
837 # mpi_run uses mpiuser
838 setstripe_getstripe $testdir $write_STRIPEPARAMS
842 local cmd="$WRITE_APPEND_TRUNCATE -n $write_REP $file"
845 mpi_run ${MACHINEFILE_OPTION} ${MACHINEFILE} \
846 -np $((num_clients * $write_THREADS)) $cmd
850 if [ $rc != 0 ] ; then
851 error "write_append_truncate failed! $rc"
857 run_write_disjoint() {
858 WRITE_DISJOINT=${WRITE_DISJOINT:-$(which write_disjoint 2> /dev/null ||
860 [ x$WRITE_DISJOINT = x ] && skip_env "write_disjoint not found"
861 [ "$NFSCLIENT" ] && skip "skipped for NFSCLIENT mode"
864 wdisjoint_THREADS=${wdisjoint_THREADS:-4}
865 wdisjoint_REP=${wdisjoint_REP:-10000}
869 # Need space estimation here.
871 print_opts WRITE_DISJOINT clients wdisjoint_THREADS wdisjoint_REP \
873 local testdir=$DIR/d0.write_disjoint
875 setstripe_getstripe $testdir $wdisjoint_STRIPEPARAMS
877 # mpi_run uses mpiuser
880 local cmd="$WRITE_DISJOINT -f $testdir/file -n $wdisjoint_REP -m \
884 mpi_run ${MACHINEFILE_OPTION} ${MACHINEFILE} \
885 -np $((num_clients * $wdisjoint_THREADS)) $cmd
889 if [ $rc != 0 ] ; then
890 error "write_disjoint failed! $rc"
895 run_parallel_grouplock() {
896 PARALLEL_GROUPLOCK=${PARALLEL_GROUPLOCK:-$(which parallel_grouplock \
897 2> /dev/null || true)}
899 [ x$PARALLEL_GROUPLOCK = x ] && skip "PARALLEL_GROUPLOCK not found"
900 [ "$NFSCLIENT" ] && skip "skipped for NFSCLIENT mode"
902 parallel_grouplock_MINTASKS=${parallel_grouplock_MINTASKS:-5}
904 print_opts clients parallel_grouplock_MINTASKS MACHINEFILE
906 local testdir=$DIR/d0.parallel_grouplock
908 setstripe_getstripe $testdir $parallel_grouplock_STRIPEPARAMS
910 # mpi_run uses mpiuser
916 for i in $(seq 12); do
918 local cmd="$PARALLEL_GROUPLOCK -g -v -d $testdir $subtest"
921 mpi_run ${MACHINEFILE_OPTION} ${MACHINEFILE} \
922 -np $parallel_grouplock_MINTASKS $cmd
924 if [ $rc != 0 ] ; then
925 error_noexit "parallel_grouplock subtests $subtest " \
928 echo "parallel_grouplock subtests $subtest PASS"
930 let status=$((status + rc))
931 # clear debug to collect one log per one test
932 do_nodes $(comma_list $(nodes_list)) lctl clear
934 [ $status -eq 0 ] || error "parallel_grouplock status: $status"
938 cleanup_statahead () {
945 for i in $(seq 0 $num_mntpts);do
946 zconf_umount_clients $clients ${mntpt_root}$i ||
947 error_exit "Failed to umount lustre on ${mntpt_root}$i"
952 if [[ -n $NFSCLIENT ]]; then
953 skip "Statahead testing is not supported on NFS clients."
955 [ x$MDSRATE = x ] && skip_env "mdsrate not found"
957 statahead_NUMMNTPTS=${statahead_NUMMNTPTS:-5}
958 statahead_NUMFILES=${statahead_NUMFILES:-500000}
960 print_opts MDSRATE clients statahead_NUMMNTPTS statahead_NUMFILES
964 # do not use default "d[0-9]*" dir name
965 # to avoid of rm $statahead_NUMFILES (500k) files in t-f cleanup
967 local testdir=$DIR/$dir
969 # cleanup only if dir exists
970 # cleanup only $statahead_NUMFILES number of files
971 # ignore the other files created by someone else
973 mdsrate_cleanup $((num_clients * 32)) $MACHINEFILE \
974 $statahead_NUMFILES $testdir 'f%%d' --ignore
977 setstripe_getstripe $testdir $statahead_STRIPEPARAMS
979 # mpi_run uses mpiuser
982 local num_files=$statahead_NUMFILES
984 local IFree=$(inodes_available)
985 if [ $IFree -lt $num_files ]; then
991 local cmd1="${MDSRATE} ${MDSRATE_DEBUG} --mknod --dir $testdir"
992 local cmd2="--nfiles $num_files --filefmt 'f%%d'"
993 local cmd="$cmd1 $cmd2"
996 mpi_run ${MACHINEFILE_OPTION} ${MACHINEFILE} \
997 -np $((num_clients * 32)) $cmd
1001 if [ $rc != 0 ] ; then
1002 error "mdsrate failed to create $rc"
1006 local num_mntpts=$statahead_NUMMNTPTS
1007 local mntpt_root=$TMP/mntpt/lustre
1008 local mntopts=$MNTOPTSTATAHEAD
1010 echo "Mounting $num_mntpts lustre clients starts on $clients"
1011 trap "cleanup_statahead $clients $mntpt_root $num_mntpts" EXIT ERR
1012 for i in $(seq 0 $num_mntpts); do
1013 zconf_mount_clients $clients ${mntpt_root}$i "$mntopts" ||
1014 error_exit "Failed to mount lustre on ${mntpt_root}$i on $clients"
1017 do_rpc_nodes $clients cancel_lru_locks mdc
1019 do_rpc_nodes $clients do_ls $mntpt_root $num_mntpts $dir
1021 mdsrate_cleanup $((num_clients * 32)) $MACHINEFILE \
1022 $num_files $testdir 'f%%d' --ignore
1024 # use rm instead of rmdir because of
1025 # testdir could contain the files created by someone else,
1026 # or by previous run where is num_files prev > num_files current
1028 cleanup_statahead $clients $mntpt_root $num_mntpts
1031 cleanup_rr_alloc () {
1033 local mntpt_root="$2"
1034 local rr_alloc_MNTPTS="$3"
1035 local mntpt_dir=$(dirname ${mntpt_root})
1037 $LFS find $DIR/$tdir -type f | xargs -n1 -P8 unlink
1038 for ((i=0; i < rr_alloc_MNTPTS; i++)); do
1039 zconf_umount_clients $clients ${mntpt_root}$i ||
1040 error_exit "Failed to umount lustre on ${mntpt_root}$i"
1042 do_nodes $clients "rm -rf $mntpt_dir"
1046 remote_mds_nodsh && skip "remote MDS with nodsh"
1048 RR_ALLOC=${RR_ALLOC:-$(which rr_alloc 2> /dev/null || true)}
1049 [[ -n "$RR_ALLOC" ]] || skip_env "rr_alloc not found"
1051 echo "===Test gives more reproduction percentage if number of "
1052 echo " client and ost are more. Test with 44 or more clients "
1053 echo " and 73 or more OSTs gives 100% reproduction rate=="
1055 declare -a diff_max_min_arr
1057 local qos_prec_objs="${TMP}/qos_and_precreated_objects"
1058 local rr_alloc_NFILES=${rr_alloc_NFILES:-555}
1059 local rr_alloc_MNTPTS=${rr_alloc_MNTPTS:-11}
1060 local total_MNTPTS=$((rr_alloc_MNTPTS * num_clients))
1061 local mntpt_root="${TMP}/rr_alloc_mntpt/lustre"
1062 test_mkdir -c $MDSCOUNT $DIR/$tdir
1063 setstripe_getstripe $DIR/$tdir $rr_alloc_STRIPEPARAMS
1065 ost_set_temp_seq_width_all $DATA_SEQ_MAX_WIDTH
1067 (( ONLY_REPEAT_ITER == 1 )) || wait_delete_completed
1070 $LFS df -i $DIR/$tdir
1071 chmod 0777 $DIR/$tdir
1073 stack_trap "cleanup_rr_alloc $clients $mntpt_root $rr_alloc_MNTPTS"
1074 for ((i=0; i < rr_alloc_MNTPTS; i++)); do
1075 zconf_mount_clients $clients ${mntpt_root}$i $MOUNT_OPTS ||
1076 error_exit "Failed to mount lustre on ${mntpt_root}$i $clients"
1079 # Save mdt values, set threshold to 100% i.e always Round Robin,
1080 # restore the saved values again after creating files...
1081 save_lustre_params mds1 \
1082 "lod.$FSNAME-MDT0000*.qos_threshold_rr" > $qos_prec_objs
1083 save_lustre_params mds1 \
1084 "osp.$FSNAME-OST*-osc-MDT0000.create_count" >> $qos_prec_objs
1085 stack_trap "restore_lustre_params <$qos_prec_objs; rm -f $qos_prec_objs"
1087 # Make sure that every osp has enough precreated objects for the file
1090 # The MDS does not precreate objects if there are at least
1091 # create_count / 2 precreated objects available for the OST.
1092 # Set 'create_count' to 2x required number to force creation.
1094 # foeo = file on each ost. calc = calculated.
1095 local foeo_calc=$((rr_alloc_NFILES * total_MNTPTS / OSTCOUNT))
1096 local create_count=$((2 * foeo_calc))
1097 local max_create_count=$(do_facet $SINGLEMDS "$LCTL get_param -n \
1098 osp.*OST0000*MDT0000.max_create_count")
1100 # create_count accepted values:
1101 # [OST_MIN_PRECREATE=32, OST_MAX_PRECREATE=20000]
1102 # values exceeding OST_MAX_PRECREATE are lowered to half of the maximum.
1103 (( create_count >= 32 )) || create_count=32
1104 (( create_count <= max_create_count )) ||
1105 create_count=$((max_create_count / 2))
1107 local mdts=$(comma_list $(mdts_nodes))
1109 do_nodes $mdts "$LCTL set_param lod.*.qos_threshold_rr=100 \
1110 osp.*.create_count=$create_count"
1112 # Check for enough precreated objects... We should not
1113 # fail here because code(osp_precreate.c) also takes care of it.
1114 # So we have good chances of passing test even if this check fails.
1115 local stop=$((SECONDS + 60))
1119 while ((SECONDS < stop)); do
1122 for ((mdt_idx = 0; mdt_idx < $MDSCOUNT; mdt_idx++)); do
1123 for ((ost_idx = 0; ost_idx < $OSTCOUNT; ost_idx++)); do
1124 local count=$(precreated_ost_obj_count \
1126 if ((count < foeo_calc / 6)); then
1127 local this_pair=mdt$mdt_idx.$ost_idx
1131 # allow one iteration to precreate,
1132 # then force create new sequence once
1133 [[ "$forced" =~ "$this_pair" ]] &&
1136 if [[ "$waited" =~ "$this_pair" ]]; then
1137 mkdir -p $DIR/$tdir.2
1138 force_new_seq_ost $DIR/$tdir.2 \
1139 mds$((mdt_idx+1)) $ost_idx
1140 forced="$forced $this_pair"
1142 waited="$waited $this_pair"
1148 (( sleep > 0 )) || break
1152 [[ -d $DIR/$tdir.2 ]] && stack_trap "rm -rf $DIR/$tdir.2"
1154 local cmd="$RR_ALLOC $mntpt_root/$tdir/f $rr_alloc_NFILES $num_clients"
1156 if [[ $total_MNTPTS -ne 0 ]]; then
1157 # Now start the actual file creation app.
1158 mpi_run "-np $total_MNTPTS" $cmd || return
1160 error "No mount point"
1163 diff_max_min_arr=($($LFS getstripe -r $DIR/$tdir/ |
1164 awk '/lmm_stripe_offset:/ {print $2}' |
1165 sort | uniq -c | tee /dev/stderr |
1166 awk 'NR==1 {min=max=$1} \
1167 { $1<min ? min=$1:min; $1>max ? max=$1:max} \
1168 END {print max-min, max, min}'))
1170 # In case of fairly large number of file creation using RR (round-robin)
1171 # there can be two cases in which deviation will occur than the regular
1172 # RR algo behaviour-
1173 # 1- When rr_alloc does not start right with 'lqr_start_count' reseeded,
1174 # 2- When rr_alloc does not finish with 'lqr_start_count == 0'.
1175 # So the difference of files for any 2 OST should not be more than 2-3.
1176 # In some cases it may be more, but shouldn't be > .3% of the files.
1177 local max_diff=$((create_count > 600 ? create_count / 200 : $MDSCOUNT))
1179 (( ${diff_max_min_arr[0]} <= $max_diff )) || {
1181 $LFS df -i $DIR/$tdir
1183 error "max/min OST objects (${diff_max_min_arr[1]} : ${diff_max_min_arr[2]}) too different"
1188 # fs_test.x is the default name for exe
1189 FS_TEST=${FS_TEST:=$(which fs_test.x 2> /dev/null || true)}
1191 local clients=${CLIENTS:-$(hostname)}
1192 local testdir=$DIR/d0.fs_test
1193 local file=${testdir}/fs_test
1194 fs_test_threads=${fs_test_threads:-2}
1195 fs_test_type=${fs_test_type:-1}
1196 fs_test_nobj=${fs_test_nobj:-10}
1197 fs_test_check=${fs_test_check:-3}
1198 fs_test_strided=${fs_test_strided:-1}
1199 fs_test_touch=${fs_test_touch:-3}
1200 fs_test_supersize=${fs_test_supersize:-1}
1201 fs_test_op=${fs_test_op:-write}
1202 fs_test_barriers=${fs_test_barriers:-bopen,bwrite,bclose}
1203 fs_test_io=${fs_test_io:-mpi}
1204 fs_test_objsize=${fs_test_objsize:-100}
1205 fs_test_objunit=${fs_test_objunit:-1048576} # 1 mb
1206 fs_test_ndirs=${fs_test_ndirs:-80000}
1208 [ x$FS_TEST = x ] && skip "FS_TEST not found"
1210 # Space estimation in bytes
1211 local space=$(df -B 1 -P $dir | tail -n 1 | awk '{ print $4 }')
1212 local total_threads=$((num_clients * fs_test_threads))
1213 echo "+ $fs_test_objsize * $fs_test_objunit * $total_threads "
1214 if [ $((space / 2)) -le \
1215 $((fs_test_objsize * fs_test_objunit * total_threads)) ]; then
1216 fs_test_objsize=$((space / 2 / fs_test_objunit /
1218 [ $fs_test_objsize -eq 0 ] &&
1219 skip_env "Need free space more than \
1220 $((2 * total_threads * fs_test_objunit)) \
1221 : have $((space / fs_test_objunit))"
1223 echo "(reduced objsize to \
1224 $((fs_test_objsize * fs_test_objunit)) bytes)"
1227 print_opts FS_TEST clients fs_test_threads fs_test_objsize MACHINEFILE
1230 setstripe_getstripe $testdir $fs_test_STRIPEPARAMS
1232 # mpi_run uses mpiuser
1235 # --nodb Turn off the database code at runtime
1236 # -g --target The path to the data file
1237 # -t --type Whether to do N-N (1) or N-1 (2)
1238 # -n --nobj The number of objects written/read by each proc
1239 # -z --size The size of each object
1240 # -d ---num_nn_dirs Number of subdirectories for files
1241 # -C --check Check every byte using argument 3.
1242 # --collective Whether to use collective I/O (for N-1, mpi-io only)
1243 # -s --strided Whether to use a strided pattern (for N-1 only)
1244 # -T --touch Touch every byte using argument 3
1245 # -o --op Whether to read only (read) or write only (write)
1246 # -b --barriers When to barrier.
1247 # -i --io Use POSIX, MPI, or PLFS IO routines (mpi|posix|plfs)
1248 # -S --supersize Specify how many objects per superblock
1250 local cmd="$FS_TEST -nodb -g $file -t $fs_test_type -n $fs_test_nobj \
1251 -z $((fs_test_objsize * fs_test_objunit)) -d $fs_test_ndirs \
1252 -C $fs_test_check -collective -s $fs_test_strided \
1253 -T $fs_test_touch -o $fs_test_op -b $fs_test_barriers \
1254 -i $fs_test_io -S $fs_test_supersize"
1257 mpi_run "-np $((num_clients * fs_test_threads))" $cmd
1260 if [ $rc != 0 ] ; then
1261 error "fs_test failed! $rc"
1267 ior_mdtest_parallel() {
1275 run_mdtest $type || rc2=$?
1276 [[ $rc2 -ne 0 ]] && echo "mdtest failed with error $rc2"
1278 wait $pids || rc1=$?
1279 [[ $rc1 -ne 0 ]] && echo "ior failed with error $rc1"
1281 [[ $rc1 -ne 0 || $rc2 -ne 0 ]] && return 1
1286 FIO=${FIO:=$(which fio 2> /dev/null || true)}
1288 local clients=${CLIENTS:-$(hostname)}
1289 local fio_jobNum=${fio_jobNum:-4}
1290 local fio_jobFile=${fio_jobFile:-$TMP/fiojobfile.$(date +%s)}
1291 local fio_bs=${fio_bs:-1}
1292 local testdir=$DIR/d0.fio
1293 local file=${testdir}/fio
1295 local propagate=false
1297 [ "$SLOW" = "no" ] || runtime=600
1299 [ x$FIO = x ] && skip_env "FIO not found"
1302 setstripe_getstripe $testdir $fio_STRIPEPARAMS
1304 # use fio job file if exists,
1305 # create a simple one if missing
1306 if ! [ -f $fio_jobFile ]; then
1307 cat >> $fio_jobFile <<EOF
1313 filename=${file}_\$(hostname)
1315 # bs size increased by $i for each job
1316 for ((i=1; i<=fio_jobNum; i++)); do
1317 cat >> $fio_jobFile <<EOF
1320 bs=$(( fio_bs * i ))m
1323 # job file is created, should be propagated to all clients
1328 # propagate the job file if not all clients have it yet or
1329 # if the job file was created during the test run
1330 if ! do_nodesv $clients " [ -f $fio_jobFile ] " ||
1332 local cfg=$(cat $fio_jobFile)
1333 do_nodes $clients "echo \\\"$cfg\\\" > ${fio_jobFile}" ||
1334 error "job file $fio_jobFile is not propagated"
1335 do_nodesv $clients "cat ${fio_jobFile}"
1338 cmd="$FIO $fio_jobFile"
1341 log "clients: $clients $cmd"
1344 do_nodesv $clients "$cmd "
1347 [ $rc = 0 ] || error "fio failed: $rc"
1352 XDD=${XDD:=$(which xdd 2> /dev/null || true)}
1354 local clients=${CLIENTS:-$(hostname)}
1355 local testdir=$DIR/d0.xdd
1356 xdd_queuedepth=${xdd_queuedepth:-4}
1357 xdd_blocksize=${xdd_blocksize:-512}
1358 xdd_reqsize=${xdd_reqsize:-128}
1359 xdd_mbytes=${xdd_mbytes:-100}
1360 xdd_passes=${xdd_passes:-40}
1361 xdd_rwratio=${xdd_rwratio:-0}
1362 xdd_ntargets=${xdd_ntargets:-6}
1363 local xdd_custom_params=${xdd_custom_params:-"-dio -stoponerror \
1364 -maxpri -minall -noproclock -nomemlock"}
1366 [ x$XDD = x ] && skip "XDD not found"
1368 print_opts XDD clients xdd_queuedepth xdd_blocksize xdd_reqsize \
1369 xdd_mbytes xdd_passes xdd_rwratio
1372 setstripe_getstripe $testdir $xdd_STRIPEPARAMS
1375 # Target files creates based on the given number of targets
1376 for (( i=0; i < $xdd_ntargets; i++ ))
1378 files+="${testdir}/xdd"$i" "
1381 # -targets specifies the devices or files to perform operation
1382 # -reqsize number of 'blocks' per operation
1383 # -mbytes number of 1024*1024-byte blocks to transfer
1384 # -blocksize size of a single 'block'
1385 # -passes number of times to read mbytes
1386 # -queuedepth number of commands to queue on the target
1387 # -rwratio percentage of read to write operations
1388 # -verbose will print out statistics on each pass
1390 local cmd="$XDD -targets $xdd_ntargets $files -reqsize $xdd_reqsize \
1391 -mbytes $xdd_mbytes -blocksize $xdd_blocksize \
1392 -passes $xdd_passes -queuedepth $xdd_queuedepth \
1393 -rwratio $xdd_rwratio -verbose $xdd_custom_params"
1397 do_nodesv $clients "$cmd "
1400 [ $rc = 0 ] || error "xdd failed: $rc"
1405 client_load_mkdir () {
1407 local parent=$(dirname $dir)
1409 local mdtcount=$($LFS df $parent 2> /dev/null | grep -c MDT)
1410 if [ $mdtcount -le 1 ] || ! is_lustre ${parent}; then
1411 mkdir $dir || return 1
1414 mdt_idx=$((RANDOM % mdtcount))
1415 if $RECOVERY_SCALE_ENABLE_STRIPED_DIRS; then
1416 # stripe_count in range [1,mdtcount]
1417 # $LFS mkdir treats stripe_count 0 and 1 the same
1418 stripe_count_opt="-c$((RANDOM % mdtcount + 1))"
1424 if $RECOVERY_SCALE_ENABLE_REMOTE_DIRS ||
1425 $RECOVERY_SCALE_ENABLE_STRIPED_DIRS; then
1426 $LFS mkdir -i$mdt_idx $stripe_count_opt $dir ||
1429 mkdir $dir || return 1
1431 $LFS getdirstripe $dir || return 1
1433 if [ -n "$client_load_SETSTRIPEPARAMS" ]; then
1434 $LFS setstripe $client_load_SETSTRIPEPARAMS $dir ||
1437 $LFS getstripe $dir || return 1
1440 enospc_detected () {
1441 grep "No space left on device" $1 | grep -qv grep