Whamcloud - gitweb
LU-691 tests: Fix OST index errors in test suite
[fs/lustre-release.git] / lustre / tests / test-framework.sh
1 #!/bin/bash
2 # vim:expandtab:shiftwidth=4:softtabstop=4:tabstop=4:
3
4 trap 'print_summary && touch $TF_FAIL && \
5     echo "test-framework exiting on error"' ERR
6 set -e
7 #set -x
8
9 export REFORMAT=${REFORMAT:-""}
10 export WRITECONF=${WRITECONF:-""}
11 export VERBOSE=${VERBOSE:-false}
12 export CATASTROPHE=${CATASTROPHE:-/proc/sys/lnet/catastrophe}
13 export GSS=false
14 export GSS_KRB5=false
15 export GSS_PIPEFS=false
16 export IDENTITY_UPCALL=default
17 export QUOTA_AUTO=1
18
19 # LOAD_LLOOP: LU-409: only load llite_lloop module if kernel < 2.6.32 or
20 #             LOAD_LLOOP is true. LOAD_LLOOP is false by default.
21 export LOAD_LLOOP=${LOAD_LLOOP:-false}
22
23 #export PDSH="pdsh -S -Rssh -w"
24
25 # function used by scripts run on remote nodes
26 LUSTRE=${LUSTRE:-$(cd $(dirname $0)/..; echo $PWD)}
27 . $LUSTRE/tests/functions.sh
28 . $LUSTRE/tests/yaml.sh
29
30 LUSTRE_TESTS_CFG_DIR=${LUSTRE_TESTS_CFG_DIR:-${LUSTRE}/tests/cfg}
31
32 EXCEPT_LIST_FILE=${EXCEPT_LIST_FILE:-${LUSTRE_TESTS_CFG_DIR}/tests-to-skip.sh}
33
34 if [ -f "$EXCEPT_LIST_FILE" ]; then
35     echo "Reading test skip list from $EXCEPT_LIST_FILE"
36     cat $EXCEPT_LIST_FILE
37     . $EXCEPT_LIST_FILE
38 fi
39
40 [ -z "$MODPROBECONF" -a -f /etc/modprobe.conf ] && MODPROBECONF=/etc/modprobe.conf
41 [ -z "$MODPROBECONF" -a -f /etc/modprobe.d/Lustre ] && MODPROBECONF=/etc/modprobe.d/Lustre
42
43 assert_DIR () {
44     local failed=""
45     [[ $DIR/ = $MOUNT/* ]] || \
46         { failed=1 && echo "DIR=$DIR not in $MOUNT. Aborting."; }
47     [[ $DIR1/ = $MOUNT1/* ]] || \
48         { failed=1 && echo "DIR1=$DIR1 not in $MOUNT1. Aborting."; }
49     [[ $DIR2/ = $MOUNT2/* ]] || \
50         { failed=1 && echo "DIR2=$DIR2 not in $MOUNT2. Aborting"; }
51
52     [ -n "$failed" ] && exit 99 || true
53 }
54
55 usage() {
56     echo "usage: $0 [-r] [-f cfgfile]"
57     echo "       -r: reformat"
58
59     exit
60 }
61
62 print_summary () {
63     trap 0
64     [ "$TESTSUITE" == "lfsck" ] && return 0
65     [ -n "$ONLY" ] && echo "WARNING: ONLY is set to $(echo $ONLY)"
66     local details
67     local form="%-13s %-17s %-9s %s %s\n"
68     printf "$form" "status" "script" "Total(sec)" "E(xcluded) S(low)"
69     echo "------------------------------------------------------------------------------------"
70     for O in $DEFAULT_SUITES; do
71         O=$(echo $O  | tr "-" "_" | tr "[:lower:]" "[:upper:]")
72         [ "${!O}" = "no" ] && continue || true
73         local o=$(echo $O  | tr "[:upper:]_" "[:lower:]-")
74         local log=${TMP}/${o}.log
75         if is_sanity_benchmark $o; then
76             log=${TMP}/sanity-benchmark.log
77         fi
78         local slow=
79         local skipped=
80         local total=
81         local status=Unfinished
82         if [ -f $log ]; then
83             skipped=$(grep excluded $log | awk '{ printf " %s", $3 }' | sed 's/test_//g')
84             slow=$(egrep "^PASS|^FAIL" $log | tr -d "("| sed s/s\)$//g | sort -nr -k 3  | head -5 |  awk '{ print $2":"$3"s" }')
85             total=$(grep duration $log | awk '{ print $2}')
86             if [ "${!O}" = "done" ]; then
87                 status=Done
88             fi
89             if $DDETAILS; then
90                 local durations=$(egrep "^PASS|^FAIL" $log |  tr -d "("| sed s/s\)$//g | awk '{ print $2":"$3"|" }')
91                 details=$(printf "%s\n%s %s %s\n" "$details" "DDETAILS" "$O" "$(echo $durations)")
92             fi
93         fi
94         printf "$form" $status "$O" "${total}" "E=$skipped"
95         printf "$form" "-" "-" "-" "S=$(echo $slow)"
96     done
97
98     for O in $DEFAULT_SUITES; do
99         O=$(echo $O  | tr "-" "_" | tr "[:lower:]" "[:upper:]")
100         if [ "${!O}" = "no" ]; then
101             printf "$form" "Skipped" "$O" ""
102         fi
103     done
104
105     # print the detailed tests durations if DDETAILS=true
106     if $DDETAILS; then
107         echo "$details"
108     fi
109 }
110
111 init_test_env() {
112     export LUSTRE=`absolute_path $LUSTRE`
113     export TESTSUITE=`basename $0 .sh`
114     export TEST_FAILED=false
115     export FAIL_ON_SKIP_ENV=${FAIL_ON_SKIP_ENV:-false}
116
117     export MKE2FS=${MKE2FS:-mke2fs}
118     export DEBUGFS=${DEBUGFS:-debugfs}
119     export TUNE2FS=${TUNE2FS:-tune2fs}
120     export E2LABEL=${E2LABEL:-e2label}
121     export DUMPE2FS=${DUMPE2FS:-dumpe2fs}
122     export E2FSCK=${E2FSCK:-e2fsck}
123     export LFSCK_BIN=${LFSCK_BIN:-lfsck}
124
125     export LFSCK_ALWAYS=${LFSCK_ALWAYS:-"no"} # check fs after each test suite
126     export FSCK_MAX_ERR=4   # File system errors left uncorrected
127
128     #[ -d /r ] && export ROOT=${ROOT:-/r}
129     export TMP=${TMP:-$ROOT/tmp}
130     export TESTSUITELOG=${TMP}/${TESTSUITE}.log
131     export LOGDIR=${LOGDIR:-${TMP}/test_logs/$(date +%s)}
132     export TESTLOG_PREFIX=$LOGDIR/$TESTSUITE
133
134     export HOSTNAME=${HOSTNAME:-$(hostname -s)}
135     if ! echo $PATH | grep -q $LUSTRE/utils; then
136         export PATH=$LUSTRE/utils:$PATH
137     fi
138     if ! echo $PATH | grep -q $LUSTRE/utils/gss; then
139         export PATH=$LUSTRE/utils/gss:$PATH
140     fi
141     if ! echo $PATH | grep -q $LUSTRE/tests; then
142         export PATH=$LUSTRE/tests:$PATH
143     fi
144     if ! echo $PATH | grep -q $LUSTRE/../lustre-iokit/sgpdd-survey; then
145         export PATH=$LUSTRE/../lustre-iokit/sgpdd-survey:$PATH
146     fi
147     export LST=${LST:-"$LUSTRE/../lnet/utils/lst"}
148     [ ! -f "$LST" ] && export LST=$(which lst)
149     export SGPDDSURVEY=${SGPDDSURVEY:-"$LUSTRE/../lustre-iokit/sgpdd-survey/sgpdd-survey")}
150     [ ! -f "$SGPDDSURVEY" ] && export SGPDDSURVEY=$(which sgpdd-survey)
151     # Ubuntu, at least, has a truncate command in /usr/bin
152     # so fully path our truncate command.
153     export TRUNCATE=${TRUNCATE:-$LUSTRE/tests/truncate}
154     export MDSRATE=${MDSRATE:-"$LUSTRE/tests/mpi/mdsrate"}
155     [ ! -f "$MDSRATE" ] && export MDSRATE=$(which mdsrate 2> /dev/null)
156     if ! echo $PATH | grep -q $LUSTRE/tests/racer; then
157         export PATH=$LUSTRE/tests/racer:$PATH:
158     fi
159     if ! echo $PATH | grep -q $LUSTRE/tests/mpi; then
160         export PATH=$LUSTRE/tests/mpi:$PATH
161     fi
162     export RSYNC_RSH=${RSYNC_RSH:-rsh}
163     export LCTL=${LCTL:-"$LUSTRE/utils/lctl"}
164     [ ! -f "$LCTL" ] && export LCTL=$(which lctl)
165     export LFS=${LFS:-"$LUSTRE/utils/lfs"}
166     [ ! -f "$LFS" ] && export LFS=$(which lfs)
167     export L_GETIDENTITY=${L_GETIDENTITY:-"$LUSTRE/utils/l_getidentity"}
168     if [ ! -f "$L_GETIDENTITY" ]; then
169         if `which l_getidentity > /dev/null 2>&1`; then
170             export L_GETIDENTITY=$(which l_getidentity)
171         else
172             export L_GETIDENTITY=NONE
173         fi
174     fi
175     export LL_DECODE_FILTER_FID=${LL_DECODE_FILTER_FID:-"$LUSTRE/utils/ll_decode_filter_fid"}
176     [ ! -f "$LL_DECODE_FILTER_FID" ] && export LL_DECODE_FILTER_FID=$(which ll_decode_filter_fid)
177     export MKFS=${MKFS:-"$LUSTRE/utils/mkfs.lustre"}
178     [ ! -f "$MKFS" ] && export MKFS=$(which mkfs.lustre)
179     export TUNEFS=${TUNEFS:-"$LUSTRE/utils/tunefs.lustre"}
180     [ ! -f "$TUNEFS" ] && export TUNEFS=$(which tunefs.lustre)
181     export CHECKSTAT="${CHECKSTAT:-"checkstat -v"} "
182     export LUSTRE_RMMOD=${LUSTRE_RMMOD:-$LUSTRE/scripts/lustre_rmmod}
183     [ ! -f "$LUSTRE_RMMOD" ] && export LUSTRE_RMMOD=$(which lustre_rmmod 2> /dev/null)
184     export FSTYPE=${FSTYPE:-"ldiskfs"}
185     export NAME=${NAME:-local}
186     export LGSSD=${LGSSD:-"$LUSTRE/utils/gss/lgssd"}
187     [ "$GSS_PIPEFS" = "true" ] && [ ! -f "$LGSSD" ] && \
188         export LGSSD=$(which lgssd)
189     export LSVCGSSD=${LSVCGSSD:-"$LUSTRE/utils/gss/lsvcgssd"}
190     [ ! -f "$LSVCGSSD" ] && export LSVCGSSD=$(which lsvcgssd 2> /dev/null)
191     export KRB5DIR=${KRB5DIR:-"/usr/kerberos"}
192     export DIR2
193     export SAVE_PWD=${SAVE_PWD:-$LUSTRE/tests}
194     export AT_MAX_PATH
195
196     if [ "$ACCEPTOR_PORT" ]; then
197         export PORT_OPT="--port $ACCEPTOR_PORT"
198     fi
199
200     case "x$SEC" in
201         xkrb5*)
202             echo "Using GSS/krb5 ptlrpc security flavor"
203             which lgss_keyring > /dev/null 2>&1 || \
204                 error_exit "built with gss disabled! SEC=$SEC"
205             GSS=true
206             GSS_KRB5=true
207             ;;
208     esac
209
210     case "x$IDUP" in
211         xtrue)
212             IDENTITY_UPCALL=true
213             ;;
214         xfalse)
215             IDENTITY_UPCALL=false
216             ;;
217     esac
218     export LOAD_MODULES_REMOTE=${LOAD_MODULES_REMOTE:-false}
219
220     # Paths on remote nodes, if different
221     export RLUSTRE=${RLUSTRE:-$LUSTRE}
222     export RPWD=${RPWD:-$PWD}
223     export I_MOUNTED=${I_MOUNTED:-"no"}
224     if [ ! -f /lib/modules/$(uname -r)/kernel/fs/lustre/mds.ko -a \
225         ! -f /lib/modules/$(uname -r)/updates/kernel/fs/lustre/mds.ko -a \
226         ! -f `dirname $0`/../mds/mds.ko ]; then
227         export CLIENTMODSONLY=yes
228     fi
229
230     export SHUTDOWN_ATTEMPTS=${SHUTDOWN_ATTEMPTS:-3}
231
232     # command line
233
234     while getopts "rvwf:" opt $*; do
235         case $opt in
236             f) CONFIG=$OPTARG;;
237             r) REFORMAT=--reformat;;
238             v) VERBOSE=true;;
239             w) WRITECONF=writeconf;;
240             \?) usage;;
241         esac
242     done
243
244     shift $((OPTIND - 1))
245     ONLY=${ONLY:-$*}
246
247     # print the durations of each test if "true"
248     DDETAILS=${DDETAILS:-false}
249     [ "$TESTSUITELOG" ] && rm -f $TESTSUITELOG || true
250     rm -f $TMP/*active
251 }
252
253 case `uname -r` in
254 2.4.*) EXT=".o"; USE_QUOTA=no; [ ! "$CLIENTONLY" ] && FSTYPE=ext3;;
255     *) EXT=".ko"; USE_QUOTA=yes;;
256 esac
257
258
259 module_loaded () {
260    /sbin/lsmod | grep -q "^\<$1\>"
261 }
262
263 # Load a module on the system where this is running.
264 #
265 # Synopsis: load_module module_name [module arguments for insmod/modprobe]
266 #
267 # If module arguments are not given but MODOPTS_<MODULE> is set, then its value
268 # will be used as the arguments.  Otherwise arguments will be obtained from
269 # /etc/modprobe.conf, from /etc/modprobe.d/Lustre, or else none will be used.
270 #
271 load_module() {
272     local optvar
273     EXT=".ko"
274     module=$1
275     shift
276     BASE=`basename $module $EXT`
277
278     module_loaded ${BASE} && return
279
280     # If no module arguments were passed, get them from $MODOPTS_<MODULE>, else from
281     # modprobe.conf
282     if [ $# -eq 0 ]; then
283         # $MODOPTS_<MODULE>; we could use associative arrays, but that's not in
284         # Bash until 4.x, so we resort to eval.
285         optvar="MODOPTS_$(basename $module | tr a-z A-Z)"
286         eval set -- \$$optvar
287         if [ $# -eq 0 -a -n "$MODPROBECONF" ]; then
288             # Nothing in $MODOPTS_<MODULE>; try modprobe.conf
289             set -- $(grep -P "^options\\s+${BASE}" $MODPROBECONF)
290             # Get rid of "options $module"
291             (($# > 0)) && shift 2
292
293             # Ensure we have accept=all for lnet
294             if [ $(basename $module) = lnet ]; then
295                 # OK, this is a bit wordy...
296                 local arg accept_all_present=false
297                 for arg in "$@"; do
298                     [ "$arg" = accept=all ] && accept_all_present=true
299                 done
300                 $accept_all_present || set -- "$@" accept=all
301             fi
302         fi
303     fi
304
305     [ $# -gt 0 ] && echo "${module} options: '$*'"
306
307     # Note that insmod will ignore anything in modprobe.conf, which is why we're
308     # passing options on the command-line.
309     if [ "$BASE" == "lnet_selftest" ] && \
310             [ -f ${LUSTRE}/../lnet/selftest/${module}${EXT} ]; then
311         insmod ${LUSTRE}/../lnet/selftest/${module}${EXT}
312     elif [ -f ${LUSTRE}/${module}${EXT} ]; then
313         insmod ${LUSTRE}/${module}${EXT} "$@"
314     else
315         # must be testing a "make install" or "rpm" installation
316         # note failed to load ptlrpc_gss is considered not fatal
317         if [ "$BASE" == "ptlrpc_gss" ]; then
318             modprobe $BASE "$@" 2>/dev/null || echo "gss/krb5 is not supported"
319         else
320             modprobe $BASE "$@"
321         fi
322     fi
323 }
324
325 llite_lloop_enabled() {
326     local n1=$(uname -r | cut -d. -f1)
327     local n2=$(uname -r | cut -d. -f2)
328     local n3=$(uname -r | cut -d- -f1 | cut -d. -f3)
329
330     # load the llite_lloop module for < 2.6.32 kernels
331     if [[ $n1 -lt 2 ]] || [[ $n1 -eq 2 && $n2 -lt 6 ]] || \
332        [[ $n1 -eq 2 && $n2 -eq 6 && $n3 -lt 32 ]] || \
333         $LOAD_LLOOP; then
334         return 0
335     fi
336     return 1
337 }
338
339 load_modules_local() {
340     if [ -n "$MODPROBE" ]; then
341         # use modprobe
342         echo "Using modprobe to load modules"
343         return 0
344     fi
345
346     echo Loading modules from $LUSTRE
347     load_module ../libcfs/libcfs/libcfs
348     [ "$PTLDEBUG" ] && lctl set_param debug="$PTLDEBUG"
349     [ "$SUBSYSTEM" ] && lctl set_param subsystem_debug="${SUBSYSTEM# }"
350     load_module ../lnet/lnet/lnet
351     LNETLND=${LNETLND:-"socklnd/ksocklnd"}
352     load_module ../lnet/klnds/$LNETLND
353     load_module lvfs/lvfs
354     load_module obdclass/obdclass
355     load_module ptlrpc/ptlrpc
356     load_module ptlrpc/gss/ptlrpc_gss
357     [ "$USE_QUOTA" = "yes" -a "$LQUOTA" != "no" ] && load_module quota/lquota $LQUOTAOPTS
358     load_module fld/fld
359     load_module fid/fid
360     load_module lmv/lmv
361     load_module mdc/mdc
362     load_module osc/osc
363     load_module lov/lov
364     load_module mgc/mgc
365     if ! client_only; then
366         grep -q crc16 /proc/kallsyms || { modprobe crc16 2>/dev/null || true; }
367         grep -q -w jbd /proc/kallsyms || { modprobe jbd 2>/dev/null || true; }
368         grep -q -w jbd2 /proc/kallsyms || { modprobe jbd2 2>/dev/null || true; }
369         [ "$FSTYPE" = "ldiskfs" ] && load_module ../ldiskfs/ldiskfs/ldiskfs
370         load_module mgs/mgs
371         load_module mds/mds
372         load_module mdd/mdd
373         load_module mdt/mdt
374         load_module lvfs/fsfilt_$FSTYPE
375         load_module cmm/cmm
376         load_module osd-ldiskfs/osd_ldiskfs
377         load_module ost/ost
378         load_module obdfilter/obdfilter
379     fi
380
381
382     load_module llite/lustre
383     llite_lloop_enabled && load_module llite/llite_lloop
384     [ -d /r ] && OGDB=${OGDB:-"/r/tmp"}
385     OGDB=${OGDB:-$TMP}
386     rm -f $OGDB/ogdb-$HOSTNAME
387     $LCTL modules > $OGDB/ogdb-$HOSTNAME
388
389     # 'mount' doesn't look in $PATH, just sbin
390     if [ -f $LUSTRE/utils/mount.lustre ] && \
391        ! grep -qe "/sbin/mount\.lustre " /proc/mounts; then
392         [ ! -f /sbin/mount.lustre ] && touch /sbin/mount.lustre
393         mount --bind $LUSTRE/utils/mount.lustre /sbin/mount.lustre || true
394     fi
395 }
396
397 load_modules () {
398     load_modules_local
399     # bug 19124
400     # load modules on remote nodes optionally
401     # lustre-tests have to be installed on these nodes
402     if $LOAD_MODULES_REMOTE ; then
403         local list=$(comma_list $(remote_nodes_list))
404         echo loading modules on $list
405         do_rpc_nodes $list load_modules 
406     fi
407 }
408
409 check_mem_leak () {
410     LEAK_LUSTRE=$(dmesg | tail -n 30 | grep "obd_memory.*leaked" || true)
411     LEAK_PORTALS=$(dmesg | tail -n 20 | grep "Portals memory leaked" || true)
412     if [ "$LEAK_LUSTRE" -o "$LEAK_PORTALS" ]; then
413         echo "$LEAK_LUSTRE" 1>&2
414         echo "$LEAK_PORTALS" 1>&2
415         mv $TMP/debug $TMP/debug-leak.`date +%s` || true
416         echo "Memory leaks detected"
417         [ -n "$IGNORE_LEAK" ] && { echo "ignoring leaks" && return 0; } || true
418         return 1
419     fi
420 }
421
422 unload_modules() {
423     wait_exit_ST client # bug 12845
424
425     $LUSTRE_RMMOD $FSTYPE || return 2
426
427     if $LOAD_MODULES_REMOTE ; then
428         local list=$(comma_list $(remote_nodes_list))
429         if [ ! -z $list ]; then
430             echo unloading modules on $list
431             do_rpc_nodes $list $LUSTRE_RMMOD $FSTYPE
432             do_rpc_nodes $list check_mem_leak
433         fi
434     fi
435
436     if grep -qe "/sbin/mount\.lustre" /proc/mounts; then
437         umount /sbin/mount.lustre || true
438         [ -w /sbin/mount.lustre -a ! -s /sbin/mount.lustre ] && \
439             rm -f /sbin/mount.lustre || true
440     fi
441
442     check_mem_leak || return 254
443
444     echo "modules unloaded."
445     return 0
446 }
447
448 check_gss_daemon_nodes() {
449     local list=$1
450     dname=$2
451
452     do_nodesv $list "num=\\\$(ps -o cmd -C $dname | grep $dname | wc -l);
453 if [ \\\"\\\$num\\\" -ne 1 ]; then
454     echo \\\$num instance of $dname;
455     exit 1;
456 fi; "
457 }
458
459 check_gss_daemon_facet() {
460     facet=$1
461     dname=$2
462
463     num=`do_facet $facet ps -o cmd -C $dname | grep $dname | wc -l`
464     if [ $num -ne 1 ]; then
465         echo "$num instance of $dname on $facet"
466         return 1
467     fi
468     return 0
469 }
470
471 send_sigint() {
472     local list=$1
473     shift
474     echo Stopping $@ on $list
475     do_nodes $list "killall -2 $@ 2>/dev/null || true"
476 }
477
478 # start gss daemons on all nodes, or
479 # "daemon" on "list" if set
480 start_gss_daemons() {
481     local list=$1
482     local daemon=$2
483
484     if [ "$list" ] && [ "$daemon" ] ; then
485         echo "Starting gss daemon on nodes: $list"
486         do_nodes $list "$daemon" || return 8
487         return 0
488     fi
489
490     local list=$(comma_list $(mdts_nodes))
491
492     echo "Starting gss daemon on mds: $list"
493     do_nodes $list "$LSVCGSSD -v" || return 1
494     if $GSS_PIPEFS; then
495         do_nodes $list "$LGSSD -v" || return 2
496     fi
497
498     list=$(comma_list $(osts_nodes))
499     echo "Starting gss daemon on ost: $list"
500     do_nodes $list "$LSVCGSSD -v" || return 3
501     # starting on clients
502
503     local clients=${CLIENTS:-`hostname`}
504     if $GSS_PIPEFS; then
505         echo "Starting $LGSSD on clients $clients "
506         do_nodes $clients  "$LGSSD -v" || return 4
507     fi
508
509     # wait daemons entering "stable" status
510     sleep 5
511
512     #
513     # check daemons are running
514     #
515     list=$(comma_list $(mdts_nodes) $(osts_nodes))
516     check_gss_daemon_nodes $list lsvcgssd || return 5
517     if $GSS_PIPEFS; then
518         list=$(comma_list $(mdts_nodes))
519         check_gss_daemon_nodes $list lgssd || return 6
520     fi
521     if $GSS_PIPEFS; then
522         check_gss_daemon_nodes $clients lgssd || return 7
523     fi
524 }
525
526 stop_gss_daemons() {
527     local list=$(comma_list $(mdts_nodes))
528     
529     send_sigint $list lsvcgssd lgssd
530
531     list=$(comma_list $(osts_nodes))
532     send_sigint $list lsvcgssd
533
534     list=${CLIENTS:-`hostname`}
535     send_sigint $list lgssd
536 }
537
538 init_gss() {
539     if $GSS; then
540         if ! module_loaded ptlrpc_gss; then
541             load_module ptlrpc/gss/ptlrpc_gss
542             module_loaded ptlrpc_gss ||
543                 error_exit "init_gss : GSS=$GSS, but gss/krb5 is not supported!"
544         fi
545         start_gss_daemons || error_exit "start gss daemon failed! rc=$?"
546
547         if [ -n "$LGSS_KEYRING_DEBUG" ]; then
548             echo $LGSS_KEYRING_DEBUG > /proc/fs/lustre/sptlrpc/gss/lgss_keyring/debug_level
549         fi
550     fi
551 }
552
553 cleanup_gss() {
554     if $GSS; then
555         stop_gss_daemons
556         # maybe cleanup credential cache?
557     fi
558 }
559
560 mdsdevlabel() {
561     local num=$1
562     local device=`mdsdevname $num`
563     local label=`do_facet mds$num "e2label ${device}" | grep -v "CMD: "`
564     echo -n $label
565 }
566
567 ostdevlabel() {
568     local num=$1
569     local device=`ostdevname $num`
570     local label=`do_facet ost$num "e2label ${device}" | grep -v "CMD: "`
571     echo -n $label
572 }
573
574 #
575 # This and set_obdfilter_param() shall be used to access OSD parameters
576 # once existed under "obdfilter":
577 #
578 #   mntdev
579 #   stats
580 #   read_cache_enable
581 #   writethrough_cache_enable
582 #
583 get_obdfilter_param() {
584         local nodes=$1
585         local device=${2:-$FSNAME-OST*}
586         local name=$3
587
588         do_nodes $nodes "$LCTL get_param -n obdfilter.$device.$name \
589                 osd-*.$device.$name 2>&1" | grep -v 'Found no match'
590 }
591
592 set_obdfilter_param() {
593         local nodes=$1
594         local device=${2:-$FSNAME-OST*}
595         local name=$3
596         local value=$4
597
598         do_nodes $nodes "$LCTL set_param -n obdfilter.$device.$name=$value \
599                 osd-*.$device.$name=$value 2>&1" | grep -v 'Found no match'
600 }
601
602 set_debug_size () {
603     local dz=${1:-$DEBUG_SIZE}
604
605     if [ -f /sys/devices/system/cpu/possible ]; then
606         local cpus=$(($(cut -d "-" -f 2 /sys/devices/system/cpu/possible)+1))
607     else
608         local cpus=$(getconf _NPROCESSORS_CONF)
609     fi
610
611     # bug 19944, adjust size to be -gt num_possible_cpus()
612     # promise 2MB for every cpu at least
613     if [ -n "$cpus" ] && [ $((cpus * 2)) -gt $dz ]; then
614         dz=$((cpus * 2))
615     fi
616     lctl set_param debug_mb=$dz
617 }
618
619 set_default_debug () {
620     local debug=${1:-"$PTLDEBUG"}
621     local subsystem_debug=${2:-"$SUBSYSTEM"}
622     local debug_size=${3:-$DEBUG_SIZE}
623
624     lctl set_param debug="$debug"
625     lctl set_param subsystem_debug="${subsystem_debug# }"
626
627     set_debug_size $debug_size
628     sync
629 }
630
631 set_default_debug_nodes () {
632     local nodes=$1
633
634     if [[ ,$nodes, = *,$HOSTNAME,* ]]; then
635         nodes=$(exclude_items_from_list "$nodes" "$HOSTNAME")
636         set_default_debug
637     fi
638
639     [[ -n $nodes ]] && do_rpc_nodes $nodes set_default_debug \
640         \\\"$PTLDEBUG\\\" \\\"$SUBSYSTEM\\\" $DEBUG_SIZE || true
641 }
642
643 set_default_debug_facet () {
644     local facet=$1
645     local node=$(facet_active_host $facet)
646     [ -z "$node" ] && echo "No host defined for facet $facet" && exit 1
647
648     set_default_debug_nodes $node
649 }
650
651 # Facet functions
652 mount_facets () {
653     local facets=${1:-$(get_facets)}
654     local facet
655
656     for facet in ${facets//,/ }; do
657         mount_facet $facet || error "Restart of $facet failed!"
658     done
659 }
660
661 mount_facet() {
662     local facet=$1
663     shift
664     local dev=$(facet_active $facet)_dev
665     local opt=${facet}_opt
666     local mntpt=$(facet_mntpt $facet)
667
668     echo "Starting ${facet}: ${!opt} $@ ${!dev} $mntpt"
669     do_facet ${facet} "mkdir -p $mntpt; mount -t lustre ${!opt} $@ ${!dev} $mntpt"
670     RC=${PIPESTATUS[0]}
671     if [ $RC -ne 0 ]; then
672         echo "mount -t lustre $@ ${!dev} $mntpt"
673         echo "Start of ${!dev} on ${facet} failed ${RC}"
674     else
675         set_default_debug_facet $facet
676
677         label=$(do_facet ${facet} "$E2LABEL ${!dev}")
678         [ -z "$label" ] && echo no label for ${!dev} && exit 1
679         eval export ${facet}_svc=${label}
680         echo Started ${label}
681     fi
682     return $RC
683 }
684
685 # start facet device options
686 start() {
687     local facet=$1
688     shift
689     local device=$1
690     shift
691     eval export ${facet}_dev=${device}
692     eval export ${facet}_opt=\"$@\"
693
694     local varname=${facet}failover_dev
695     if [ -n "${!varname}" ] ; then
696         eval export ${facet}failover_dev=${!varname}
697     else
698         eval export ${facet}failover_dev=$device
699     fi
700
701     local mntpt=$(facet_mntpt $facet)
702     do_facet ${facet} mkdir -p $mntpt
703     eval export ${facet}_MOUNT=$mntpt
704     mount_facet ${facet}
705     RC=$?
706     return $RC
707 }
708
709 stop() {
710     local running
711     local facet=$1
712     shift
713     local HOST=`facet_active_host $facet`
714     [ -z $HOST ] && echo stop: no host for $facet && return 0
715
716     local mntpt=$(facet_mntpt $facet)
717     running=$(do_facet ${facet} "grep -c $mntpt' ' /proc/mounts") || true
718     if [ ${running} -ne 0 ]; then
719         echo "Stopping $mntpt (opts:$@)"
720         do_facet ${facet} umount -d $@ $mntpt
721     fi
722
723     # umount should block, but we should wait for unrelated obd's
724     # like the MGS or MGC to also stop.
725     wait_exit_ST ${facet}
726 }
727
728 version_code() {
729     # split arguments like "1.8.6-wc3" into "1", "8", "6", "wc3"
730     eval set -- $(tr "[:punct:]" " " <<< $*)
731
732     echo -n $((($1 << 16) | ($2 << 8) | $3))
733 }
734
735 get_lustre_version() {
736     local facet=${1:-"$SINGLEMDS"}
737     do_facet $facet $LCTL get_param -n version | awk '/^lustre:/ {print $2}'
738 }
739
740 lustre_version_code() {
741     local facet=${1:-"$SINGLEMDS"}
742     version_code $(get_lustre_version $1)
743 }
744
745 # save quota version (both administrative and operational quotas)
746 # add an additional parameter if mountpoint is ever different from $MOUNT
747 #
748 # XXX This function is kept for interoperability with old server (< 2.3.50),
749 #     it should be removed whenever we drop the interoperability for such
750 #     server.
751 quota_save_version() {
752     local fsname=${2:-$FSNAME}
753     local spec=$1
754     local ver=$(tr -c -d "123" <<< $spec)
755     local type=$(tr -c -d "ug" <<< $spec)
756
757     [ -n "$ver" -a "$ver" != "3" ] && error "wrong quota version specifier"
758
759     [ -n "$type" ] && { $LFS quotacheck -$type $MOUNT || error "quotacheck has failed"; }
760
761     do_facet mgs "lctl conf_param ${fsname}-MDT*.mdd.quota_type=$spec"
762     local varsvc
763     local osts=$(get_facets OST)
764     for ost in ${osts//,/ }; do
765         varsvc=${ost}_svc
766         do_facet mgs "lctl conf_param ${!varsvc}.ost.quota_type=$spec"
767     done
768 }
769
770 # client could mount several lustre
771 #
772 # XXX This function is kept for interoperability with old server (< 2.3.50),
773 #     it should be removed whenever we drop the interoperability for such
774 #     server.
775 quota_type() {
776     local fsname=${1:-$FSNAME}
777     local rc=0
778     do_facet $SINGLEMDS lctl get_param mdd.${fsname}-MDT*.quota_type ||
779         rc=$?
780     do_nodes $(comma_list $(osts_nodes)) \
781         lctl get_param obdfilter.${fsname}-OST*.quota_type || rc=$?
782     return $rc
783 }
784
785 # XXX This function is kept for interoperability with old server (< 2.3.50),
786 #     it should be removed whenever we drop the interoperability for such
787 #     server.
788 restore_quota_old() {
789         local mntpt=${1:-$MOUNT}
790         local quota_type=$(quota_type $FSNAME | grep MDT | cut -d "=" -f2)
791         if [ ! "$old_QUOTA_TYPE" ] ||
792                 [ "$quota_type" = "$old_QUOTA_TYPE" ]; then
793                 return
794         fi
795         quota_save_version $old_QUOTA_TYPE
796 }
797
798 # XXX This function is kept for interoperability with old server (< 2.3.50),
799 #     it should be removed whenever we drop the interoperability for such
800 #     server.
801 setup_quota_old(){
802         local mntpt=$1
803
804     # We need save the original quota_type params, and restore them after testing
805
806     # Suppose that quota type the same on mds and ost
807     local quota_type=$(quota_type | grep MDT | cut -d "=" -f2)
808     [ ${PIPESTATUS[0]} -eq 0 ] || error "quota_type failed!"
809     echo "[HOST:$HOSTNAME] [old_quota_type:$quota_type] [new_quota_type:$QUOTA_TYPE]"
810     if [ "$quota_type" != "$QUOTA_TYPE" ]; then
811         export old_QUOTA_TYPE=$quota_type
812         quota_save_version $QUOTA_TYPE
813     else
814         qtype=$(tr -c -d "ug" <<< $QUOTA_TYPE)
815         $LFS quotacheck -$qtype $mntpt || error "quotacheck has failed for $type"
816     fi
817
818     local quota_usrs=$QUOTA_USERS
819
820     # get_filesystem_size
821     local disksz=$(lfs_df $mntpt | grep "summary" | awk '{print $2}')
822     local blk_soft=$((disksz + 1024))
823     local blk_hard=$((blk_soft + blk_soft / 20)) # Go 5% over
824
825     local Inodes=$(lfs_df -i $mntpt | grep "summary" | awk '{print $2}')
826     local i_soft=$Inodes
827     local i_hard=$((i_soft + i_soft / 20))
828
829     echo "Total disk size: $disksz  block-softlimit: $blk_soft block-hardlimit:
830         $blk_hard inode-softlimit: $i_soft inode-hardlimit: $i_hard"
831
832     local cmd
833     for usr in $quota_usrs; do
834         echo "Setting up quota on $HOSTNAME:$mntpt for $usr..."
835         for type in u g; do
836             cmd="$LFS setquota -$type $usr -b $blk_soft -B $blk_hard -i $i_soft -I $i_hard $mntpt"
837             echo "+ $cmd"
838             eval $cmd || error "$cmd FAILED!"
839         done
840         # display the quota status
841         echo "Quota settings for $usr : "
842         $LFS quota -v -u $usr $mntpt || true
843     done
844 }
845
846 # get mdt quota type
847 mdt_quota_type() {
848         local varsvc=${SINGLEMDS}_svc
849         do_facet $SINGLEMDS $LCTL get_param -n \
850                 osd-$FSTYPE.${!varsvc}.quota_slave.enabled
851 }
852
853 # get ost quota type
854 ost_quota_type() {
855         # All OSTs should have same quota type
856         local varsvc=ost1_svc
857         do_facet ost1 $LCTL get_param -n \
858                 osd-$FSTYPE.${!varsvc}.quota_slave.enabled
859 }
860
861 # restore old quota type settings
862 restore_quota() {
863         if [ $(lustre_version_code $SINGLEMDS) -lt $(version_code 2.3.50) ]; then
864                 restore_quota_old
865                 return
866         fi
867
868         if [ "$old_MDT_QUOTA_TYPE" ]; then
869                 do_facet mgs $LCTL conf_param \
870                         $FSNAME.quota.mdt=$old_MDT_QUOTA_TYPE
871         fi
872         if [ "$old_OST_QUOTA_TYPE" ]; then
873                 do_facet mgs $LCTL conf_param \
874                         $FSNAME.quota.ost=$old_OST_QUOTA_TYPE
875         fi
876 }
877
878 # Handle the case when there is a space in the lfs df
879 # "filesystem summary" line the same as when there is no space.
880 # This will allow fixing the "lfs df" summary line in the future.
881 lfs_df() {
882         $LFS df $* | sed -e 's/filesystem /filesystem_/'
883 }
884
885 setup_quota(){
886         if [ $(lustre_version_code $SINGLEMDS) -lt $(version_code 2.3.50) ]; then
887                 setup_quota_old $1
888                 return
889         fi
890
891         local mntpt=$1
892
893         # save old quota type & set new quota type
894         local mdt_qtype=$(mdt_quota_type)
895         local ost_qtype=$(ost_quota_type)
896
897         echo "[HOST:$HOSTNAME] [old_mdt_qtype:$mdt_qtype]" \
898                 "[old_ost_qtype:$ost_qtype] [new_qtype:$QUOTA_TYPE]"
899
900         export old_MDT_QUOTA_TYPE=$mdt_qtype
901         export old_OST_QUOTA_TYPE=$ost_qtype
902
903         do_facet mgs $LCTL conf_param $FSNAME.quota.mdt=$QUOTA_TYPE ||
904                 error "set mdt quota type failed"
905         do_facet mgs $LCTL conf_param $FSNAME.quota.ost=$QUOTA_TYPE ||
906                 error "set ost quota type failed"
907
908         local quota_usrs=$QUOTA_USERS
909
910         # get_filesystem_size
911         local disksz=$(lfs_df $mntpt | grep "summary" | awk '{print $2}')
912         local blk_soft=$((disksz + 1024))
913         local blk_hard=$((blk_soft + blk_soft / 20)) # Go 5% over
914
915         local inodes=$(lfs_df -i $mntpt | grep "summary" | awk '{print $2}')
916         local i_soft=$inodes
917         local i_hard=$((i_soft + i_soft / 20))
918
919         echo "Total disk size: $disksz  block-softlimit: $blk_soft" \
920                 "block-hardlimit: $blk_hard inode-softlimit: $i_soft" \
921                 "inode-hardlimit: $i_hard"
922
923         local cmd
924         for usr in $quota_usrs; do
925                 echo "Setting up quota on $HOSTNAME:$mntpt for $usr..."
926                 for type in u g; do
927                         cmd="$LFS setquota -$type $usr -b $blk_soft"
928                         cmd="$cmd -B $blk_hard -i $i_soft -I $i_hard $mntpt"
929                         echo "+ $cmd"
930                         eval $cmd || error "$cmd FAILED!"
931                 done
932                 # display the quota status
933                 echo "Quota settings for $usr : "
934                 $LFS quota -v -u $usr $mntpt || true
935         done
936 }
937
938 zconf_mount() {
939     local client=$1
940     local mnt=$2
941     local OPTIONS=${3:-$MOUNTOPT}
942
943     local device=$MGSNID:/$FSNAME
944     if [ -z "$mnt" -o -z "$FSNAME" ]; then
945         echo Bad zconf mount command: opt=$OPTIONS dev=$device mnt=$mnt
946         exit 1
947     fi
948
949     echo "Starting client: $client: $OPTIONS $device $mnt"
950     do_node $client mkdir -p $mnt
951     do_node $client mount -t lustre $OPTIONS $device $mnt || return 1
952
953     set_default_debug_nodes $client
954
955     return 0
956 }
957
958 zconf_umount() {
959     local client=$1
960     local mnt=$2
961     local force
962     local busy 
963     local need_kill
964
965     [ "$3" ] && force=-f
966     local running=$(do_node $client "grep -c $mnt' ' /proc/mounts") || true
967     if [ $running -ne 0 ]; then
968         echo "Stopping client $client $mnt (opts:$force)"
969         do_node $client lsof -t $mnt || need_kill=no
970         if [ "x$force" != "x" -a "x$need_kill" != "xno" ]; then
971             pids=$(do_node $client lsof -t $mnt | sort -u);
972             if [ -n $pids ]; then
973                 do_node $client kill -9 $pids || true
974             fi
975         fi
976
977         busy=$(do_node $client "umount $force $mnt 2>&1" | grep -c "busy") || true
978         if [ $busy -ne 0 ] ; then
979             echo "$mnt is still busy, wait one second" && sleep 1
980             do_node $client umount $force $mnt
981         fi
982     fi
983 }
984
985 # nodes is comma list
986 sanity_mount_check_nodes () {
987     local nodes=$1
988     shift
989     local mnts="$@"
990     local mnt
991
992     # FIXME: assume that all cluster nodes run the same os
993     [ "$(uname)" = Linux ] || return 0
994
995     local rc=0
996     for mnt in $mnts ; do
997         do_nodes $nodes "running=\\\$(grep -c $mnt' ' /proc/mounts);
998 mpts=\\\$(mount | grep -c $mnt' ');
999 if [ \\\$running -ne \\\$mpts ]; then
1000     echo \\\$(hostname) env are INSANE!;
1001     exit 1;
1002 fi"
1003     [ $? -eq 0 ] || rc=1 
1004     done
1005     return $rc
1006 }
1007
1008 sanity_mount_check_servers () {
1009     [ "$CLIENTONLY" ] && 
1010         { echo "CLIENTONLY mode, skip mount_check_servers"; return 0; } || true
1011     echo Checking servers environments
1012
1013     # FIXME: modify get_facets to display all facets wo params
1014     local facets="$(get_facets OST),$(get_facets MDS),mgs"
1015     local node
1016     local mntpt
1017     local facet
1018     for facet in ${facets//,/ }; do
1019         node=$(facet_host ${facet})
1020         mntpt=$(facet_mntpt $facet)
1021         sanity_mount_check_nodes $node $mntpt ||
1022             { error "server $node environments are insane!"; return 1; }
1023     done
1024 }
1025
1026 sanity_mount_check_clients () {
1027     local clients=${1:-$CLIENTS}
1028     local mntpt=${2:-$MOUNT}
1029     local mntpt2=${3:-$MOUNT2}
1030
1031     [ -z $clients ] && clients=$(hostname)
1032     echo Checking clients $clients environments
1033
1034     sanity_mount_check_nodes $clients $mntpt $mntpt2 ||
1035        error "clients environments are insane!"
1036 }
1037
1038 sanity_mount_check () {
1039     sanity_mount_check_servers || return 1
1040     sanity_mount_check_clients || return 2
1041 }
1042
1043 # mount clients if not mouted
1044 zconf_mount_clients() {
1045     local clients=$1
1046     local mnt=$2
1047     local OPTIONS=${3:-$MOUNTOPT}
1048
1049     local device=$MGSNID:/$FSNAME
1050     if [ -z "$mnt" -o -z "$FSNAME" ]; then
1051         echo Bad zconf mount command: opt=$OPTIONS dev=$device mnt=$mnt
1052         exit 1
1053     fi
1054
1055     echo "Starting client $clients: $OPTIONS $device $mnt"
1056
1057     do_nodes $clients "
1058 running=\\\$(mount | grep -c $mnt' ');
1059 rc=0;
1060 if [ \\\$running -eq 0 ] ; then
1061     mkdir -p $mnt;
1062     mount -t lustre $OPTIONS $device $mnt;
1063     rc=\\\$?;
1064 fi;
1065 exit \\\$rc" || return ${PIPESTATUS[0]}
1066
1067     echo "Started clients $clients: "
1068     do_nodes $clients "mount | grep $mnt' '"
1069
1070     set_default_debug_nodes $clients
1071
1072     return 0
1073 }
1074
1075 zconf_umount_clients() {
1076     local clients=$1
1077     local mnt=$2
1078     local force
1079
1080     [ "$3" ] && force=-f
1081
1082     echo "Stopping clients: $clients $mnt (opts:$force)"
1083     do_nodes $clients "running=\\\$(grep -c $mnt' ' /proc/mounts);
1084 if [ \\\$running -ne 0 ] ; then
1085 echo Stopping client \\\$(hostname) $mnt opts:$force;
1086 lsof -t $mnt || need_kill=no;
1087 if [ "x$force" != "x" -a "x\\\$need_kill" != "xno" ]; then
1088     pids=\\\$(lsof -t $mnt | sort -u);
1089     if [ -n \\\"\\\$pids\\\" ]; then
1090              kill -9 \\\$pids;
1091     fi
1092 fi;
1093 busy=\\\$(umount $force $mnt 2>&1 | grep -c "busy");
1094 if [ \\\$busy -ne 0 ] ; then
1095     echo "$mnt is still busy, wait one second" && sleep 1;
1096     umount $force $mnt;
1097 fi
1098 fi"
1099 }
1100
1101 shutdown_node () {
1102     local node=$1
1103     echo + $POWER_DOWN $node
1104     $POWER_DOWN $node
1105 }
1106
1107 shutdown_node_hard () {
1108     local host=$1
1109     local attempts=$SHUTDOWN_ATTEMPTS
1110
1111     for i in $(seq $attempts) ; do
1112         shutdown_node $host
1113         sleep 1
1114         wait_for_function --quiet "! ping -w 3 -c 1 $host" 5 1 && return 0
1115         echo "waiting for $host to fail attempts=$attempts"
1116         [ $i -lt $attempts ] || \
1117             { echo "$host still pingable after power down! attempts=$attempts" && return 1; } 
1118     done
1119 }
1120
1121 shutdown_client() {
1122     local client=$1
1123     local mnt=${2:-$MOUNT}
1124     local attempts=3
1125
1126     if [ "$FAILURE_MODE" = HARD ]; then
1127         shutdown_node_hard $client
1128     else
1129        zconf_umount_clients $client $mnt -f
1130     fi
1131 }
1132
1133 facets_on_host () {
1134     local host=$1
1135     local facets="$(get_facets OST),$(get_facets MDS)"
1136     local affected
1137
1138     combined_mgs_mds || facets="$facets,mgs"
1139
1140     for facet in ${facets//,/ }; do
1141         if [ $(facet_active_host $facet) == $host ]; then
1142            affected="$affected $facet"
1143         fi
1144     done
1145
1146     echo $(comma_list $affected)
1147 }
1148
1149 facet_up() {
1150         local facet=$1
1151         local host=${2:-$(facet_host $facet)}
1152
1153         local label=$(convert_facet2label $facet)
1154         do_node $host $LCTL dl | awk '{print $4}' | grep -q -x $label
1155 }
1156
1157 facets_up_on_host () {
1158     local host=$1
1159     local facets=$(facets_on_host $host)
1160     local affected_up
1161
1162     for facet in ${facets//,/ }; do
1163         if $(facet_up $facet $host); then
1164             affected_up="$affected_up $facet"
1165         fi
1166     done
1167
1168     echo $(comma_list $affected_up)
1169 }
1170
1171 shutdown_facet() {
1172     local facet=$1
1173
1174     if [ "$FAILURE_MODE" = HARD ]; then
1175         shutdown_node_hard $(facet_active_host $facet)
1176     else
1177         stop $facet
1178     fi
1179 }
1180
1181 reboot_node() {
1182     local node=$1
1183     echo + $POWER_UP $node
1184     $POWER_UP $node
1185 }
1186
1187 remount_facet() {
1188     local facet=$1
1189
1190     stop $facet
1191     mount_facet $facet
1192 }
1193
1194 reboot_facet() {
1195     local facet=$1
1196     if [ "$FAILURE_MODE" = HARD ]; then
1197         reboot_node $(facet_active_host $facet)
1198     else
1199         sleep 10
1200     fi
1201 }
1202
1203 boot_node() {
1204     local node=$1
1205     if [ "$FAILURE_MODE" = HARD ]; then
1206        reboot_node $node
1207        wait_for_host $node
1208     fi
1209 }
1210
1211 facets_hosts () {
1212     local facets=$1
1213     local hosts
1214
1215     for facet in ${facets//,/ }; do
1216         hosts=$(expand_list $hosts $(facet_host $facet) )
1217     done
1218
1219     echo $hosts
1220 }
1221
1222 _check_progs_installed () {
1223     local progs=$@
1224     local rc=0
1225
1226     for prog in $progs; do
1227         if ! [ "$(which $prog)"  -o  "${!prog}" ]; then
1228            echo $prog missing on $(hostname)
1229            rc=1
1230         fi
1231     done
1232     return $rc
1233 }
1234
1235 check_progs_installed () {
1236     local nodes=$1
1237     shift
1238
1239     do_rpc_nodes $nodes _check_progs_installed $@
1240 }
1241
1242 # recovery-scale functions
1243 node_var_name() {
1244     echo __$(echo $1 | tr '-' '_' | tr '.' '_')
1245 }
1246
1247 start_client_load() {
1248     local client=$1
1249     local load=$2
1250     local var=$(node_var_name $client)_load
1251     eval export ${var}=$load
1252
1253     do_node $client "PATH=$PATH MOUNT=$MOUNT ERRORS_OK=$ERRORS_OK \
1254 BREAK_ON_ERROR=$BREAK_ON_ERROR \
1255 END_RUN_FILE=$END_RUN_FILE \
1256 LOAD_PID_FILE=$LOAD_PID_FILE \
1257 TESTLOG_PREFIX=$TESTLOG_PREFIX \
1258 TESTNAME=$TESTNAME \
1259 DBENCH_LIB=$DBENCH_LIB \
1260 DBENCH_SRC=$DBENCH_SRC \
1261 run_${load}.sh" &
1262     local ppid=$!
1263     log "Started client load: ${load} on $client"
1264
1265     # get the children process IDs
1266     local pids=$(ps --ppid $ppid -o pid= | xargs)
1267     CLIENT_LOAD_PIDS="$CLIENT_LOAD_PIDS $ppid $pids"
1268     return 0
1269 }
1270
1271 start_client_loads () {
1272     local -a clients=(${1//,/ })
1273     local numloads=${#CLIENT_LOADS[@]}
1274     local testnum
1275
1276     for ((nodenum=0; nodenum < ${#clients[@]}; nodenum++ )); do
1277         testnum=$((nodenum % numloads))
1278         start_client_load ${clients[nodenum]} ${CLIENT_LOADS[testnum]}
1279     done
1280     # bug 22169: wait the background threads to start
1281     sleep 2
1282 }
1283
1284 # only for remote client
1285 check_client_load () {
1286     local client=$1
1287     local var=$(node_var_name $client)_load
1288     local TESTLOAD=run_${!var}.sh
1289
1290     ps auxww | grep -v grep | grep $client | grep -q "$TESTLOAD" || return 1
1291
1292     # bug 18914: try to connect several times not only when
1293     # check ps, but  while check_catastrophe also
1294     local tries=3
1295     local RC=254
1296     while [ $RC = 254 -a $tries -gt 0 ]; do
1297         let tries=$tries-1
1298         # assume success
1299         RC=0
1300         if ! check_catastrophe $client; then
1301             RC=${PIPESTATUS[0]}
1302             if [ $RC -eq 254 ]; then
1303                 # FIXME: not sure how long we shuold sleep here
1304                 sleep 10
1305                 continue
1306             fi
1307             echo "check catastrophe failed: RC=$RC "
1308             return $RC
1309         fi
1310     done
1311     # We can continue try to connect if RC=254
1312     # Just print the warning about this
1313     if [ $RC = 254 ]; then
1314         echo "got a return status of $RC from do_node while checking catastrophe on $client"
1315     fi
1316
1317     # see if the load is still on the client
1318     tries=3
1319     RC=254
1320     while [ $RC = 254 -a $tries -gt 0 ]; do
1321         let tries=$tries-1
1322         # assume success
1323         RC=0
1324         if ! do_node $client "ps auxwww | grep -v grep | grep -q $TESTLOAD"; then
1325             RC=${PIPESTATUS[0]}
1326             sleep 30
1327         fi
1328     done
1329     if [ $RC = 254 ]; then
1330         echo "got a return status of $RC from do_node while checking (catastrophe and 'ps') the client load on $client"
1331         # see if we can diagnose a bit why this is
1332     fi
1333
1334     return $RC
1335 }
1336 check_client_loads () {
1337    local clients=${1//,/ }
1338    local client=
1339    local rc=0
1340
1341    for client in $clients; do
1342       check_client_load $client
1343       rc=${PIPESTATUS[0]}
1344       if [ "$rc" != 0 ]; then
1345         log "Client load failed on node $client, rc=$rc"
1346         return $rc
1347       fi
1348    done
1349 }
1350
1351 restart_client_loads () {
1352     local clients=${1//,/ }
1353     local expectedfail=${2:-""}
1354     local client=
1355     local rc=0
1356
1357     for client in $clients; do
1358         check_client_load $client
1359         rc=${PIPESTATUS[0]}
1360         if [ "$rc" != 0 -a "$expectedfail" ]; then
1361             local var=$(node_var_name $client)_load
1362             start_client_load $client ${!var}
1363             echo "Restarted client load ${!var}: on $client. Checking ..."
1364             check_client_load $client
1365             rc=${PIPESTATUS[0]}
1366             if [ "$rc" != 0 ]; then
1367                 log "Client load failed to restart on node $client, rc=$rc"
1368                 # failure one client load means test fail
1369                 # we do not need to check other
1370                 return $rc
1371             fi
1372         else
1373             return $rc
1374         fi
1375     done
1376 }
1377
1378 # Start vmstat and save its process ID in a file.
1379 start_vmstat() {
1380     local nodes=$1
1381     local pid_file=$2
1382
1383     [ -z "$nodes" -o -z "$pid_file" ] && return 0
1384
1385     do_nodes $nodes \
1386         "vmstat 1 > $TESTLOG_PREFIX.$TESTNAME.vmstat.\\\$(hostname -s).log \
1387         2>/dev/null </dev/null & echo \\\$! > $pid_file"
1388 }
1389
1390 # Display the nodes on which client loads failed.
1391 print_end_run_file() {
1392     local file=$1
1393     local node
1394
1395     [ -s $file ] || return 0
1396
1397     echo "Found the END_RUN_FILE file: $file"
1398     cat $file
1399
1400     # A client load will stop if it finds the END_RUN_FILE file.
1401     # That does not mean the client load actually failed though.
1402     # The first node in END_RUN_FILE is the one we are interested in.
1403     read node < $file
1404
1405     if [ -n "$node" ]; then
1406         local var=$(node_var_name $node)_load
1407
1408         local prefix=$TESTLOG_PREFIX
1409         [ -n "$TESTNAME" ] && prefix=$prefix.$TESTNAME
1410         local stdout_log=$prefix.run_${!var}_stdout.$node.log
1411         local debug_log=$(echo $stdout_log | sed 's/\(.*\)stdout/\1debug/')
1412
1413         echo "Client load ${!var} failed on node $node:"
1414         echo "$stdout_log"
1415         echo "$debug_log"
1416     fi
1417 }
1418
1419 # Stop the process which had its PID saved in a file.
1420 stop_process() {
1421     local nodes=$1
1422     local pid_file=$2
1423
1424     [ -z "$nodes" -o -z "$pid_file" ] && return 0
1425
1426     do_nodes $nodes "test -f $pid_file &&
1427         { kill -s TERM \\\$(cat $pid_file); rm -f $pid_file; }" || true
1428 }
1429
1430 # Stop all client loads.
1431 stop_client_loads() {
1432     local nodes=${1:-$CLIENTS}
1433     local pid_file=$2
1434
1435     # stop the client loads
1436     stop_process $nodes $pid_file
1437
1438     # clean up the processes that started them
1439     [ -n "$CLIENT_LOAD_PIDS" ] && kill -9 $CLIENT_LOAD_PIDS 2>/dev/null || true
1440 }
1441 # End recovery-scale functions
1442
1443 # verify that lustre actually cleaned up properly
1444 cleanup_check() {
1445     [ -f $CATASTROPHE ] && [ `cat $CATASTROPHE` -ne 0 ] && \
1446         error "LBUG/LASSERT detected"
1447     BUSY=`dmesg | grep -i destruct || true`
1448     if [ "$BUSY" ]; then
1449         echo "$BUSY" 1>&2
1450         [ -e $TMP/debug ] && mv $TMP/debug $TMP/debug-busy.`date +%s`
1451         exit 205
1452     fi
1453
1454     check_mem_leak || exit 204
1455
1456     [ "`lctl dl 2> /dev/null | wc -l`" -gt 0 ] && lctl dl && \
1457         echo "$0: lustre didn't clean up..." 1>&2 && return 202 || true
1458
1459     if module_loaded lnet || module_loaded libcfs; then
1460         echo "$0: modules still loaded..." 1>&2
1461         /sbin/lsmod 1>&2
1462         return 203
1463     fi
1464     return 0
1465 }
1466
1467 wait_update () {
1468     local node=$1
1469     local TEST=$2
1470     local FINAL=$3
1471     local MAX=${4:-90}
1472
1473         local RESULT
1474         local WAIT=0
1475         local sleep=5
1476         while [ true ]; do
1477             RESULT=$(do_node $node "$TEST")
1478             if [ "$RESULT" == "$FINAL" ]; then
1479                 [ -z "$RESULT" -o $WAIT -le $sleep ] ||
1480                     echo "Updated after ${WAIT}s: wanted '$FINAL' got '$RESULT'"
1481                 return 0
1482             fi
1483             [ $WAIT -ge $MAX ] && break
1484             echo "Waiting $((MAX - WAIT)) secs for update"
1485             WAIT=$((WAIT + sleep))
1486             sleep $sleep
1487         done
1488         echo "Update not seen after ${MAX}s: wanted '$FINAL' got '$RESULT'"
1489         return 3
1490 }
1491
1492 wait_update_facet() {
1493         local facet=$1
1494         shift
1495         wait_update $(facet_active_host $facet) "$@"
1496 }
1497
1498 wait_delete_completed () {
1499     local TOTALPREV=`lctl get_param -n osc.*.kbytesavail | \
1500                      awk 'BEGIN{total=0}; {total+=$1}; END{print total}'`
1501
1502     local WAIT=0
1503     local MAX_WAIT=20
1504     while [ "$WAIT" -ne "$MAX_WAIT" ]; do
1505         sleep 1
1506         TOTAL=`lctl get_param -n osc.*.kbytesavail | \
1507                awk 'BEGIN{total=0}; {total+=$1}; END{print total}'`
1508         [ "$TOTAL" -eq "$TOTALPREV" ] && return 0
1509         echo "Waiting delete completed ... prev: $TOTALPREV current: $TOTAL "
1510         TOTALPREV=$TOTAL
1511         WAIT=$(( WAIT + 1))
1512     done
1513     echo "Delete is not completed in $MAX_WAIT sec"
1514     return 1
1515 }
1516
1517 wait_for_host() {
1518     local hostlist=$1
1519
1520     # we can use "for" here because we are waiting the slowest
1521     for host in ${hostlist//,/ }; do
1522         check_network "$host" 900
1523     done
1524     while ! do_nodes $hostlist hostname  > /dev/null; do sleep 5; done
1525 }
1526
1527 wait_for_facet() {
1528     local facetlist=$1
1529     local hostlist
1530
1531     for facet in ${facetlist//,/ }; do
1532         hostlist=$(expand_list $hostlist $(facet_active_host $facet))
1533     done
1534     wait_for_host $hostlist
1535 }
1536
1537 _wait_recovery_complete () {
1538     local param=$1
1539
1540     # Use default policy if $2 is not passed by caller.
1541     local MAX=${2:-$(max_recovery_time)}
1542
1543     local WAIT=0
1544     local STATUS=
1545
1546     while [ $WAIT -lt $MAX ]; do
1547         STATUS=$(lctl get_param -n $param | grep status)
1548         echo $param $STATUS
1549         [[ $STATUS = "status: COMPLETE" || $STATUS = "status: INACTIVE" ]] && return 0
1550         sleep 5
1551         WAIT=$((WAIT + 5))
1552         echo "Waiting $((MAX - WAIT)) secs for $param recovery done. $STATUS"
1553     done
1554     echo "$param recovery not done in $MAX sec. $STATUS"
1555     return 1
1556 }
1557
1558 wait_recovery_complete () {
1559     local facet=$1
1560
1561     # with an assumption that at_max is the same on all nodes
1562     local MAX=${2:-$(max_recovery_time)}
1563
1564     local facets=$facet
1565     if [ "$FAILURE_MODE" = HARD ]; then
1566         facets=$(facets_on_host $(facet_active_host $facet))
1567     fi
1568     echo affected facets: $facets
1569
1570     # we can use "for" here because we are waiting the slowest
1571     for facet in ${facets//,/ }; do
1572         local var_svc=${facet}_svc
1573         local param="*.${!var_svc}.recovery_status"
1574
1575         local host=$(facet_active_host $facet)
1576         do_rpc_nodes $host _wait_recovery_complete $param $MAX
1577     done
1578 }
1579
1580 wait_mds_ost_sync () {
1581     # just because recovery is done doesn't mean we've finished
1582     # orphan cleanup. Wait for llogs to get synchronized.
1583     echo "Waiting for orphan cleanup..."
1584     # MAX value includes time needed for MDS-OST reconnection
1585     local MAX=$(( TIMEOUT * 2 ))
1586     local WAIT=0
1587     while [ $WAIT -lt $MAX ]; do
1588         local -a sync=($(do_nodes $(comma_list $(osts_nodes)) \
1589             "$LCTL get_param -n obdfilter.*.mds_sync"))
1590         local con=1
1591         local i
1592         for ((i=0; i<${#sync[@]}; i++)); do
1593             [ ${sync[$i]} -eq 0 ] && continue
1594             # there is a not finished MDS-OST synchronization
1595             con=0
1596             break;
1597         done
1598         sleep 2 # increase waiting time and cover statfs cache
1599         [ ${con} -eq 1 ] && return 0
1600         echo "Waiting $WAIT secs for $facet mds-ost sync done."
1601         WAIT=$((WAIT + 2))
1602     done
1603     echo "$facet recovery not done in $MAX sec. $STATUS"
1604     return 1
1605 }
1606
1607 wait_destroy_complete () {
1608     echo "Waiting for destroy to be done..."
1609     # MAX value shouldn't be big as this mean server responsiveness
1610     # never increase this just to make test pass but investigate
1611     # why it takes so long time
1612     local MAX=5
1613     local WAIT=0
1614     while [ $WAIT -lt $MAX ]; do
1615         local -a RPCs=($($LCTL get_param -n osc.*.destroys_in_flight))
1616         local con=1
1617         for ((i=0; i<${#RPCs[@]}; i++)); do
1618             [ ${RPCs[$i]} -eq 0 ] && continue
1619             # there are still some destroy RPCs in flight
1620             con=0
1621             break;
1622         done
1623         sleep 1
1624         [ ${con} -eq 1 ] && return 0 # done waiting
1625         echo "Waiting $WAIT secs for destroys to be done."
1626         WAIT=$((WAIT + 1))
1627     done
1628     echo "Destroys weren't done in $MAX sec."
1629     return 1
1630 }
1631
1632 wait_exit_ST () {
1633     local facet=$1
1634
1635     local WAIT=0
1636     local INTERVAL=1
1637     local running
1638     # conf-sanity 31 takes a long time cleanup
1639     while [ $WAIT -lt 300 ]; do
1640         running=$(do_facet ${facet} "lsmod | grep lnet > /dev/null && lctl dl | grep ' ST '") || true
1641         [ -z "${running}" ] && return 0
1642         echo "waited $WAIT for${running}"
1643         [ $INTERVAL -lt 64 ] && INTERVAL=$((INTERVAL + INTERVAL))
1644         sleep $INTERVAL
1645         WAIT=$((WAIT + INTERVAL))
1646     done
1647     echo "service didn't stop after $WAIT seconds.  Still running:"
1648     echo ${running}
1649     return 1
1650 }
1651
1652 wait_remote_prog () {
1653    local prog=$1
1654    local WAIT=0
1655    local INTERVAL=5
1656    local rc=0
1657
1658    [ "$PDSH" = "no_dsh" ] && return 0
1659
1660    while [ $WAIT -lt $2 ]; do
1661         running=$(ps uax | grep "$PDSH.*$prog.*$MOUNT" | grep -v grep) || true
1662         [ -z "${running}" ] && return 0 || true
1663         echo "waited $WAIT for: "
1664         echo "$running"
1665         [ $INTERVAL -lt 60 ] && INTERVAL=$((INTERVAL + INTERVAL))
1666         sleep $INTERVAL
1667         WAIT=$((WAIT + INTERVAL))
1668     done
1669     local pids=$(ps  uax | grep "$PDSH.*$prog.*$MOUNT" | grep -v grep | awk '{print $2}')
1670     [ -z "$pids" ] && return 0
1671     echo "$PDSH processes still exists after $WAIT seconds.  Still running: $pids"
1672     # FIXME: not portable
1673     for pid in $pids; do
1674         cat /proc/${pid}/status || true
1675         cat /proc/${pid}/wchan || true
1676         echo "Killing $pid"
1677         kill -9 $pid || true
1678         sleep 1
1679         ps -P $pid && rc=1
1680     done
1681
1682     return $rc
1683 }
1684
1685 clients_up() {
1686     # not every config has many clients
1687     sleep 1
1688     if [ ! -z "$CLIENTS" ]; then
1689         $PDSH $CLIENTS "stat -f $MOUNT" > /dev/null
1690     else
1691         stat -f $MOUNT > /dev/null
1692     fi
1693 }
1694
1695 client_up() {
1696     local client=$1
1697     # usually checked on particular client or locally
1698     sleep 1
1699     if [ ! -z "$client" ]; then
1700         $PDSH $client "stat -f $MOUNT" > /dev/null
1701     else
1702         stat -f $MOUNT > /dev/null
1703     fi
1704 }
1705
1706 client_evicted() {
1707     ! client_up $1
1708 }
1709
1710 client_reconnect() {
1711     uname -n >> $MOUNT/recon
1712     if [ -z "$CLIENTS" ]; then
1713         df $MOUNT; uname -n >> $MOUNT/recon
1714     else
1715         do_nodes $CLIENTS "df $MOUNT; uname -n >> $MOUNT/recon" > /dev/null
1716     fi
1717     echo Connected clients:
1718     cat $MOUNT/recon
1719     ls -l $MOUNT/recon > /dev/null
1720     rm $MOUNT/recon
1721 }
1722
1723 affected_facets () {
1724     local facet=$1
1725
1726     local host=$(facet_active_host $facet)
1727     local affected=$facet
1728
1729     if [ "$FAILURE_MODE" = HARD ]; then
1730         affected=$(facets_up_on_host $host)
1731     fi
1732     echo $affected
1733 }
1734
1735 facet_failover() {
1736     local facet=$1
1737     local sleep_time=$2
1738     local host=$(facet_active_host $facet)
1739
1740     echo "Failing $facet on node $host"
1741
1742     local affected=$(affected_facets $facet)
1743
1744     shutdown_facet $facet
1745
1746     echo affected facets: $affected
1747
1748     [ -n "$sleep_time" ] && sleep $sleep_time
1749
1750     reboot_facet $facet
1751
1752     change_active $affected
1753
1754     wait_for_facet $affected
1755     # start mgs first if it is affected
1756     if ! combined_mgs_mds && list_member $affected mgs; then
1757         mount_facet mgs || error "Restart of mgs failed"
1758     fi
1759     # FIXME; has to be changed to mount all facets concurrently
1760     affected=$(exclude_items_from_list $affected mgs)
1761     mount_facets $affected
1762 }
1763
1764 obd_name() {
1765     local facet=$1
1766 }
1767
1768 replay_barrier() {
1769     local facet=$1
1770     do_facet $facet sync
1771     df $MOUNT
1772
1773     # make sure there will be no seq change
1774     local clients=${CLIENTS:-$HOSTNAME}
1775     do_nodes $clients "f=${MOUNT}/fsa-\\\$(hostname); mcreate \\\$f; rm \\\$f"
1776
1777     local svc=${facet}_svc
1778     do_facet $facet $LCTL --device %${!svc} notransno
1779     do_facet $facet $LCTL --device %${!svc} readonly
1780     do_facet $facet $LCTL mark "$facet REPLAY BARRIER on ${!svc}"
1781     $LCTL mark "local REPLAY BARRIER on ${!svc}"
1782 }
1783
1784 replay_barrier_nodf() {
1785     local facet=$1    echo running=${running}
1786     do_facet $facet sync
1787     local svc=${facet}_svc
1788     echo Replay barrier on ${!svc}
1789     do_facet $facet $LCTL --device %${!svc} notransno
1790     do_facet $facet $LCTL --device %${!svc} readonly
1791     do_facet $facet $LCTL mark "$facet REPLAY BARRIER on ${!svc}"
1792     $LCTL mark "local REPLAY BARRIER on ${!svc}"
1793 }
1794
1795 replay_barrier_nosync() {
1796     local facet=$1    echo running=${running}
1797     local svc=${facet}_svc
1798     echo Replay barrier on ${!svc}
1799     do_facet $facet $LCTL --device %${!svc} notransno
1800     do_facet $facet $LCTL --device %${!svc} readonly
1801     do_facet $facet $LCTL mark "$facet REPLAY BARRIER on ${!svc}"
1802     $LCTL mark "local REPLAY BARRIER on ${!svc}"
1803 }
1804
1805 mds_evict_client() {
1806     UUID=`lctl get_param -n mdc.${mds1_svc}-mdc-*.uuid`
1807     do_facet mds1 "lctl set_param -n mdt.${mds1_svc}.evict_client $UUID"
1808 }
1809
1810 ost_evict_client() {
1811     UUID=`lctl get_param -n devices| grep ${ost1_svc}-osc- | egrep -v 'MDT' | awk '{print $5}'`
1812     do_facet ost1 "lctl set_param -n obdfilter.${ost1_svc}.evict_client $UUID"
1813 }
1814
1815 fail() {
1816     facet_failover $* || error "failover: $?"
1817     clients_up || error "post-failover df: $?"
1818 }
1819
1820 fail_nodf() {
1821         local facet=$1
1822         facet_failover $facet
1823 }
1824
1825 fail_abort() {
1826     local facet=$1
1827     stop $facet
1828     change_active $facet
1829     wait_for_facet $facet
1830     mount_facet $facet -o abort_recovery
1831     clients_up || echo "first df failed: $?"
1832     clients_up || error "post-failover df: $?"
1833 }
1834
1835 do_lmc() {
1836     echo There is no lmc.  This is mountconf, baby.
1837     exit 1
1838 }
1839
1840 h2name_or_ip() {
1841     if [ "$1" = "client" -o "$1" = "'*'" ]; then echo \'*\'; else
1842         echo $1"@$2"
1843     fi
1844 }
1845
1846 h2ptl() {
1847    if [ "$1" = "client" -o "$1" = "'*'" ]; then echo \'*\'; else
1848        ID=`xtprocadmin -n $1 2>/dev/null | egrep -v 'NID' | awk '{print $1}'`
1849        if [ -z "$ID" ]; then
1850            echo "Could not get a ptl id for $1..."
1851            exit 1
1852        fi
1853        echo $ID"@ptl"
1854    fi
1855 }
1856 declare -fx h2ptl
1857
1858 h2tcp() {
1859     h2name_or_ip "$1" "tcp"
1860 }
1861 declare -fx h2tcp
1862
1863 h2elan() {
1864     if [ "$1" = "client" -o "$1" = "'*'" ]; then echo \'*\'; else
1865         if type __h2elan >/dev/null 2>&1; then
1866             ID=$(__h2elan $1)
1867         else
1868             ID=`echo $1 | sed 's/[^0-9]*//g'`
1869         fi
1870         echo $ID"@elan"
1871     fi
1872 }
1873 declare -fx h2elan
1874
1875 h2o2ib() {
1876     h2name_or_ip "$1" "o2ib"
1877 }
1878 declare -fx h2o2ib
1879
1880 facet_host() {
1881     local facet=$1
1882
1883     [ "$facet" == client ] && echo -n $HOSTNAME && return
1884     varname=${facet}_HOST
1885     if [ -z "${!varname}" ]; then
1886         if [ "${facet:0:3}" == "ost" ]; then
1887             eval ${facet}_HOST=${ost_HOST}
1888         fi
1889     fi
1890     echo -n ${!varname}
1891 }
1892
1893 facet_active() {
1894     local facet=$1
1895     local activevar=${facet}active
1896
1897     if [ -f $TMP/${facet}active ] ; then
1898         source $TMP/${facet}active
1899     fi
1900
1901     active=${!activevar}
1902     if [ -z "$active" ] ; then
1903         echo -n ${facet}
1904     else
1905         echo -n ${active}
1906     fi
1907 }
1908
1909 facet_active_host() {
1910     local facet=$1
1911     local active=`facet_active $facet`
1912     if [ "$facet" == client ]; then
1913         echo $HOSTNAME
1914     else
1915         echo `facet_host $active`
1916     fi
1917 }
1918
1919 change_active() {
1920     local facetlist=$1
1921     local facet
1922
1923     facetlist=$(exclude_items_from_list $facetlist mgs)
1924
1925     for facet in ${facetlist//,/ }; do
1926     local failover=${facet}failover
1927     local host=`facet_host $failover`
1928     [ -z "$host" ] && return
1929
1930     local curactive=`facet_active $facet`
1931     if [ -z "${curactive}" -o "$curactive" == "$failover" ] ; then
1932         eval export ${facet}active=$facet
1933     else
1934         eval export ${facet}active=$failover
1935     fi
1936     # save the active host for this facet
1937     local activevar=${facet}active
1938     echo "$activevar=${!activevar}" > $TMP/$activevar
1939     [[ $facet = mds1 ]] && combined_mgs_mds && \
1940         echo "mgsactive=${!activevar}" > $TMP/mgsactive
1941     local TO=`facet_active_host $facet`
1942     echo "Failover $facet to $TO"
1943     done
1944 }
1945
1946 do_node() {
1947     local verbose=false
1948     # do not stripe off hostname if verbose, bug 19215
1949     if [ x$1 = x--verbose ]; then
1950         shift
1951         verbose=true
1952     fi
1953
1954     local HOST=$1
1955     shift
1956     local myPDSH=$PDSH
1957     if [ "$HOST" = "$HOSTNAME" ]; then
1958         myPDSH="no_dsh"
1959     elif [ -z "$myPDSH" -o "$myPDSH" = "no_dsh" ]; then
1960         echo "cannot run remote command on $HOST with $myPDSH"
1961         return 128
1962     fi
1963     if $VERBOSE; then
1964         echo "CMD: $HOST $@" >&2
1965         $myPDSH $HOST "$LCTL mark \"$@\"" > /dev/null 2>&1 || :
1966     fi
1967
1968     if [ "$myPDSH" = "rsh" ]; then
1969 # we need this because rsh does not return exit code of an executed command
1970         local command_status="$TMP/cs"
1971         rsh $HOST ":> $command_status"
1972         rsh $HOST "(PATH=\$PATH:$RLUSTRE/utils:$RLUSTRE/tests:/sbin:/usr/sbin;
1973                     cd $RPWD; LUSTRE=\"$RLUSTRE\" sh -c \"$@\") ||
1974                     echo command failed >$command_status"
1975         [ -n "$($myPDSH $HOST cat $command_status)" ] && return 1 || true
1976         return 0
1977     fi
1978
1979     if $verbose ; then
1980         # print HOSTNAME for myPDSH="no_dsh"
1981         if [[ $myPDSH = no_dsh ]]; then
1982             $myPDSH $HOST "(PATH=\$PATH:$RLUSTRE/utils:$RLUSTRE/tests:/sbin:/usr/sbin; cd $RPWD; LUSTRE=\"$RLUSTRE\" sh -c \"$@\")" | sed -e "s/^/${HOSTNAME}: /"
1983         else
1984             $myPDSH $HOST "(PATH=\$PATH:$RLUSTRE/utils:$RLUSTRE/tests:/sbin:/usr/sbin; cd $RPWD; LUSTRE=\"$RLUSTRE\" sh -c \"$@\")"
1985         fi
1986     else
1987         $myPDSH $HOST "(PATH=\$PATH:$RLUSTRE/utils:$RLUSTRE/tests:/sbin:/usr/sbin; cd $RPWD; LUSTRE=\"$RLUSTRE\" sh -c \"$@\")" | sed "s/^${HOST}: //"
1988     fi
1989     return ${PIPESTATUS[0]}
1990 }
1991
1992 do_nodev() {
1993     do_node --verbose "$@"
1994 }
1995
1996 single_local_node () {
1997    [ "$1" = "$HOSTNAME" ]
1998 }
1999
2000 # Outputs environment variable assignments that should be passed to remote nodes
2001 get_env_vars() {
2002     local var
2003     local value
2004
2005     for var in ${!MODOPTS_*}; do
2006         value=${!var}
2007         echo "${var}=\"$value\""
2008     done
2009 }
2010
2011 do_nodes() {
2012     local verbose=false
2013     # do not stripe off hostname if verbose, bug 19215
2014     if [ x$1 = x--verbose ]; then
2015         shift
2016         verbose=true
2017     fi
2018
2019     local rnodes=$1
2020     shift
2021
2022     if single_local_node $rnodes; then
2023         if $verbose; then
2024            do_nodev $rnodes "$@"
2025         else
2026            do_node $rnodes "$@"
2027         fi
2028         return $?
2029     fi
2030
2031     # This is part from do_node
2032     local myPDSH=$PDSH
2033
2034     [ -z "$myPDSH" -o "$myPDSH" = "no_dsh" -o "$myPDSH" = "rsh" ] && \
2035         echo "cannot run remote command on $rnodes with $myPDSH" && return 128
2036
2037     export FANOUT=$(get_node_count "${rnodes//,/ }")
2038     if $VERBOSE; then
2039         echo "CMD: $rnodes $@" >&2
2040         $myPDSH $rnodes "$LCTL mark \"$@\"" > /dev/null 2>&1 || :
2041     fi
2042
2043     # do not replace anything from pdsh output if -N is used
2044     # -N     Disable hostname: prefix on lines of output.
2045     if $verbose || [[ $myPDSH = *-N* ]]; then
2046         $myPDSH $rnodes "(PATH=\$PATH:$RLUSTRE/utils:$RLUSTRE/tests:/sbin:/usr/sbin; cd $RPWD; LUSTRE=\"$RLUSTRE\" $(get_env_vars) sh -c \"$@\")"
2047     else
2048         $myPDSH $rnodes "(PATH=\$PATH:$RLUSTRE/utils:$RLUSTRE/tests:/sbin:/usr/sbin; cd $RPWD; LUSTRE=\"$RLUSTRE\" $(get_env_vars) sh -c \"$@\")" | sed -re "s/^[^:]*: //g"
2049     fi
2050     return ${PIPESTATUS[0]}
2051 }
2052
2053 do_facet() {
2054     local facet=$1
2055     shift
2056     local HOST=`facet_active_host $facet`
2057     [ -z $HOST ] && echo No host defined for facet ${facet} && exit 1
2058     do_node $HOST "$@"
2059 }
2060
2061 do_nodesv() {
2062     do_nodes --verbose "$@"
2063 }
2064
2065 add() {
2066     local facet=$1
2067     shift
2068     # make sure its not already running
2069     stop ${facet} -f
2070     rm -f $TMP/${facet}active
2071     [[ $facet = mds1 ]] && combined_mgs_mds && rm -f $TMP/mgsactive
2072     do_facet ${facet} $MKFS $*
2073 }
2074
2075 ostdevname() {
2076     num=$1
2077     DEVNAME=OSTDEV$num
2078     #if $OSTDEVn isn't defined, default is $OSTDEVBASE + num
2079     eval DEVPTR=${!DEVNAME:=${OSTDEVBASE}${num}}
2080     echo -n $DEVPTR
2081 }
2082
2083 mdsdevname() {
2084     num=$1
2085     DEVNAME=MDSDEV$num
2086     #if $MDSDEVn isn't defined, default is $MDSDEVBASE + num
2087     eval DEVPTR=${!DEVNAME:=${MDSDEVBASE}${num}}
2088     echo -n $DEVPTR
2089 }
2090
2091 facet_mntpt () {
2092     local facet=$1
2093     [[ $facet = mgs ]] && combined_mgs_mds && facet="mds1"
2094
2095     local var=${facet}_MOUNT
2096     eval mntpt=${!var:-${MOUNT%/*}/$facet}
2097
2098     echo -n $mntpt
2099 }
2100
2101 ########
2102 ## MountConf setup
2103
2104 stopall() {
2105     # make sure we are using the primary server, so test-framework will
2106     # be able to clean up properly.
2107     activemds=`facet_active mds1`
2108     if [ $activemds != "mds1" ]; then
2109         fail mds1
2110     fi
2111
2112     local clients=$CLIENTS
2113     [ -z $clients ] && clients=$(hostname)
2114
2115     zconf_umount_clients $clients $MOUNT "$*" || true
2116     [ -n "$MOUNT2" ] && zconf_umount_clients $clients $MOUNT2 "$*" || true
2117
2118     [ "$CLIENTONLY" ] && return
2119     # The add fn does rm ${facet}active file, this would be enough
2120     # if we use do_facet <facet> only after the facet added, but
2121     # currently we use do_facet mds in local.sh
2122     for num in `seq $MDSCOUNT`; do
2123         stop mds$num -f
2124         rm -f ${TMP}/mds${num}active
2125     done
2126     combined_mgs_mds && rm -f $TMP/mgsactive
2127
2128     for num in `seq $OSTCOUNT`; do
2129         stop ost$num -f
2130         rm -f $TMP/ost${num}active
2131     done
2132
2133     if ! combined_mgs_mds ; then
2134         stop mgs
2135     fi
2136
2137     return 0
2138 }
2139
2140 cleanup_echo_devs () {
2141     local devs=$($LCTL dl | grep echo | awk '{print $4}')
2142
2143     for dev in $devs; do
2144         $LCTL --device $dev cleanup
2145         $LCTL --device $dev detach
2146     done
2147 }
2148
2149 cleanupall() {
2150     nfs_client_mode && return
2151
2152     stopall $*
2153     cleanup_echo_devs
2154
2155     unload_modules
2156     cleanup_gss
2157 }
2158
2159 combined_mgs_mds () {
2160     [[ $MDSDEV1 = $MGSDEV ]] && [[ $mds1_HOST = $mgs_HOST ]]
2161 }
2162
2163 facet_number() {
2164     local facet=$1
2165
2166     local number=$(echo -n $facet | sed -e 's/^fs[0-9]\+//' |
2167                    sed -e 's/^[a-z]\+//')
2168
2169     [[ -z $number ]] && number=1
2170
2171     echo -n $number
2172 }
2173
2174 mkfs_opts() {
2175     local facet=$1
2176
2177     local index=$(($(facet_number $facet) - 1))
2178     local tgt=$(echo $facet | tr -d [:digit:] | tr "[:lower:]" "[:upper:]")
2179     local optvar=${tgt}_MKFS_OPTS
2180     local opt=${!optvar}
2181
2182     # FIXME: ! combo  mgs/mds + mgsfailover is not supported yet
2183     [[ $facet = mgs ]] && echo $opt && return
2184
2185     # --index option
2186     [[ $opt != *--index* ]] && opt+=" --index=$index"
2187
2188     # 1.
2189     # --failnode options
2190     local var=${facet}failover_HOST
2191     if [ x"${!var}" != x ] && [ x"${!var}" != x$(facet_host $facet) ] ; then
2192         local failnode=$(h2$NETTYPE ${!var})
2193         failnode="--failnode=$failnode"
2194         # options does not contain
2195         # or contains wrong --failnode=
2196         if [[ $opt != *${failnode}* ]]; then
2197             opt=$(echo $opt | sed 's/--failnode=.* / /')
2198             opt="$opt $failnode"
2199         fi
2200     fi
2201
2202     # 2.
2203     # --mgsnode options
2204     # no additional mkfs mds "--mgsnode" option for this configuration
2205     if [[ $facet = mds ]] && combined_mgs_mds; then
2206         echo $opt
2207         return
2208     fi
2209
2210     # additional mkfs "--mgsnode"
2211     local mgsnode="--mgsnode=$MGSNID"
2212     opt=${opt//$mgsnode }
2213     for nid in ${MGSNID//:/ }; do
2214         local mgsnode="--mgsnode=$nid"
2215         # options does not contain
2216         # --mgsnode=$nid
2217         if [[ $opt != *${mgsnode}" "* ]]; then
2218             opt="$opt --mgsnode=$nid"
2219         fi
2220     done
2221
2222     echo $opt
2223 }
2224
2225 formatall() {
2226     if [ "$IAMDIR" == "yes" ]; then
2227         MDS_MKFS_OPTS="$MDS_MKFS_OPTS --iam-dir"
2228     fi
2229
2230     [ "$FSTYPE" ] && FSTYPE_OPT="--backfstype $FSTYPE"
2231
2232     stopall
2233     # We need ldiskfs here, may as well load them all
2234     load_modules
2235     [ "$CLIENTONLY" ] && return
2236     echo Formatting mgs, mds, osts
2237     if ! combined_mgs_mds ; then
2238         add mgs $(mkfs_opts mgs) $FSTYPE_OPT --reformat $MGSDEV || exit 10
2239     fi
2240
2241     for num in `seq $MDSCOUNT`; do
2242         echo "Format mds$num: $(mdsdevname $num)"
2243         if $VERBOSE; then
2244             add mds$num $(mkfs_opts mds) $FSTYPE_OPT --reformat $(mdsdevname $num) || exit 10
2245         else
2246             add mds$num $(mkfs_opts mds) $FSTYPE_OPT --reformat $(mdsdevname $num) > /dev/null || exit 10
2247         fi
2248     done
2249
2250     # the ost-s could have different OST_MKFS_OPTS
2251     # because of different failnode-s
2252     for num in `seq $OSTCOUNT`; do
2253         echo "Format ost$num: $(ostdevname $num)"
2254         if $VERBOSE; then
2255             add ost$num $(mkfs_opts ost${num}) $FSTYPE_OPT --reformat `ostdevname $num` || exit 10
2256         else
2257             add ost$num $(mkfs_opts ost${num}) $FSTYPE_OPT --reformat `ostdevname $num` > /dev/null || exit 10
2258         fi
2259     done
2260 }
2261
2262 mount_client() {
2263     grep " $1 " /proc/mounts || zconf_mount $HOSTNAME $*
2264 }
2265
2266 umount_client() {
2267     grep " $1 " /proc/mounts && zconf_umount `hostname` $*
2268 }
2269
2270 # return value:
2271 # 0: success, the old identity set already.
2272 # 1: success, the old identity does not set.
2273 # 2: fail.
2274 switch_identity() {
2275     local num=$1
2276     local switch=$2
2277     local j=`expr $num - 1`
2278     local MDT="`(do_facet mds$num lctl get_param -N mdt.*MDT*$j 2>/dev/null | cut -d"." -f2 2>/dev/null) || true`"
2279
2280     if [ -z "$MDT" ]; then
2281         return 2
2282     fi
2283
2284     local old="`do_facet mds$num "lctl get_param -n mdt.$MDT.identity_upcall"`"
2285
2286     if $switch; then
2287         do_facet mds$num "lctl set_param -n mdt.$MDT.identity_upcall \"$L_GETIDENTITY\""
2288     else
2289         do_facet mds$num "lctl set_param -n mdt.$MDT.identity_upcall \"NONE\""
2290     fi
2291
2292     do_facet mds$num "lctl set_param -n mdt/$MDT/identity_flush=-1"
2293
2294     if [ $old = "NONE" ]; then
2295         return 1
2296     else
2297         return 0
2298     fi
2299 }
2300
2301 remount_client()
2302 {
2303         zconf_umount `hostname` $1 || error "umount failed"
2304         zconf_mount `hostname` $1 || error "mount failed"
2305 }
2306
2307 writeconf_facet () {
2308     local facet=$1
2309     local dev=$2
2310
2311     do_facet $facet "$TUNEFS --writeconf $dev"
2312 }
2313
2314 writeconf_all () {
2315     for num in `seq $MDSCOUNT`; do
2316         DEVNAME=$(mdsdevname $num)
2317         writeconf_facet mds$num $DEVNAME
2318     done
2319
2320     for num in `seq $OSTCOUNT`; do
2321         DEVNAME=$(ostdevname $num)
2322         writeconf_facet ost$num $DEVNAME
2323     done
2324 }
2325
2326 setupall() {
2327     nfs_client_mode && return
2328
2329     sanity_mount_check ||
2330         error "environments are insane!"
2331
2332     load_modules
2333
2334     if [ -z "$CLIENTONLY" ]; then
2335         echo Setup mgs, mdt, osts
2336         echo $WRITECONF | grep -q "writeconf" && \
2337             writeconf_all
2338         if ! combined_mgs_mds ; then
2339             start mgs $MGSDEV $MGS_MOUNT_OPTS
2340         fi
2341
2342         for num in `seq $MDSCOUNT`; do
2343             DEVNAME=$(mdsdevname $num)
2344             start mds$num $DEVNAME $MDS_MOUNT_OPTS
2345
2346             # We started mds, now we should set failover variables properly.
2347             # Set mds${num}failover_HOST if it is not set (the default failnode).
2348             local varname=mds${num}failover_HOST
2349             if [ -z "${!varname}" ]; then
2350                 eval mds${num}failover_HOST=$(facet_host mds$num)
2351             fi
2352
2353             if [ $IDENTITY_UPCALL != "default" ]; then
2354                 switch_identity $num $IDENTITY_UPCALL
2355             fi
2356         done
2357         for num in `seq $OSTCOUNT`; do
2358             DEVNAME=$(ostdevname $num)
2359             start ost$num $DEVNAME $OST_MOUNT_OPTS
2360
2361             # We started ost$num, now we should set ost${num}failover variable properly.
2362             # Set ost${num}failover_HOST if it is not set (the default failnode).
2363             varname=ost${num}failover_HOST
2364             if [ -z "${!varname}" ]; then
2365                 eval ost${num}failover_HOST=$(facet_host ost${num})
2366             fi
2367
2368         done
2369     fi
2370
2371     init_gss
2372
2373     # wait a while to allow sptlrpc configuration be propogated to targets,
2374     # only needed when mounting new target devices.
2375     if $GSS; then
2376         sleep 10
2377     fi
2378
2379     [ "$DAEMONFILE" ] && $LCTL debug_daemon start $DAEMONFILE $DAEMONSIZE
2380     mount_client $MOUNT
2381     [ -n "$CLIENTS" ] && zconf_mount_clients $CLIENTS $MOUNT
2382     clients_up
2383
2384     if [ "$MOUNT_2" ]; then
2385         mount_client $MOUNT2
2386         [ -n "$CLIENTS" ] && zconf_mount_clients $CLIENTS $MOUNT2
2387     fi
2388
2389     init_param_vars
2390
2391     # by remounting mdt before ost, initial connect from mdt to ost might
2392     # timeout because ost is not ready yet. wait some time to its fully
2393     # recovery. initial obd_connect timeout is 5s; in GSS case it's preceeded
2394     # by a context negotiation rpc with $TIMEOUT.
2395     # FIXME better by monitoring import status.
2396     if $GSS; then
2397         set_flavor_all $SEC
2398         sleep $((TIMEOUT + 5))
2399     else
2400         sleep 5
2401     fi
2402 }
2403
2404 mounted_lustre_filesystems() {
2405         awk '($3 ~ "lustre" && $1 ~ ":") { print $2 }' /proc/mounts
2406 }
2407
2408 init_facet_vars () {
2409     [ "$CLIENTONLY" ] && return 0
2410     local facet=$1
2411     shift
2412     local device=$1
2413
2414     shift
2415
2416     eval export ${facet}_dev=${device}
2417     eval export ${facet}_opt=\"$@\"
2418
2419     local dev=${facet}_dev
2420     local label=$(do_facet ${facet} "$E2LABEL ${!dev}")
2421     [ -z "$label" ] && echo no label for ${!dev} && exit 1
2422
2423     eval export ${facet}_svc=${label}
2424
2425     local varname=${facet}failover_HOST
2426     if [ -z "${!varname}" ]; then
2427        eval $varname=$(facet_host $facet) 
2428     fi
2429
2430     # ${facet}failover_dev is set in cfg file
2431     varname=${facet}failover_dev
2432     if [ -n "${!varname}" ] ; then
2433         eval export ${facet}failover_dev=${!varname}
2434     else
2435         eval export ${facet}failover_dev=$device
2436     fi
2437
2438     # get mount point of already mounted device
2439     # is facet_dev is already mounted then use the real
2440     #  mount point of this facet; otherwise use $(facet_mntpt $facet)
2441     # i.e. ${facet}_MOUNT if specified by user or default
2442     local mntpt=$(do_facet ${facet} cat /proc/mounts | \
2443             awk '"'${!dev}'" == $1 && $3 == "lustre" { print $2 }')
2444     if [ -z $mntpt ]; then
2445         mntpt=$(facet_mntpt $facet)
2446     fi
2447     eval export ${facet}_MOUNT=$mntpt
2448 }
2449
2450 init_facets_vars () {
2451     local DEVNAME
2452
2453     if ! remote_mds_nodsh; then 
2454         for num in `seq $MDSCOUNT`; do
2455             DEVNAME=`mdsdevname $num`
2456             init_facet_vars mds$num $DEVNAME $MDS_MOUNT_OPTS
2457         done
2458     fi
2459
2460     combined_mgs_mds || init_facet_vars mgs $MGSDEV $MGS_MOUNT_OPTS
2461
2462     remote_ost_nodsh && return
2463
2464     for num in `seq $OSTCOUNT`; do
2465         DEVNAME=`ostdevname $num`
2466         init_facet_vars ost$num $DEVNAME $OST_MOUNT_OPTS
2467     done
2468 }
2469
2470 osc_ensure_active () {
2471     local facet=$1
2472     local timeout=$2
2473     local period=0
2474
2475     while [ $period -lt $timeout ]; do
2476         count=$(do_facet $facet "lctl dl | grep ' IN osc ' 2>/dev/null | wc -l")
2477         if [ $count -eq 0 ]; then
2478             break
2479         fi
2480
2481         echo "There are $count OST are inactive, wait $period seconds, and try again"
2482         sleep 3
2483         period=$((period+3))
2484     done
2485
2486     [ $period -lt $timeout ] || log "$count OST are inactive after $timeout seconds, give up"
2487 }
2488
2489 init_param_vars () {
2490     remote_mds_nodsh ||
2491         TIMEOUT=$(do_facet $SINGLEMDS "lctl get_param -n timeout")
2492
2493     log "Using TIMEOUT=$TIMEOUT"
2494
2495     osc_ensure_active $SINGLEMDS $TIMEOUT
2496     osc_ensure_active client $TIMEOUT
2497
2498     if [ $QUOTA_AUTO -ne 0 ]; then
2499         if [ "$ENABLE_QUOTA" ]; then
2500             echo "enable quota as required"
2501             setup_quota $MOUNT || return 2
2502         else
2503             echo "disable quota as required"
2504             [ $(lustre_version_code $SINGLEMDS) -lt $(version_code 2.3.50) ] &&
2505                 $LFS quotaoff -ug $MOUNT > /dev/null 2>&1
2506         fi
2507     fi
2508
2509     return 0
2510 }
2511
2512 nfs_client_mode () {
2513     if [ "$NFSCLIENT" ]; then
2514         echo "NFSCLIENT mode: setup, cleanup, check config skipped"
2515         local clients=$CLIENTS
2516         [ -z $clients ] && clients=$(hostname)
2517
2518         # FIXME: remove hostname when 19215 fixed
2519         do_nodes $clients "echo \\\$(hostname); grep ' '$MOUNT' ' /proc/mounts"
2520         declare -a nfsexport=(`grep ' '$MOUNT' ' /proc/mounts | awk '{print $1}' | awk -F: '{print $1 " "  $2}'`)
2521         if [[ ${#nfsexport[@]} -eq 0 ]]; then
2522                 error_exit NFSCLIENT=$NFSCLIENT mode, but no NFS export found!
2523         fi
2524         do_nodes ${nfsexport[0]} "echo \\\$(hostname); df -T  ${nfsexport[1]}"
2525         return
2526     fi
2527     return 1
2528 }
2529
2530 check_config_client () {
2531     local mntpt=$1
2532
2533     local mounted=$(mount | grep " $mntpt ")
2534     if [ "$CLIENTONLY" ]; then
2535         # bug 18021
2536         # CLIENTONLY should not depend on *_HOST settings
2537         local mgc=$($LCTL device_list | awk '/MGC/ {print $4}')
2538         # in theory someone could create a new,
2539         # client-only config file that assumed lustre was already
2540         # configured and didn't set the MGSNID. If MGSNID is not set,
2541         # then we should use the mgs nid currently being used 
2542         # as the default value. bug 18021
2543         [[ x$MGSNID = x ]] &&
2544             MGSNID=${mgc//MGC/}
2545
2546         if [[ x$mgc != xMGC$MGSNID ]]; then
2547             if [ "$mgs_HOST" ]; then
2548                 local mgc_ip=$(ping -q -c1 -w1 $mgs_HOST | grep PING | awk '{print $3}' | sed -e "s/(//g" -e "s/)//g")
2549 #                [[ x$mgc = xMGC$mgc_ip@$NETTYPE ]] ||
2550 #                    error_exit "MGSNID=$MGSNID, mounted: $mounted, MGC : $mgc"
2551             fi
2552         fi
2553         return 0
2554     fi
2555
2556     local myMGS_host=$mgs_HOST   
2557     if [ "$NETTYPE" = "ptl" ]; then
2558         myMGS_host=$(h2ptl $mgs_HOST | sed -e s/@ptl//) 
2559     fi
2560
2561     echo Checking config lustre mounted on $mntpt
2562     local mgshost=$(mount | grep " $mntpt " | awk -F@ '{print $1}')
2563     mgshost=$(echo $mgshost | awk -F: '{print $1}')
2564
2565 #    if [ "$mgshost" != "$myMGS_host" ]; then
2566 #            log "Bad config file: lustre is mounted with mgs $mgshost, but mgs_HOST=$mgs_HOST, NETTYPE=$NETTYPE
2567 #                   Please use correct config or set mds_HOST correctly!"
2568 #    fi
2569
2570 }
2571
2572 check_config_clients () {
2573     local clients=${CLIENTS:-$HOSTNAME}
2574     local mntpt=$1
2575
2576     nfs_client_mode && return
2577
2578     do_rpc_nodes $clients check_config_client $mntpt
2579
2580     sanity_mount_check ||
2581         error "environments are insane!"
2582 }
2583
2584 check_timeout () {
2585     local mdstimeout=$(do_facet $SINGLEMDS "lctl get_param -n timeout")
2586     local cltimeout=$(lctl get_param -n timeout)
2587     if [ $mdstimeout -ne $TIMEOUT ] || [ $mdstimeout -ne $cltimeout ]; then
2588         error "timeouts are wrong! mds: $mdstimeout, client: $cltimeout, TIMEOUT=$TIMEOUT"
2589         return 1
2590     fi
2591 }
2592
2593 is_mounted () {
2594     local mntpt=$1
2595     [ -z $mntpt ] && return 1
2596     local mounted=$(mounted_lustre_filesystems)
2597
2598     echo $mounted' ' | grep -w -q $mntpt' '
2599 }
2600
2601 is_empty_dir() {
2602     [ $(find $1 -maxdepth 1 -print | wc -l) = 1 ] && return 0
2603     return 1
2604 }
2605
2606 # empty lustre filesystem may have empty directories lost+found and .lustre
2607 is_empty_fs() {
2608     [ $(find $1 -maxdepth 1 -name lost+found -o -name .lustre -prune -o \
2609        -print | wc -l) = 1 ] || return 1
2610     [ ! -d $1/lost+found ] || is_empty_dir $1/lost+found && return 0
2611     [ ! -d $1/.lustre ] || is_empty_dir $1/.lustre && return 0
2612     return 1
2613 }
2614
2615 check_and_setup_lustre() {
2616     nfs_client_mode && return
2617
2618     local MOUNTED=$(mounted_lustre_filesystems)
2619
2620     local do_check=true
2621     # 1.
2622     # both MOUNT and MOUNT2 are not mounted
2623     if ! is_mounted $MOUNT && ! is_mounted $MOUNT2; then
2624         [ "$REFORMAT" ] && formatall
2625         # setupall mounts both MOUNT and MOUNT2 (if MOUNT_2 is set)
2626         setupall
2627         is_mounted $MOUNT || error "NAME=$NAME not mounted"
2628         export I_MOUNTED=yes
2629         do_check=false
2630     # 2.
2631     # MOUNT2 is mounted
2632     elif is_mounted $MOUNT2; then
2633             # 3.
2634             # MOUNT2 is mounted, while MOUNT_2 is not set
2635             if ! [ "$MOUNT_2" ]; then
2636                 cleanup_mount $MOUNT2
2637                 export I_UMOUNTED2=yes
2638
2639             # 4.
2640             # MOUNT2 is mounted, MOUNT_2 is set
2641             else
2642                 # FIXME: what to do if check_config failed?
2643                 # i.e. if:
2644                 # 1) remote client has mounted other Lustre fs ?
2645                 # 2) it has insane env ?
2646                 # let's try umount MOUNT2 on all clients and mount it again:
2647                 if ! check_config_clients $MOUNT2; then
2648                     cleanup_mount $MOUNT2
2649                     restore_mount $MOUNT2
2650                     export I_MOUNTED2=yes
2651                 fi
2652             fi 
2653
2654     # 5.
2655     # MOUNT is mounted MOUNT2 is not mounted
2656     elif [ "$MOUNT_2" ]; then
2657         restore_mount $MOUNT2
2658         export I_MOUNTED2=yes
2659     fi
2660
2661     if $do_check; then
2662         # FIXME: what to do if check_config failed?
2663         # i.e. if:
2664         # 1) remote client has mounted other Lustre fs?
2665         # 2) lustre is mounted on remote_clients atall ?
2666         check_config_clients $MOUNT
2667         init_facets_vars
2668         init_param_vars
2669
2670         set_default_debug_nodes $(comma_list $(nodes_list))
2671     fi
2672
2673     if $GSS; then
2674         init_gss
2675         set_flavor_all $SEC
2676     fi
2677
2678     if [ "$ONLY" == "setup" ]; then
2679         exit 0
2680     fi
2681 }
2682
2683 restore_mount () {
2684    local clients=${CLIENTS:-$HOSTNAME}
2685    local mntpt=$1
2686
2687    zconf_mount_clients $clients $mntpt
2688 }
2689
2690 cleanup_mount () {
2691     local clients=${CLIENTS:-$HOSTNAME}
2692     local mntpt=$1
2693
2694     zconf_umount_clients $clients $mntpt    
2695 }
2696
2697 cleanup_and_setup_lustre() {
2698     if [ "$ONLY" == "cleanup" -o "`mount | grep $MOUNT`" ]; then
2699         lctl set_param debug=0 || true
2700         cleanupall
2701         if [ "$ONLY" == "cleanup" ]; then
2702             exit 0
2703         fi
2704     fi
2705     check_and_setup_lustre
2706 }
2707
2708 # Get all of the server target devices from a given server node and type.
2709 get_mnt_devs() {
2710         local node=$1
2711         local type=$2
2712         local devs
2713         local dev
2714
2715         if [ "$type" == ost ]; then
2716                 devs=$(get_obdfilter_param $node "" mntdev)
2717         else
2718                 devs=$(do_node $node \
2719                        "lctl get_param -n osd-*.$FSNAME-M*.mntdev")
2720         fi
2721         for dev in $devs; do
2722                 case $dev in
2723                 *loop*) do_node $node "losetup $dev" | \
2724                                 sed -e "s/.*(//" -e "s/).*//" ;;
2725                 *) echo $dev ;;
2726                 esac
2727         done
2728 }
2729
2730 # Get all of the server target devices.
2731 get_svr_devs() {
2732     local i
2733
2734     # MDT device
2735     MDTDEV=$(get_mnt_devs $(mdts_nodes) mdt)
2736
2737     # OST devices
2738     i=0
2739     for node in $(osts_nodes); do
2740         OSTDEVS[i]=$(get_mnt_devs $node ost)
2741         i=$((i + 1))
2742     done
2743 }
2744
2745 # Run e2fsck on MDT or OST device.
2746 run_e2fsck() {
2747     local node=$1
2748     local target_dev=$2
2749     local extra_opts=$3
2750
2751     df > /dev/null      # update statfs data on disk
2752     local cmd="$E2FSCK -d -v -t -t -f -n $extra_opts $target_dev"
2753     echo $cmd
2754     local rc=0
2755     do_node $node $cmd || rc=$?
2756     [ $rc -le $FSCK_MAX_ERR ] || \
2757         error "$cmd returned $rc, should be <= $FSCK_MAX_ERR"
2758     return 0
2759 }
2760
2761 # verify a directory is shared among nodes.
2762 check_shared_dir() {
2763     local dir=$1
2764
2765     [ -z "$dir" ] && return 1
2766     do_rpc_nodes $(comma_list $(nodes_list)) check_logdir $dir
2767     check_write_access $dir || return 1
2768     return 0
2769 }
2770
2771 # Run e2fsck on MDT and OST(s) to generate databases used for lfsck.
2772 generate_db() {
2773     local i
2774     local ostidx
2775     local dev
2776
2777     check_shared_dir $SHARED_DIRECTORY ||
2778         error "$SHARED_DIRECTORY isn't a shared directory"
2779
2780     export MDSDB=$SHARED_DIRECTORY/mdsdb
2781     export OSTDB=$SHARED_DIRECTORY/ostdb
2782
2783     [ $MDSCOUNT -eq 1 ] || error "CMD is not supported"
2784
2785     run_e2fsck $(mdts_nodes) $MDTDEV "--mdsdb $MDSDB"
2786
2787     i=0
2788     ostidx=0
2789     OSTDB_LIST=""
2790     for node in $(osts_nodes); do
2791         for dev in ${OSTDEVS[i]}; do
2792             run_e2fsck $node $dev "--mdsdb $MDSDB --ostdb $OSTDB-$ostidx"
2793             OSTDB_LIST="$OSTDB_LIST $OSTDB-$ostidx"
2794             ostidx=$((ostidx + 1))
2795         done
2796         i=$((i + 1))
2797     done
2798 }
2799
2800 run_lfsck() {
2801     local cmd="$LFSCK_BIN -c -l --mdsdb $MDSDB --ostdb $OSTDB_LIST $MOUNT"
2802     echo $cmd
2803     local rc=0
2804     eval $cmd || rc=$?
2805     [ $rc -le $FSCK_MAX_ERR ] || \
2806         error "$cmd returned $rc, should be <= $FSCK_MAX_ERR"
2807     echo "lfsck finished with rc=$rc"
2808
2809     rm -rvf $MDSDB* $OSTDB* || true
2810     return 0
2811 }
2812
2813 check_and_cleanup_lustre() {
2814     if [ "$LFSCK_ALWAYS" = "yes" -a "$TESTSUITE" != "lfsck" ]; then
2815         get_svr_devs
2816         generate_db
2817         run_lfsck
2818     fi
2819
2820         if is_mounted $MOUNT; then
2821                 [ -n "$DIR" ] && rm -rf $DIR/[Rdfs][0-9]* ||
2822                         error "remove sub-test dirs failed"
2823                 [ "$ENABLE_QUOTA" ] && restore_quota || true
2824         fi
2825
2826     if [ "$I_UMOUNTED2" = "yes" ]; then
2827         restore_mount $MOUNT2 || error "restore $MOUNT2 failed"
2828     fi
2829
2830     if [ "$I_MOUNTED2" = "yes" ]; then
2831         cleanup_mount $MOUNT2
2832     fi
2833
2834     if [ "$I_MOUNTED" = "yes" ]; then
2835         cleanupall -f || error "cleanup failed"
2836         unset I_MOUNTED
2837     fi
2838 }
2839
2840 #######
2841 # General functions
2842
2843 wait_for_function () {
2844     local quiet=""
2845
2846     # suppress fn both stderr and stdout
2847     if [ "$1" = "--quiet" ]; then
2848         shift
2849         quiet=" > /dev/null 2>&1"
2850
2851     fi
2852
2853     local fn=$1
2854     local max=${2:-900}
2855     local sleep=${3:-5}
2856
2857     local wait=0
2858
2859     while true; do
2860
2861         eval $fn $quiet && return 0
2862
2863         wait=$((wait + sleep))
2864         [ $wait -lt $max ] || return 1
2865         echo waiting $fn, $((max - wait)) secs left ...
2866         sleep $sleep
2867     done
2868 }
2869
2870 check_network() {
2871     local host=$1
2872     local max=$2
2873     local sleep=${3:-5}
2874
2875     echo `date +"%H:%M:%S (%s)"` waiting for $host network $max secs ...
2876     if ! wait_for_function --quiet "ping -c 1 -w 3 $host" $max $sleep ; then
2877         echo "Network not available!"
2878         exit 1
2879     fi
2880
2881     echo `date +"%H:%M:%S (%s)"` network interface is UP
2882 }
2883
2884 no_dsh() {
2885     shift
2886     eval $@
2887 }
2888
2889 comma_list() {
2890     # the sed converts spaces to commas, but leaves the last space
2891     # alone, so the line doesn't end with a comma.
2892     echo "$*" | tr -s " " "\n" | sort -b -u | tr "\n" " " | sed 's/ \([^$]\)/,\1/g'
2893 }
2894
2895 list_member () {
2896     local list=$1
2897     local item=$2
2898     echo $list | grep -qw $item
2899 }
2900
2901 # list, excluded are the comma separated lists
2902 exclude_items_from_list () {
2903     local list=$1
2904     local excluded=$2
2905     local item
2906
2907     list=${list//,/ }
2908     for item in ${excluded//,/ }; do
2909         list=$(echo " $list " | sed -re "s/\s+$item\s+/ /g")
2910     done
2911     echo $(comma_list $list)
2912 }
2913
2914 # list, expand  are the comma separated lists
2915 expand_list () {
2916     local list=${1//,/ }
2917     local expand=${2//,/ }
2918     local expanded=
2919
2920     expanded=$(for i in $list $expand; do echo $i; done | sort -u)
2921     echo $(comma_list $expanded)
2922 }
2923
2924 testslist_filter () {
2925     local script=$LUSTRE/tests/${TESTSUITE}.sh
2926
2927     [ -f $script ] || return 0
2928
2929     local start_at=$START_AT
2930     local stop_at=$STOP_AT
2931
2932     local var=${TESTSUITE//-/_}_START_AT
2933     [ x"${!var}" != x ] && start_at=${!var}
2934     var=${TESTSUITE//-/_}_STOP_AT
2935     [ x"${!var}" != x ] && stop_at=${!var}
2936
2937     sed -n 's/^test_\([^ (]*\).*/\1/p' $script | \
2938         awk ' BEGIN { if ("'${start_at:-0}'" != 0) flag = 1 }
2939             /^'${start_at}'$/ {flag = 0}
2940             {if (flag == 1) print $0}
2941             /^'${stop_at}'$/ { flag = 1 }'
2942 }
2943
2944 absolute_path() {
2945     (cd `dirname $1`; echo $PWD/`basename $1`)
2946 }
2947
2948 get_facets () {
2949     local types=${1:-"OST MDS MGS"}
2950
2951     local list=""
2952
2953     for entry in $types; do
2954         local name=$(echo $entry | tr "[:upper:]" "[:lower:]")
2955         local type=$(echo $entry | tr "[:lower:]" "[:upper:]")
2956
2957         case $type in
2958                 MGS ) list="$list $name";;
2959             MDS|OST ) local count=${type}COUNT
2960                        for ((i=1; i<=${!count}; i++)) do
2961                           list="$list ${name}$i"
2962                       done;;
2963                   * ) error "Invalid facet type"
2964                  exit 1;;
2965         esac
2966     done
2967     echo $(comma_list $list)
2968 }
2969
2970 ##################################
2971 # Adaptive Timeouts funcs
2972
2973 at_is_enabled() {
2974     # only check mds, we assume at_max is the same on all nodes
2975     local at_max=$(do_facet $SINGLEMDS "lctl get_param -n at_max")
2976     if [ $at_max -eq 0 ]; then
2977         return 1
2978     else
2979         return 0
2980     fi
2981 }
2982
2983 at_get() {
2984     local facet=$1
2985     local at=$2
2986
2987     # suppose that all ost-s have the same $at value set
2988     [[ $facet = ost ]] && facet=ost1
2989
2990     do_facet $facet "lctl get_param -n $at"
2991 }
2992
2993 at_max_get() {
2994     at_get $1 at_max
2995 }
2996
2997 at_min_get() {
2998         at_get $1 at_min
2999 }
3000
3001 at_max_set() {
3002     local at_max=$1
3003     shift
3004
3005     local facet
3006     local hosts
3007     for facet in $@; do
3008         if [ $facet == "ost" ]; then
3009             facet=$(get_facets OST)
3010         elif [ $facet == "mds" ]; then
3011             facet=$(get_facets MDS)
3012         fi
3013         hosts=$(expand_list $hosts $(facets_hosts $facet))
3014     done
3015
3016     do_nodes $hosts lctl set_param at_max=$at_max
3017 }
3018
3019 ##################################
3020 # OBD_FAIL funcs
3021
3022 drop_request() {
3023 # OBD_FAIL_MDS_ALL_REQUEST_NET
3024     RC=0
3025     do_facet $SINGLEMDS lctl set_param fail_loc=0x123
3026     do_facet client "$1" || RC=$?
3027     do_facet $SINGLEMDS lctl set_param fail_loc=0
3028     return $RC
3029 }
3030
3031 drop_reply() {
3032 # OBD_FAIL_MDS_ALL_REPLY_NET
3033     RC=0
3034     do_facet $SINGLEMDS lctl set_param fail_loc=0x122
3035     do_facet client "$@" || RC=$?
3036     do_facet $SINGLEMDS lctl set_param fail_loc=0
3037     return $RC
3038 }
3039
3040 drop_reint_reply() {
3041 # OBD_FAIL_MDS_REINT_NET_REP
3042     RC=0
3043     do_facet $SINGLEMDS lctl set_param fail_loc=0x119
3044     do_facet client "$@" || RC=$?
3045     do_facet $SINGLEMDS lctl set_param fail_loc=0
3046     return $RC
3047 }
3048
3049 pause_bulk() {
3050 #define OBD_FAIL_OST_BRW_PAUSE_BULK      0x214
3051     RC=0
3052     do_facet ost1 lctl set_param fail_loc=0x214
3053     do_facet client "$1" || RC=$?
3054     do_facet client "sync"
3055     do_facet ost1 lctl set_param fail_loc=0
3056     return $RC
3057 }
3058
3059 drop_ldlm_cancel() {
3060 #define OBD_FAIL_LDLM_CANCEL             0x304
3061     RC=0
3062     do_facet client lctl set_param fail_loc=0x304
3063     do_facet client "$@" || RC=$?
3064     do_facet client lctl set_param fail_loc=0
3065     return $RC
3066 }
3067
3068 drop_bl_callback() {
3069 #define OBD_FAIL_LDLM_BL_CALLBACK        0x305
3070     RC=0
3071     do_facet client lctl set_param fail_loc=0x305
3072     do_facet client "$@" || RC=$?
3073     do_facet client lctl set_param fail_loc=0
3074     return $RC
3075 }
3076
3077 drop_ldlm_reply() {
3078 #define OBD_FAIL_LDLM_REPLY              0x30c
3079     RC=0
3080     do_facet $SINGLEMDS lctl set_param fail_loc=0x30c
3081     do_facet client "$@" || RC=$?
3082     do_facet $SINGLEMDS lctl set_param fail_loc=0
3083     return $RC
3084 }
3085
3086 clear_failloc() {
3087     facet=$1
3088     pause=$2
3089     sleep $pause
3090     echo "clearing fail_loc on $facet"
3091     do_facet $facet "lctl set_param fail_loc=0 2>/dev/null || true"
3092 }
3093
3094 set_nodes_failloc () {
3095     do_nodes $(comma_list $1)  lctl set_param fail_loc=$2
3096 }
3097
3098 cancel_lru_locks() {
3099     $LCTL mark "cancel_lru_locks $1 start"
3100     for d in `lctl get_param -N ldlm.namespaces.*.lru_size | egrep -i $1`; do
3101         $LCTL set_param -n $d=clear
3102     done
3103     $LCTL get_param ldlm.namespaces.*.lock_unused_count | egrep -i $1 | grep -v '=0'
3104     $LCTL mark "cancel_lru_locks $1 stop"
3105 }
3106
3107 default_lru_size()
3108 {
3109         NR_CPU=$(grep -c "processor" /proc/cpuinfo)
3110         DEFAULT_LRU_SIZE=$((100 * NR_CPU))
3111         echo "$DEFAULT_LRU_SIZE"
3112 }
3113
3114 lru_resize_enable()
3115 {
3116     lctl set_param ldlm.namespaces.*$1*.lru_size=0
3117 }
3118
3119 lru_resize_disable()
3120 {
3121     lctl set_param ldlm.namespaces.*$1*.lru_size $(default_lru_size)
3122 }
3123
3124 pgcache_empty() {
3125     local FILE
3126     for FILE in `lctl get_param -N "llite.*.dump_page_cache"`; do
3127         if [ `lctl get_param -n $FILE | wc -l` -gt 1 ]; then
3128             echo there is still data in page cache $FILE ?
3129             lctl get_param -n $FILE
3130             return 1
3131         fi
3132     done
3133     return 0
3134 }
3135
3136 debugsave() {
3137     DEBUGSAVE="$(lctl get_param -n debug)"
3138 }
3139
3140 debugrestore() {
3141     [ -n "$DEBUGSAVE" ] && \
3142         do_nodes $(comma_list $(nodes_list)) "$LCTL set_param debug=\\\"${DEBUGSAVE}\\\";"
3143     DEBUGSAVE=""
3144 }
3145
3146 debug_size_save() {
3147     DEBUG_SIZE_SAVED="$(lctl get_param -n debug_mb)"
3148 }
3149
3150 debug_size_restore() {
3151     [ -n "$DEBUG_SIZE_SAVED" ] && \
3152         do_nodes $(comma_list $(nodes_list)) "$LCTL set_param debug_mb=$DEBUG_SIZE_SAVED"
3153     DEBUG_SIZE_SAVED=""
3154 }
3155
3156 start_full_debug_logging() {
3157     debugsave
3158     debug_size_save
3159
3160     local FULLDEBUG=-1
3161     local DEBUG_SIZE=150
3162
3163     do_nodes $(comma_list $(nodes_list)) "$LCTL set_param debug_mb=$DEBUG_SIZE"
3164     do_nodes $(comma_list $(nodes_list)) "$LCTL set_param debug=$FULLDEBUG;"
3165 }
3166
3167 stop_full_debug_logging() {
3168     debug_size_restore
3169     debugrestore
3170 }
3171
3172 ##################################
3173 # Test interface
3174 ##################################
3175
3176 error_noexit() {
3177     local TYPE=${TYPE:-"FAIL"}
3178
3179     local dump=true
3180     # do not dump logs if $1=false
3181     if [ "x$1" = "xfalse" ]; then
3182         shift
3183         dump=false
3184     fi
3185
3186     log " ${TESTSUITE} ${TESTNAME}: @@@@@@ ${TYPE}: $@ "
3187
3188     mkdir -p $LOGDIR
3189     # We need to dump the logs on all nodes
3190     if $dump; then
3191         gather_logs $(comma_list $(nodes_list))
3192     fi
3193
3194     debugrestore
3195     [ "$TESTSUITELOG" ] && echo "$0: ${TYPE}: $TESTNAME $@" >> $TESTSUITELOG
3196     echo "$@" > $LOGDIR/err
3197 }
3198
3199 exit_status () {
3200     local status=0
3201     local log=$TESTSUITELOG
3202
3203     [ -f "$log" ] && grep -q FAIL: $log && status=1
3204     exit $status
3205 }
3206
3207 error() {
3208     error_noexit "$@"
3209     exit 1
3210 }
3211
3212 error_exit() {
3213     error "$@"
3214 }
3215
3216 # use only if we are ignoring failures for this test, bugno required.
3217 # (like ALWAYS_EXCEPT, but run the test and ignore the results.)
3218 # e.g. error_ignore 5494 "your message"
3219 error_ignore() {
3220     local TYPE="IGNORE (bz$1)"
3221     shift
3222     error_noexit "$@"
3223 }
3224
3225 skip_env () {
3226     $FAIL_ON_SKIP_ENV && error false $@ || skip $@
3227 }
3228
3229 skip() {
3230     echo
3231     log " SKIP: $TESTSUITE $TESTNAME $@"
3232
3233     if [[ -n "$ALWAYS_SKIPPED" ]]; then
3234         skip_logged $TESTNAME "$@"
3235     else
3236         mkdir -p $LOGDIR
3237         echo "$@" > $LOGDIR/skip
3238     fi
3239
3240     [[ -n "$TESTSUITELOG" ]] &&
3241         echo "$TESTSUITE: SKIP: $TESTNAME $@" >> $TESTSUITELOG || true
3242 }
3243
3244 build_test_filter() {
3245     EXCEPT="$EXCEPT $(testslist_filter)"
3246
3247     [ "$ONLY" ] && log "only running test `echo $ONLY`"
3248     for O in $ONLY; do
3249         eval ONLY_${O}=true
3250     done
3251     [ "$EXCEPT$ALWAYS_EXCEPT" ] && \
3252         log "excepting tests: `echo $EXCEPT $ALWAYS_EXCEPT`"
3253     [ "$EXCEPT_SLOW" ] && \
3254         log "skipping tests SLOW=no: `echo $EXCEPT_SLOW`"
3255     for E in $EXCEPT; do
3256         eval EXCEPT_${E}=true
3257     done
3258     for E in $ALWAYS_EXCEPT; do
3259         eval EXCEPT_ALWAYS_${E}=true
3260     done
3261     for E in $EXCEPT_SLOW; do
3262         eval EXCEPT_SLOW_${E}=true
3263     done
3264     for G in $GRANT_CHECK_LIST; do
3265         eval GCHECK_ONLY_${G}=true
3266         done
3267 }
3268
3269 basetest() {
3270     if [[ $1 = [a-z]* ]]; then
3271         echo $1
3272     else
3273         echo ${1%%[a-z]*}
3274     fi
3275 }
3276
3277 # print a newline if the last test was skipped
3278 export LAST_SKIPPED=
3279 export ALWAYS_SKIPPED=
3280 #
3281 # Main entry into test-framework. This is called with the name and
3282 # description of a test. The name is used to find the function to run
3283 # the test using "test_$name".
3284 #
3285 # This supports a variety of methods of specifying specific test to
3286 # run or not run.  These need to be documented...
3287 #
3288 run_test() {
3289     assert_DIR
3290
3291     export base=`basetest $1`
3292     if [ ! -z "$ONLY" ]; then
3293         testname=ONLY_$1
3294         if [ ${!testname}x != x ]; then
3295             [ "$LAST_SKIPPED" ] && echo "" && LAST_SKIPPED=
3296             run_one_logged $1 "$2"
3297             return $?
3298         fi
3299         testname=ONLY_$base
3300         if [ ${!testname}x != x ]; then
3301             [ "$LAST_SKIPPED" ] && echo "" && LAST_SKIPPED=
3302             run_one_logged $1 "$2"
3303             return $?
3304         fi
3305         LAST_SKIPPED="y"
3306         echo -n "."
3307         return 0
3308     fi
3309
3310     LAST_SKIPPED="y"
3311     ALWAYS_SKIPPED="y"
3312     testname=EXCEPT_$1
3313     if [ ${!testname}x != x ]; then
3314         TESTNAME=test_$1 skip "skipping excluded test $1"
3315         return 0
3316     fi
3317     testname=EXCEPT_$base
3318     if [ ${!testname}x != x ]; then
3319         TESTNAME=test_$1 skip "skipping excluded test $1 (base $base)"
3320         return 0
3321     fi
3322     testname=EXCEPT_ALWAYS_$1
3323     if [ ${!testname}x != x ]; then
3324         TESTNAME=test_$1 skip "skipping ALWAYS excluded test $1"
3325         return 0
3326     fi
3327     testname=EXCEPT_ALWAYS_$base
3328     if [ ${!testname}x != x ]; then
3329         TESTNAME=test_$1 skip "skipping ALWAYS excluded test $1 (base $base)"
3330         return 0
3331     fi
3332     testname=EXCEPT_SLOW_$1
3333     if [ ${!testname}x != x ]; then
3334         TESTNAME=test_$1 skip "skipping SLOW test $1"
3335         return 0
3336     fi
3337     testname=EXCEPT_SLOW_$base
3338     if [ ${!testname}x != x ]; then
3339         TESTNAME=test_$1 skip "skipping SLOW test $1 (base $base)"
3340         return 0
3341     fi
3342
3343     LAST_SKIPPED=
3344     ALWAYS_SKIPPED=
3345     run_one_logged $1 "$2"
3346
3347     return $?
3348 }
3349
3350 equals_msg() {
3351     banner "$*"
3352 }
3353
3354 log() {
3355     echo "$*"
3356     module_loaded lnet || load_modules
3357
3358     local MSG="$*"
3359     # Get rid of '
3360     MSG=${MSG//\'/\\\'}
3361     MSG=${MSG//\(/\\\(}
3362     MSG=${MSG//\)/\\\)}
3363     MSG=${MSG//\;/\\\;}
3364     MSG=${MSG//\|/\\\|}
3365     MSG=${MSG//\>/\\\>}
3366     MSG=${MSG//\</\\\<}
3367     MSG=${MSG//\//\\\/}
3368     do_nodes $(comma_list $(nodes_list)) $LCTL mark "$MSG" 2> /dev/null || true
3369 }
3370
3371 trace() {
3372         log "STARTING: $*"
3373         strace -o $TMP/$1.strace -ttt $*
3374         RC=$?
3375         log "FINISHED: $*: rc $RC"
3376         return 1
3377 }
3378
3379 complete () {
3380     equals_msg $1 test complete, duration $2 sec
3381     [ -f "$TESTSUITELOG" ] && egrep .FAIL $TESTSUITELOG || true
3382     echo duration $2 >>$TESTSUITELOG
3383 }
3384
3385 pass() {
3386     # Set TEST_STATUS here. It will be used for logging the result.
3387     TEST_STATUS="PASS"
3388
3389     if [[ -f $LOGDIR/err ]]; then
3390         TEST_STATUS="FAIL"
3391     elif [[ -f $LOGDIR/skip ]]; then
3392         TEST_STATUS="SKIP"
3393     fi
3394     echo "$TEST_STATUS $@" 2>&1 | tee -a $TESTSUITELOG
3395 }
3396
3397 check_mds() {
3398     local FFREE=$(do_node $SINGLEMDS \
3399         lctl get_param -n osd*.*MDT*.filesfree | calc_sum)
3400     local FTOTAL=$(do_node $SINGLEMDS \
3401         lctl get_param -n osd*.*MDT*.filestotal | calc_sum)
3402
3403     [ $FFREE -ge $FTOTAL ] && error "files free $FFREE > total $FTOTAL" || true
3404 }
3405
3406 reset_fail_loc () {
3407     echo -n "Resetting fail_loc on all nodes..."
3408     do_nodes $(comma_list $(nodes_list)) "lctl set_param -n fail_loc=0 2>/dev/null || true"
3409     echo done.
3410 }
3411
3412
3413 #
3414 # Log a message (on all nodes) padded with "=" before and after. 
3415 # Also appends a timestamp and prepends the testsuite name.
3416
3417
3418 EQUALS="===================================================================================================="
3419 banner() {
3420     msg="== ${TESTSUITE} $*"
3421     last=${msg: -1:1}
3422     [[ $last != "=" && $last != " " ]] && msg="$msg "
3423     msg=$(printf '%s%.*s'  "$msg"  $((${#EQUALS} - ${#msg})) $EQUALS )
3424     # always include at least == after the message
3425     log "$msg== $(date +"%H:%M:%S (%s)")"
3426 }
3427
3428 #
3429 # Run a single test function and cleanup after it.  
3430 #
3431 # This function should be run in a subshell so the test func can
3432 # exit() without stopping the whole script.
3433 #
3434 run_one() {
3435     local testnum=$1
3436     local message=$2
3437     tfile=f${testnum}
3438     export tdir=d0.${TESTSUITE}/d${base}
3439     export TESTNAME=test_$testnum
3440     local SAVE_UMASK=`umask`
3441     umask 0022
3442
3443     banner "test $testnum: $message"
3444     test_${testnum} || error "test_$testnum failed with $?"
3445     cd $SAVE_PWD
3446     reset_fail_loc
3447     check_grant ${testnum} || error "check_grant $testnum failed with $?"
3448     check_catastrophe || error "LBUG/LASSERT detected"
3449     ps auxww | grep -v grep | grep -q multiop && error "multiop still running"
3450     unset TESTNAME
3451     unset tdir
3452     umask $SAVE_UMASK
3453     return 0
3454 }
3455
3456 #
3457 # Wrapper around run_one to ensure:
3458 #  - test runs in subshell
3459 #  - output of test is saved to separate log file for error reporting
3460 #  - test result is saved to data file
3461 #
3462 run_one_logged() {
3463     local BEFORE=`date +%s`
3464     local TEST_ERROR
3465     local name=${TESTSUITE}.test_${1}.test_log.$(hostname -s).log
3466     local test_log=$LOGDIR/$name
3467     rm -rf $LOGDIR/err
3468     rm -rf $LOGDIR/skip
3469     local SAVE_UMASK=`umask`
3470     umask 0022
3471
3472     echo
3473     log_sub_test_begin test_${1}
3474     (run_one $1 "$2") 2>&1 | tee $test_log
3475     local RC=${PIPESTATUS[0]}
3476
3477     [ $RC -ne 0 ] && [ ! -f $LOGDIR/err ] && \
3478         echo "test_$1 returned $RC" | tee $LOGDIR/err
3479
3480     duration=$((`date +%s` - $BEFORE))
3481     pass "$1" "(${duration}s)"
3482
3483     if [[ -f $LOGDIR/err ]]; then
3484         TEST_ERROR=$(cat $LOGDIR/err)
3485     elif [[ -f $LOGDIR/skip ]]; then
3486         TEST_ERROR=$(cat $LOGDIR/skip)
3487     fi
3488     log_sub_test_end $TEST_STATUS $duration "$RC" "$TEST_ERROR"
3489
3490     if [ -f $LOGDIR/err ]; then
3491         $FAIL_ON_ERROR && exit $RC
3492     fi
3493
3494     umask $SAVE_UMASK
3495
3496     return 0
3497 }
3498
3499 #
3500 # Print information of skipped tests to result.yml
3501 #
3502 skip_logged(){
3503     log_sub_test_begin $1
3504     shift
3505     log_sub_test_end "SKIP" "0" "0" "$@"
3506 }
3507
3508 canonical_path() {
3509     (cd `dirname $1`; echo $PWD/`basename $1`)
3510 }
3511
3512
3513 check_grant() {
3514     export base=`basetest $1`
3515     [ "$CHECK_GRANT" == "no" ] && return 0
3516
3517         testname=GCHECK_ONLY_${base}
3518         [ ${!testname}x == x ] && return 0
3519
3520     echo -n "checking grant......"
3521
3522         local clients=$CLIENTS
3523         [ -z $clients ] && clients=$(hostname)
3524
3525     # sync all the data and make sure no pending data on server
3526     do_nodes $clients sync
3527
3528     # get client grant
3529     client_grant=`do_nodes $clients \
3530                     "$LCTL get_param -n osc.${FSNAME}-*.cur_*grant_bytes" | \
3531                     awk '{total += $1} END{print total}'`
3532
3533     # get server grant
3534     server_grant=`do_nodes $(comma_list $(osts_nodes)) \
3535                     "$LCTL get_param -n obdfilter.${FSNAME}-OST*.tot_granted" | \
3536                     awk '{total += $1} END{print total}'`
3537
3538     # check whether client grant == server grant
3539     if [ $client_grant -ne $server_grant ]; then
3540         echo "failed: client:${client_grant} server: ${server_grant}."
3541         do_nodes $(comma_list $(osts_nodes)) \
3542                    "$LCTL get_param obdfilter.${FSNAME}-OST*.tot*"
3543         do_nodes $clients "$LCTL get_param osc.${FSNAME}-*.cur_*_bytes"
3544         return 1
3545     else
3546         echo "pass: client:${client_grant} server: ${server_grant}"
3547     fi
3548
3549 }
3550
3551 ########################
3552 # helper functions
3553
3554 osc_to_ost()
3555 {
3556     osc=$1
3557     ost=`echo $1 | awk -F_ '{print $3}'`
3558     if [ -z $ost ]; then
3559         ost=`echo $1 | sed 's/-osc.*//'`
3560     fi
3561     echo $ost
3562 }
3563
3564 ostuuid_from_index()
3565 {
3566     $LFS osts $2 | sed -ne "/^$1: /s/.* \(.*\) .*$/\1/p"
3567 }
3568
3569 ostname_from_index() {
3570     local uuid=$(ostuuid_from_index $1)
3571     echo ${uuid/_UUID/}
3572 }
3573
3574 index_from_ostuuid()
3575 {
3576     $LFS osts $2 | sed -ne "/${1}/s/\(.*\): .* .*$/\1/p"
3577 }
3578
3579 remote_node () {
3580     local node=$1
3581     [ "$node" != "$(hostname)" ]
3582 }
3583
3584 remote_mds ()
3585 {
3586     local node
3587     for node in $(mdts_nodes); do
3588         remote_node $node && return 0
3589     done
3590     return 1
3591 }
3592
3593 remote_mds_nodsh()
3594 {
3595     [ "$CLIENTONLY" ] && return 0 || true
3596     remote_mds && [ "$PDSH" = "no_dsh" -o -z "$PDSH" -o -z "$mds_HOST" ]
3597 }
3598
3599 require_dsh_mds()
3600 {
3601         remote_mds_nodsh && echo "SKIP: $TESTSUITE: remote MDS with nodsh" && \
3602             MSKIPPED=1 && return 1
3603         return 0
3604 }
3605
3606 remote_ost ()
3607 {
3608     local node
3609     for node in $(osts_nodes) ; do
3610         remote_node $node && return 0
3611     done
3612     return 1
3613 }
3614
3615 remote_ost_nodsh()
3616 {
3617     [ "$CLIENTONLY" ] && return 0 || true 
3618     remote_ost && [ "$PDSH" = "no_dsh" -o -z "$PDSH" -o -z "$ost_HOST" ]
3619 }
3620
3621 require_dsh_ost()
3622 {
3623         remote_ost_nodsh && echo "SKIP: $TESTSUITE: remote OST with nodsh" && \
3624             OSKIPPED=1 && return 1
3625         return 0
3626 }
3627
3628 remote_mgs_nodsh()
3629 {
3630     local MGS 
3631     MGS=$(facet_host mgs)
3632     remote_node $MGS && [ "$PDSH" = "no_dsh" -o -z "$PDSH" -o -z "$ost_HOST" ]
3633 }
3634
3635 local_mode ()
3636 {
3637     remote_mds_nodsh || remote_ost_nodsh || \
3638         $(single_local_node $(comma_list $(nodes_list)))
3639 }
3640
3641 mdts_nodes () {
3642     local MDSNODES
3643     local NODES_sort
3644     for num in `seq $MDSCOUNT`; do
3645         MDSNODES="$MDSNODES $(facet_host mds$num)"
3646     done
3647     NODES_sort=$(for i in $MDSNODES; do echo $i; done | sort -u)
3648
3649     echo $NODES_sort
3650 }
3651
3652 remote_servers () {
3653     remote_ost && remote_mds
3654 }
3655
3656 facets_nodes () {
3657     local facets=$1
3658     local nodes
3659     local NODES_sort
3660
3661     for facet in ${facets//,/ }; do
3662         if [ "$FAILURE_MODE" = HARD ]; then
3663             nodes="$nodes $(facet_active_host $facet)"
3664         else
3665             nodes="$nodes $(facet_host $facet)"
3666         fi
3667     done
3668     NODES_sort=$(for i in $nodes; do echo $i; done | sort -u)
3669
3670     echo $NODES_sort
3671 }
3672
3673 osts_nodes () {
3674     local facets=$(get_facets OST)
3675     local nodes=$(facets_nodes $facets)
3676
3677     echo $nodes
3678 }
3679
3680 nodes_list () {
3681     # FIXME. We need a list of clients
3682     local myNODES=$HOSTNAME
3683     local myNODES_sort
3684
3685     # CLIENTS (if specified) contains the local client
3686     [ -n "$CLIENTS" ] && myNODES=${CLIENTS//,/ }
3687
3688     if [ "$PDSH" -a "$PDSH" != "no_dsh" ]; then
3689         myNODES="$myNODES $(facets_nodes $(get_facets))"
3690     fi
3691
3692     myNODES_sort=$(for i in $myNODES; do echo $i; done | sort -u)
3693
3694     echo $myNODES_sort
3695 }
3696
3697 remote_nodes_list () {
3698     local rnodes=$(nodes_list)
3699     rnodes=$(echo " $rnodes " | sed -re "s/\s+$HOSTNAME\s+/ /g")
3700     echo $rnodes
3701 }
3702
3703 init_clients_lists () {
3704     # Sanity check: exclude the local client from RCLIENTS
3705     local rclients=$(echo " $RCLIENTS " | sed -re "s/\s+$HOSTNAME\s+/ /g")
3706
3707     # Sanity check: exclude the dup entries
3708     rclients=$(for i in $rclients; do echo $i; done | sort -u)
3709
3710     local clients="$SINGLECLIENT $HOSTNAME $rclients"
3711
3712     # Sanity check: exclude the dup entries from CLIENTS
3713     # for those configs which has SINGLCLIENT set to local client
3714     clients=$(for i in $clients; do echo $i; done | sort -u)
3715
3716     CLIENTS=`comma_list $clients`
3717     local -a remoteclients=($rclients)
3718     for ((i=0; $i<${#remoteclients[@]}; i++)); do
3719             varname=CLIENT$((i + 2))
3720             eval $varname=${remoteclients[i]}
3721     done
3722
3723     CLIENTCOUNT=$((${#remoteclients[@]} + 1))
3724 }
3725
3726 get_random_entry () {
3727     local rnodes=$1
3728
3729     rnodes=${rnodes//,/ }
3730
3731     local -a nodes=($rnodes)
3732     local num=${#nodes[@]} 
3733     local i=$((RANDOM * num * 2 / 65536))
3734
3735     echo ${nodes[i]}
3736 }
3737
3738 client_only () {
3739     [ "$CLIENTONLY" ] || [ "$CLIENTMODSONLY" = yes ]
3740 }
3741
3742 is_patchless ()
3743 {
3744     lctl get_param version | grep -q patchless
3745 }
3746
3747 check_versions() {
3748     [ "$(lustre_version_code client)" = "$(lustre_version_code $SINGLEMDS)" -a \
3749       "$(lustre_version_code client)" = "$(lustre_version_code ost1)" ]
3750 }
3751
3752 get_node_count() {
3753     local nodes="$@"
3754     echo $nodes | wc -w || true
3755 }
3756
3757 mixed_ost_devs () {
3758     local nodes=$(osts_nodes)
3759     local osscount=$(get_node_count "$nodes")
3760     [ ! "$OSTCOUNT" = "$osscount" ]
3761 }
3762
3763 mixed_mdt_devs () {
3764     local nodes=$(mdts_nodes)
3765     local mdtcount=$(get_node_count "$nodes")
3766     [ ! "$MDSCOUNT" = "$mdtcount" ]
3767 }
3768
3769 generate_machine_file() {
3770     local nodes=${1//,/ }
3771     local machinefile=$2
3772     rm -f $machinefile
3773     for node in $nodes; do
3774         echo $node >>$machinefile || \
3775             { echo "can not generate machinefile $machinefile" && return 1; }
3776     done
3777 }
3778
3779 get_stripe () {
3780     local file=$1/stripe
3781     touch $file
3782     $LFS getstripe -v $file || error
3783     rm -f $file
3784 }
3785
3786 setstripe_nfsserver () {
3787     local dir=$1
3788
3789     local nfsserver=$(awk '"'$dir'" ~ $2 && $3 ~ "nfs" && $2 != "/" \
3790                 { print $1 }' /proc/mounts | cut -f 1 -d : | head -1)
3791
3792     [ -z $nfsserver ] && echo "$dir is not nfs mounted" && return 1
3793
3794     do_nodev $nfsserver lfs setstripe "$@"
3795 }
3796
3797 # Check and add a test group.
3798 add_group() {
3799         local group_id=$1
3800         local group_name=$2
3801         local rc=0
3802
3803         local gid=$(getent group $group_name | cut -d: -f3)
3804         if [[ -n "$gid" ]]; then
3805                 [[ "$gid" -eq "$group_id" ]] || {
3806                         error_noexit "inconsistent group ID:" \
3807                                      "new: $group_id, old: $gid"
3808                         rc=1
3809                 }
3810         else
3811                 groupadd -g $group_id $group_name
3812                 rc=${PIPESTATUS[0]}
3813         fi
3814
3815         return $rc
3816 }
3817
3818 # Check and add a test user.
3819 add_user() {
3820         local user_id=$1
3821         shift
3822         local user_name=$1
3823         shift
3824         local group_name=$1
3825         shift
3826         local home=$1
3827         shift
3828         local opts="$@"
3829         local rc=0
3830
3831         local uid=$(getent passwd $user_name | cut -d: -f3)
3832         if [[ -n "$uid" ]]; then
3833                 if [[ "$uid" -eq "$user_id" ]]; then
3834                         local dir=$(getent passwd $user_name | cut -d: -f6)
3835                         if [[ "$dir" != "$home" ]]; then
3836                                 mkdir -p $home
3837                                 usermod -d $home $user_name
3838                                 rc=${PIPESTATUS[0]}
3839                         fi
3840                 else
3841                         error_noexit "inconsistent user ID:" \
3842                                      "new: $user_id, old: $uid"
3843                         rc=1
3844                 fi
3845         else
3846                 mkdir -p $home
3847                 useradd -M -u $user_id -d $home -g $group_name $opts $user_name
3848                 rc=${PIPESTATUS[0]}
3849         fi
3850
3851         return $rc
3852 }
3853
3854 check_runas_id_ret() {
3855     local myRC=0
3856     local myRUNAS_UID=$1
3857     local myRUNAS_GID=$2
3858     shift 2
3859     local myRUNAS=$@
3860     if [ -z "$myRUNAS" ]; then
3861         error_exit "myRUNAS command must be specified for check_runas_id"
3862     fi
3863     if $GSS_KRB5; then
3864         $myRUNAS krb5_login.sh || \
3865             error "Failed to refresh Kerberos V5 TGT for UID $myRUNAS_ID."
3866     fi
3867     mkdir $DIR/d0_runas_test
3868     chmod 0755 $DIR
3869     chown $myRUNAS_UID:$myRUNAS_GID $DIR/d0_runas_test
3870     $myRUNAS touch $DIR/d0_runas_test/f$$ || myRC=$?
3871     rm -rf $DIR/d0_runas_test
3872     return $myRC
3873 }
3874
3875 check_runas_id() {
3876     local myRUNAS_UID=$1
3877     local myRUNAS_GID=$2
3878     shift 2
3879     local myRUNAS=$@
3880     check_runas_id_ret $myRUNAS_UID $myRUNAS_GID $myRUNAS || \
3881         error "unable to write to $DIR/d0_runas_test as UID $myRUNAS_UID.
3882         Please set RUNAS_ID to some UID which exists on MDS and client or
3883         add user $myRUNAS_UID:$myRUNAS_GID on these nodes."
3884 }
3885
3886 # obtain the UID/GID for MPI_USER
3887 get_mpiuser_id() {
3888     local mpi_user=$1
3889
3890     MPI_USER_UID=$(do_facet client "getent passwd $mpi_user | cut -d: -f3;
3891 exit \\\${PIPESTATUS[0]}") || error_exit "failed to get the UID for $mpi_user"
3892
3893     MPI_USER_GID=$(do_facet client "getent passwd $mpi_user | cut -d: -f4;
3894 exit \\\${PIPESTATUS[0]}") || error_exit "failed to get the GID for $mpi_user"
3895 }
3896
3897 # obtain and cache Kerberos ticket-granting ticket
3898 refresh_krb5_tgt() {
3899     local myRUNAS_UID=$1
3900     local myRUNAS_GID=$2
3901     shift 2
3902     local myRUNAS=$@
3903     if [ -z "$myRUNAS" ]; then
3904         error_exit "myRUNAS command must be specified for refresh_krb5_tgt"
3905     fi
3906
3907     CLIENTS=${CLIENTS:-$HOSTNAME}
3908     do_nodes $CLIENTS "set -x
3909 if ! $myRUNAS krb5_login.sh; then
3910     echo "Failed to refresh Krb5 TGT for UID/GID $myRUNAS_UID/$myRUNAS_GID."
3911     exit 1
3912 fi"
3913 }
3914
3915 # Run multiop in the background, but wait for it to print
3916 # "PAUSING" to its stdout before returning from this function.
3917 multiop_bg_pause() {
3918     MULTIOP_PROG=${MULTIOP_PROG:-multiop}
3919     FILE=$1
3920     ARGS=$2
3921
3922     TMPPIPE=/tmp/multiop_open_wait_pipe.$$
3923     mkfifo $TMPPIPE
3924
3925     echo "$MULTIOP_PROG $FILE v$ARGS"
3926     $MULTIOP_PROG $FILE v$ARGS > $TMPPIPE &
3927
3928     echo "TMPPIPE=${TMPPIPE}"
3929     read -t 60 multiop_output < $TMPPIPE
3930     if [ $? -ne 0 ]; then
3931         rm -f $TMPPIPE
3932         return 1
3933     fi
3934     rm -f $TMPPIPE
3935     if [ "$multiop_output" != "PAUSING" ]; then
3936         echo "Incorrect multiop output: $multiop_output"
3937         kill -9 $PID
3938         return 1
3939     fi
3940
3941     return 0
3942 }
3943
3944 do_and_time () {
3945     local cmd=$1
3946     local rc
3947
3948     SECONDS=0
3949     eval '$cmd'
3950     
3951     [ ${PIPESTATUS[0]} -eq 0 ] || rc=1
3952
3953     echo $SECONDS
3954     return $rc
3955 }
3956
3957 inodes_available () {
3958     local IFree=$($LFS df -i $MOUNT | grep ^$FSNAME | awk '{print $4}' | sort -un | head -1) || return 1
3959     echo $IFree
3960 }
3961
3962 mdsrate_inodes_available () {
3963     local min_inodes=$(inodes_available)
3964     echo $((min_inodes * 99 / 100))
3965 }
3966
3967 # reset llite stat counters
3968 clear_llite_stats(){
3969         lctl set_param -n llite.*.stats 0
3970 }
3971
3972 # sum llite stat items
3973 calc_llite_stats() {
3974         local res=$(lctl get_param -n llite.*.stats |
3975                     awk 'BEGIN {s = 0} END {print s} /^'"$1"'/ {s += $2}')
3976         echo $res
3977 }
3978
3979 # reset osc stat counters
3980 clear_osc_stats(){
3981         lctl set_param -n osc.*.osc_stats 0
3982 }
3983
3984 # sum osc stat items
3985 calc_osc_stats() {
3986         local res=$(lctl get_param -n osc.*.osc_stats |
3987                     awk 'BEGIN {s = 0} END {print s} /^'"$1"'/ {s += $2}')
3988         echo $res
3989 }
3990
3991 calc_sum () {
3992         awk 'BEGIN {s = 0}; {s += $1}; END {print s}'
3993 }
3994
3995 calc_osc_kbytes () {
3996         df $MOUNT > /dev/null
3997         $LCTL get_param -n osc.*[oO][sS][cC][-_][0-9a-f]*.$1 | calc_sum
3998 }
3999
4000 # save_lustre_params(node, parameter_mask)
4001 # generate a stream of formatted strings (<node> <param name>=<param value>)
4002 save_lustre_params() {
4003         local s
4004         do_nodesv $1 "lctl get_param $2 | while read s; do echo \\\$s; done"
4005 }
4006
4007 # restore lustre parameters from input stream, produces by save_lustre_params
4008 restore_lustre_params() {
4009         local node
4010         local name
4011         local val
4012         while IFS=" =" read node name val; do
4013                 do_node ${node//:/} "lctl set_param -n $name $val"
4014         done
4015 }
4016
4017 check_catastrophe() {
4018     local rnodes=${1:-$(comma_list $(remote_nodes_list))}
4019     local C=$CATASTROPHE
4020     [ -f $C ] && [ $(cat $C) -ne 0 ] && return 1
4021
4022     if [ $rnodes ]; then
4023         do_nodes $rnodes "rc=\\\$([ -f $C ] && echo \\\$(< $C) || echo 0);
4024 if [ \\\$rc -ne 0 ]; then echo \\\$(hostname): \\\$rc; fi
4025 exit \\\$rc;"
4026     fi 
4027 }
4028
4029 # $1 node
4030 # $2 file
4031 # $3 $RUNAS
4032 get_stripe_info() {
4033         local tmp_file
4034
4035         stripe_size=0
4036         stripe_count=0
4037         stripe_index=0
4038         tmp_file=$(mktemp)
4039
4040         do_facet $1 $3 lfs getstripe -v $2 > $tmp_file
4041
4042         stripe_size=`awk '$1 ~ /size/ {print $2}' $tmp_file`
4043         stripe_count=`awk '$1 ~ /count/ {print $2}' $tmp_file`
4044         stripe_index=`awk '$1 ~ /stripe_offset/ {print $2}' $tmp_file`
4045         rm -f $tmp_file
4046 }
4047
4048 # CMD: determine mds index where directory inode presents
4049 get_mds_dir () {
4050     local dir=$1
4051     local file=$dir/f0.get_mds_dir_tmpfile
4052
4053     mkdir -p $dir
4054     rm -f $file
4055     sleep 1
4056     local iused=$(lfs df -i $dir | grep MDT | awk '{print $3}')
4057     local -a oldused=($iused)
4058
4059     openfile -f O_CREAT:O_LOV_DELAY_CREATE -m 0644 $file > /dev/null
4060     sleep 1
4061     iused=$(lfs df -i $dir | grep MDT | awk '{print $3}')
4062     local -a newused=($iused)
4063
4064     local num=0
4065     for ((i=0; i<${#newused[@]}; i++)); do
4066          if [ ${oldused[$i]} -lt ${newused[$i]} ];  then
4067              echo $(( i + 1 ))
4068              rm -f $file
4069              return 0
4070          fi
4071     done
4072     error "mdt-s : inodes count OLD ${oldused[@]} NEW ${newused[@]}"
4073 }
4074
4075 mdsrate_cleanup () {
4076     if [ -d $4 ]; then
4077         mpi_run -np $1 -machinefile $2 ${MDSRATE} --unlink --nfiles $3 --dir $4 --filefmt $5 $6
4078         rmdir $4
4079     fi
4080 }
4081
4082 delayed_recovery_enabled () {
4083     local var=${SINGLEMDS}_svc
4084     do_facet $SINGLEMDS lctl get_param -n mdd.${!var}.stale_export_age > /dev/null 2>&1
4085 }
4086
4087 ########################
4088
4089 convert_facet2label() { 
4090     local facet=$1
4091
4092     if [ x$facet = xost ]; then
4093        facet=ost1
4094     fi
4095
4096     local varsvc=${facet}_svc
4097
4098     if [ -n ${!varsvc} ]; then
4099         echo ${!varsvc}
4100     else  
4101         error "No lablel for $facet!"
4102     fi
4103 }
4104
4105 get_clientosc_proc_path() {
4106     local ost=$1
4107
4108     # exclude -osc-M*
4109     echo "${1}-osc-[!M]*"
4110 }
4111
4112 # If the 2.0 MDS was mounted on 1.8 device, then the OSC and LOV names
4113 # used by MDT would not be changed.
4114 # mdt lov: fsname-mdtlov
4115 # mdt osc: fsname-OSTXXXX-osc
4116 mds_on_old_device() {
4117     local mds=${1:-"$SINGLEMDS"}
4118
4119     if [ $(lustre_version_code $mds) -gt $(version_code 1.9.0) ]; then
4120         do_facet $mds "lctl list_param osc.$FSNAME-OST*-osc \
4121             > /dev/null 2>&1" && return 0
4122     fi
4123     return 1
4124 }
4125
4126 get_mdtosc_proc_path() {
4127     local mds_facet=$1
4128     local ost_label=${2:-"*OST*"}
4129
4130     [ "$mds_facet" = "mds" ] && mds_facet=$SINGLEMDS
4131     local mdt_label=$(convert_facet2label $mds_facet)
4132     local mdt_index=$(echo $mdt_label | sed -e 's/^.*-//')
4133
4134     if [ $(lustre_version_code $mds_facet) -le $(version_code 1.8.0) ] ||
4135        mds_on_old_device $mds_facet; then
4136         echo "${ost_label}-osc"
4137     else
4138         echo "${ost_label}-osc-${mdt_index}"
4139     fi
4140 }
4141
4142 get_osc_import_name() {
4143     local facet=$1
4144     local ost=$2
4145     local label=$(convert_facet2label $ost)
4146
4147     if [ "${facet:0:3}" = "mds" ]; then
4148         get_mdtosc_proc_path $facet $label
4149         return 0
4150     fi
4151
4152     get_clientosc_proc_path $label
4153     return 0
4154 }
4155
4156 _wait_import_state () {
4157     local expected=$1
4158     local CONN_PROC=$2
4159     local maxtime=${3:-$(max_recovery_time)}
4160     local CONN_STATE
4161     local i=0
4162
4163     CONN_STATE=$($LCTL get_param -n $CONN_PROC 2>/dev/null | cut -f2)
4164     while [ "${CONN_STATE}" != "${expected}" ]; do
4165         if [ "${expected}" == "DISCONN" ]; then
4166             # for disconn we can check after proc entry is removed
4167             [ "x${CONN_STATE}" == "x" ] && return 0
4168             #  with AT enabled, we can have connect request timeout near of
4169             # reconnect timeout and test can't see real disconnect
4170             [ "${CONN_STATE}" == "CONNECTING" ] && return 0
4171         fi
4172         [ $i -ge $maxtime ] && \
4173             error "can't put import for $CONN_PROC into ${expected} state after $i sec, have ${CONN_STATE}" && \
4174             return 1
4175         sleep 1
4176         CONN_STATE=$($LCTL get_param -n $CONN_PROC 2>/dev/null | cut -f2)
4177         i=$(($i + 1))
4178     done
4179
4180     log "$CONN_PROC in ${CONN_STATE} state after $i sec"
4181     return 0
4182 }
4183
4184 wait_import_state() {
4185     local state=$1
4186     local params=$2
4187     local maxtime=${3:-$(max_recovery_time)}
4188     local param
4189
4190     for param in ${params//,/ }; do
4191         _wait_import_state $state $param $maxtime || return
4192     done
4193 }
4194
4195 # One client request could be timed out because server was not ready
4196 # when request was sent by client.
4197 # The request timeout calculation details :
4198 # ptl_send_rpc ()
4199 #      /* We give the server rq_timeout secs to process the req, and
4200 #      add the network latency for our local timeout. */
4201 #      request->rq_deadline = request->rq_sent + request->rq_timeout +
4202 #           ptlrpc_at_get_net_latency(request) ;
4203 #
4204 # ptlrpc_connect_import ()
4205 #      request->rq_timeout = INITIAL_CONNECT_TIMEOUT
4206 #
4207 # init_imp_at () ->
4208 #   -> at_init(&at->iat_net_latency, 0, 0) -> iat_net_latency=0
4209 # ptlrpc_at_get_net_latency(request) ->
4210 #       at_get (max (iat_net_latency=0, at_min)) = at_min
4211 #
4212 # i.e.:
4213 # request->rq_timeout + ptlrpc_at_get_net_latency(request) =
4214 # INITIAL_CONNECT_TIMEOUT + at_min
4215 #
4216 # We will use obd_timeout instead of INITIAL_CONNECT_TIMEOUT
4217 # because we can not get this value in runtime,
4218 # the value depends on configure options, and it is not stored in /proc.
4219 # obd_support.h:
4220 # #define CONNECTION_SWITCH_MIN 5U
4221 # #ifndef CRAY_XT3
4222 # #define INITIAL_CONNECT_TIMEOUT max(CONNECTION_SWITCH_MIN,obd_timeout/20)
4223 # #else
4224 # #define INITIAL_CONNECT_TIMEOUT max(CONNECTION_SWITCH_MIN,obd_timeout/2)
4225
4226 request_timeout () {
4227     local facet=$1
4228
4229     # request->rq_timeout = INITIAL_CONNECT_TIMEOUT
4230     local init_connect_timeout=$TIMEOUT
4231     [[ $init_connect_timeout -ge 5 ]] || init_connect_timeout=5
4232
4233     local at_min=$(at_get $facet at_min)
4234
4235     echo $((init_connect_timeout + at_min))
4236 }
4237
4238 wait_osc_import_state() {
4239     local facet=$1
4240     local ost_facet=$2
4241     local expected=$3
4242     local ost=$(get_osc_import_name $facet $ost_facet)
4243
4244     local param="osc.${ost}.ost_server_uuid"
4245
4246     # 1. wait the deadline of client 1st request (it could be skipped)
4247     # 2. wait the deadline of client 2nd request
4248     local maxtime=$(( 2 * $(request_timeout $facet)))
4249
4250     if ! do_rpc_nodes $(facet_host $facet) \
4251         _wait_import_state $expected $param $maxtime; then
4252             error "import is not in ${expected} state"
4253             return 1
4254     fi
4255
4256     return 0
4257 }
4258
4259 get_clientmdc_proc_path() {
4260     echo "${1}-mdc-*"
4261 }
4262
4263 do_rpc_nodes () {
4264     local list=$1
4265     shift
4266
4267     # Add paths to lustre tests for 32 and 64 bit systems.
4268     local RPATH="PATH=$RLUSTRE/tests:/usr/lib/lustre/tests:/usr/lib64/lustre/tests:$PATH"
4269     do_nodesv $list "${RPATH} NAME=${NAME} sh rpc.sh $@ "
4270 }
4271
4272 wait_clients_import_state () {
4273     local list=$1
4274     local facet=$2
4275     local expected=$3
4276
4277     local facets=$facet
4278
4279     if [ "$FAILURE_MODE" = HARD ]; then
4280         facets=$(facets_on_host $(facet_active_host $facet))
4281     fi
4282
4283     for facet in ${facets//,/ }; do
4284     local label=$(convert_facet2label $facet)
4285     local proc_path
4286     case $facet in
4287         ost* ) proc_path="osc.$(get_clientosc_proc_path $label).ost_server_uuid" ;;
4288         mds* ) proc_path="mdc.$(get_clientmdc_proc_path $label).mds_server_uuid" ;;
4289         *) error "unknown facet!" ;;
4290     esac
4291     local params=$(expand_list $params $proc_path)
4292     done
4293
4294     if ! do_rpc_nodes $list wait_import_state $expected $params; then
4295         error "import is not in ${expected} state"
4296         return 1
4297     fi
4298 }
4299
4300 oos_full() {
4301         local -a AVAILA
4302         local -a GRANTA
4303         local OSCFULL=1
4304         AVAILA=($(do_nodes $(comma_list $(osts_nodes)) \
4305                   $LCTL get_param obdfilter.*.kbytesavail))
4306         GRANTA=($(do_nodes $(comma_list $(osts_nodes)) \
4307                   $LCTL get_param -n obdfilter.*.tot_granted))
4308         for ((i=0; i<${#AVAILA[@]}; i++)); do
4309                 local -a AVAIL1=(${AVAILA[$i]//=/ })
4310                 GRANT=$((${GRANTA[$i]}/1024))
4311                 echo -n $(echo ${AVAIL1[0]} | cut -d"." -f2) avl=${AVAIL1[1]} grnt=$GRANT diff=$((AVAIL1[1] - GRANT))
4312                 [ $((AVAIL1[1] - GRANT)) -lt 400 ] && OSCFULL=0 && echo " FULL" || echo
4313         done
4314         return $OSCFULL
4315 }
4316
4317 pool_list () {
4318    do_facet mgs lctl pool_list $1
4319 }
4320
4321 create_pool() {
4322     local fsname=${1%%.*}
4323     local poolname=${1##$fsname.}
4324
4325     do_facet mgs lctl pool_new $1
4326     local RC=$?
4327     # get param should return err unless pool is created
4328     [[ $RC -ne 0 ]] && return $RC
4329
4330     wait_update $HOSTNAME "lctl get_param -n lov.$fsname-*.pools.$poolname \
4331         2>/dev/null || echo foo" "" || RC=1
4332     if [[ $RC -eq 0 ]]; then
4333         add_pool_to_list $1
4334     else
4335         error "pool_new failed $1"
4336     fi
4337     return $RC
4338 }
4339
4340 add_pool_to_list () {
4341     local fsname=${1%%.*}
4342     local poolname=${1##$fsname.}
4343
4344     local listvar=${fsname}_CREATED_POOLS
4345     eval export ${listvar}=$(expand_list ${!listvar} $poolname)
4346 }
4347
4348 remove_pool_from_list () {
4349     local fsname=${1%%.*}
4350     local poolname=${1##$fsname.}
4351
4352     local listvar=${fsname}_CREATED_POOLS
4353     eval export ${listvar}=$(exclude_items_from_list ${!listvar} $poolname)
4354 }
4355
4356 destroy_pool_int() {
4357     local ost
4358     local OSTS=$(do_facet $SINGLEMDS lctl pool_list $1 | \
4359         awk '$1 !~ /^Pool:/ {print $1}')
4360     for ost in $OSTS; do
4361         do_facet mgs lctl pool_remove $1 $ost
4362     done
4363     do_facet mgs lctl pool_destroy $1
4364 }
4365
4366 # <fsname>.<poolname> or <poolname>
4367 destroy_pool() {
4368     local fsname=${1%%.*}
4369     local poolname=${1##$fsname.}
4370
4371     [[ x$fsname = x$poolname ]] && fsname=$FSNAME
4372
4373     local RC
4374
4375     pool_list $fsname.$poolname || return $?
4376
4377     destroy_pool_int $fsname.$poolname
4378     RC=$?
4379     [[ $RC -ne 0 ]] && return $RC
4380
4381     wait_update $HOSTNAME "lctl get_param -n lov.$fsname-*.pools.$poolname \
4382       2>/dev/null || echo foo" "foo" || RC=1
4383
4384     if [[ $RC -eq 0 ]]; then
4385         remove_pool_from_list $fsname.$poolname
4386     else
4387         error "destroy pool failed $1"
4388     fi
4389     return $RC
4390 }
4391
4392 destroy_pools () {
4393     local fsname=${1:-$FSNAME}
4394     local poolname
4395     local listvar=${fsname}_CREATED_POOLS
4396
4397     pool_list $fsname
4398
4399     [ x${!listvar} = x ] && return 0
4400
4401     echo destroy the created pools: ${!listvar}
4402     for poolname in ${!listvar//,/ }; do
4403         destroy_pool $fsname.$poolname
4404     done
4405 }
4406
4407 cleanup_pools () {
4408     local fsname=${1:-$FSNAME}
4409     trap 0
4410     destroy_pools $fsname
4411 }
4412
4413 gather_logs () {
4414     local list=$1
4415
4416     local ts=$(date +%s)
4417     local docp=true
4418
4419     if [[ ! -f "$YAML_LOG" ]]; then
4420         # init_logging is not performed before gather_logs,
4421         # so the $LOGDIR needs to be checked here
4422         check_shared_dir $LOGDIR && touch $LOGDIR/shared
4423     fi
4424
4425     [ -f $LOGDIR/shared ] && docp=false
4426
4427     # dump lustre logs, dmesg
4428
4429     prefix="$LOGDIR/${TESTSUITE}.${TESTNAME}"
4430     suffix="$ts.log"
4431     echo "Dumping lctl log to ${prefix}.*.${suffix}"
4432
4433     if [ "$CLIENTONLY" -o "$PDSH" == "no_dsh" ]; then
4434         echo "Dumping logs only on local client."
4435         $LCTL dk > ${prefix}.debug_log.$(hostname -s).${suffix}
4436         dmesg > ${prefix}.dmesg.$(hostname -s).${suffix}
4437         return
4438     fi
4439
4440     do_nodesv $list \
4441         "$LCTL dk > ${prefix}.debug_log.\\\$(hostname -s).${suffix};
4442          dmesg > ${prefix}.dmesg.\\\$(hostname -s).${suffix}"
4443     if $docp; then
4444         do_nodes $list rsync -az "${prefix}.*.${suffix}" $HOSTNAME:$LOGDIR
4445     fi
4446 }
4447
4448 do_ls () {
4449     local mntpt_root=$1
4450     local num_mntpts=$2
4451     local dir=$3
4452     local i
4453     local cmd
4454     local pids
4455     local rc=0
4456
4457     for i in $(seq 0 $num_mntpts); do
4458         cmd="ls -laf ${mntpt_root}$i/$dir"
4459         echo + $cmd;
4460         $cmd > /dev/null &
4461         pids="$pids $!"
4462     done
4463     echo pids=$pids
4464     for pid in $pids; do
4465         wait $pid || rc=$?
4466     done
4467
4468     return $rc
4469 }
4470
4471 # target_start_and_reset_recovery_timer()
4472 #        service_time = at_est2timeout(service_time);
4473 #        service_time += 2 * (CONNECTION_SWITCH_MAX + CONNECTION_SWITCH_INC +
4474 #                             INITIAL_CONNECT_TIMEOUT);
4475 # CONNECTION_SWITCH_MAX : min(25U, max(CONNECTION_SWITCH_MIN,obd_timeout))
4476 #define CONNECTION_SWITCH_INC 1
4477 #define INITIAL_CONNECT_TIMEOUT max(CONNECTION_SWITCH_MIN,obd_timeout/20)
4478 #define CONNECTION_SWITCH_MIN 5U
4479
4480 max_recovery_time () {
4481     local init_connect_timeout=$((TIMEOUT / 20))
4482     [[ $init_connect_timeout -ge 5 ]] || init_connect_timeout=5
4483
4484     local service_time=$(($(at_max_get client) +
4485                           $((2 * $((25 + 1 + init_connect_timeout))))))
4486
4487     echo $service_time
4488 }
4489
4490 get_clients_mount_count () {
4491     local clients=${CLIENTS:-`hostname`}
4492
4493     # we need to take into account the clients mounts and
4494     # exclude mds/ost mounts if any;
4495     do_nodes $clients cat /proc/mounts | grep lustre | grep $MOUNT | wc -l
4496 }
4497
4498 # gss functions
4499 PROC_CLI="srpc_info"
4500
4501 combination()
4502 {
4503     local M=$1
4504     local N=$2
4505     local R=1
4506
4507     if [ $M -lt $N ]; then
4508         R=0
4509     else
4510         N=$((N + 1))
4511         while [ $N -lt $M ]; do
4512             R=$((R * N))
4513             N=$((N + 1))
4514         done
4515     fi
4516
4517     echo $R
4518     return 0
4519 }
4520
4521 calc_connection_cnt() {
4522     local dir=$1
4523
4524     # MDT->MDT = 2 * C(M, 2)
4525     # MDT->OST = M * O
4526     # CLI->OST = C * O
4527     # CLI->MDT = C * M
4528     comb_m2=$(combination $MDSCOUNT 2)
4529
4530     local num_clients=$(get_clients_mount_count)
4531
4532     local cnt_mdt2mdt=$((comb_m2 * 2))
4533     local cnt_mdt2ost=$((MDSCOUNT * OSTCOUNT))
4534     local cnt_cli2ost=$((num_clients * OSTCOUNT))
4535     local cnt_cli2mdt=$((num_clients * MDSCOUNT))
4536     local cnt_all2ost=$((cnt_mdt2ost + cnt_cli2ost))
4537     local cnt_all2mdt=$((cnt_mdt2mdt + cnt_cli2mdt))
4538     local cnt_all2all=$((cnt_mdt2ost + cnt_mdt2mdt + cnt_cli2ost + cnt_cli2mdt))
4539
4540     local var=cnt_$dir
4541     local res=${!var}
4542
4543     echo $res
4544 }
4545
4546 set_rule()
4547 {
4548     local tgt=$1
4549     local net=$2
4550     local dir=$3
4551     local flavor=$4
4552     local cmd="$tgt.srpc.flavor"
4553
4554     if [ $net == "any" ]; then
4555         net="default"
4556     fi
4557     cmd="$cmd.$net"
4558
4559     if [ $dir != "any" ]; then
4560         cmd="$cmd.$dir"
4561     fi
4562
4563     cmd="$cmd=$flavor"
4564     log "Setting sptlrpc rule: $cmd"
4565     do_facet mgs "$LCTL conf_param $cmd"
4566 }
4567
4568 count_flvr()
4569 {
4570     local output=$1
4571     local flavor=$2
4572     local count=0
4573
4574     rpc_flvr=`echo $flavor | awk -F - '{ print $1 }'`
4575     bulkspec=`echo $flavor | awk -F - '{ print $2 }'`
4576
4577     count=`echo "$output" | grep "rpc flavor" | grep $rpc_flvr | wc -l`
4578
4579     if [ "x$bulkspec" != "x" ]; then
4580         algs=`echo $bulkspec | awk -F : '{ print $2 }'`
4581
4582         if [ "x$algs" != "x" ]; then
4583             bulk_count=`echo "$output" | grep "bulk flavor" | grep $algs | wc -l`
4584         else
4585             bulk=`echo $bulkspec | awk -F : '{ print $1 }'`
4586             if [ $bulk == "bulkn" ]; then
4587                 bulk_count=`echo "$output" | grep "bulk flavor" \
4588                             | grep "null/null" | wc -l`
4589             elif [ $bulk == "bulki" ]; then
4590                 bulk_count=`echo "$output" | grep "bulk flavor" \
4591                             | grep "/null" | grep -v "null/" | wc -l`
4592             else
4593                 bulk_count=`echo "$output" | grep "bulk flavor" \
4594                             | grep -v "/null" | grep -v "null/" | wc -l`
4595             fi
4596         fi
4597
4598         [ $bulk_count -lt $count ] && count=$bulk_count
4599     fi
4600
4601     echo $count
4602 }
4603
4604 flvr_cnt_cli2mdt()
4605 {
4606     local flavor=$1
4607     local cnt
4608
4609     local clients=${CLIENTS:-`hostname`}
4610
4611     for c in ${clients//,/ }; do
4612         output=`do_node $c lctl get_param -n mdc.*-MDT*-mdc-*.$PROC_CLI 2>/dev/null`
4613         tmpcnt=`count_flvr "$output" $flavor`
4614         cnt=$((cnt + tmpcnt))
4615     done
4616     echo $cnt
4617 }
4618
4619 flvr_cnt_cli2ost()
4620 {
4621     local flavor=$1
4622     local cnt
4623
4624     local clients=${CLIENTS:-`hostname`}
4625
4626     for c in ${clients//,/ }; do
4627         output=`do_node $c lctl get_param -n osc.*OST*-osc-[^M][^D][^T]*.$PROC_CLI 2>/dev/null`
4628         tmpcnt=`count_flvr "$output" $flavor`
4629         cnt=$((cnt + tmpcnt))
4630     done
4631     echo $cnt
4632 }
4633
4634 flvr_cnt_mdt2mdt()
4635 {
4636     local flavor=$1
4637     local cnt=0
4638
4639     if [ $MDSCOUNT -le 1 ]; then
4640         echo 0
4641         return
4642     fi
4643
4644     for num in `seq $MDSCOUNT`; do
4645         output=`do_facet mds$num lctl get_param -n mdc.*-MDT*-mdc[0-9]*.$PROC_CLI 2>/dev/null`
4646         tmpcnt=`count_flvr "$output" $flavor`
4647         cnt=$((cnt + tmpcnt))
4648     done
4649     echo $cnt;
4650 }
4651
4652 flvr_cnt_mdt2ost()
4653 {
4654     local flavor=$1
4655     local cnt=0
4656     local mdtosc
4657
4658     for num in `seq $MDSCOUNT`; do
4659         mdtosc=$(get_mdtosc_proc_path mds$num)
4660         mdtosc=${mdtosc/-MDT*/-MDT\*}
4661         output=$(do_facet mds$num lctl get_param -n \
4662             osc.$mdtosc.$PROC_CLI 2>/dev/null)
4663         tmpcnt=`count_flvr "$output" $flavor`
4664         cnt=$((cnt + tmpcnt))
4665     done
4666     echo $cnt;
4667 }
4668
4669 flvr_cnt_mgc2mgs()
4670 {
4671     local flavor=$1
4672
4673     output=`do_facet client lctl get_param -n mgc.*.$PROC_CLI 2>/dev/null`
4674     count_flvr "$output" $flavor
4675 }
4676
4677 do_check_flavor()
4678 {
4679     local dir=$1        # from to
4680     local flavor=$2     # flavor expected
4681     local res=0
4682
4683     if [ $dir == "cli2mdt" ]; then
4684         res=`flvr_cnt_cli2mdt $flavor`
4685     elif [ $dir == "cli2ost" ]; then
4686         res=`flvr_cnt_cli2ost $flavor`
4687     elif [ $dir == "mdt2mdt" ]; then
4688         res=`flvr_cnt_mdt2mdt $flavor`
4689     elif [ $dir == "mdt2ost" ]; then
4690         res=`flvr_cnt_mdt2ost $flavor`
4691     elif [ $dir == "all2ost" ]; then
4692         res1=`flvr_cnt_mdt2ost $flavor`
4693         res2=`flvr_cnt_cli2ost $flavor`
4694         res=$((res1 + res2))
4695     elif [ $dir == "all2mdt" ]; then
4696         res1=`flvr_cnt_mdt2mdt $flavor`
4697         res2=`flvr_cnt_cli2mdt $flavor`
4698         res=$((res1 + res2))
4699     elif [ $dir == "all2all" ]; then
4700         res1=`flvr_cnt_mdt2ost $flavor`
4701         res2=`flvr_cnt_cli2ost $flavor`
4702         res3=`flvr_cnt_mdt2mdt $flavor`
4703         res4=`flvr_cnt_cli2mdt $flavor`
4704         res=$((res1 + res2 + res3 + res4))
4705     fi
4706
4707     echo $res
4708 }
4709
4710 wait_flavor()
4711 {
4712     local dir=$1        # from to
4713     local flavor=$2     # flavor expected
4714     local expect=${3:-$(calc_connection_cnt $dir)}     # number expected
4715
4716     local res=0
4717
4718     for ((i=0;i<20;i++)); do
4719         echo -n "checking $dir..."
4720         res=$(do_check_flavor $dir $flavor)
4721         echo "found $res/$expect $flavor connections"
4722         [ $res -ge $expect ] && return 0
4723         sleep 4
4724     done
4725
4726     echo "Error checking $flavor of $dir: expect $expect, actual $res"
4727     return 1
4728 }
4729
4730 restore_to_default_flavor()
4731 {
4732     local proc="mgs.MGS.live.$FSNAME"
4733
4734     echo "restoring to default flavor..."
4735
4736     nrule=`do_facet mgs lctl get_param -n $proc 2>/dev/null | grep ".srpc.flavor." | wc -l`
4737
4738     # remove all existing rules if any
4739     if [ $nrule -ne 0 ]; then
4740         echo "$nrule existing rules"
4741         for rule in `do_facet mgs lctl get_param -n $proc 2>/dev/null | grep ".srpc.flavor."`; do
4742             echo "remove rule: $rule"
4743             spec=`echo $rule | awk -F = '{print $1}'`
4744             do_facet mgs "$LCTL conf_param -d $spec"
4745         done
4746     fi
4747
4748     # verify no rules left
4749     nrule=`do_facet mgs lctl get_param -n $proc 2>/dev/null | grep ".srpc.flavor." | wc -l`
4750     [ $nrule -ne 0 ] && error "still $nrule rules left"
4751
4752     # wait for default flavor to be applied
4753     # currently default flavor for all connections are 'null'
4754     wait_flavor all2all null
4755     echo "now at default flavor settings"
4756 }
4757
4758 set_flavor_all()
4759 {
4760     local flavor=${1:-null}
4761
4762     echo "setting all flavor to $flavor"
4763
4764     # FIXME need parameter to this fn
4765     # and remove global vars
4766     local cnt_all2all=$(calc_connection_cnt all2all)
4767
4768     local res=$(do_check_flavor all2all $flavor)
4769     if [ $res -eq $cnt_all2all ]; then
4770         echo "already have total $res $flavor connections"
4771         return
4772     fi
4773
4774     echo "found $res $flavor out of total $cnt_all2all connections"
4775     restore_to_default_flavor
4776
4777     [[ $flavor = null ]] && return 0
4778
4779     set_rule $FSNAME any any $flavor
4780     wait_flavor all2all $flavor
4781 }
4782
4783
4784 check_logdir() {
4785     local dir=$1
4786     # Checking for shared logdir
4787     if [ ! -d $dir ]; then
4788         # Not found. Create local logdir
4789         mkdir -p $dir
4790     else
4791         touch $dir/check_file.$(hostname -s)
4792     fi
4793     return 0
4794 }
4795
4796 check_write_access() {
4797     local dir=$1
4798     local node
4799     local file
4800
4801     for node in $(nodes_list); do
4802         file=$dir/check_file.$(short_hostname $node)
4803         if [[ ! -f "$file" ]]; then
4804             # Logdir not accessible/writable from this node.
4805             return 1
4806         fi
4807         rm -f $file || return 1
4808     done
4809     return 0
4810 }
4811
4812 init_logging() {
4813     if [[ -n $YAML_LOG ]]; then
4814         return
4815     fi
4816     local SAVE_UMASK=`umask`
4817     umask 0000
4818
4819     export YAML_LOG=${LOGDIR}/results.yml
4820     mkdir -p $LOGDIR
4821     init_clients_lists
4822
4823     if check_shared_dir $LOGDIR; then
4824         touch $LOGDIR/shared
4825         echo "Logging to shared log directory: $LOGDIR"
4826     else
4827         echo "Logging to local directory: $LOGDIR"
4828     fi
4829
4830     yml_nodes_file $LOGDIR >> $YAML_LOG
4831     yml_results_file >> $YAML_LOG
4832
4833     umask $SAVE_UMASK
4834 }
4835
4836 log_test() {
4837     yml_log_test $1 >> $YAML_LOG
4838 }
4839
4840 log_test_status() {
4841      yml_log_test_status $@ >> $YAML_LOG
4842 }
4843
4844 log_sub_test_begin() {
4845     yml_log_sub_test_begin "$@" >> $YAML_LOG
4846 }
4847
4848 log_sub_test_end() {
4849     yml_log_sub_test_end "$@" >> $YAML_LOG
4850 }
4851
4852 run_llverdev()
4853 {
4854         local dev=$1
4855         local llverdev_opts=$2
4856         local devname=$(basename $1)
4857         local size=$(grep "$devname"$ /proc/partitions | awk '{print $3}')
4858         # loop devices aren't in /proc/partitions
4859         [ "x$size" == "x" ] && local size=$(ls -l $dev | awk '{print $5}')
4860
4861         size=$(($size / 1024 / 1024)) # Gb
4862
4863         local partial_arg=""
4864         # Run in partial (fast) mode if the size
4865         # of a partition > 1 GB
4866         [ $size -gt 1 ] && partial_arg="-p"
4867
4868         llverdev --force $partial_arg $llverdev_opts $dev
4869 }
4870
4871 run_llverfs()
4872 {
4873         local dir=$1
4874         local llverfs_opts=$2
4875         local partial_arg=""
4876         local size=$(df -B G $dir |tail -n 1 |awk '{print $2}' |sed 's/G//') #GB
4877
4878         # Run in partial (fast) mode if the size
4879         # of a partition > 1 GB
4880         [ $size -gt 1 ] && partial_arg="-p"
4881
4882         llverfs $partial_arg $llverfs_opts $dir
4883 }
4884
4885 remove_mdt_files() {
4886     local facet=$1
4887     local mdtdev=$2
4888     shift 2
4889     local files="$@"
4890     local mntpt=${MOUNT%/*}/$facet
4891
4892     echo "removing files from $mdtdev on $facet: $files"
4893     mount -t $FSTYPE $MDS_MOUNT_OPTS $mdtdev $mntpt || return $?
4894     rc=0;
4895     for f in $files; do
4896         rm $mntpt/ROOT/$f || { rc=$?; break; }
4897     done
4898     umount -f $mntpt || return $?
4899     return $rc
4900 }
4901
4902 duplicate_mdt_files() {
4903     local facet=$1
4904     local mdtdev=$2
4905     shift 2
4906     local files="$@"
4907     local mntpt=${MOUNT%/*}/$facet
4908
4909     echo "duplicating files on $mdtdev on $facet: $files"
4910     mkdir -p $mntpt || return $?
4911     mount -t $FSTYPE $MDS_MOUNT_OPTS $mdtdev $mntpt || return $?
4912
4913     do_umount() {
4914         trap 0
4915         popd > /dev/null
4916         rm $tmp
4917         umount -f $mntpt
4918     }
4919     trap do_umount EXIT
4920
4921     tmp=$(mktemp $TMP/setfattr.XXXXXXXXXX)
4922     pushd $mntpt/ROOT > /dev/null || return $?
4923     rc=0
4924     for f in $files; do
4925         touch $f.bad || return $?
4926         getfattr -n trusted.lov $f | sed "s#$f#&.bad#" > $tmp
4927         rc=${PIPESTATUS[0]}
4928         [ $rc -eq 0 ] || return $rc
4929         setfattr --restore $tmp || return $?
4930     done
4931     do_umount
4932 }
4933
4934 run_sgpdd () {
4935     local devs=${1//,/ }
4936     shift
4937     local params=$@
4938     local rslt=$TMP/sgpdd_survey
4939
4940     # sgpdd-survey cleanups ${rslt}.* files
4941
4942     local cmd="rslt=$rslt $params scsidevs=\"$devs\" $SGPDDSURVEY"
4943     echo + $cmd
4944     eval $cmd
4945     cat ${rslt}.detail
4946 }
4947
4948 # returns the canonical name for an ldiskfs device
4949 ldiskfs_canon() {
4950         local dev="$1"
4951         local facet="$2"
4952
4953         do_facet $facet "dv=\\\$(lctl get_param -n $dev);
4954 if foo=\\\$(lvdisplay -c \\\$dv 2>/dev/null); then
4955     echo dm-\\\${foo##*:};
4956 else
4957     echo \\\$(basename \\\$dv);
4958 fi;"
4959 }
4960
4961 is_sanity_benchmark() {
4962     local benchmarks="dbench bonnie iozone fsx"
4963     local suite=$1
4964     for b in $benchmarks; do
4965         if [ "$b" == "$suite" ]; then
4966             return 0
4967         fi
4968     done
4969     return 1
4970 }
4971
4972 min_ost_size () {
4973     $LCTL get_param -n osc.*.kbytesavail | sort -n | head -n1
4974 }