Whamcloud - gitweb
LU-5499 tests: keep /sbin/mount.lustre until cleanup
[fs/lustre-release.git] / lustre / tests / test-framework.sh
1 #!/bin/bash
2
3 trap 'print_summary && touch $TF_FAIL && \
4     echo "test-framework exiting on error"' ERR
5 set -e
6 #set -x
7
8 export LANG=en_US
9 export EJOURNAL=${EJOURNAL:-""}
10 export REFORMAT=${REFORMAT:-""}
11 export WRITECONF=${WRITECONF:-""}
12 export VERBOSE=${VERBOSE:-false}
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 # specify environment variable containing batch job name for server statistics
19 export JOBID_VAR=${JOBID_VAR:-"procname_uid"}  # or "existing" or "disable"
20
21 # LOAD_LLOOP: LU-409: only load llite_lloop module if kernel < 2.6.32 or
22 #             LOAD_LLOOP is true. LOAD_LLOOP is false by default.
23 export LOAD_LLOOP=${LOAD_LLOOP:-false}
24
25 #export PDSH="pdsh -S -Rssh -w"
26 export MOUNT_CMD=${MOUNT_CMD:-"mount -t lustre"}
27
28 # function used by scripts run on remote nodes
29 LUSTRE=${LUSTRE:-$(cd $(dirname $0)/..; echo $PWD)}
30 . $LUSTRE/tests/functions.sh
31 . $LUSTRE/tests/yaml.sh
32
33 export LD_LIBRARY_PATH=${LUSTRE}/utils:${LD_LIBRARY_PATH}
34
35 LUSTRE_TESTS_CFG_DIR=${LUSTRE_TESTS_CFG_DIR:-${LUSTRE}/tests/cfg}
36
37 EXCEPT_LIST_FILE=${EXCEPT_LIST_FILE:-${LUSTRE_TESTS_CFG_DIR}/tests-to-skip.sh}
38
39 if [ -f "$EXCEPT_LIST_FILE" ]; then
40     echo "Reading test skip list from $EXCEPT_LIST_FILE"
41     cat $EXCEPT_LIST_FILE
42     . $EXCEPT_LIST_FILE
43 fi
44
45 # check config files for options in decreasing order of preference
46 [ -z "$MODPROBECONF" -a -f /etc/modprobe.d/lustre.conf ] &&
47     MODPROBECONF=/etc/modprobe.d/lustre.conf
48 [ -z "$MODPROBECONF" -a -f /etc/modprobe.d/Lustre ] &&
49     MODPROBECONF=/etc/modprobe.d/Lustre
50 [ -z "$MODPROBECONF" -a -f /etc/modprobe.conf ] &&
51     MODPROBECONF=/etc/modprobe.conf
52
53 assert_DIR () {
54     local failed=""
55     [[ $DIR/ = $MOUNT/* ]] || \
56         { failed=1 && echo "DIR=$DIR not in $MOUNT. Aborting."; }
57     [[ $DIR1/ = $MOUNT1/* ]] || \
58         { failed=1 && echo "DIR1=$DIR1 not in $MOUNT1. Aborting."; }
59     [[ $DIR2/ = $MOUNT2/* ]] || \
60         { failed=1 && echo "DIR2=$DIR2 not in $MOUNT2. Aborting"; }
61
62     [ -n "$failed" ] && exit 99 || true
63 }
64
65 usage() {
66     echo "usage: $0 [-r] [-f cfgfile]"
67     echo "       -r: reformat"
68
69     exit
70 }
71
72 print_summary () {
73     trap 0
74     [ "$TESTSUITE" == "lfsck" ] && return 0
75     [ -n "$ONLY" ] && echo "WARNING: ONLY is set to $(echo $ONLY)"
76     local details
77     local form="%-13s %-17s %-9s %s %s\n"
78     printf "$form" "status" "script" "Total(sec)" "E(xcluded) S(low)"
79     echo "------------------------------------------------------------------------------------"
80     for O in $DEFAULT_SUITES; do
81         O=$(echo $O  | tr "-" "_" | tr "[:lower:]" "[:upper:]")
82         [ "${!O}" = "no" ] && continue || true
83         local o=$(echo $O  | tr "[:upper:]_" "[:lower:]-")
84         local log=${TMP}/${o}.log
85         if is_sanity_benchmark $o; then
86             log=${TMP}/sanity-benchmark.log
87         fi
88         local slow=
89         local skipped=
90         local total=
91         local status=Unfinished
92         if [ -f $log ]; then
93                 skipped=$(grep excluded $log | awk '{ printf " %s", $3 }' |
94                         sed 's/test_//g')
95                 slow=$(egrep "^PASS|^FAIL" $log | tr -d "("| sed s/s\)$//g |
96                         sort -nr -k 3  | head -n5 |  awk '{ print $2":"$3"s" }')
97                 total=$(grep duration $log | awk '{ print $2 }')
98                 if [ "${!O}" = "done" ]; then
99                         status=Done
100                 fi
101                 if $DDETAILS; then
102                         local durations=$(egrep "^PASS|^FAIL" $log |
103                                 tr -d "("| sed s/s\)$//g |
104                                 awk '{ print $2":"$3"|" }')
105                         details=$(printf "%s\n%s %s %s\n" "$details" \
106                                 "DDETAILS" "$O" "$(echo $durations)")
107                 fi
108         fi
109         printf "$form" $status "$O" "${total}" "E=$skipped"
110         printf "$form" "-" "-" "-" "S=$(echo $slow)"
111     done
112
113     for O in $DEFAULT_SUITES; do
114         O=$(echo $O  | tr "-" "_" | tr "[:lower:]" "[:upper:]")
115         if [ "${!O}" = "no" ]; then
116             printf "$form" "Skipped" "$O" ""
117         fi
118     done
119
120     # print the detailed tests durations if DDETAILS=true
121     if $DDETAILS; then
122         echo "$details"
123     fi
124 }
125
126 init_test_env() {
127         export LUSTRE=$(absolute_path $LUSTRE)
128         export TESTSUITE=$(basename $0 .sh)
129         export TEST_FAILED=false
130         export FAIL_ON_SKIP_ENV=${FAIL_ON_SKIP_ENV:-false}
131         export RPC_MODE=${RPC_MODE:-false}
132
133     export MKE2FS=$MKE2FS
134     if [ -z "$MKE2FS" ]; then
135         if which mkfs.ldiskfs >/dev/null 2>&1; then
136             export MKE2FS=mkfs.ldiskfs
137         else
138             export MKE2FS=mke2fs
139         fi
140     fi
141
142     export DEBUGFS=$DEBUGFS
143     if [ -z "$DEBUGFS" ]; then
144         if which debugfs.ldiskfs >/dev/null 2>&1; then
145             export DEBUGFS=debugfs.ldiskfs
146         else
147             export DEBUGFS=debugfs
148         fi
149     fi
150
151     export TUNE2FS=$TUNE2FS
152     if [ -z "$TUNE2FS" ]; then
153         if which tunefs.ldiskfs >/dev/null 2>&1; then
154             export TUNE2FS=tunefs.ldiskfs
155         else
156             export TUNE2FS=tune2fs
157         fi
158     fi
159
160     export E2LABEL=$E2LABEL
161     if [ -z "$E2LABEL" ]; then
162         if which label.ldiskfs >/dev/null 2>&1; then
163             export E2LABEL=label.ldiskfs
164         else
165             export E2LABEL=e2label
166         fi
167     fi
168
169     export DUMPE2FS=$DUMPE2FS
170     if [ -z "$DUMPE2FS" ]; then
171         if which dumpfs.ldiskfs >/dev/null 2>&1; then
172             export DUMPE2FS=dumpfs.ldiskfs
173         else
174             export DUMPE2FS=dumpe2fs
175         fi
176     fi
177
178     export E2FSCK=$E2FSCK
179     if [ -z "$E2FSCK" ]; then
180         if which fsck.ldiskfs >/dev/null 2>&1; then
181             export E2FSCK=fsck.ldiskfs
182         else
183             export E2FSCK=e2fsck
184         fi
185     fi
186
187         export RESIZE2FS=$RESIZE2FS
188         if [ -z "$RESIZE2FS" ]; then
189                 if which resizefs.ldiskfs >/dev/null 2>&1; then
190                         export RESIZE2FS=resizefs.ldiskfs
191                 else
192                         export RESIZE2FS=resize2fs
193                 fi
194         fi
195
196     export LFSCK_BIN=${LFSCK_BIN:-lfsck}
197     export LFSCK_ALWAYS=${LFSCK_ALWAYS:-"no"} # check fs after each test suite
198     export FSCK_MAX_ERR=4   # File system errors left uncorrected
199
200         export ZFS=${ZFS:-zfs}
201         export ZPOOL=${ZPOOL:-zpool}
202         export ZDB=${ZDB:-zdb}
203         export PARTPROBE=${PARTPROBE:-partprobe}
204
205     #[ -d /r ] && export ROOT=${ROOT:-/r}
206     export TMP=${TMP:-$ROOT/tmp}
207     export TESTSUITELOG=${TMP}/${TESTSUITE}.log
208     export LOGDIR=${LOGDIR:-${TMP}/test_logs/$(date +%s)}
209     export TESTLOG_PREFIX=$LOGDIR/$TESTSUITE
210
211     export HOSTNAME=${HOSTNAME:-$(hostname -s)}
212     if ! echo $PATH | grep -q $LUSTRE/utils; then
213         export PATH=$LUSTRE/utils:$PATH
214     fi
215     if ! echo $PATH | grep -q $LUSTRE/utils/gss; then
216         export PATH=$LUSTRE/utils/gss:$PATH
217     fi
218     if ! echo $PATH | grep -q $LUSTRE/tests; then
219         export PATH=$LUSTRE/tests:$PATH
220     fi
221     if ! echo $PATH | grep -q $LUSTRE/../lustre-iokit/sgpdd-survey; then
222         export PATH=$LUSTRE/../lustre-iokit/sgpdd-survey:$PATH
223     fi
224     export LST=${LST:-"$LUSTRE/../lnet/utils/lst"}
225     [ ! -f "$LST" ] && export LST=$(which lst)
226     export SGPDDSURVEY=${SGPDDSURVEY:-"$LUSTRE/../lustre-iokit/sgpdd-survey/sgpdd-survey")}
227     [ ! -f "$SGPDDSURVEY" ] && export SGPDDSURVEY=$(which sgpdd-survey)
228         export MCREATE=${MCREATE:-mcreate}
229     # Ubuntu, at least, has a truncate command in /usr/bin
230     # so fully path our truncate command.
231     export TRUNCATE=${TRUNCATE:-$LUSTRE/tests/truncate}
232     export MDSRATE=${MDSRATE:-"$LUSTRE/tests/mpi/mdsrate"}
233     [ ! -f "$MDSRATE" ] && export MDSRATE=$(which mdsrate 2> /dev/null)
234     if ! echo $PATH | grep -q $LUSTRE/tests/racer; then
235         export PATH=$LUSTRE/tests/racer:$PATH:
236     fi
237     if ! echo $PATH | grep -q $LUSTRE/tests/mpi; then
238         export PATH=$LUSTRE/tests/mpi:$PATH
239     fi
240     export RSYNC_RSH=${RSYNC_RSH:-rsh}
241
242     export LCTL=${LCTL:-"$LUSTRE/utils/lctl"}
243     [ ! -f "$LCTL" ] && export LCTL=$(which lctl)
244     export LFS=${LFS:-"$LUSTRE/utils/lfs"}
245     [ ! -f "$LFS" ] && export LFS=$(which lfs)
246     SETSTRIPE=${SETSTRIPE:-"$LFS setstripe"}
247     GETSTRIPE=${GETSTRIPE:-"$LFS getstripe"}
248
249     export L_GETIDENTITY=${L_GETIDENTITY:-"$LUSTRE/utils/l_getidentity"}
250     if [ ! -f "$L_GETIDENTITY" ]; then
251         if `which l_getidentity > /dev/null 2>&1`; then
252             export L_GETIDENTITY=$(which l_getidentity)
253         else
254             export L_GETIDENTITY=NONE
255         fi
256     fi
257     export LL_DECODE_FILTER_FID=${LL_DECODE_FILTER_FID:-"$LUSTRE/utils/ll_decode_filter_fid"}
258     [ ! -f "$LL_DECODE_FILTER_FID" ] && export LL_DECODE_FILTER_FID="ll_decode_filter_fid"
259     export MKFS=${MKFS:-"$LUSTRE/utils/mkfs.lustre"}
260     [ ! -f "$MKFS" ] && export MKFS="mkfs.lustre"
261     export TUNEFS=${TUNEFS:-"$LUSTRE/utils/tunefs.lustre"}
262     [ ! -f "$TUNEFS" ] && export TUNEFS="tunefs.lustre"
263     export CHECKSTAT="${CHECKSTAT:-"checkstat -v"} "
264     export LUSTRE_RMMOD=${LUSTRE_RMMOD:-$LUSTRE/scripts/lustre_rmmod}
265     [ ! -f "$LUSTRE_RMMOD" ] &&
266         export LUSTRE_RMMOD=$(which lustre_rmmod 2> /dev/null)
267     export LFS_MIGRATE=${LFS_MIGRATE:-$LUSTRE/scripts/lfs_migrate}
268     [ ! -f "$LFS_MIGRATE" ] &&
269         export LFS_MIGRATE=$(which lfs_migrate 2> /dev/null)
270     export NAME=${NAME:-local}
271     export LGSSD=${LGSSD:-"$LUSTRE/utils/gss/lgssd"}
272     [ "$GSS_PIPEFS" = "true" ] && [ ! -f "$LGSSD" ] && \
273         export LGSSD=$(which lgssd)
274     export LSVCGSSD=${LSVCGSSD:-"$LUSTRE/utils/gss/lsvcgssd"}
275     [ ! -f "$LSVCGSSD" ] && export LSVCGSSD=$(which lsvcgssd 2> /dev/null)
276     export KRB5DIR=${KRB5DIR:-"/usr/kerberos"}
277     export DIR2
278     export SAVE_PWD=${SAVE_PWD:-$LUSTRE/tests}
279     export AT_MAX_PATH
280
281     if [ "$ACCEPTOR_PORT" ]; then
282         export PORT_OPT="--port $ACCEPTOR_PORT"
283     fi
284
285     case "x$SEC" in
286         xkrb5*)
287             echo "Using GSS/krb5 ptlrpc security flavor"
288             which lgss_keyring > /dev/null 2>&1 || \
289                 error_exit "built with gss disabled! SEC=$SEC"
290             GSS=true
291             GSS_KRB5=true
292             ;;
293     esac
294
295     case "x$IDUP" in
296         xtrue)
297             IDENTITY_UPCALL=true
298             ;;
299         xfalse)
300             IDENTITY_UPCALL=false
301             ;;
302     esac
303
304     export LOAD_MODULES_REMOTE=${LOAD_MODULES_REMOTE:-false}
305
306     # Paths on remote nodes, if different
307     export RLUSTRE=${RLUSTRE:-$LUSTRE}
308     export RPWD=${RPWD:-$PWD}
309     export I_MOUNTED=${I_MOUNTED:-"no"}
310         if [ ! -f /lib/modules/$(uname -r)/kernel/fs/lustre/mdt.ko -a \
311              ! -f /lib/modules/$(uname -r)/updates/kernel/fs/lustre/mdt.ko -a \
312              ! -f /lib/modules/$(uname -r)/extra/kernel/fs/lustre/mdt.ko -a \
313              ! -f $LUSTRE/mdt/mdt.ko ]; then
314             export CLIENTMODSONLY=yes
315         fi
316
317         export SHUTDOWN_ATTEMPTS=${SHUTDOWN_ATTEMPTS:-3}
318         export OSD_TRACK_DECLARES_LBUG=${OSD_TRACK_DECLARES_LBUG:-"yes"}
319
320     # command line
321
322     while getopts "rvwf:" opt $*; do
323         case $opt in
324             f) CONFIG=$OPTARG;;
325             r) REFORMAT=--reformat;;
326             v) VERBOSE=true;;
327             w) WRITECONF=writeconf;;
328             \?) usage;;
329         esac
330     done
331
332     shift $((OPTIND - 1))
333     ONLY=${ONLY:-$*}
334
335         # print the durations of each test if "true"
336         DDETAILS=${DDETAILS:-false}
337         [ "$TESTSUITELOG" ] && rm -f $TESTSUITELOG || true
338         if ! $RPC_MODE; then
339                 rm -f $TMP/*active
340         fi
341 }
342
343 check_cpt_number() {
344         local facet=$1
345         local ncpts
346
347         ncpts=$(do_facet $facet "lctl get_param -n " \
348                 "cpu_partition_table 2>/dev/null| wc -l" || echo 1)
349
350         if [ $ncpts -eq 0 ]; then
351                 echo "1"
352         else
353                 echo $ncpts
354         fi
355 }
356
357 version_code() {
358     # split arguments like "1.8.6-wc3" into "1", "8", "6", "wc3"
359     eval set -- $(tr "[:punct:]" " " <<< $*)
360
361     echo -n "$((($1 << 16) | ($2 << 8) | $3))"
362 }
363
364 export LINUX_VERSION=$(uname -r | sed -e "s/\([0-9]*\.[0-9]*\.[0-9]*\).*/\1/")
365 export LINUX_VERSION_CODE=$(version_code ${LINUX_VERSION//\./ })
366
367 module_loaded () {
368    /sbin/lsmod | grep -q "^\<$1\>"
369 }
370
371 # Load a module on the system where this is running.
372 #
373 # Synopsis: load_module module_name [module arguments for insmod/modprobe]
374 #
375 # If module arguments are not given but MODOPTS_<MODULE> is set, then its value
376 # will be used as the arguments.  Otherwise arguments will be obtained from
377 # /etc/modprobe.conf, from /etc/modprobe.d/Lustre, or else none will be used.
378 #
379 load_module() {
380     local optvar
381     EXT=".ko"
382     module=$1
383     shift
384     BASE=`basename $module $EXT`
385
386     module_loaded ${BASE} && return
387
388     # If no module arguments were passed, get them from $MODOPTS_<MODULE>, else from
389     # modprobe.conf
390     if [ $# -eq 0 ]; then
391         # $MODOPTS_<MODULE>; we could use associative arrays, but that's not in
392         # Bash until 4.x, so we resort to eval.
393         optvar="MODOPTS_$(basename $module | tr a-z A-Z)"
394         eval set -- \$$optvar
395         if [ $# -eq 0 -a -n "$MODPROBECONF" ]; then
396                 # Nothing in $MODOPTS_<MODULE>; try modprobe.conf
397                 local opt
398                 opt=$(awk -v var="^options $BASE" '$0 ~ var \
399                         {gsub("'"options $BASE"'",""); print}' $MODPROBECONF)
400                 set -- $(echo -n $opt)
401
402                 # Ensure we have accept=all for lnet
403                 if [ $(basename $module) = lnet ]; then
404                         # OK, this is a bit wordy...
405                         local arg accept_all_present=false
406
407                         for arg in "$@"; do
408                                 [ "$arg" = accept=all ] && \
409                                         accept_all_present=true
410                         done
411                         $accept_all_present || set -- "$@" accept=all
412                 fi
413                 export $optvar="$*"
414         fi
415     fi
416
417     [ $# -gt 0 ] && echo "${module} options: '$*'"
418
419     # Note that insmod will ignore anything in modprobe.conf, which is why we're
420     # passing options on the command-line.
421     if [ "$BASE" == "lnet_selftest" ] && \
422             [ -f ${LUSTRE}/../lnet/selftest/${module}${EXT} ]; then
423         insmod ${LUSTRE}/../lnet/selftest/${module}${EXT}
424     elif [ -f ${LUSTRE}/${module}${EXT} ]; then
425         insmod ${LUSTRE}/${module}${EXT} "$@"
426     else
427         # must be testing a "make install" or "rpm" installation
428         # note failed to load ptlrpc_gss is considered not fatal
429         if [ "$BASE" == "ptlrpc_gss" ]; then
430             modprobe $BASE "$@" 2>/dev/null || echo "gss/krb5 is not supported"
431         else
432             modprobe $BASE "$@"
433         fi
434     fi
435 }
436
437 llite_lloop_enabled() {
438     local n1=$(uname -r | cut -d. -f1)
439     local n2=$(uname -r | cut -d. -f2)
440     local n3=$(uname -r | cut -d- -f1 | cut -d. -f3)
441
442     # load the llite_lloop module for < 2.6.32 kernels
443     if [[ $n1 -lt 2 ]] || [[ $n1 -eq 2 && $n2 -lt 6 ]] || \
444        [[ $n1 -eq 2 && $n2 -eq 6 && $n3 -lt 32 ]] || \
445         $LOAD_LLOOP; then
446         return 0
447     fi
448     return 1
449 }
450
451 load_modules_local() {
452         if [ -n "$MODPROBE" ]; then
453                 # use modprobe
454                 echo "Using modprobe to load modules"
455                 return 0
456         fi
457
458         echo Loading modules from $LUSTRE
459
460         local ncpus
461
462         if [ -f /sys/devices/system/cpu/online ]; then
463                 ncpus=$(($(cut -d "-" -f 2 /sys/devices/system/cpu/online) + 1))
464                 echo "detected $ncpus online CPUs by sysfs"
465         else
466                 ncpus=$(getconf _NPROCESSORS_CONF 2>/dev/null)
467                 local rc=$?
468                 if [ $rc -eq 0 ]; then
469                         echo "detected $ncpus online CPUs by getconf"
470                 else
471                         echo "Can't detect number of CPUs"
472                         ncpus=1
473                 fi
474         fi
475
476         # if there is only one CPU core, libcfs can only create one partition
477         # if there is more than 4 CPU cores, libcfs should create multiple CPU
478         # partitions. So we just force libcfs to create 2 partitions for
479         # system with 2 or 4 cores
480         if [ $ncpus -le 4 ] && [ $ncpus -gt 1 ]; then
481                 # force to enable multiple CPU partitions
482                 echo "Force libcfs to create 2 CPU partitions"
483                 MODOPTS_LIBCFS="cpu_npartitions=2 $MODOPTS_LIBCFS"
484         else
485                 echo "libcfs will create CPU partition based on online CPUs"
486         fi
487
488         load_module ../libcfs/libcfs/libcfs
489
490     [ "$PTLDEBUG" ] && lctl set_param debug="$PTLDEBUG"
491     [ "$SUBSYSTEM" ] && lctl set_param subsystem_debug="${SUBSYSTEM# }"
492     load_module ../lnet/lnet/lnet
493     LNETLND=${LNETLND:-"socklnd/ksocklnd"}
494     load_module ../lnet/klnds/$LNETLND
495     load_module obdclass/obdclass
496     load_module ptlrpc/ptlrpc
497     load_module ptlrpc/gss/ptlrpc_gss
498     load_module fld/fld
499     load_module fid/fid
500     load_module lmv/lmv
501     load_module mdc/mdc
502     load_module osc/osc
503     load_module lov/lov
504     load_module mgc/mgc
505     load_module obdecho/obdecho
506     if ! client_only; then
507         SYMLIST=/proc/kallsyms
508         grep -q crc16 $SYMLIST || { modprobe crc16 2>/dev/null || true; }
509         grep -q -w jbd $SYMLIST || { modprobe jbd 2>/dev/null || true; }
510         grep -q -w jbd2 $SYMLIST || { modprobe jbd2 2>/dev/null || true; }
511                 load_module lfsck/lfsck
512                 [ "$LQUOTA" != "no" ] && load_module quota/lquota $LQUOTAOPTS
513                 if [[ $(node_fstypes $HOSTNAME) == *zfs* ]]; then
514                         modprobe zfs
515                         load_module osd-zfs/osd_zfs
516                 fi
517                 if [[ $(node_fstypes $HOSTNAME) == *ldiskfs* ]]; then
518                         grep -q exportfs_decode_fh $SYMLIST ||
519                                 { modprobe exportfs 2> /dev/null || true; }
520                         load_module ../ldiskfs/ldiskfs
521                         load_module osd-ldiskfs/osd_ldiskfs
522                 fi
523                 load_module nodemap/nodemap
524                 load_module mgs/mgs
525                 load_module mdd/mdd
526                 load_module mdt/mdt
527                 load_module ost/ost
528                 load_module lod/lod
529                 load_module osp/osp
530                 load_module ofd/ofd
531                 load_module osp/osp
532     fi
533
534         load_module llite/lustre
535         llite_lloop_enabled && load_module llite/llite_lloop
536         [ -d /r ] && OGDB=${OGDB:-"/r/tmp"}
537         OGDB=${OGDB:-$TMP}
538         rm -f $OGDB/ogdb-$HOSTNAME
539         $LCTL modules > $OGDB/ogdb-$HOSTNAME
540
541         # 'mount' doesn't look in $PATH, just sbin
542         local mount_lustre=$LUSTRE/utils/mount.lustre
543         if [ -f $mount_lustre ]; then
544                 local sbin_mount=/sbin/mount.lustre
545                 if grep -qe "$sbin_mount " /proc/mounts; then
546                         cmp $mount_lustre $sbin_mount || umount $sbin_mount
547                 fi
548                 if ! grep -qe "$sbin_mount " /proc/mounts; then
549                         [ ! -f "$sbin_mount" ] && touch "$sbin_mount"
550                         if [ ! -s "$sbin_mount" -a -w "$sbin_mount" ]; then
551                                 cat <<- EOF > "$sbin_mount"
552                                 #!/bin/sh
553                                 #STUB MARK
554                                 echo "This $sbin_mount just a mountpoint." 1>&2
555                                 echo "It is never supposed to be run." 1>&2
556                                 logger -p emerg -- "using stub $sbin_mount $@"
557                                 exit 1
558                                 EOF
559                                 chmod a+x $sbin_mount
560                         fi
561                         mount --bind $mount_lustre $sbin_mount ||
562                                 error "can't bind $mount_lustre to $sbin_mount"
563                 fi
564         fi
565 }
566
567 load_modules () {
568         load_modules_local
569         # bug 19124
570         # load modules on remote nodes optionally
571         # lustre-tests have to be installed on these nodes
572         if $LOAD_MODULES_REMOTE; then
573                 local list=$(comma_list $(remote_nodes_list))
574                 if [ -n "$list" ]; then
575                         echo "loading modules on: '$list'"
576                         do_rpc_nodes "$list" load_modules_local
577                 fi
578         fi
579 }
580
581 check_mem_leak () {
582     LEAK_LUSTRE=$(dmesg | tail -n 30 | grep "obd_memory.*leaked" || true)
583     LEAK_PORTALS=$(dmesg | tail -n 20 | grep "Portals memory leaked" || true)
584     if [ "$LEAK_LUSTRE" -o "$LEAK_PORTALS" ]; then
585         echo "$LEAK_LUSTRE" 1>&2
586         echo "$LEAK_PORTALS" 1>&2
587         mv $TMP/debug $TMP/debug-leak.`date +%s` || true
588         echo "Memory leaks detected"
589         [ -n "$IGNORE_LEAK" ] && { echo "ignoring leaks" && return 0; } || true
590         return 1
591     fi
592 }
593
594 unload_modules() {
595         wait_exit_ST client # bug 12845
596
597         $LUSTRE_RMMOD ldiskfs || return 2
598
599         if $LOAD_MODULES_REMOTE; then
600                 local list=$(comma_list $(remote_nodes_list))
601                 if [ -n "$list" ]; then
602                         echo "unloading modules on: '$list'"
603                         do_rpc_nodes "$list" $LUSTRE_RMMOD ldiskfs
604                         do_rpc_nodes "$list" check_mem_leak
605                 fi
606         fi
607
608         local sbin_mount=/sbin/mount.lustre
609         if grep -qe "$sbin_mount " /proc/mounts; then
610                 umount $sbin_mount || true
611                 [ -s $sbin_mount ] && ! grep -q "STUB MARK" $sbin_mount ||
612                         rm -f $sbin_mount
613         fi
614
615         check_mem_leak || return 254
616
617         echo "modules unloaded."
618         return 0
619 }
620
621 fs_log_size() {
622         local facet=${1:-$SINGLEMDS}
623         local fstype=$(facet_fstype $facet)
624         local size=0
625         case $fstype in
626                 ldiskfs) size=50;; # largest seen is 44, leave some headroom
627                 zfs)     size=400;; # largest seen is 384
628         esac
629
630         echo -n $size
631 }
632
633 check_gss_daemon_nodes() {
634     local list=$1
635     dname=$2
636
637     do_nodesv $list "num=\\\$(ps -o cmd -C $dname | grep $dname | wc -l);
638 if [ \\\"\\\$num\\\" -ne 1 ]; then
639     echo \\\$num instance of $dname;
640     exit 1;
641 fi; "
642 }
643
644 check_gss_daemon_facet() {
645     facet=$1
646     dname=$2
647
648     num=`do_facet $facet ps -o cmd -C $dname | grep $dname | wc -l`
649     if [ $num -ne 1 ]; then
650         echo "$num instance of $dname on $facet"
651         return 1
652     fi
653     return 0
654 }
655
656 send_sigint() {
657     local list=$1
658     shift
659     echo Stopping $@ on $list
660     do_nodes $list "killall -2 $@ 2>/dev/null || true"
661 }
662
663 # start gss daemons on all nodes, or
664 # "daemon" on "list" if set
665 start_gss_daemons() {
666     local list=$1
667     local daemon=$2
668
669     if [ "$list" ] && [ "$daemon" ] ; then
670         echo "Starting gss daemon on nodes: $list"
671         do_nodes $list "$daemon" || return 8
672         return 0
673     fi
674
675     local list=$(comma_list $(mdts_nodes))
676     echo "Starting gss daemon on mds: $list"
677     do_nodes $list "$LSVCGSSD -v" || return 1
678     if $GSS_PIPEFS; then
679         do_nodes $list "$LGSSD -v" || return 2
680     fi
681
682     list=$(comma_list $(osts_nodes))
683     echo "Starting gss daemon on ost: $list"
684     do_nodes $list "$LSVCGSSD -v" || return 3
685     # starting on clients
686
687     local clients=${CLIENTS:-`hostname`}
688     if $GSS_PIPEFS; then
689         echo "Starting $LGSSD on clients $clients "
690         do_nodes $clients  "$LGSSD -v" || return 4
691     fi
692
693     # wait daemons entering "stable" status
694     sleep 5
695
696     #
697     # check daemons are running
698     #
699     list=$(comma_list $(mdts_nodes) $(osts_nodes))
700     check_gss_daemon_nodes $list lsvcgssd || return 5
701     if $GSS_PIPEFS; then
702         list=$(comma_list $(mdts_nodes))
703         check_gss_daemon_nodes $list lgssd || return 6
704     fi
705     if $GSS_PIPEFS; then
706         check_gss_daemon_nodes $clients lgssd || return 7
707     fi
708 }
709
710 stop_gss_daemons() {
711     local list=$(comma_list $(mdts_nodes))
712
713     send_sigint $list lsvcgssd lgssd
714
715     list=$(comma_list $(osts_nodes))
716     send_sigint $list lsvcgssd
717
718     list=${CLIENTS:-`hostname`}
719     send_sigint $list lgssd
720 }
721
722 init_gss() {
723     if $GSS; then
724         if ! module_loaded ptlrpc_gss; then
725             load_module ptlrpc/gss/ptlrpc_gss
726             module_loaded ptlrpc_gss ||
727                 error_exit "init_gss : GSS=$GSS, but gss/krb5 is not supported!"
728         fi
729         if $GSS_KRB5; then
730                 start_gss_daemons || error_exit "start gss daemon failed! rc=$?"
731         fi
732
733         if [ -n "$LGSS_KEYRING_DEBUG" ]; then
734                 lctl set_param -n \
735                     sptlrpc.gss.lgss_keyring.debug_level=$LGSS_KEYRING_DEBUG
736         fi
737     fi
738 }
739
740 cleanup_gss() {
741     if $GSS; then
742         stop_gss_daemons
743         # maybe cleanup credential cache?
744     fi
745 }
746
747 facet_svc() {
748         local facet=$1
749         local var=${facet}_svc
750
751         echo -n ${!var}
752 }
753
754 facet_type() {
755         local facet=$1
756
757         echo -n $facet | sed -e 's/^fs[0-9]\+//' -e 's/[0-9_]\+//' |
758                 tr '[:lower:]' '[:upper:]'
759 }
760
761 facet_number() {
762         local facet=$1
763
764         if [ $facet == mgs ]; then
765                 return 1
766         fi
767
768         echo -n $facet | sed -e 's/^fs[0-9]\+//' | sed -e 's/^[a-z]\+//'
769 }
770
771 facet_fstype() {
772         local facet=$1
773         local var
774
775         var=${facet}_FSTYPE
776         if [ -n "${!var}" ]; then
777                 echo -n ${!var}
778                 return
779         fi
780
781         var=$(facet_type $facet)FSTYPE
782         if [ -n "${!var}" ]; then
783                 echo -n ${!var}
784                 return
785         fi
786
787         if [ -n "$FSTYPE" ]; then
788                 echo -n $FSTYPE
789                 return
790         fi
791
792         if [[ $facet == mgs ]] && combined_mgs_mds; then
793                 facet_fstype mds1
794                 return
795         fi
796
797         return 1
798 }
799
800 node_fstypes() {
801         local node=$1
802         local fstypes
803         local fstype
804         local facets=$(get_facets)
805         local facet
806
807         for facet in ${facets//,/ }; do
808                 if [ $node == $(facet_host $facet) ] ||
809                    [ $node == "$(facet_failover_host $facet)" ]; then
810                         fstype=$(facet_fstype $facet)
811                         if [[ $fstypes != *$fstype* ]]; then
812                                 fstypes+="${fstypes:+,}$fstype"
813                         fi
814                 fi
815         done
816         echo -n $fstypes
817 }
818
819 devicelabel() {
820         local facet=$1
821         local dev=$2
822         local label
823         local fstype=$(facet_fstype $facet)
824
825         case $fstype in
826         ldiskfs)
827                 label=$(do_facet ${facet} "$E2LABEL ${dev} 2>/dev/null");;
828         zfs)
829                 label=$(do_facet ${facet} "$ZFS get -H -o value lustre:svname \
830                                            ${dev} 2>/dev/null");;
831         *)
832                 error "unknown fstype!";;
833         esac
834
835         echo -n $label
836 }
837
838 mdsdevlabel() {
839         local num=$1
840         local device=$(mdsdevname $num)
841         local label=$(devicelabel mds$num ${device} | grep -v "CMD: ")
842         echo -n $label
843 }
844
845 ostdevlabel() {
846         local num=$1
847         local device=$(ostdevname $num)
848         local label=$(devicelabel ost$num ${device} | grep -v "CMD: ")
849         echo -n $label
850 }
851
852 #
853 # Get the device of a facet.
854 #
855 facet_device() {
856         local facet=$1
857         local device
858
859         case $facet in
860                 mgs) device=$(mgsdevname) ;;
861                 mds*) device=$(mdsdevname $(facet_number $facet)) ;;
862                 ost*) device=$(ostdevname $(facet_number $facet)) ;;
863                 fs2mds) device=$(mdsdevname 1_2) ;;
864                 fs2ost) device=$(ostdevname 1_2) ;;
865                 fs3ost) device=$(ostdevname 2_2) ;;
866                 *) ;;
867         esac
868
869         echo -n $device
870 }
871
872 #
873 # Get the virtual device of a facet.
874 #
875 facet_vdevice() {
876         local facet=$1
877         local device
878
879         case $facet in
880                 mgs) device=$(mgsvdevname) ;;
881                 mds*) device=$(mdsvdevname $(facet_number $facet)) ;;
882                 ost*) device=$(ostvdevname $(facet_number $facet)) ;;
883                 fs2mds) device=$(mdsvdevname 1_2) ;;
884                 fs2ost) device=$(ostvdevname 1_2) ;;
885                 fs3ost) device=$(ostvdevname 2_2) ;;
886                 *) ;;
887         esac
888
889         echo -n $device
890 }
891
892 #
893 # Re-read the partition table on failover partner host.
894 # After a ZFS storage pool is created on a shared device, the partition table
895 # on the device may change. However, the operating system on the failover
896 # host may not notice the change automatically. Without the up-to-date partition
897 # block devices, 'zpool import ..' cannot find the labels, whose positions are
898 # relative to partition rather than disk beginnings.
899 #
900 # This function performs partprobe on the failover host to make it re-read the
901 # partition table.
902 #
903 refresh_partition_table() {
904         local facet=$1
905         local device=$2
906         local host
907
908         host=$(facet_passive_host $facet)
909         if [[ -n "$host" ]]; then
910                 do_node $host "$PARTPROBE $device"
911         fi
912 }
913
914 #
915 # Get ZFS storage pool name.
916 #
917 zpool_name() {
918         local facet=$1
919         local device
920         local poolname
921
922         device=$(facet_device $facet)
923         # poolname is string before "/"
924         poolname="${device%%/*}"
925
926         echo -n $poolname
927 }
928
929 #
930 # Create ZFS storage pool.
931 #
932 create_zpool() {
933         local facet=$1
934         local poolname=$2
935         local vdev=$3
936         shift 3
937         local opts=${@:-"-o cachefile=none"}
938
939         do_facet $facet "$ZPOOL list -H $poolname >/dev/null 2>&1 ||
940                 $ZPOOL create -f $opts $poolname $vdev"
941 }
942
943 #
944 # Create ZFS file system.
945 #
946 create_zfs() {
947         local facet=$1
948         local dataset=$2
949         shift 2
950         local opts=${@:-"-o mountpoint=legacy"}
951
952         do_facet $facet "$ZFS list -H $dataset >/dev/null 2>&1 ||
953                 $ZFS create $opts $dataset"
954 }
955
956 #
957 # Export ZFS storage pool.
958 # Before exporting the pool, all datasets within the pool should be unmounted.
959 #
960 export_zpool() {
961         local facet=$1
962         shift
963         local opts="$@"
964         local poolname
965
966         poolname=$(zpool_name $facet)
967
968         if [[ -n "$poolname" ]]; then
969                 do_facet $facet "! $ZPOOL list -H $poolname >/dev/null 2>&1 ||
970                         grep -q ^$poolname/ /proc/mounts ||
971                         $ZPOOL export $opts $poolname"
972         fi
973 }
974
975 #
976 # Destroy ZFS storage pool.
977 # Destroy the given pool and free up any devices for other use. This command
978 # tries to unmount any active datasets before destroying the pool.
979 # -f    Force any active datasets contained within the pool to be unmounted.
980 #
981 destroy_zpool() {
982         local facet=$1
983         local poolname=${2:-$(zpool_name $facet)}
984
985         if [[ -n "$poolname" ]]; then
986                 do_facet $facet "! $ZPOOL list -H $poolname >/dev/null 2>&1 ||
987                         $ZPOOL destroy -f $poolname"
988         fi
989 }
990
991 #
992 # Import ZFS storage pool.
993 # Force importing, even if the pool appears to be potentially active.
994 #
995 import_zpool() {
996         local facet=$1
997         shift
998         local opts=${@:-"-o cachefile=none"}
999         local poolname
1000
1001         poolname=$(zpool_name $facet)
1002
1003         if [[ -n "$poolname" ]]; then
1004                 opts+=" -d $(dirname $(facet_vdevice $facet))"
1005                 do_facet $facet "$ZPOOL list -H $poolname >/dev/null 2>&1 ||
1006                         $ZPOOL import -f $opts $poolname"
1007         fi
1008 }
1009
1010 #
1011 # Set the "cachefile=none" property on ZFS storage pool so that the pool
1012 # is not automatically imported on system startup.
1013 #
1014 # In a failover environment, this will provide resource level fencing which
1015 # will ensure that the same ZFS storage pool will not be imported concurrently
1016 # on different nodes.
1017 #
1018 disable_zpool_cache() {
1019         local facet=$1
1020         local poolname
1021
1022         poolname=$(zpool_name $facet)
1023
1024         if [[ -n "$poolname" ]]; then
1025                 do_facet $facet "$ZPOOL set cachefile=none $poolname"
1026         fi
1027 }
1028
1029 #
1030 # This and set_osd_param() shall be used to access OSD parameters
1031 # once existed under "obdfilter":
1032 #
1033 #   mntdev
1034 #   stats
1035 #   read_cache_enable
1036 #   writethrough_cache_enable
1037 #
1038 get_osd_param() {
1039         local nodes=$1
1040         local device=${2:-$FSNAME-OST*}
1041         local name=$3
1042
1043         do_nodes $nodes "$LCTL get_param -n obdfilter.$device.$name \
1044                 osd-*.$device.$name 2>&1" | grep -v 'Found no match'
1045 }
1046
1047 set_osd_param() {
1048         local nodes=$1
1049         local device=${2:-$FSNAME-OST*}
1050         local name=$3
1051         local value=$4
1052
1053         do_nodes $nodes "$LCTL set_param -n obdfilter.$device.$name=$value \
1054                 osd-*.$device.$name=$value 2>&1" | grep -v 'Found no match'
1055 }
1056
1057 set_debug_size () {
1058     local dz=${1:-$DEBUG_SIZE}
1059
1060     if [ -f /sys/devices/system/cpu/possible ]; then
1061         local cpus=$(($(cut -d "-" -f 2 /sys/devices/system/cpu/possible)+1))
1062     else
1063         local cpus=$(getconf _NPROCESSORS_CONF)
1064     fi
1065
1066     # bug 19944, adjust size to be -gt num_possible_cpus()
1067     # promise 2MB for every cpu at least
1068     if [ -n "$cpus" ] && [ $((cpus * 2)) -gt $dz ]; then
1069         dz=$((cpus * 2))
1070     fi
1071     lctl set_param debug_mb=$dz
1072 }
1073
1074 set_default_debug () {
1075     local debug=${1:-"$PTLDEBUG"}
1076     local subsys=${2:-"$SUBSYSTEM"}
1077     local debug_size=${3:-$DEBUG_SIZE}
1078
1079     [ -n "$debug" ] && lctl set_param debug="$debug" >/dev/null
1080     [ -n "$subsys" ] && lctl set_param subsystem_debug="${subsys# }" >/dev/null
1081
1082     [ -n "$debug_size" ] && set_debug_size $debug_size > /dev/null
1083 }
1084
1085 set_default_debug_nodes () {
1086         local nodes="$1"
1087
1088         if [[ ,$nodes, = *,$HOSTNAME,* ]]; then
1089                 nodes=$(exclude_items_from_list "$nodes" "$HOSTNAME")
1090                 set_default_debug
1091         fi
1092
1093         do_rpc_nodes "$nodes" set_default_debug \
1094                 \\\"$PTLDEBUG\\\" \\\"$SUBSYSTEM\\\" $DEBUG_SIZE || true
1095 }
1096
1097 set_default_debug_facet () {
1098     local facet=$1
1099     local node=$(facet_active_host $facet)
1100     [ -z "$node" ] && echo "No host defined for facet $facet" && exit 1
1101
1102     set_default_debug_nodes $node
1103 }
1104
1105 # Facet functions
1106 mount_facets () {
1107         local facets=${1:-$(get_facets)}
1108         local facet
1109
1110         for facet in ${facets//,/ }; do
1111                 mount_facet $facet
1112                 local RC=$?
1113                 [ $RC -eq 0 ] && continue
1114
1115                 if [ "$TESTSUITE.$TESTNAME" = "replay-dual.test_0a" ]; then
1116                         skip "Restart of $facet failed!." && touch $LU482_FAILED
1117                 else
1118                         error "Restart of $facet failed!"
1119                 fi
1120                 return $RC
1121         done
1122 }
1123
1124 #
1125 # Add argument "arg" (e.g., "loop") to the comma-separated list
1126 # of arguments for option "opt" (e.g., "-o") on command
1127 # line "opts" (e.g., "-o flock").
1128 #
1129 csa_add() {
1130         local opts=$1
1131         local opt=$2
1132         local arg=$3
1133         local opt_pattern="\([[:space:]]\+\|^\)$opt"
1134
1135         if echo "$opts" | grep -q $opt_pattern; then
1136                 opts=$(echo "$opts" | sed -e \
1137                         "s/$opt_pattern[[:space:]]*[^[:space:]]\+/&,$arg/")
1138         else
1139                 opts+="${opts:+ }$opt $arg"
1140         fi
1141         echo -n "$opts"
1142 }
1143
1144 mount_facet() {
1145         local facet=$1
1146         shift
1147         local dev=$(facet_active $facet)_dev
1148         local opt=${facet}_opt
1149         local mntpt=$(facet_mntpt $facet)
1150         local opts="${!opt} $@"
1151
1152         if [ $(facet_fstype $facet) == ldiskfs ] &&
1153            ! do_facet $facet test -b ${!dev}; then
1154                 opts=$(csa_add "$opts" -o loop)
1155         fi
1156
1157         if [[ $(facet_fstype $facet) == zfs ]]; then
1158                 # import ZFS storage pool
1159                 import_zpool $facet || return ${PIPESTATUS[0]}
1160         fi
1161
1162         echo "Starting ${facet}: $opts ${!dev} $mntpt"
1163         # for testing LU-482 error handling in mount_facets() and test_0a()
1164         if [ -f $TMP/test-lu482-trigger ]; then
1165                 RC=2
1166         else
1167                 do_facet ${facet} "mkdir -p $mntpt; $MOUNT_CMD $opts \
1168                                    ${!dev} $mntpt"
1169                 RC=${PIPESTATUS[0]}
1170         fi
1171         if [ $RC -ne 0 ]; then
1172                 echo "Start of ${!dev} on ${facet} failed ${RC}"
1173     else
1174         set_default_debug_facet $facet
1175
1176                 label=$(devicelabel ${facet} ${!dev})
1177         [ -z "$label" ] && echo no label for ${!dev} && exit 1
1178         eval export ${facet}_svc=${label}
1179         echo Started ${label}
1180     fi
1181     return $RC
1182 }
1183
1184 # start facet device options
1185 start() {
1186     local facet=$1
1187     shift
1188     local device=$1
1189     shift
1190     eval export ${facet}_dev=${device}
1191     eval export ${facet}_opt=\"$@\"
1192
1193     local varname=${facet}failover_dev
1194     if [ -n "${!varname}" ] ; then
1195         eval export ${facet}failover_dev=${!varname}
1196     else
1197         eval export ${facet}failover_dev=$device
1198     fi
1199
1200         local mntpt=$(facet_mntpt $facet)
1201         do_facet ${facet} mkdir -p $mntpt
1202         eval export ${facet}_MOUNT=$mntpt
1203         mount_facet ${facet}
1204         RC=$?
1205
1206         if [[ $facet == mds* ]]; then
1207                 do_facet $facet \
1208                         lctl set_param -n mdt.${FSNAME}*.enable_remote_dir=1 \
1209                                 2>/dev/null
1210         fi
1211
1212         return $RC
1213 }
1214
1215 stop() {
1216     local running
1217     local facet=$1
1218     shift
1219     local HOST=`facet_active_host $facet`
1220     [ -z $HOST ] && echo stop: no host for $facet && return 0
1221
1222     local mntpt=$(facet_mntpt $facet)
1223     running=$(do_facet ${facet} "grep -c $mntpt' ' /proc/mounts") || true
1224     if [ ${running} -ne 0 ]; then
1225         echo "Stopping $mntpt (opts:$@) on $HOST"
1226         do_facet ${facet} umount -d $@ $mntpt
1227     fi
1228
1229         # umount should block, but we should wait for unrelated obd's
1230         # like the MGS or MGC to also stop.
1231         wait_exit_ST ${facet} || return ${PIPESTATUS[0]}
1232
1233         if [[ $(facet_fstype $facet) == zfs ]]; then
1234                 # export ZFS storage pool
1235                 export_zpool $facet
1236         fi
1237 }
1238
1239 # save quota version (both administrative and operational quotas)
1240 # add an additional parameter if mountpoint is ever different from $MOUNT
1241 #
1242 # XXX This function is kept for interoperability with old server (< 2.3.50),
1243 #     it should be removed whenever we drop the interoperability for such
1244 #     server.
1245 quota_save_version() {
1246     local fsname=${2:-$FSNAME}
1247     local spec=$1
1248     local ver=$(tr -c -d "123" <<< $spec)
1249     local type=$(tr -c -d "ug" <<< $spec)
1250
1251     [ -n "$ver" -a "$ver" != "3" ] && error "wrong quota version specifier"
1252
1253     [ -n "$type" ] && { $LFS quotacheck -$type $MOUNT || error "quotacheck has failed"; }
1254
1255     do_facet mgs "lctl conf_param ${fsname}-MDT*.mdd.quota_type=$spec"
1256     local varsvc
1257     local osts=$(get_facets OST)
1258     for ost in ${osts//,/ }; do
1259         varsvc=${ost}_svc
1260         do_facet mgs "lctl conf_param ${!varsvc}.ost.quota_type=$spec"
1261     done
1262 }
1263
1264 # client could mount several lustre
1265 #
1266 # XXX This function is kept for interoperability with old server (< 2.3.50),
1267 #     it should be removed whenever we drop the interoperability for such
1268 #     server.
1269 quota_type() {
1270         local fsname=${1:-$FSNAME}
1271         local rc=0
1272         do_facet $SINGLEMDS lctl get_param mdd.${fsname}-MDT*.quota_type ||
1273                 rc=$?
1274         do_nodes $(comma_list $(osts_nodes)) \
1275                 lctl get_param obdfilter.${fsname}-OST*.quota_type || rc=$?
1276         return $rc
1277 }
1278
1279 # XXX This function is kept for interoperability with old server (< 2.3.50),
1280 #     it should be removed whenever we drop the interoperability for such
1281 #     server.
1282 restore_quota_old() {
1283         local mntpt=${1:-$MOUNT}
1284         local quota_type=$(quota_type $FSNAME | grep MDT | cut -d "=" -f2)
1285         if [ ! "$old_QUOTA_TYPE" ] ||
1286                 [ "$quota_type" = "$old_QUOTA_TYPE" ]; then
1287                 return
1288         fi
1289         quota_save_version $old_QUOTA_TYPE
1290 }
1291
1292 # XXX This function is kept for interoperability with old server (< 2.3.50),
1293 #     it should be removed whenever we drop the interoperability for such
1294 #     server.
1295 setup_quota_old(){
1296         local mntpt=$1
1297
1298         # no quota enforcement for now and accounting works out of the box
1299         return
1300
1301     # We need save the original quota_type params, and restore them after testing
1302
1303     # Suppose that quota type the same on mds and ost
1304     local quota_type=$(quota_type | grep MDT | cut -d "=" -f2)
1305     [ ${PIPESTATUS[0]} -eq 0 ] || error "quota_type failed!"
1306     echo "[HOST:$HOSTNAME] [old_quota_type:$quota_type] [new_quota_type:$QUOTA_TYPE]"
1307     if [ "$quota_type" != "$QUOTA_TYPE" ]; then
1308         export old_QUOTA_TYPE=$quota_type
1309         quota_save_version $QUOTA_TYPE
1310     else
1311         qtype=$(tr -c -d "ug" <<< $QUOTA_TYPE)
1312         $LFS quotacheck -$qtype $mntpt || error "quotacheck has failed for $type"
1313     fi
1314
1315     local quota_usrs=$QUOTA_USERS
1316
1317     # get_filesystem_size
1318     local disksz=$(lfs_df $mntpt | grep "summary"  | awk '{print $2}')
1319     local blk_soft=$((disksz + 1024))
1320     local blk_hard=$((blk_soft + blk_soft / 20)) # Go 5% over
1321
1322     local Inodes=$(lfs_df -i $mntpt | grep "summary"  | awk '{print $2}')
1323     local i_soft=$Inodes
1324     local i_hard=$((i_soft + i_soft / 20))
1325
1326     echo "Total disk size: $disksz  block-softlimit: $blk_soft block-hardlimit:
1327         $blk_hard inode-softlimit: $i_soft inode-hardlimit: $i_hard"
1328
1329     local cmd
1330     for usr in $quota_usrs; do
1331         echo "Setting up quota on $HOSTNAME:$mntpt for $usr..."
1332         for type in u g; do
1333             cmd="$LFS setquota -$type $usr -b $blk_soft -B $blk_hard -i $i_soft -I $i_hard $mntpt"
1334             echo "+ $cmd"
1335             eval $cmd || error "$cmd FAILED!"
1336         done
1337         # display the quota status
1338         echo "Quota settings for $usr : "
1339         $LFS quota -v -u $usr $mntpt || true
1340     done
1341 }
1342
1343 # get mdt quota type
1344 mdt_quota_type() {
1345         local varsvc=${SINGLEMDS}_svc
1346         do_facet $SINGLEMDS $LCTL get_param -n \
1347                 osd-$(facet_fstype $SINGLEMDS).${!varsvc}.quota_slave.enabled
1348 }
1349
1350 # get ost quota type
1351 ost_quota_type() {
1352         # All OSTs should have same quota type
1353         local varsvc=ost1_svc
1354         do_facet ost1 $LCTL get_param -n \
1355                 osd-$(facet_fstype ost1).${!varsvc}.quota_slave.enabled
1356 }
1357
1358 # restore old quota type settings
1359 restore_quota() {
1360         if [ $(lustre_version_code $SINGLEMDS) -lt $(version_code 2.3.50) ]; then
1361                 restore_quota_old
1362                 return
1363         fi
1364
1365         if [ "$old_MDT_QUOTA_TYPE" ]; then
1366                 do_facet mgs $LCTL conf_param \
1367                         $FSNAME.quota.mdt=$old_MDT_QUOTA_TYPE
1368         fi
1369         if [ "$old_OST_QUOTA_TYPE" ]; then
1370                 do_facet mgs $LCTL conf_param \
1371                         $FSNAME.quota.ost=$old_OST_QUOTA_TYPE
1372         fi
1373 }
1374
1375 # Handle the case when there is a space in the lfs df
1376 # "filesystem summary" line the same as when there is no space.
1377 # This will allow fixing the "lfs df" summary line in the future.
1378 lfs_df() {
1379         $LFS df $* | sed -e 's/filesystem /filesystem_/'
1380 }
1381
1382 # Get free inodes on the MDT specified by mdt index, free indoes on
1383 # the whole filesystem will be returned when index == -1.
1384 mdt_free_inodes() {
1385         local index=$1
1386         local free_inodes
1387         local mdt_uuid
1388
1389         if [ $index -eq -1 ]; then
1390                 mdt_uuid="summary"
1391         else
1392                 mdt_uuid=$(mdtuuid_from_index $index)
1393         fi
1394
1395         free_inodes=$(lfs_df -i $MOUNT | grep $mdt_uuid | awk '{print $4}')
1396         echo $free_inodes
1397 }
1398
1399 setup_quota(){
1400         if [ $(lustre_version_code $SINGLEMDS) -lt $(version_code 2.3.50) ]; then
1401                 setup_quota_old $1
1402                 return
1403         fi
1404
1405         local mntpt=$1
1406
1407         # save old quota type & set new quota type
1408         local mdt_qtype=$(mdt_quota_type)
1409         local ost_qtype=$(ost_quota_type)
1410
1411         echo "[HOST:$HOSTNAME] [old_mdt_qtype:$mdt_qtype]" \
1412                 "[old_ost_qtype:$ost_qtype] [new_qtype:$QUOTA_TYPE]"
1413
1414         export old_MDT_QUOTA_TYPE=$mdt_qtype
1415         export old_OST_QUOTA_TYPE=$ost_qtype
1416
1417         do_facet mgs $LCTL conf_param $FSNAME.quota.mdt=$QUOTA_TYPE ||
1418                 error "set mdt quota type failed"
1419         do_facet mgs $LCTL conf_param $FSNAME.quota.ost=$QUOTA_TYPE ||
1420                 error "set ost quota type failed"
1421
1422         local quota_usrs=$QUOTA_USERS
1423
1424         # get_filesystem_size
1425         local disksz=$(lfs_df $mntpt | grep "summary" | awk '{print $2}')
1426         local blk_soft=$((disksz + 1024))
1427         local blk_hard=$((blk_soft + blk_soft / 20)) # Go 5% over
1428
1429         local inodes=$(lfs_df -i $mntpt | grep "summary" | awk '{print $2}')
1430         local i_soft=$inodes
1431         local i_hard=$((i_soft + i_soft / 20))
1432
1433         echo "Total disk size: $disksz  block-softlimit: $blk_soft" \
1434                 "block-hardlimit: $blk_hard inode-softlimit: $i_soft" \
1435                 "inode-hardlimit: $i_hard"
1436
1437         local cmd
1438         for usr in $quota_usrs; do
1439                 echo "Setting up quota on $HOSTNAME:$mntpt for $usr..."
1440                 for type in u g; do
1441                         cmd="$LFS setquota -$type $usr -b $blk_soft"
1442                         cmd="$cmd -B $blk_hard -i $i_soft -I $i_hard $mntpt"
1443                         echo "+ $cmd"
1444                         eval $cmd || error "$cmd FAILED!"
1445                 done
1446                 # display the quota status
1447                 echo "Quota settings for $usr : "
1448                 $LFS quota -v -u $usr $mntpt || true
1449         done
1450 }
1451
1452 zconf_mount() {
1453     local client=$1
1454     local mnt=$2
1455     local opts=${3:-$MOUNT_OPTS}
1456     opts=${opts:+-o $opts}
1457     local flags=${4:-$MOUNT_FLAGS}
1458
1459     local device=$MGSNID:/$FSNAME
1460     if [ -z "$mnt" -o -z "$FSNAME" ]; then
1461         echo Bad zconf mount command: opt=$flags $opts dev=$device mnt=$mnt
1462         exit 1
1463     fi
1464
1465     echo "Starting client: $client: $flags $opts $device $mnt"
1466     do_node $client mkdir -p $mnt
1467     do_node $client $MOUNT_CMD $flags $opts $device $mnt || return 1
1468
1469     set_default_debug_nodes $client
1470
1471     return 0
1472 }
1473
1474 zconf_umount() {
1475     local client=$1
1476     local mnt=$2
1477     local force
1478     local busy 
1479     local need_kill
1480
1481     [ "$3" ] && force=-f
1482     local running=$(do_node $client "grep -c $mnt' ' /proc/mounts") || true
1483     if [ $running -ne 0 ]; then
1484         echo "Stopping client $client $mnt (opts:$force)"
1485         do_node $client lsof -t $mnt || need_kill=no
1486         if [ "x$force" != "x" -a "x$need_kill" != "xno" ]; then
1487             pids=$(do_node $client lsof -t $mnt | sort -u);
1488             if [ -n $pids ]; then
1489                 do_node $client kill -9 $pids || true
1490             fi
1491         fi
1492
1493         busy=$(do_node $client "umount $force $mnt 2>&1" | grep -c "busy") || true
1494         if [ $busy -ne 0 ] ; then
1495             echo "$mnt is still busy, wait one second" && sleep 1
1496             do_node $client umount $force $mnt
1497         fi
1498     fi
1499 }
1500
1501 # nodes is comma list
1502 sanity_mount_check_nodes () {
1503     local nodes=$1
1504     shift
1505     local mnts="$@"
1506     local mnt
1507
1508     # FIXME: assume that all cluster nodes run the same os
1509     [ "$(uname)" = Linux ] || return 0
1510
1511     local rc=0
1512     for mnt in $mnts ; do
1513         do_nodes $nodes "running=\\\$(grep -c $mnt' ' /proc/mounts);
1514 mpts=\\\$(mount | grep -c $mnt' ');
1515 if [ \\\$running -ne \\\$mpts ]; then
1516     echo \\\$(hostname) env are INSANE!;
1517     exit 1;
1518 fi"
1519     [ $? -eq 0 ] || rc=1 
1520     done
1521     return $rc
1522 }
1523
1524 sanity_mount_check_servers () {
1525     [ "$CLIENTONLY" ] && 
1526         { echo "CLIENTONLY mode, skip mount_check_servers"; return 0; } || true
1527     echo Checking servers environments
1528
1529     # FIXME: modify get_facets to display all facets wo params
1530     local facets="$(get_facets OST),$(get_facets MDS),mgs"
1531     local node
1532     local mntpt
1533     local facet
1534     for facet in ${facets//,/ }; do
1535         node=$(facet_host ${facet})
1536         mntpt=$(facet_mntpt $facet)
1537         sanity_mount_check_nodes $node $mntpt ||
1538             { error "server $node environments are insane!"; return 1; }
1539     done
1540 }
1541
1542 sanity_mount_check_clients () {
1543     local clients=${1:-$CLIENTS}
1544     local mntpt=${2:-$MOUNT}
1545     local mntpt2=${3:-$MOUNT2}
1546
1547     [ -z $clients ] && clients=$(hostname)
1548     echo Checking clients $clients environments
1549
1550     sanity_mount_check_nodes $clients $mntpt $mntpt2 ||
1551        error "clients environments are insane!"
1552 }
1553
1554 sanity_mount_check () {
1555     sanity_mount_check_servers || return 1
1556     sanity_mount_check_clients || return 2
1557 }
1558
1559 # mount clients if not mouted
1560 zconf_mount_clients() {
1561     local clients=$1
1562     local mnt=$2
1563     local opts=${3:-$MOUNT_OPTS}
1564     opts=${opts:+-o $opts}
1565     local flags=${4:-$MOUNT_FLAGS}
1566
1567     local device=$MGSNID:/$FSNAME
1568     if [ -z "$mnt" -o -z "$FSNAME" ]; then
1569         echo Bad zconf mount command: opt=$flags $opts dev=$device mnt=$mnt
1570         exit 1
1571     fi
1572
1573     echo "Starting client $clients: $flags $opts $device $mnt"
1574
1575     do_nodes $clients "
1576 running=\\\$(mount | grep -c $mnt' ');
1577 rc=0;
1578 if [ \\\$running -eq 0 ] ; then
1579     mkdir -p $mnt;
1580     $MOUNT_CMD $flags $opts $device $mnt;
1581     rc=\\\$?;
1582 fi;
1583 exit \\\$rc" || return ${PIPESTATUS[0]}
1584
1585     echo "Started clients $clients: "
1586     do_nodes $clients "mount | grep $mnt' '"
1587
1588     set_default_debug_nodes $clients
1589
1590     return 0
1591 }
1592
1593 zconf_umount_clients() {
1594     local clients=$1
1595     local mnt=$2
1596     local force
1597
1598     [ "$3" ] && force=-f
1599
1600     echo "Stopping clients: $clients $mnt (opts:$force)"
1601     do_nodes $clients "running=\\\$(grep -c $mnt' ' /proc/mounts);
1602 if [ \\\$running -ne 0 ] ; then
1603 echo Stopping client \\\$(hostname) $mnt opts:$force;
1604 lsof $mnt || need_kill=no;
1605 if [ "x$force" != "x" -a "x\\\$need_kill" != "xno" ]; then
1606     pids=\\\$(lsof -t $mnt | sort -u);
1607     if [ -n \\\"\\\$pids\\\" ]; then
1608              kill -9 \\\$pids;
1609     fi
1610 fi;
1611 while umount $force $mnt 2>&1 | grep -q "busy"; do
1612     echo "$mnt is still busy, wait one second" && sleep 1;
1613 done;
1614 fi"
1615 }
1616
1617 shutdown_node () {
1618     local node=$1
1619     echo + $POWER_DOWN $node
1620     $POWER_DOWN $node
1621 }
1622
1623 shutdown_node_hard () {
1624     local host=$1
1625     local attempts=$SHUTDOWN_ATTEMPTS
1626
1627     for i in $(seq $attempts) ; do
1628         shutdown_node $host
1629         sleep 1
1630         wait_for_function --quiet "! ping -w 3 -c 1 $host" 5 1 && return 0
1631         echo "waiting for $host to fail attempts=$attempts"
1632         [ $i -lt $attempts ] || \
1633             { echo "$host still pingable after power down! attempts=$attempts" && return 1; } 
1634     done
1635 }
1636
1637 shutdown_client() {
1638     local client=$1
1639     local mnt=${2:-$MOUNT}
1640     local attempts=3
1641
1642     if [ "$FAILURE_MODE" = HARD ]; then
1643         shutdown_node_hard $client
1644     else
1645        zconf_umount_clients $client $mnt -f
1646     fi
1647 }
1648
1649 facets_on_host () {
1650     local host=$1
1651     local facets="$(get_facets OST),$(get_facets MDS)"
1652     local affected
1653
1654     combined_mgs_mds || facets="$facets,mgs"
1655
1656     for facet in ${facets//,/ }; do
1657         if [ $(facet_active_host $facet) == $host ]; then
1658            affected="$affected $facet"
1659         fi
1660     done
1661
1662     echo $(comma_list $affected)
1663 }
1664
1665 facet_up() {
1666         local facet=$1
1667         local host=${2:-$(facet_host $facet)}
1668
1669         local label=$(convert_facet2label $facet)
1670         do_node $host $LCTL dl | awk '{ print $4 }' | grep -q "^$label\$"
1671 }
1672
1673 facets_up_on_host () {
1674     local host=$1
1675     local facets=$(facets_on_host $host)
1676     local affected_up
1677
1678     for facet in ${facets//,/ }; do
1679         if $(facet_up $facet $host); then
1680             affected_up="$affected_up $facet"
1681         fi
1682     done
1683
1684     echo $(comma_list $affected_up)
1685 }
1686
1687 shutdown_facet() {
1688     local facet=$1
1689
1690     if [ "$FAILURE_MODE" = HARD ]; then
1691         shutdown_node_hard $(facet_active_host $facet)
1692     else
1693         stop $facet
1694     fi
1695 }
1696
1697 reboot_node() {
1698     local node=$1
1699     echo + $POWER_UP $node
1700     $POWER_UP $node
1701 }
1702
1703 remount_facet() {
1704     local facet=$1
1705
1706     stop $facet
1707     mount_facet $facet
1708 }
1709
1710 reboot_facet() {
1711         local facet=$1
1712         if [ "$FAILURE_MODE" = HARD ]; then
1713                 reboot_node $(facet_active_host $facet)
1714         else
1715                 sleep 10
1716         fi
1717 }
1718
1719 boot_node() {
1720     local node=$1
1721     if [ "$FAILURE_MODE" = HARD ]; then
1722        reboot_node $node
1723        wait_for_host $node
1724     fi
1725 }
1726
1727 facets_hosts () {
1728     local facets=$1
1729     local hosts
1730
1731     for facet in ${facets//,/ }; do
1732         hosts=$(expand_list $hosts $(facet_host $facet) )
1733     done
1734
1735     echo $hosts
1736 }
1737
1738 _check_progs_installed () {
1739     local progs=$@
1740     local rc=0
1741
1742     for prog in $progs; do
1743         if ! [ "$(which $prog)"  -o  "${!prog}" ]; then
1744            echo $prog missing on $(hostname)
1745            rc=1
1746         fi
1747     done
1748     return $rc
1749 }
1750
1751 check_progs_installed () {
1752         local nodes=$1
1753         shift
1754
1755         do_rpc_nodes "$nodes" _check_progs_installed $@
1756 }
1757
1758 # recovery-scale functions
1759 node_var_name() {
1760     echo __$(echo $1 | tr '-' '_' | tr '.' '_')
1761 }
1762
1763 start_client_load() {
1764     local client=$1
1765     local load=$2
1766     local var=$(node_var_name $client)_load
1767     eval export ${var}=$load
1768
1769     do_node $client "PATH=$PATH MOUNT=$MOUNT ERRORS_OK=$ERRORS_OK \
1770 BREAK_ON_ERROR=$BREAK_ON_ERROR \
1771 END_RUN_FILE=$END_RUN_FILE \
1772 LOAD_PID_FILE=$LOAD_PID_FILE \
1773 TESTLOG_PREFIX=$TESTLOG_PREFIX \
1774 TESTNAME=$TESTNAME \
1775 DBENCH_LIB=$DBENCH_LIB \
1776 DBENCH_SRC=$DBENCH_SRC \
1777 CLIENT_COUNT=$((CLIENTCOUNT - 1)) \
1778 LFS=$LFS \
1779 run_${load}.sh" &
1780     local ppid=$!
1781     log "Started client load: ${load} on $client"
1782
1783     # get the children process IDs
1784     local pids=$(ps --ppid $ppid -o pid= | xargs)
1785     CLIENT_LOAD_PIDS="$CLIENT_LOAD_PIDS $ppid $pids"
1786     return 0
1787 }
1788
1789 start_client_loads () {
1790     local -a clients=(${1//,/ })
1791     local numloads=${#CLIENT_LOADS[@]}
1792     local testnum
1793
1794     for ((nodenum=0; nodenum < ${#clients[@]}; nodenum++ )); do
1795         testnum=$((nodenum % numloads))
1796         start_client_load ${clients[nodenum]} ${CLIENT_LOADS[testnum]}
1797     done
1798     # bug 22169: wait the background threads to start
1799     sleep 2
1800 }
1801
1802 # only for remote client
1803 check_client_load () {
1804     local client=$1
1805     local var=$(node_var_name $client)_load
1806     local TESTLOAD=run_${!var}.sh
1807
1808     ps auxww | grep -v grep | grep $client | grep -q "$TESTLOAD" || return 1
1809
1810     # bug 18914: try to connect several times not only when
1811     # check ps, but  while check_catastrophe also
1812     local tries=3
1813     local RC=254
1814     while [ $RC = 254 -a $tries -gt 0 ]; do
1815         let tries=$tries-1
1816         # assume success
1817         RC=0
1818         if ! check_catastrophe $client; then
1819             RC=${PIPESTATUS[0]}
1820             if [ $RC -eq 254 ]; then
1821                 # FIXME: not sure how long we shuold sleep here
1822                 sleep 10
1823                 continue
1824             fi
1825             echo "check catastrophe failed: RC=$RC "
1826             return $RC
1827         fi
1828     done
1829     # We can continue try to connect if RC=254
1830     # Just print the warning about this
1831     if [ $RC = 254 ]; then
1832         echo "got a return status of $RC from do_node while checking catastrophe on $client"
1833     fi
1834
1835     # see if the load is still on the client
1836     tries=3
1837     RC=254
1838     while [ $RC = 254 -a $tries -gt 0 ]; do
1839         let tries=$tries-1
1840         # assume success
1841         RC=0
1842         if ! do_node $client "ps auxwww | grep -v grep | grep -q $TESTLOAD"; then
1843             RC=${PIPESTATUS[0]}
1844             sleep 30
1845         fi
1846     done
1847     if [ $RC = 254 ]; then
1848         echo "got a return status of $RC from do_node while checking (catastrophe and 'ps') the client load on $client"
1849         # see if we can diagnose a bit why this is
1850     fi
1851
1852     return $RC
1853 }
1854 check_client_loads () {
1855    local clients=${1//,/ }
1856    local client=
1857    local rc=0
1858
1859    for client in $clients; do
1860       check_client_load $client
1861       rc=${PIPESTATUS[0]}
1862       if [ "$rc" != 0 ]; then
1863         log "Client load failed on node $client, rc=$rc"
1864         return $rc
1865       fi
1866    done
1867 }
1868
1869 restart_client_loads () {
1870     local clients=${1//,/ }
1871     local expectedfail=${2:-""}
1872     local client=
1873     local rc=0
1874
1875     for client in $clients; do
1876         check_client_load $client
1877         rc=${PIPESTATUS[0]}
1878         if [ "$rc" != 0 -a "$expectedfail" ]; then
1879             local var=$(node_var_name $client)_load
1880             start_client_load $client ${!var}
1881             echo "Restarted client load ${!var}: on $client. Checking ..."
1882             check_client_load $client
1883             rc=${PIPESTATUS[0]}
1884             if [ "$rc" != 0 ]; then
1885                 log "Client load failed to restart on node $client, rc=$rc"
1886                 # failure one client load means test fail
1887                 # we do not need to check other
1888                 return $rc
1889             fi
1890         else
1891             return $rc
1892         fi
1893     done
1894 }
1895
1896 # Start vmstat and save its process ID in a file.
1897 start_vmstat() {
1898     local nodes=$1
1899     local pid_file=$2
1900
1901     [ -z "$nodes" -o -z "$pid_file" ] && return 0
1902
1903     do_nodes $nodes \
1904         "vmstat 1 > $TESTLOG_PREFIX.$TESTNAME.vmstat.\\\$(hostname -s).log \
1905         2>/dev/null </dev/null & echo \\\$! > $pid_file"
1906 }
1907
1908 # Display the nodes on which client loads failed.
1909 print_end_run_file() {
1910     local file=$1
1911     local node
1912
1913     [ -s $file ] || return 0
1914
1915     echo "Found the END_RUN_FILE file: $file"
1916     cat $file
1917
1918     # A client load will stop if it finds the END_RUN_FILE file.
1919     # That does not mean the client load actually failed though.
1920     # The first node in END_RUN_FILE is the one we are interested in.
1921     read node < $file
1922
1923     if [ -n "$node" ]; then
1924         local var=$(node_var_name $node)_load
1925
1926         local prefix=$TESTLOG_PREFIX
1927         [ -n "$TESTNAME" ] && prefix=$prefix.$TESTNAME
1928         local stdout_log=$prefix.run_${!var}_stdout.$node.log
1929         local debug_log=$(echo $stdout_log | sed 's/\(.*\)stdout/\1debug/')
1930
1931         echo "Client load ${!var} failed on node $node:"
1932         echo "$stdout_log"
1933         echo "$debug_log"
1934     fi
1935 }
1936
1937 # Stop the process which had its PID saved in a file.
1938 stop_process() {
1939     local nodes=$1
1940     local pid_file=$2
1941
1942     [ -z "$nodes" -o -z "$pid_file" ] && return 0
1943
1944     do_nodes $nodes "test -f $pid_file &&
1945         { kill -s TERM \\\$(cat $pid_file); rm -f $pid_file; }" || true
1946 }
1947
1948 # Stop all client loads.
1949 stop_client_loads() {
1950     local nodes=${1:-$CLIENTS}
1951     local pid_file=$2
1952
1953     # stop the client loads
1954     stop_process $nodes $pid_file
1955
1956     # clean up the processes that started them
1957     [ -n "$CLIENT_LOAD_PIDS" ] && kill -9 $CLIENT_LOAD_PIDS 2>/dev/null || true
1958 }
1959 # End recovery-scale functions
1960
1961 # verify that lustre actually cleaned up properly
1962 cleanup_check() {
1963         VAR=$(lctl get_param -n catastrophe 2>&1)
1964         if [ $? = 0 ] ; then
1965                 if [ $VAR != 0 ]; then
1966                         error "LBUG/LASSERT detected"
1967                 fi
1968         fi
1969         BUSY=$(dmesg | grep -i destruct || true)
1970         if [ -n "$BUSY" ]; then
1971                 echo "$BUSY" 1>&2
1972                 [ -e $TMP/debug ] && mv $TMP/debug $TMP/debug-busy.$(date +%s)
1973                 exit 205
1974         fi
1975
1976         check_mem_leak || exit 204
1977
1978         [[ $($LCTL dl 2>/dev/null | wc -l) -gt 0 ]] && $LCTL dl &&
1979                 echo "$TESTSUITE: lustre didn't clean up..." 1>&2 &&
1980                 return 202 || true
1981
1982         if module_loaded lnet || module_loaded libcfs; then
1983                 echo "$TESTSUITE: modules still loaded..." 1>&2
1984                 /sbin/lsmod 1>&2
1985                 return 203
1986         fi
1987         return 0
1988 }
1989
1990 wait_update () {
1991         local verbose=false
1992         if [[ "$1" == "--verbose" ]]; then
1993                 shift
1994                 verbose=true
1995         fi
1996
1997         local node=$1
1998         local TEST=$2
1999         local FINAL=$3
2000         local MAX=${4:-90}
2001         local RESULT
2002         local PREV_RESULT
2003         local WAIT=0
2004         local sleep=1
2005         local print=10
2006
2007         PREV_RESULT=$(do_node $node "$TEST")
2008         while [ true ]; do
2009                 RESULT=$(do_node $node "$TEST")
2010                 if [[ "$RESULT" == "$FINAL" ]]; then
2011                         [[ -z "$RESULT" || $WAIT -le $sleep ]] ||
2012                                 echo "Updated after ${WAIT}s: wanted '$FINAL'"\
2013                                      "got '$RESULT'"
2014                         return 0
2015                 fi
2016                 if [[ $verbose && "$RESULT" != "$PREV_RESULT" ]]; then
2017                         echo "Changed after ${WAIT}s: from '$PREV_RESULT'"\
2018                              "to '$RESULT'"
2019                         PREV_RESULT=$RESULT
2020                 fi
2021                 [[ $WAIT -ge $MAX ]] && break
2022                 [[ $((WAIT % print)) -eq 0 ]] &&
2023                         echo "Waiting $((MAX - WAIT)) secs for update"
2024                 WAIT=$((WAIT + sleep))
2025                 sleep $sleep
2026         done
2027         echo "Update not seen after ${MAX}s: wanted '$FINAL' got '$RESULT'"
2028         return 3
2029 }
2030
2031 wait_update_facet() {
2032         local facet=$1
2033         shift
2034         wait_update $(facet_active_host $facet) "$@"
2035 }
2036
2037 sync_all_data() {
2038         do_nodes $(comma_list $(mdts_nodes)) \
2039             "lctl set_param -n osd*.*MDT*.force_sync 1"
2040         do_nodes $(comma_list $(osts_nodes)) \
2041             "lctl set_param -n osd*.*OS*.force_sync 1" 2>&1 |
2042                 grep -v 'Found no match'
2043 }
2044
2045 wait_delete_completed_mds() {
2046         local MAX_WAIT=${1:-20}
2047         local mds2sync=""
2048         local stime=$(date +%s)
2049         local etime
2050         local node
2051         local changes
2052
2053         # find MDS with pending deletions
2054         for node in $(mdts_nodes); do
2055                 changes=$(do_node $node "$LCTL get_param -n osc.*MDT*.sync_*" \
2056                         2>/dev/null | calc_sum)
2057                 if [[ $changes -eq 0 ]]; then
2058                         continue
2059                 fi
2060                 mds2sync="$mds2sync $node"
2061         done
2062         if [ -z "$mds2sync" ]; then
2063                 return
2064         fi
2065         mds2sync=$(comma_list $mds2sync)
2066
2067         # sync MDS transactions
2068         do_nodes $mds2sync "$LCTL set_param -n osd*.*MD*.force_sync 1"
2069
2070         # wait till all changes are sent and commmitted by OSTs
2071         # for ldiskfs space is released upon execution, but DMU
2072         # do this upon commit
2073
2074         local WAIT=0
2075         while [[ $WAIT -ne $MAX_WAIT ]]; do
2076                 changes=$(do_nodes $mds2sync \
2077                         "$LCTL get_param -n osc.*MDT*.sync_*" | calc_sum)
2078                 #echo "$node: $changes changes on all"
2079                 if [[ $changes -eq 0 ]]; then
2080                         etime=$(date +%s)
2081                         #echo "delete took $((etime - stime)) seconds"
2082                         return
2083                 fi
2084                 sleep 1
2085                 WAIT=$(( WAIT + 1))
2086         done
2087
2088         etime=$(date +%s)
2089         echo "Delete is not completed in $((etime - stime)) seconds"
2090         do_nodes $mds2sync "$LCTL get_param osc.*MDT*.sync_*"
2091 }
2092
2093 wait_for_host() {
2094     local hostlist=$1
2095
2096     # we can use "for" here because we are waiting the slowest
2097     for host in ${hostlist//,/ }; do
2098         check_network "$host" 900
2099     done
2100     while ! do_nodes $hostlist hostname  > /dev/null; do sleep 5; done
2101 }
2102
2103 wait_for_facet() {
2104     local facetlist=$1
2105     local hostlist
2106
2107     for facet in ${facetlist//,/ }; do
2108         hostlist=$(expand_list $hostlist $(facet_active_host $facet))
2109     done
2110     wait_for_host $hostlist
2111 }
2112
2113 _wait_recovery_complete () {
2114     local param=$1
2115
2116     # Use default policy if $2 is not passed by caller.
2117     local MAX=${2:-$(max_recovery_time)}
2118
2119     local WAIT=0
2120     local STATUS=
2121
2122     while [ $WAIT -lt $MAX ]; do
2123         STATUS=$(lctl get_param -n $param | grep status)
2124         echo $param $STATUS
2125         [[ $STATUS = "status: COMPLETE" || $STATUS = "status: INACTIVE" ]] && return 0
2126         sleep 5
2127         WAIT=$((WAIT + 5))
2128         echo "Waiting $((MAX - WAIT)) secs for $param recovery done. $STATUS"
2129     done
2130     echo "$param recovery not done in $MAX sec. $STATUS"
2131     return 1
2132 }
2133
2134 wait_recovery_complete () {
2135     local facet=$1
2136
2137     # with an assumption that at_max is the same on all nodes
2138     local MAX=${2:-$(max_recovery_time)}
2139
2140     local facets=$facet
2141     if [ "$FAILURE_MODE" = HARD ]; then
2142         facets=$(facets_on_host $(facet_active_host $facet))
2143     fi
2144     echo affected facets: $facets
2145
2146         # we can use "for" here because we are waiting the slowest
2147         for facet in ${facets//,/ }; do
2148                 local var_svc=${facet}_svc
2149                 local param="*.${!var_svc}.recovery_status"
2150
2151                 local host=$(facet_active_host $facet)
2152                 do_rpc_nodes "$host" _wait_recovery_complete $param $MAX
2153         done
2154 }
2155
2156 wait_mds_ost_sync () {
2157         # just because recovery is done doesn't mean we've finished
2158         # orphan cleanup. Wait for llogs to get synchronized.
2159         echo "Waiting for orphan cleanup..."
2160         # MAX value includes time needed for MDS-OST reconnection
2161         local MAX=$(( TIMEOUT * 2 ))
2162         local WAIT_TIMEOUT=${1:-$MAX}
2163         local WAIT=0
2164         local new_wait=true
2165         local list=$(comma_list $(mdts_nodes))
2166         local cmd="$LCTL get_param -n osp.*osc*.old_sync_processed"
2167         if ! do_facet $SINGLEMDS \
2168                 "$LCTL list_param osp.*osc*.old_sync_processed 2> /dev/null"
2169         then
2170                 # old way, use mds_sync
2171                 new_wait=false
2172                 list=$(comma_list $(osts_nodes))
2173                 cmd="$LCTL get_param -n obdfilter.*.mds_sync"
2174         fi
2175
2176         echo "wait $WAIT_TIMEOUT secs maximumly for $list mds-ost sync done."
2177         while [ $WAIT -lt $WAIT_TIMEOUT ]; do
2178                 local -a sync=($(do_nodes $list "$cmd"))
2179                 local con=1
2180                 local i
2181                 for ((i=0; i<${#sync[@]}; i++)); do
2182                         if $new_wait; then
2183                                 [ ${sync[$i]} -eq 1 ] && continue
2184                         else
2185                                 [ ${sync[$i]} -eq 0 ] && continue
2186                         fi
2187                         # there is a not finished MDS-OST synchronization
2188                         con=0
2189                         break;
2190                 done
2191                 sleep 2 # increase waiting time and cover statfs cache
2192                 [ ${con} -eq 1 ] && return 0
2193                 echo "Waiting $WAIT secs for $list $i mds-ost sync done."
2194                 WAIT=$((WAIT + 2))
2195         done
2196
2197         # show which nodes are not finished.
2198         do_nodes $list "$cmd"
2199         echo "$facet recovery node $i not done in $WAIT_TIMEOUT sec. $STATUS"
2200         return 1
2201 }
2202
2203 wait_destroy_complete () {
2204         echo "Waiting for local destroys to complete"
2205         # MAX value shouldn't be big as this mean server responsiveness
2206         # never increase this just to make test pass but investigate
2207         # why it takes so long time
2208         local MAX=5
2209         local WAIT=0
2210         while [ $WAIT -lt $MAX ]; do
2211                 local -a RPCs=($($LCTL get_param -n osc.*.destroys_in_flight))
2212                 local con=1
2213                 local i
2214
2215                 for ((i=0; i<${#RPCs[@]}; i++)); do
2216                         [ ${RPCs[$i]} -eq 0 ] && continue
2217                         # there are still some destroy RPCs in flight
2218                         con=0
2219                         break;
2220                 done
2221                 sleep 1
2222                 [ ${con} -eq 1 ] && return 0 # done waiting
2223                 echo "Waiting ${WAIT}s for local destroys to complete"
2224                 WAIT=$((WAIT + 1))
2225         done
2226         echo "Local destroys weren't done in $MAX sec."
2227         return 1
2228 }
2229
2230 wait_delete_completed() {
2231         wait_delete_completed_mds $1 || return $?
2232         wait_destroy_complete
2233 }
2234
2235 wait_exit_ST () {
2236     local facet=$1
2237
2238     local WAIT=0
2239     local INTERVAL=1
2240     local running
2241     # conf-sanity 31 takes a long time cleanup
2242     while [ $WAIT -lt 300 ]; do
2243         running=$(do_facet ${facet} "lsmod | grep lnet > /dev/null && lctl dl | grep ' ST '") || true
2244         [ -z "${running}" ] && return 0
2245         echo "waited $WAIT for${running}"
2246         [ $INTERVAL -lt 64 ] && INTERVAL=$((INTERVAL + INTERVAL))
2247         sleep $INTERVAL
2248         WAIT=$((WAIT + INTERVAL))
2249     done
2250     echo "service didn't stop after $WAIT seconds.  Still running:"
2251     echo ${running}
2252     return 1
2253 }
2254
2255 wait_remote_prog () {
2256    local prog=$1
2257    local WAIT=0
2258    local INTERVAL=5
2259    local rc=0
2260
2261    [ "$PDSH" = "no_dsh" ] && return 0
2262
2263    while [ $WAIT -lt $2 ]; do
2264         running=$(ps uax | grep "$PDSH.*$prog.*$MOUNT" | grep -v grep) || true
2265         [ -z "${running}" ] && return 0 || true
2266         echo "waited $WAIT for: "
2267         echo "$running"
2268         [ $INTERVAL -lt 60 ] && INTERVAL=$((INTERVAL + INTERVAL))
2269         sleep $INTERVAL
2270         WAIT=$((WAIT + INTERVAL))
2271     done
2272     local pids=$(ps  uax | grep "$PDSH.*$prog.*$MOUNT" | grep -v grep | awk '{print $2}')
2273     [ -z "$pids" ] && return 0
2274     echo "$PDSH processes still exists after $WAIT seconds.  Still running: $pids"
2275     # FIXME: not portable
2276     for pid in $pids; do
2277         cat /proc/${pid}/status || true
2278         cat /proc/${pid}/wchan || true
2279         echo "Killing $pid"
2280         kill -9 $pid || true
2281         sleep 1
2282         ps -P $pid && rc=1
2283     done
2284
2285     return $rc
2286 }
2287
2288 clients_up() {
2289     # not every config has many clients
2290     sleep 1
2291     if [ ! -z "$CLIENTS" ]; then
2292         $PDSH $CLIENTS "stat -f $MOUNT" > /dev/null
2293     else
2294         stat -f $MOUNT > /dev/null
2295     fi
2296 }
2297
2298 client_up() {
2299     local client=$1
2300     # usually checked on particular client or locally
2301     sleep 1
2302     if [ ! -z "$client" ]; then
2303         $PDSH $client "stat -f $MOUNT" > /dev/null
2304     else
2305         stat -f $MOUNT > /dev/null
2306     fi
2307 }
2308
2309 client_evicted() {
2310     ! client_up $1
2311 }
2312
2313 client_reconnect_try() {
2314     uname -n >> $MOUNT/recon
2315     if [ -z "$CLIENTS" ]; then
2316         df $MOUNT; uname -n >> $MOUNT/recon
2317     else
2318         do_nodes $CLIENTS "df $MOUNT; uname -n >> $MOUNT/recon" > /dev/null
2319     fi
2320     echo Connected clients:
2321     cat $MOUNT/recon
2322     ls -l $MOUNT/recon > /dev/null
2323     rm $MOUNT/recon
2324 }
2325
2326 client_reconnect() {
2327         # one client_reconnect_try call does not always do the job...
2328         while true ; do
2329                 client_reconnect_try && break
2330                 sleep 1
2331         done
2332 }
2333
2334 affected_facets () {
2335     local facet=$1
2336
2337     local host=$(facet_active_host $facet)
2338     local affected=$facet
2339
2340     if [ "$FAILURE_MODE" = HARD ]; then
2341         affected=$(facets_up_on_host $host)
2342     fi
2343     echo $affected
2344 }
2345
2346 facet_failover() {
2347         local facets=$1
2348         local sleep_time=$2
2349         local -a affecteds
2350         local facet
2351         local total=0
2352         local index=0
2353         local skip
2354
2355         #Because it will only get up facets, we need get affected
2356         #facets before shutdown
2357         #For HARD Failure mode, it needs make sure facets on the same
2358         #HOST will only be shutdown and reboot once
2359         for facet in ${facets//,/ }; do
2360                 local affected_facet
2361                 skip=0
2362                 #check whether facet has been included in other affected facets
2363                 for ((index=0; index<$total; index++)); do
2364                         [[ *,$facet,* == ,${affecteds[index]}, ]] && skip=1
2365                 done
2366
2367                 if [ $skip -eq 0 ]; then
2368                         affecteds[$total]=$(affected_facets $facet)
2369                         total=$((total+1))
2370                 fi
2371         done
2372
2373         for ((index=0; index<$total; index++)); do
2374                 facet=$(echo ${affecteds[index]} | tr -s " " | cut -d"," -f 1)
2375                 local host=$(facet_active_host $facet)
2376                 echo "Failing ${affecteds[index]} on $host"
2377                 shutdown_facet $facet
2378         done
2379
2380         for ((index=0; index<$total; index++)); do
2381                 facet=$(echo ${affecteds[index]} | tr -s " " | cut -d"," -f 1)
2382                 echo reboot facets: ${affecteds[index]}
2383
2384                 reboot_facet $facet
2385
2386                 change_active ${affecteds[index]}
2387
2388                 wait_for_facet ${affecteds[index]}
2389                 # start mgs first if it is affected
2390                 if ! combined_mgs_mds &&
2391                         list_member ${affecteds[index]} mgs; then
2392                         mount_facet mgs || error "Restart of mgs failed"
2393                 fi
2394                 # FIXME; has to be changed to mount all facets concurrently
2395                 affected=$(exclude_items_from_list ${affecteds[index]} mgs)
2396                 echo mount facets: ${affecteds[index]}
2397                 mount_facets ${affecteds[index]}
2398         done
2399 }
2400
2401 obd_name() {
2402     local facet=$1
2403 }
2404
2405 replay_barrier() {
2406         local facet=$1
2407         do_facet $facet "sync; sync; sync"
2408         df $MOUNT
2409
2410         # make sure there will be no seq change
2411         local clients=${CLIENTS:-$HOSTNAME}
2412         local f=fsa-\\\$\(hostname\)
2413         do_nodes $clients "mcreate $MOUNT/$f; rm $MOUNT/$f"
2414         do_nodes $clients "if [ -d $MOUNT2 ]; then mcreate $MOUNT2/$f; rm $MOUNT2/$f; fi"
2415
2416         local svc=${facet}_svc
2417         do_facet $facet $LCTL --device ${!svc} notransno
2418         #
2419         # If a ZFS OSD is made read-only here, its pool is "freezed". This
2420         # in-memory state has to be cleared by either rebooting the host or
2421         # exporting and reimporting the pool.
2422         #
2423         # Although the uberblocks are not updated when a pool is freezed,
2424         # transactions are still written to the disks. Modified blocks may be
2425         # cached in memory when tests try reading them back. The
2426         # export-and-reimport process also evicts any cached pool data from
2427         # memory to provide the correct "data loss" semantics.
2428         #
2429         # In the test framework, the exporting and importing operations are
2430         # handled by stop() and mount_facet() separately, which are used
2431         # inside fail() and fail_abort().
2432         #
2433         do_facet $facet $LCTL --device ${!svc} readonly
2434         do_facet $facet $LCTL mark "$facet REPLAY BARRIER on ${!svc}"
2435         $LCTL mark "local REPLAY BARRIER on ${!svc}"
2436 }
2437
2438 replay_barrier_nodf() {
2439         local facet=$1    echo running=${running}
2440         do_facet $facet "sync; sync; sync"
2441         local svc=${facet}_svc
2442         echo Replay barrier on ${!svc}
2443         do_facet $facet $LCTL --device ${!svc} notransno
2444         do_facet $facet $LCTL --device ${!svc} readonly
2445         do_facet $facet $LCTL mark "$facet REPLAY BARRIER on ${!svc}"
2446         $LCTL mark "local REPLAY BARRIER on ${!svc}"
2447 }
2448
2449 replay_barrier_nosync() {
2450         local facet=$1    echo running=${running}
2451         local svc=${facet}_svc
2452         echo Replay barrier on ${!svc}
2453         do_facet $facet $LCTL --device ${!svc} notransno
2454         do_facet $facet $LCTL --device ${!svc} readonly
2455         do_facet $facet $LCTL mark "$facet REPLAY BARRIER on ${!svc}"
2456         $LCTL mark "local REPLAY BARRIER on ${!svc}"
2457 }
2458
2459 #
2460 # Get Lustre client uuid for a given Lustre mount point.
2461 #
2462 get_client_uuid() {
2463         local mntpnt=${1:-$MOUNT}
2464
2465         local name=$($LFS getname $mntpnt | cut -d' ' -f1)
2466         local uuid=$($LCTL get_param -n llite.$name.uuid)
2467
2468         echo -n $uuid
2469 }
2470
2471 mds_evict_client() {
2472         local mntpnt=${1:-$MOUNT}
2473         local uuid=$(get_client_uuid $mntpnt)
2474
2475         do_facet $SINGLEMDS \
2476                 "$LCTL set_param -n mdt.${mds1_svc}.evict_client $uuid"
2477 }
2478
2479 ost_evict_client() {
2480         local mntpnt=${1:-$MOUNT}
2481         local uuid=$(get_client_uuid $mntpnt)
2482
2483         do_facet ost1 \
2484                 "$LCTL set_param -n obdfilter.${ost1_svc}.evict_client $uuid"
2485 }
2486
2487 fail() {
2488         local facets=$1
2489         local clients=${CLIENTS:-$HOSTNAME}
2490
2491         facet_failover $* || error "failover: $?"
2492         wait_clients_import_state "$clients" "$facets" FULL
2493         clients_up || error "post-failover df: $?"
2494 }
2495
2496 fail_nodf() {
2497         local facet=$1
2498         facet_failover $facet
2499 }
2500
2501 fail_abort() {
2502         local facet=$1
2503         stop $facet
2504         change_active $facet
2505         wait_for_facet $facet
2506         mount_facet $facet -o abort_recovery
2507         clients_up || echo "first df failed: $?"
2508         clients_up || error "post-failover df: $?"
2509 }
2510
2511 do_lmc() {
2512     echo There is no lmc.  This is mountconf, baby.
2513     exit 1
2514 }
2515
2516 host_nids_address() {
2517     local nodes=$1
2518     local kind=$2
2519
2520     if [ -n "$kind" ]; then
2521         nids=$(do_nodes $nodes "$LCTL list_nids | grep $kind | cut -f 1 -d '@'")
2522     else
2523         nids=$(do_nodes $nodes "$LCTL list_nids all | cut -f 1 -d '@'")
2524     fi
2525     echo $nids
2526 }
2527
2528 h2name_or_ip() {
2529         if [ "$1" = "'*'" ]; then echo \'*\'; else
2530                 echo $1"@$2"
2531         fi
2532 }
2533
2534 h2ptl() {
2535         if [ "$1" = "'*'" ]; then echo \'*\'; else
2536                 ID=`xtprocadmin -n $1 2>/dev/null | egrep -v 'NID' | \
2537                                                         awk '{print $1}'`
2538                 if [ -z "$ID" ]; then
2539                         echo "Could not get a ptl id for $1..."
2540                         exit 1
2541                 fi
2542                 echo $ID"@ptl"
2543         fi
2544 }
2545 declare -fx h2ptl
2546
2547 h2tcp() {
2548         h2name_or_ip "$1" "tcp"
2549 }
2550 declare -fx h2tcp
2551
2552 h2elan() {
2553         if [ "$1" = "'*'" ]; then echo \'*\'; else
2554                 if type __h2elan >/dev/null 2>&1; then
2555                         ID=$(__h2elan $1)
2556                 else
2557                         ID=`echo $1 | sed 's/[^0-9]*//g'`
2558                 fi
2559                 echo $ID"@elan"
2560         fi
2561 }
2562 declare -fx h2elan
2563
2564 h2o2ib() {
2565         h2name_or_ip "$1" "o2ib"
2566 }
2567 declare -fx h2o2ib
2568
2569 # This enables variables in cfg/"setup".sh files to support the pdsh HOSTLIST
2570 # expressions format. As a bonus we can then just pass in those variables
2571 # to pdsh. What this function does is take a HOSTLIST type string and
2572 # expand it into a space deliminated list for us.
2573 hostlist_expand() {
2574     local hostlist=$1
2575     local offset=$2
2576     local myList
2577     local item
2578     local list
2579
2580     [ -z "$hostlist" ] && return
2581
2582     # Translate the case of [..],..,[..] to [..] .. [..]
2583     list="${hostlist/],/] }"
2584     front=${list%%[*}
2585     [[ "$front" == *,* ]] && {
2586         new="${list%,*} "
2587         old="${list%,*},"
2588         list=${list/${old}/${new}}
2589     }
2590
2591     for item in $list; do
2592         # Test if we have any []'s at all
2593         if [ "$item" != "${item/\[/}" ]; then {
2594             # Expand the [*] into list
2595             name=${item%%[*}
2596             back=${item#*]}
2597
2598             if [ "$name" != "$item" ]; then
2599                 group=${item#$name[*}
2600                 group=${group%%]*}
2601
2602                 for range in ${group//,/ }; do
2603                     begin=${range%-*}
2604                     end=${range#*-}
2605
2606                     # Number of leading zeros
2607                     padlen=${#begin}
2608                     padlen2=${#end}
2609                     end=$(echo $end | sed 's/0*//')
2610                     [[ -z "$end" ]] && end=0
2611                     [[ $padlen2 -gt $padlen ]] && {
2612                         [[ $padlen2 -eq ${#end} ]] && padlen2=0
2613                         padlen=$padlen2
2614                     }
2615                     begin=$(echo $begin | sed 's/0*//')
2616                     [ -z $begin ] && begin=0
2617
2618                     for num in $(seq -f "%0${padlen}g" $begin $end); do
2619                         value="${name#*,}${num}${back}"
2620                         [ "$value" != "${value/\[/}" ] && {
2621                             value=$(hostlist_expand "$value")
2622                         }
2623                         myList="$myList $value"
2624                     done
2625                 done
2626             fi
2627         } else {
2628             myList="$myList $item"
2629         } fi
2630     done
2631     myList=${myList//,/ }
2632     myList=${myList:1} # Remove first character which is a space
2633
2634     # Filter any duplicates without sorting
2635     list="$myList "
2636     myList="${list%% *}"
2637
2638     while [[ "$list" != ${myList##* } ]]; do
2639         list=${list//${list%% *} /}
2640         myList="$myList ${list%% *}"
2641     done
2642     myList="${myList%* }";
2643
2644     # We can select an object at a offset in the list
2645     [ $# -eq 2 ] && {
2646         cnt=0
2647         for item in $myList; do
2648             let cnt=cnt+1
2649             [ $cnt -eq $offset ] && {
2650                 myList=$item
2651             }
2652         done
2653         [ $(get_node_count $myList) -ne 1 ] && myList=""
2654     }
2655     echo $myList
2656 }
2657
2658 facet_host() {
2659         local facet=$1
2660         local varname
2661
2662         [ "$facet" == client ] && echo -n $HOSTNAME && return
2663         varname=${facet}_HOST
2664         if [ -z "${!varname}" ]; then
2665                 if [ "${facet:0:3}" == "ost" ]; then
2666                         local fh=${facet%failover}_HOST
2667                         eval export ${facet}_HOST=${!fh}
2668                         if [ -z "${!varname}" ]; then
2669                                 eval export ${facet}_HOST=${ost_HOST}
2670                         fi
2671                 elif [ "${facet:0:3}" == "mdt" -o \
2672                         "${facet:0:3}" == "mds" -o \
2673                         "${facet:0:3}" == "mgs" ]; then
2674                         eval export ${facet}_HOST=${mds_HOST}
2675                 fi
2676         fi
2677         echo -n ${!varname}
2678 }
2679
2680 facet_failover_host() {
2681         local facet=$1
2682         local varname
2683
2684         var=${facet}failover_HOST
2685         if [ -n "${!var}" ]; then
2686                 echo ${!var}
2687                 return
2688         fi
2689
2690         if [ "${facet:0:3}" == "mdt" -o "${facet:0:3}" == "mds" -o \
2691              "${facet:0:3}" == "mgs" ]; then
2692
2693                 eval export ${facet}failover_host=${mds_HOST}
2694                 echo ${mds_HOST}
2695                 return
2696         fi
2697
2698         if [[ $facet == ost* ]]; then
2699                 eval export ${facet}failover_host=${ost_HOST}
2700                 echo ${ost_HOST}
2701                 return
2702         fi
2703 }
2704
2705 facet_active() {
2706     local facet=$1
2707     local activevar=${facet}active
2708
2709     if [ -f $TMP/${facet}active ] ; then
2710         source $TMP/${facet}active
2711     fi
2712
2713     active=${!activevar}
2714     if [ -z "$active" ] ; then
2715         echo -n ${facet}
2716     else
2717         echo -n ${active}
2718     fi
2719 }
2720
2721 facet_active_host() {
2722     local facet=$1
2723     local active=`facet_active $facet`
2724     if [ "$facet" == client ]; then
2725         echo $HOSTNAME
2726     else
2727         echo `facet_host $active`
2728     fi
2729 }
2730
2731 # Get the passive failover partner host of facet.
2732 facet_passive_host() {
2733         local facet=$1
2734         [[ $facet = client ]] && return
2735
2736         local host=${facet}_HOST
2737         local failover_host=${facet}failover_HOST
2738         local active_host=$(facet_active_host $facet)
2739
2740         [[ -z ${!failover_host} || ${!failover_host} = ${!host} ]] && return
2741
2742         if [[ $active_host = ${!host} ]]; then
2743                 echo -n ${!failover_host}
2744         else
2745                 echo -n ${!host}
2746         fi
2747 }
2748
2749 change_active() {
2750     local facetlist=$1
2751     local facet
2752
2753     facetlist=$(exclude_items_from_list $facetlist mgs)
2754
2755     for facet in ${facetlist//,/ }; do
2756     local failover=${facet}failover
2757     local host=`facet_host $failover`
2758     [ -z "$host" ] && return
2759
2760     local curactive=`facet_active $facet`
2761     if [ -z "${curactive}" -o "$curactive" == "$failover" ] ; then
2762         eval export ${facet}active=$facet
2763     else
2764         eval export ${facet}active=$failover
2765     fi
2766     # save the active host for this facet
2767     local activevar=${facet}active
2768     echo "$activevar=${!activevar}" > $TMP/$activevar
2769     [[ $facet = mds1 ]] && combined_mgs_mds && \
2770         echo "mgsactive=${!activevar}" > $TMP/mgsactive
2771     local TO=`facet_active_host $facet`
2772     echo "Failover $facet to $TO"
2773     done
2774 }
2775
2776 do_node() {
2777     local verbose=false
2778     # do not stripe off hostname if verbose, bug 19215
2779     if [ x$1 = x--verbose ]; then
2780         shift
2781         verbose=true
2782     fi
2783
2784     local HOST=$1
2785     shift
2786     local myPDSH=$PDSH
2787     if [ "$HOST" = "$HOSTNAME" ]; then
2788         myPDSH="no_dsh"
2789     elif [ -z "$myPDSH" -o "$myPDSH" = "no_dsh" ]; then
2790         echo "cannot run remote command on $HOST with $myPDSH"
2791         return 128
2792     fi
2793     if $VERBOSE; then
2794         echo "CMD: $HOST $@" >&2
2795         $myPDSH $HOST "$LCTL mark \"$@\"" > /dev/null 2>&1 || :
2796     fi
2797
2798     if [ "$myPDSH" = "rsh" ]; then
2799 # we need this because rsh does not return exit code of an executed command
2800         local command_status="$TMP/cs"
2801         rsh $HOST ":> $command_status"
2802         rsh $HOST "(PATH=\$PATH:$RLUSTRE/utils:$RLUSTRE/tests:/sbin:/usr/sbin;
2803                     cd $RPWD; LUSTRE=\"$RLUSTRE\" sh -c \"$@\") ||
2804                     echo command failed >$command_status"
2805         [ -n "$($myPDSH $HOST cat $command_status)" ] && return 1 || true
2806         return 0
2807     fi
2808
2809     if $verbose ; then
2810         # print HOSTNAME for myPDSH="no_dsh"
2811         if [[ $myPDSH = no_dsh ]]; then
2812             $myPDSH $HOST "(PATH=\$PATH:$RLUSTRE/utils:$RLUSTRE/tests:/sbin:/usr/sbin; cd $RPWD; LUSTRE=\"$RLUSTRE\" sh -c \"$@\")" | sed -e "s/^/${HOSTNAME}: /"
2813         else
2814             $myPDSH $HOST "(PATH=\$PATH:$RLUSTRE/utils:$RLUSTRE/tests:/sbin:/usr/sbin; cd $RPWD; LUSTRE=\"$RLUSTRE\" sh -c \"$@\")"
2815         fi
2816     else
2817         $myPDSH $HOST "(PATH=\$PATH:$RLUSTRE/utils:$RLUSTRE/tests:/sbin:/usr/sbin; cd $RPWD; LUSTRE=\"$RLUSTRE\" sh -c \"$@\")" | sed "s/^${HOST}: //"
2818     fi
2819     return ${PIPESTATUS[0]}
2820 }
2821
2822 do_nodev() {
2823     do_node --verbose "$@"
2824 }
2825
2826 single_local_node () {
2827    [ "$1" = "$HOSTNAME" ]
2828 }
2829
2830 # Outputs environment variable assignments that should be passed to remote nodes
2831 get_env_vars() {
2832         local var
2833         local value
2834         local facets=$(get_facets)
2835         local facet
2836
2837         for var in ${!MODOPTS_*}; do
2838                 value=${!var}
2839                 echo -n " ${var}=\"$value\""
2840         done
2841
2842         for facet in ${facets//,/ }; do
2843                 var=${facet}_FSTYPE
2844                 if [ -n "${!var}" ]; then
2845                         echo -n " $var=${!var}"
2846                 fi
2847         done
2848
2849         for var in MGSFSTYPE MDSFSTYPE OSTFSTYPE; do
2850                 if [ -n "${!var}" ]; then
2851                         echo -n " $var=${!var}"
2852                 fi
2853         done
2854
2855         if [ -n "$FSTYPE" ]; then
2856                 echo -n " FSTYPE=$FSTYPE"
2857         fi
2858 }
2859
2860 do_nodes() {
2861     local verbose=false
2862     # do not stripe off hostname if verbose, bug 19215
2863     if [ x$1 = x--verbose ]; then
2864         shift
2865         verbose=true
2866     fi
2867
2868     local rnodes=$1
2869     shift
2870
2871     if single_local_node $rnodes; then
2872         if $verbose; then
2873            do_nodev $rnodes "$@"
2874         else
2875            do_node $rnodes "$@"
2876         fi
2877         return $?
2878     fi
2879
2880     # This is part from do_node
2881     local myPDSH=$PDSH
2882
2883     [ -z "$myPDSH" -o "$myPDSH" = "no_dsh" -o "$myPDSH" = "rsh" ] && \
2884         echo "cannot run remote command on $rnodes with $myPDSH" && return 128
2885
2886     export FANOUT=$(get_node_count "${rnodes//,/ }")
2887     if $VERBOSE; then
2888         echo "CMD: $rnodes $@" >&2
2889         $myPDSH $rnodes "$LCTL mark \"$@\"" > /dev/null 2>&1 || :
2890     fi
2891
2892     # do not replace anything from pdsh output if -N is used
2893     # -N     Disable hostname: prefix on lines of output.
2894     if $verbose || [[ $myPDSH = *-N* ]]; then
2895         $myPDSH $rnodes "(PATH=\$PATH:$RLUSTRE/utils:$RLUSTRE/tests:/sbin:/usr/sbin; cd $RPWD; LUSTRE=\"$RLUSTRE\" $(get_env_vars) sh -c \"$@\")"
2896     else
2897         $myPDSH $rnodes "(PATH=\$PATH:$RLUSTRE/utils:$RLUSTRE/tests:/sbin:/usr/sbin; cd $RPWD; LUSTRE=\"$RLUSTRE\" $(get_env_vars) sh -c \"$@\")" | sed -re "s/^[^:]*: //g"
2898     fi
2899     return ${PIPESTATUS[0]}
2900 }
2901
2902 do_facet() {
2903     local facet=$1
2904     shift
2905     local HOST=`facet_active_host $facet`
2906     [ -z $HOST ] && echo No host defined for facet ${facet} && exit 1
2907     do_node $HOST "$@"
2908 }
2909
2910 # Function: do_facet_random_file $FACET $FILE $SIZE
2911 # Creates FILE with random content on the given FACET of given SIZE
2912
2913 do_facet_random_file() {
2914         local facet="$1"
2915         local fpath="$2"
2916         local fsize="$3"
2917         local cmd="dd if=/dev/urandom of='$fpath' bs=$fsize count=1"
2918         do_facet $facet "$cmd 2>/dev/null"
2919 }
2920
2921 do_facet_create_file() {
2922         local facet="$1"
2923         local fpath="$2"
2924         local fsize="$3"
2925         local cmd="dd if=/dev/zero of='$fpath' bs=$fsize count=1"
2926         do_facet $facet "$cmd 2>/dev/null"
2927 }
2928
2929 do_nodesv() {
2930     do_nodes --verbose "$@"
2931 }
2932
2933 add() {
2934         local facet=$1
2935         shift
2936         # make sure its not already running
2937         stop ${facet} -f
2938         rm -f $TMP/${facet}active
2939         [[ $facet = mds1 ]] && combined_mgs_mds && rm -f $TMP/mgsactive
2940         do_facet ${facet} $MKFS $* || return ${PIPESTATUS[0]}
2941
2942         if [[ $(facet_fstype $facet) == zfs ]]; then
2943                 #
2944                 # After formatting a ZFS target, "cachefile=none" property will
2945                 # be set on the ZFS storage pool so that the pool is not
2946                 # automatically imported on system startup. And then the pool
2947                 # will be exported so as to leave the importing and exporting
2948                 # operations handled by mount_facet() and stop() separately.
2949                 #
2950                 refresh_partition_table $facet $(facet_vdevice $facet)
2951                 disable_zpool_cache $facet
2952                 export_zpool $facet
2953         fi
2954 }
2955
2956 # Device formatted as ost
2957 ostdevname() {
2958         local num=$1
2959         local DEVNAME=OSTDEV$num
2960
2961         local fstype=$(facet_fstype ost$num)
2962
2963         case $fstype in
2964                 ldiskfs )
2965                         #if $OSTDEVn isn't defined, default is $OSTDEVBASE + num
2966                         eval DEVPTR=${!DEVNAME:=${OSTDEVBASE}${num}};;
2967                 zfs )
2968                         #try $OSTZFSDEVn - independent of vdev
2969                         DEVNAME=OSTZFSDEV$num
2970                         eval DEVPTR=${!DEVNAME:=${FSNAME}-ost${num}/ost${num}};;
2971                 * )
2972                         error "unknown fstype!";;
2973         esac
2974
2975     echo -n $DEVPTR
2976 }
2977
2978 # Physical device location of data
2979 ostvdevname() {
2980         local num=$1
2981         local DEVNAME
2982         local VDEVPTR
2983
2984         local fstype=$(facet_fstype ost$num)
2985
2986         case $fstype in
2987                 ldiskfs )
2988                         # vdevs are not supported by ldiskfs
2989                         eval VDEVPTR="";;
2990                 zfs )
2991                         #if $OSTDEVn isn't defined, default is $OSTDEVBASE{n}
2992                         # Device formated by zfs
2993                         DEVNAME=OSTDEV$num
2994                         eval VDEVPTR=${!DEVNAME:=${OSTDEVBASE}${num}};;
2995                 * )
2996                         error "unknown fstype!";;
2997         esac
2998
2999         echo -n $VDEVPTR
3000 }
3001
3002 # Logical device formated for lustre
3003 mdsdevname() {
3004         local num=$1
3005         local DEVNAME=MDSDEV$num
3006
3007         local fstype=$(facet_fstype mds$num)
3008
3009         case $fstype in
3010                 ldiskfs )
3011                         #if $MDSDEVn isn't defined, default is $MDSDEVBASE{n}
3012                         eval DEVPTR=${!DEVNAME:=${MDSDEVBASE}${num}};;
3013                 zfs )
3014                         # try $MDSZFSDEVn - independent of vdev
3015                         DEVNAME=MDSZFSDEV$num
3016                         eval DEVPTR=${!DEVNAME:=${FSNAME}-mdt${num}/mdt${num}};;
3017                 * )
3018                         error "unknown fstype!";;
3019         esac
3020
3021         echo -n $DEVPTR
3022 }
3023
3024 # Physical location of data
3025 mdsvdevname() {
3026         local VDEVPTR=""
3027         local num=$1
3028         local fstype=$(facet_fstype mds$num)
3029
3030         case $fstype in
3031                 ldiskfs )
3032                         # vdevs are not supported by ldiskfs
3033                         eval VDEVPTR="";;
3034                 zfs )
3035                         # if $MDSDEVn isn't defined, default is $MDSDEVBASE{n}
3036                         # Device formated by ZFS
3037                         local DEVNAME=MDSDEV$num
3038                         eval VDEVPTR=${!DEVNAME:=${MDSDEVBASE}${num}};;
3039                 * )
3040                         error "unknown fstype!";;
3041         esac
3042
3043         echo -n $VDEVPTR
3044 }
3045
3046 mgsdevname() {
3047         local DEVPTR
3048         local fstype=$(facet_fstype mgs)
3049
3050         case $fstype in
3051         ldiskfs )
3052                 if [ $(facet_host mgs) = $(facet_host mds1) ] &&
3053                    ( [ -z "$MGSDEV" ] || [ $MGSDEV = $(mdsdevname 1) ] ); then
3054                         DEVPTR=$(mdsdevname 1)
3055                 else
3056                         DEVPTR=$MGSDEV
3057                 fi;;
3058         zfs )
3059                 if [ $(facet_host mgs) = $(facet_host mds1) ] &&
3060                     ( [ -z "$MGSZFSDEV" ] &&
3061                         [ -z "$MGSDEV" -o "$MGSDEV" = $(mdsvdevname 1) ] ); then
3062                         DEVPTR=$(mdsdevname 1)
3063                 else
3064                         DEVPTR=${MGSZFSDEV:-${FSNAME}-mgs/mgs}
3065                 fi;;
3066         * )
3067                 error "unknown fstype!";;
3068         esac
3069
3070         echo -n $DEVPTR
3071 }
3072
3073 mgsvdevname() {
3074         local VDEVPTR=""
3075
3076         local fstype=$(facet_fstype mgs)
3077
3078         case $fstype in
3079         ldiskfs )
3080                 # vdevs are not supported by ldiskfs
3081                 ;;
3082         zfs )
3083                 if [ $(facet_host mgs) = $(facet_host mds1) ] &&
3084                    ( [ -z "$MGSDEV" ] &&
3085                        [ -z "$MGSZFSDEV" -o "$MGSZFSDEV" = $(mdsdevname 1) ]); then
3086                         VDEVPTR=$(mdsvdevname 1)
3087                 elif [ -n "$MGSDEV" ]; then
3088                         VDEVPTR=$MGSDEV
3089                 fi;;
3090         * )
3091                 error "unknown fstype!";;
3092         esac
3093
3094         echo -n $VDEVPTR
3095 }
3096
3097 facet_mntpt () {
3098     local facet=$1
3099     [[ $facet = mgs ]] && combined_mgs_mds && facet="mds1"
3100
3101     local var=${facet}_MOUNT
3102     eval mntpt=${!var:-${MOUNT%/*}/$facet}
3103
3104     echo -n $mntpt
3105 }
3106
3107 mount_ldiskfs() {
3108         local facet=$1
3109         local dev=$(facet_device $facet)
3110         local mnt=$(facet_mntpt $facet)
3111         local opts
3112
3113         if ! do_facet $facet test -b $dev; then
3114                 opts="-o loop"
3115         fi
3116         do_facet $facet mount -t ldiskfs $opts $dev $mnt
3117 }
3118
3119 unmount_ldiskfs() {
3120         local facet=$1
3121         local dev=$(facet_device $facet)
3122         local mnt=$(facet_mntpt $facet)
3123
3124         do_facet $facet umount -d $mnt
3125 }
3126
3127 var_name() {
3128         echo -n "$1" | tr -c '[:alnum:]\n' '_'
3129 }
3130
3131 mount_zfs() {
3132         local facet=$1
3133         local ds=$(facet_device $facet)
3134         local mnt=$(facet_mntpt $facet)
3135         local canmnt
3136         local mntpt
3137
3138         import_zpool $facet
3139         canmnt=$(do_facet $facet $ZFS get -H -o value canmount $ds)
3140         mntpt=$(do_facet $facet $ZFS get -H -o value mountpoint $ds)
3141         do_facet $facet $ZFS set canmount=noauto $ds
3142         #
3143         # The "legacy" mount method is used here because "zfs unmount $mnt"
3144         # calls stat(2) on $mnt/../*, which may include $MOUNT.  If certain
3145         # targets are not available at the time, the stat(2) on $MOUNT will
3146         # hang.
3147         #
3148         do_facet $facet $ZFS set mountpoint=legacy $ds
3149         do_facet $facet mount -t zfs $ds $mnt
3150         eval export mz_$(var_name ${facet}_$ds)_canmount=$canmnt
3151         eval export mz_$(var_name ${facet}_$ds)_mountpoint=$mntpt
3152 }
3153
3154 unmount_zfs() {
3155         local facet=$1
3156         local ds=$(facet_device $facet)
3157         local mnt=$(facet_mntpt $facet)
3158         local var_mntpt=mz_$(var_name ${facet}_$ds)_mountpoint
3159         local var_canmnt=mz_$(var_name ${facet}_$ds)_canmount
3160         local mntpt=${!var_mntpt}
3161         local canmnt=${!var_canmnt}
3162
3163         unset $var_mntpt
3164         unset $var_canmnt
3165         do_facet $facet umount $mnt
3166         do_facet $facet $ZFS set mountpoint=$mntpt $ds
3167         do_facet $facet $ZFS set canmount=$canmnt $ds
3168         export_zpool $facet
3169 }
3170
3171 mount_fstype() {
3172         local facet=$1
3173         local fstype=$(facet_fstype $facet)
3174
3175         mount_$fstype $facet
3176 }
3177
3178 unmount_fstype() {
3179         local facet=$1
3180         local fstype=$(facet_fstype $facet)
3181
3182         unmount_$fstype $facet
3183 }
3184
3185 ########
3186 ## MountConf setup
3187
3188 stopall() {
3189     # make sure we are using the primary server, so test-framework will
3190     # be able to clean up properly.
3191     activemds=`facet_active mds1`
3192     if [ $activemds != "mds1" ]; then
3193         fail mds1
3194     fi
3195
3196     local clients=$CLIENTS
3197     [ -z $clients ] && clients=$(hostname)
3198
3199     zconf_umount_clients $clients $MOUNT "$*" || true
3200     [ -n "$MOUNT2" ] && zconf_umount_clients $clients $MOUNT2 "$*" || true
3201
3202     [ "$CLIENTONLY" ] && return
3203     # The add fn does rm ${facet}active file, this would be enough
3204     # if we use do_facet <facet> only after the facet added, but
3205     # currently we use do_facet mds in local.sh
3206     for num in `seq $MDSCOUNT`; do
3207         stop mds$num -f
3208         rm -f ${TMP}/mds${num}active
3209     done
3210     combined_mgs_mds && rm -f $TMP/mgsactive
3211
3212     for num in `seq $OSTCOUNT`; do
3213         stop ost$num -f
3214         rm -f $TMP/ost${num}active
3215     done
3216
3217     if ! combined_mgs_mds ; then
3218         stop mgs
3219     fi
3220
3221     return 0
3222 }
3223
3224 cleanup_echo_devs () {
3225     local devs=$($LCTL dl | grep echo | awk '{print $4}')
3226
3227     for dev in $devs; do
3228         $LCTL --device $dev cleanup
3229         $LCTL --device $dev detach
3230     done
3231 }
3232
3233 cleanupall() {
3234     nfs_client_mode && return
3235
3236     stopall $*
3237     cleanup_echo_devs
3238
3239     unload_modules
3240     cleanup_gss
3241 }
3242
3243 combined_mgs_mds () {
3244         [[ "$(mdsdevname 1)" = "$(mgsdevname)" ]] &&
3245                 [[ "$(facet_host mds1)" = "$(facet_host mgs)" ]]
3246 }
3247
3248 lower() {
3249         echo -n "$1" | tr '[:upper:]' '[:lower:]'
3250 }
3251
3252 upper() {
3253         echo -n "$1" | tr '[:lower:]' '[:upper:]'
3254 }
3255
3256 mkfs_opts() {
3257         local facet=$1
3258         local dev=$2
3259         local fsname=${3:-"$FSNAME"}
3260         local type=$(facet_type $facet)
3261         local index=$(($(facet_number $facet) - 1))
3262         local fstype=$(facet_fstype $facet)
3263         local host=$(facet_host $facet)
3264         local opts
3265         local fs_mkfs_opts
3266         local var
3267
3268         if [ $type == MGS ] && combined_mgs_mds; then
3269                 return 1
3270         fi
3271
3272         if [ $type == MGS ] || ( [ $type == MDS ] &&
3273                                  [ "$dev" == $(mgsdevname) ] &&
3274                                  [ "$host" == "$(facet_host mgs)" ] ); then
3275                 opts="--mgs"
3276         else
3277                 opts="--mgsnode=$MGSNID"
3278         fi
3279
3280         if [ $type != MGS ]; then
3281                 opts+=" --fsname=$fsname --$(lower ${type/MDS/MDT}) \
3282                         --index=$index"
3283         fi
3284
3285         var=${facet}failover_HOST
3286         if [ -n "${!var}" ] && [ ${!var} != $(facet_host $facet) ]; then
3287                 opts+=" --failnode=$(h2$NETTYPE ${!var})"
3288         fi
3289
3290         opts+=${TIMEOUT:+" --param=sys.timeout=$TIMEOUT"}
3291         opts+=${LDLM_TIMEOUT:+" --param=sys.ldlm_timeout=$LDLM_TIMEOUT"}
3292
3293         if [ $type == MDS ]; then
3294                 opts+=${SECLEVEL:+" --param=mdt.sec_level"}
3295                 opts+=${MDSCAPA:+" --param-mdt.capa=$MDSCAPA"}
3296                 opts+=${STRIPE_BYTES:+" --param=lov.stripesize=$STRIPE_BYTES"}
3297                 opts+=${STRIPES_PER_OBJ:+" --param=lov.stripecount=$STRIPES_PER_OBJ"}
3298                 opts+=${L_GETIDENTITY:+" --param=mdt.identity_upcall=$L_GETIDENTITY"}
3299
3300                 if [ $fstype == ldiskfs ]; then
3301                         # Check for wide striping
3302                         if [ $OSTCOUNT -gt 160 ]; then
3303                                 MDSJOURNALSIZE=${MDSJOURNALSIZE:-4096}
3304                                 fs_mkfs_opts+="-O large_xattr"
3305                         fi
3306
3307                         fs_mkfs_opts+=${MDSJOURNALSIZE:+" -J size=$MDSJOURNALSIZE"}
3308                         if [ ! -z $EJOURNAL ]; then
3309                                 fs_mkfs_opts+=${MDSJOURNALSIZE:+" device=$EJOURNAL"}
3310                         fi
3311                         fs_mkfs_opts+=${MDSISIZE:+" -i $MDSISIZE"}
3312                 fi
3313         fi
3314
3315         if [ $type == OST ]; then
3316                 opts+=${SECLEVEL:+" --param=ost.sec_level"}
3317                 opts+=${OSSCAPA:+" --param=ost.capa=$OSSCAPA"}
3318
3319                 if [ $fstype == ldiskfs ]; then
3320                         fs_mkfs_opts+=${OSTJOURNALSIZE:+" -J size=$OSTJOURNALSIZE"}
3321                 fi
3322         fi
3323
3324         opts+=" --backfstype=$fstype"
3325
3326         var=${type}SIZE
3327         if [ -n "${!var}" ]; then
3328                 opts+=" --device-size=${!var}"
3329         fi
3330
3331         var=$(upper $fstype)_MKFS_OPTS
3332         fs_mkfs_opts+=${!var:+" ${!var}"}
3333
3334         var=${type}_FS_MKFS_OPTS
3335         fs_mkfs_opts+=${!var:+" ${!var}"}
3336
3337         if [ -n "${fs_mkfs_opts## }" ]; then
3338                 opts+=" --mkfsoptions=\\\"${fs_mkfs_opts## }\\\""
3339         fi
3340
3341         var=${type}OPT
3342         opts+=${!var:+" ${!var}"}
3343
3344         echo -n "$opts"
3345 }
3346
3347 formatall() {
3348         local quiet
3349
3350         if ! $VERBOSE; then
3351                 quiet=yes
3352         fi
3353
3354         stopall
3355         # We need ldiskfs here, may as well load them all
3356         load_modules
3357         [ "$CLIENTONLY" ] && return
3358         echo Formatting mgs, mds, osts
3359         if ! combined_mgs_mds ; then
3360                 echo "Format mgs: $(mgsdevname)"
3361                 add mgs $(mkfs_opts mgs $(mgsdevname)) --reformat \
3362                         $(mgsdevname) $(mgsvdevname) ${quiet:+>/dev/null} ||
3363                         exit 10
3364         fi
3365
3366         for num in $(seq $MDSCOUNT); do
3367                 echo "Format mds$num: $(mdsdevname $num)"
3368                 add mds$num $(mkfs_opts mds$num $(mdsdevname ${num})) \
3369                         --reformat $(mdsdevname $num) $(mdsvdevname $num) \
3370                         ${quiet:+>/dev/null} || exit 10
3371         done
3372
3373         for num in $(seq $OSTCOUNT); do
3374                 echo "Format ost$num: $(ostdevname $num)"
3375                 add ost$num $(mkfs_opts ost$num $(ostdevname ${num})) \
3376                         --reformat $(ostdevname $num) $(ostvdevname ${num}) \
3377                         ${quiet:+>/dev/null} || exit 10
3378         done
3379 }
3380
3381 mount_client() {
3382     grep " $1 " /proc/mounts || zconf_mount $HOSTNAME $*
3383 }
3384
3385 umount_client() {
3386     grep " $1 " /proc/mounts && zconf_umount `hostname` $*
3387 }
3388
3389 # return value:
3390 # 0: success, the old identity set already.
3391 # 1: success, the old identity does not set.
3392 # 2: fail.
3393 switch_identity() {
3394     local num=$1
3395     local switch=$2
3396     local j=`expr $num - 1`
3397     local MDT="`(do_facet mds$num lctl get_param -N mdt.*MDT*$j 2>/dev/null | cut -d"." -f2 2>/dev/null) || true`"
3398
3399     if [ -z "$MDT" ]; then
3400         return 2
3401     fi
3402
3403     local old="`do_facet mds$num "lctl get_param -n mdt.$MDT.identity_upcall"`"
3404
3405     if $switch; then
3406         do_facet mds$num "lctl set_param -n mdt.$MDT.identity_upcall \"$L_GETIDENTITY\""
3407     else
3408         do_facet mds$num "lctl set_param -n mdt.$MDT.identity_upcall \"NONE\""
3409     fi
3410
3411     do_facet mds$num "lctl set_param -n mdt/$MDT/identity_flush=-1"
3412
3413     if [ $old = "NONE" ]; then
3414         return 1
3415     else
3416         return 0
3417     fi
3418 }
3419
3420 remount_client()
3421 {
3422         zconf_umount `hostname` $1 || error "umount failed"
3423         zconf_mount `hostname` $1 || error "mount failed"
3424 }
3425
3426 writeconf_facet() {
3427         local facet=$1
3428         local dev=$2
3429
3430         stop ${facet} -f
3431         rm -f $TMP/${facet}active
3432         do_facet ${facet} "$TUNEFS --quiet --writeconf $dev" || return 1
3433         return 0
3434 }
3435
3436 writeconf_all () {
3437         local mdt_count=${1:-$MDSCOUNT}
3438         local ost_count=${2:-$OSTCOUNT}
3439         local rc=0
3440
3441         for num in $(seq $mdt_count); do
3442                 DEVNAME=$(mdsdevname $num)
3443                 writeconf_facet mds$num $DEVNAME || rc=$?
3444         done
3445
3446         for num in $(seq $ost_count); do
3447                 DEVNAME=$(ostdevname $num)
3448                 writeconf_facet ost$num $DEVNAME || rc=$?
3449         done
3450         return $rc
3451 }
3452
3453 setupall() {
3454     nfs_client_mode && return
3455
3456     sanity_mount_check ||
3457         error "environments are insane!"
3458
3459     load_modules
3460
3461     if [ -z "$CLIENTONLY" ]; then
3462         echo Setup mgs, mdt, osts
3463         echo $WRITECONF | grep -q "writeconf" && \
3464             writeconf_all
3465         if ! combined_mgs_mds ; then
3466                         start mgs $(mgsdevname) $MGS_MOUNT_OPTS
3467         fi
3468
3469         for num in `seq $MDSCOUNT`; do
3470             DEVNAME=$(mdsdevname $num)
3471             start mds$num $DEVNAME $MDS_MOUNT_OPTS
3472
3473             # We started mds, now we should set failover variables properly.
3474             # Set mds${num}failover_HOST if it is not set (the default failnode).
3475             local varname=mds${num}failover_HOST
3476             if [ -z "${!varname}" ]; then
3477                 eval mds${num}failover_HOST=$(facet_host mds$num)
3478             fi
3479
3480             if [ $IDENTITY_UPCALL != "default" ]; then
3481                 switch_identity $num $IDENTITY_UPCALL
3482             fi
3483         done
3484         for num in `seq $OSTCOUNT`; do
3485             DEVNAME=$(ostdevname $num)
3486             start ost$num $DEVNAME $OST_MOUNT_OPTS
3487
3488             # We started ost$num, now we should set ost${num}failover variable properly.
3489             # Set ost${num}failover_HOST if it is not set (the default failnode).
3490             varname=ost${num}failover_HOST
3491             if [ -z "${!varname}" ]; then
3492                 eval ost${num}failover_HOST=$(facet_host ost${num})
3493             fi
3494
3495         done
3496     fi
3497
3498     init_gss
3499
3500     # wait a while to allow sptlrpc configuration be propogated to targets,
3501     # only needed when mounting new target devices.
3502     if $GSS; then
3503         sleep 10
3504     fi
3505
3506     [ "$DAEMONFILE" ] && $LCTL debug_daemon start $DAEMONFILE $DAEMONSIZE
3507     mount_client $MOUNT
3508     [ -n "$CLIENTS" ] && zconf_mount_clients $CLIENTS $MOUNT
3509     clients_up
3510
3511     if [ "$MOUNT_2" ]; then
3512         mount_client $MOUNT2
3513         [ -n "$CLIENTS" ] && zconf_mount_clients $CLIENTS $MOUNT2
3514     fi
3515
3516     init_param_vars
3517
3518     # by remounting mdt before ost, initial connect from mdt to ost might
3519     # timeout because ost is not ready yet. wait some time to its fully
3520     # recovery. initial obd_connect timeout is 5s; in GSS case it's preceeded
3521     # by a context negotiation rpc with $TIMEOUT.
3522     # FIXME better by monitoring import status.
3523     if $GSS; then
3524         set_flavor_all $SEC
3525         sleep $((TIMEOUT + 5))
3526     else
3527         sleep 5
3528     fi
3529 }
3530
3531 mounted_lustre_filesystems() {
3532         awk '($3 ~ "lustre" && $1 ~ ":") { print $2 }' /proc/mounts
3533 }
3534
3535 init_facet_vars () {
3536         [ "$CLIENTONLY" ] && return 0
3537         local facet=$1
3538         shift
3539         local device=$1
3540
3541         shift
3542
3543         eval export ${facet}_dev=${device}
3544         eval export ${facet}_opt=\"$@\"
3545
3546         local dev=${facet}_dev
3547
3548         # We need to loop for the label
3549         # in case its not initialized yet.
3550         for wait_time in {0,1,3,5,10}; do
3551
3552                 if [ $wait_time -gt 0 ]; then
3553                         echo "${!dev} not yet initialized,"\
3554                                 "waiting ${wait_time} seconds."
3555                         sleep $wait_time
3556                 fi
3557
3558                 local label=$(devicelabel ${facet} ${!dev})
3559
3560                 # Check to make sure the label does
3561                 # not include ffff at the end of the label.
3562                 # This indicates it has not been initialized yet.
3563
3564                 if [[ $label =~ [f|F]{4}$ ]]; then
3565                         # label is not initialized, unset the result
3566                         # and either try again or fail
3567                         unset label
3568                 else
3569                         break
3570                 fi
3571         done
3572
3573         [ -z "$label" ] && echo no label for ${!dev} && exit 1
3574
3575         eval export ${facet}_svc=${label}
3576
3577         local varname=${facet}failover_HOST
3578         if [ -z "${!varname}" ]; then
3579                 eval export $varname=$(facet_host $facet)
3580         fi
3581
3582         varname=${facet}_HOST
3583         if [ -z "${!varname}" ]; then
3584                 eval export $varname=$(facet_host $facet)
3585         fi
3586
3587         # ${facet}failover_dev is set in cfg file
3588         varname=${facet}failover_dev
3589         if [ -n "${!varname}" ] ; then
3590                 eval export ${facet}failover_dev=${!varname}
3591         else
3592                 eval export ${facet}failover_dev=$device
3593         fi
3594
3595         # get mount point of already mounted device
3596         # is facet_dev is already mounted then use the real
3597         #  mount point of this facet; otherwise use $(facet_mntpt $facet)
3598         # i.e. ${facet}_MOUNT if specified by user or default
3599         local mntpt=$(do_facet ${facet} cat /proc/mounts | \
3600                         awk '"'${!dev}'" == $1 && $3 == "lustre" { print $2 }')
3601         if [ -z $mntpt ]; then
3602                 mntpt=$(facet_mntpt $facet)
3603         fi
3604         eval export ${facet}_MOUNT=$mntpt
3605 }
3606
3607 init_facets_vars () {
3608         local DEVNAME
3609
3610         if ! remote_mds_nodsh; then
3611                 for num in $(seq $MDSCOUNT); do
3612                         DEVNAME=`mdsdevname $num`
3613                         init_facet_vars mds$num $DEVNAME $MDS_MOUNT_OPTS
3614                 done
3615         fi
3616
3617         combined_mgs_mds || init_facet_vars mgs $(mgsdevname) $MGS_MOUNT_OPTS
3618
3619         if ! remote_ost_nodsh; then
3620                 for num in $(seq $OSTCOUNT); do
3621                         DEVNAME=$(ostdevname $num)
3622                         init_facet_vars ost$num $DEVNAME $OST_MOUNT_OPTS
3623                 done
3624         fi
3625 }
3626
3627 osc_ensure_active () {
3628     local facet=$1
3629     local timeout=$2
3630     local period=0
3631
3632     while [ $period -lt $timeout ]; do
3633         count=$(do_facet $facet "lctl dl | grep ' IN osc ' 2>/dev/null | wc -l")
3634         if [ $count -eq 0 ]; then
3635             break
3636         fi
3637
3638         echo "There are $count OST are inactive, wait $period seconds, and try again"
3639         sleep 3
3640         period=$((period+3))
3641     done
3642
3643     [ $period -lt $timeout ] || log "$count OST are inactive after $timeout seconds, give up"
3644 }
3645
3646 set_conf_param_and_check() {
3647         local myfacet=$1
3648         local TEST=$2
3649         local PARAM=$3
3650         local ORIG=$(do_facet $myfacet "$TEST")
3651         if [ $# -gt 3 ]; then
3652                 local FINAL=$4
3653         else
3654                 local -i FINAL
3655                 FINAL=$((ORIG + 5))
3656         fi
3657         echo "Setting $PARAM from $ORIG to $FINAL"
3658         do_facet mgs "$LCTL conf_param $PARAM='$FINAL'" ||
3659                 error "conf_param $PARAM failed"
3660
3661         wait_update $(facet_host $myfacet) "$TEST" "$FINAL" ||
3662                 error "check $PARAM failed!"
3663 }
3664
3665 init_param_vars () {
3666         remote_mds_nodsh ||
3667                 TIMEOUT=$(do_facet $SINGLEMDS "lctl get_param -n timeout")
3668
3669         log "Using TIMEOUT=$TIMEOUT"
3670
3671         osc_ensure_active $SINGLEMDS $TIMEOUT
3672         osc_ensure_active client $TIMEOUT
3673
3674         if [ -n "$(lctl get_param -n mdc.*.connect_flags|grep jobstats)" ]; then
3675                 local current_jobid_var=$($LCTL get_param -n jobid_var)
3676
3677                 if [ $JOBID_VAR = "existing" ]; then
3678                         echo "keeping jobstats as $current_jobid_var"
3679                 elif [ $current_jobid_var != $JOBID_VAR ]; then
3680                         echo "seting jobstats to $JOBID_VAR"
3681
3682                         set_conf_param_and_check client                 \
3683                                 "$LCTL get_param -n jobid_var"          \
3684                                 "$FSNAME.sys.jobid_var" $JOBID_VAR
3685                 fi
3686         else
3687                 echo "jobstats not supported by server"
3688         fi
3689
3690         if [ $QUOTA_AUTO -ne 0 ]; then
3691                 if [ "$ENABLE_QUOTA" ]; then
3692                         echo "enable quota as required"
3693                         setup_quota $MOUNT || return 2
3694                 else
3695                         echo "disable quota as required"
3696                         # $LFS quotaoff -ug $MOUNT > /dev/null 2>&1
3697                 fi
3698         fi
3699         return 0
3700 }
3701
3702 nfs_client_mode () {
3703     if [ "$NFSCLIENT" ]; then
3704         echo "NFSCLIENT mode: setup, cleanup, check config skipped"
3705         local clients=$CLIENTS
3706         [ -z $clients ] && clients=$(hostname)
3707
3708         # FIXME: remove hostname when 19215 fixed
3709         do_nodes $clients "echo \\\$(hostname); grep ' '$MOUNT' ' /proc/mounts"
3710         declare -a nfsexport=(`grep ' '$MOUNT' ' /proc/mounts | awk '{print $1}' | awk -F: '{print $1 " "  $2}'`)
3711         if [[ ${#nfsexport[@]} -eq 0 ]]; then
3712                 error_exit NFSCLIENT=$NFSCLIENT mode, but no NFS export found!
3713         fi
3714         do_nodes ${nfsexport[0]} "echo \\\$(hostname); df -T  ${nfsexport[1]}"
3715         return
3716     fi
3717     return 1
3718 }
3719
3720 check_config_client () {
3721     local mntpt=$1
3722
3723     local mounted=$(mount | grep " $mntpt ")
3724     if [ "$CLIENTONLY" ]; then
3725         # bug 18021
3726         # CLIENTONLY should not depend on *_HOST settings
3727         local mgc=$($LCTL device_list | awk '/MGC/ {print $4}')
3728         # in theory someone could create a new,
3729         # client-only config file that assumed lustre was already
3730         # configured and didn't set the MGSNID. If MGSNID is not set,
3731         # then we should use the mgs nid currently being used 
3732         # as the default value. bug 18021
3733         [[ x$MGSNID = x ]] &&
3734             MGSNID=${mgc//MGC/}
3735
3736         if [[ x$mgc != xMGC$MGSNID ]]; then
3737             if [ "$mgs_HOST" ]; then
3738                 local mgc_ip=$(ping -q -c1 -w1 $mgs_HOST | grep PING | awk '{print $3}' | sed -e "s/(//g" -e "s/)//g")
3739 #                [[ x$mgc = xMGC$mgc_ip@$NETTYPE ]] ||
3740 #                    error_exit "MGSNID=$MGSNID, mounted: $mounted, MGC : $mgc"
3741             fi
3742         fi
3743         return 0
3744     fi
3745
3746     local myMGS_host=$mgs_HOST   
3747     if [ "$NETTYPE" = "ptl" ]; then
3748         myMGS_host=$(h2ptl $mgs_HOST | sed -e s/@ptl//) 
3749     fi
3750
3751     echo Checking config lustre mounted on $mntpt
3752     local mgshost=$(mount | grep " $mntpt " | awk -F@ '{print $1}')
3753     mgshost=$(echo $mgshost | awk -F: '{print $1}')
3754
3755 #    if [ "$mgshost" != "$myMGS_host" ]; then
3756 #            log "Bad config file: lustre is mounted with mgs $mgshost, but mgs_HOST=$mgs_HOST, NETTYPE=$NETTYPE
3757 #                   Please use correct config or set mds_HOST correctly!"
3758 #    fi
3759
3760 }
3761
3762 check_config_clients () {
3763         local clients=${CLIENTS:-$HOSTNAME}
3764         local mntpt=$1
3765
3766         nfs_client_mode && return
3767
3768         do_rpc_nodes "$clients" check_config_client $mntpt
3769
3770         sanity_mount_check || error "environments are insane!"
3771 }
3772
3773 check_timeout () {
3774     local mdstimeout=$(do_facet $SINGLEMDS "lctl get_param -n timeout")
3775     local cltimeout=$(lctl get_param -n timeout)
3776     if [ $mdstimeout -ne $TIMEOUT ] || [ $mdstimeout -ne $cltimeout ]; then
3777         error "timeouts are wrong! mds: $mdstimeout, client: $cltimeout, TIMEOUT=$TIMEOUT"
3778         return 1
3779     fi
3780 }
3781
3782 is_mounted () {
3783     local mntpt=$1
3784     [ -z $mntpt ] && return 1
3785     local mounted=$(mounted_lustre_filesystems)
3786
3787     echo $mounted' ' | grep -w -q $mntpt' '
3788 }
3789
3790 is_empty_dir() {
3791         [ $(find $1 -maxdepth 1 -print | wc -l) = 1 ] && return 0
3792         return 1
3793 }
3794
3795 # empty lustre filesystem may have empty directories lost+found and .lustre
3796 is_empty_fs() {
3797         # exclude .lustre & lost+found
3798         [ $(find $1 -maxdepth 1 -name lost+found -o -name .lustre -prune -o \
3799                 -print | wc -l) = 1 ] || return 1
3800         [ ! -d $1/lost+found ] || is_empty_dir $1/lost+found || return 1
3801         if [ $(lustre_version_code $SINGLEMDS) -gt $(version_code 2.4.0) ]; then
3802                 # exclude .lustre/fid (LU-2780)
3803                 [ $(find $1/.lustre -maxdepth 1 -name fid -prune -o \
3804                         -print | wc -l) = 1 ] || return 1
3805         else
3806                 [ ! -d $1/.lustre ] || is_empty_dir $1/.lustre || return 1
3807         fi
3808         return 0
3809 }
3810
3811 check_and_setup_lustre() {
3812     nfs_client_mode && return
3813
3814     local MOUNTED=$(mounted_lustre_filesystems)
3815
3816     local do_check=true
3817     # 1.
3818     # both MOUNT and MOUNT2 are not mounted
3819     if ! is_mounted $MOUNT && ! is_mounted $MOUNT2; then
3820         [ "$REFORMAT" ] && formatall
3821         # setupall mounts both MOUNT and MOUNT2 (if MOUNT_2 is set)
3822         setupall
3823         is_mounted $MOUNT || error "NAME=$NAME not mounted"
3824         export I_MOUNTED=yes
3825         do_check=false
3826     # 2.
3827     # MOUNT2 is mounted
3828     elif is_mounted $MOUNT2; then
3829             # 3.
3830             # MOUNT2 is mounted, while MOUNT_2 is not set
3831             if ! [ "$MOUNT_2" ]; then
3832                 cleanup_mount $MOUNT2
3833                 export I_UMOUNTED2=yes
3834
3835             # 4.
3836             # MOUNT2 is mounted, MOUNT_2 is set
3837             else
3838                 # FIXME: what to do if check_config failed?
3839                 # i.e. if:
3840                 # 1) remote client has mounted other Lustre fs ?
3841                 # 2) it has insane env ?
3842                 # let's try umount MOUNT2 on all clients and mount it again:
3843                 if ! check_config_clients $MOUNT2; then
3844                     cleanup_mount $MOUNT2
3845                     restore_mount $MOUNT2
3846                     export I_MOUNTED2=yes
3847                 fi
3848             fi 
3849
3850     # 5.
3851     # MOUNT is mounted MOUNT2 is not mounted
3852     elif [ "$MOUNT_2" ]; then
3853         restore_mount $MOUNT2
3854         export I_MOUNTED2=yes
3855     fi
3856
3857     if $do_check; then
3858         # FIXME: what to do if check_config failed?
3859         # i.e. if:
3860         # 1) remote client has mounted other Lustre fs?
3861         # 2) lustre is mounted on remote_clients atall ?
3862         check_config_clients $MOUNT
3863         init_facets_vars
3864         init_param_vars
3865
3866         set_default_debug_nodes $(comma_list $(nodes_list))
3867     fi
3868
3869         if [ $(lower $OSD_TRACK_DECLARES_LBUG) == 'yes' ] ; then
3870                 local facets=""
3871                 [ "$(facet_fstype ost1)" = "ldiskfs" ] &&
3872                         facets="$(get_facets OST)"
3873                 [ "$(facet_fstype mds1)" = "ldiskfs" ] &&
3874                         facets="$facets,$(get_facets MDS)"
3875                 [ "$(facet_fstype mgs)" = "ldiskfs" ] &&
3876                         facets="$facets,mgs"
3877                 local nodes="$(facets_hosts ${facets})"
3878                 if [ -n "$nodes" ] ; then
3879                         do_nodes $nodes "$LCTL set_param \
3880                                  osd-ldiskfs.track_declares_assert=1 || true"
3881                 fi
3882         fi
3883
3884         init_gss
3885         if $GSS; then
3886                 set_flavor_all $SEC
3887         fi
3888
3889         #Enable remote MDT create for testing
3890         for num in $(seq $MDSCOUNT); do
3891                 do_facet mds$num \
3892                         lctl set_param -n mdt.${FSNAME}*.enable_remote_dir=1 \
3893                                 2>/dev/null
3894         done
3895
3896         if [ "$ONLY" == "setup" ]; then
3897                 exit 0
3898         fi
3899 }
3900
3901 restore_mount () {
3902    local clients=${CLIENTS:-$HOSTNAME}
3903    local mntpt=$1
3904
3905    zconf_mount_clients $clients $mntpt
3906 }
3907
3908 cleanup_mount () {
3909         local clients=${CLIENTS:-$HOSTNAME}
3910         local mntpt=$1
3911
3912         zconf_umount_clients $clients $mntpt
3913 }
3914
3915 cleanup_and_setup_lustre() {
3916     if [ "$ONLY" == "cleanup" -o "`mount | grep $MOUNT`" ]; then
3917         lctl set_param debug=0 || true
3918         cleanupall
3919         if [ "$ONLY" == "cleanup" ]; then
3920             exit 0
3921         fi
3922     fi
3923     check_and_setup_lustre
3924 }
3925
3926 # Get all of the server target devices from a given server node and type.
3927 get_mnt_devs() {
3928         local node=$1
3929         local type=$2
3930         local devs
3931         local dev
3932
3933         if [ "$type" == ost ]; then
3934                 devs=$(get_osd_param $node "" mntdev)
3935         else
3936                 devs=$(do_node $node $LCTL get_param -n osd-*.$FSNAME-M*.mntdev)
3937         fi
3938         for dev in $devs; do
3939                 case $dev in
3940                 *loop*) do_node $node "losetup $dev" | \
3941                                 sed -e "s/.*(//" -e "s/).*//" ;;
3942                 *) echo $dev ;;
3943                 esac
3944         done
3945 }
3946
3947 # Get all of the server target devices.
3948 get_svr_devs() {
3949         local node
3950         local i
3951
3952         # Master MDS parameters used by lfsck
3953         MDTNODE=$(facet_active_host $SINGLEMDS)
3954         MDTDEV=$(echo $(get_mnt_devs $MDTNODE mdt) | awk '{print $1}')
3955
3956         # MDT devices
3957         i=0
3958         for node in $(mdts_nodes); do
3959                 MDTDEVS[i]=$(get_mnt_devs $node mdt)
3960                 i=$((i + 1))
3961         done
3962
3963         # OST devices
3964         i=0
3965         for node in $(osts_nodes); do
3966                 OSTDEVS[i]=$(get_mnt_devs $node ost)
3967                 i=$((i + 1))
3968         done
3969 }
3970
3971 # Run e2fsck on MDT or OST device.
3972 run_e2fsck() {
3973         local node=$1
3974         local target_dev=$2
3975         local extra_opts=$3
3976         local cmd="$E2FSCK -d -v -t -t -f $extra_opts $target_dev"
3977         local log=$TMP/e2fsck.log
3978         local rc=0
3979
3980         echo $cmd
3981         do_node $node $cmd 2>&1 | tee $log
3982         rc=${PIPESTATUS[0]}
3983         if [ -n "$(grep "DNE mode isn't supported" $log)" ]; then
3984                 rm -f $log
3985                 if [ $MDSCOUNT -gt 1 ]; then
3986                         skip "DNE mode isn't supported!"
3987                         cleanupall
3988                         exit_status
3989                 else
3990                         error "It's not DNE mode."
3991                 fi
3992         fi
3993         rm -f $log
3994
3995         [ $rc -le $FSCK_MAX_ERR ] ||
3996                 error "$cmd returned $rc, should be <= $FSCK_MAX_ERR"
3997
3998         return 0
3999 }
4000
4001 #
4002 # Run resize2fs on MDT or OST device.
4003 #
4004 run_resize2fs() {
4005         local facet=$1
4006         local device=$2
4007         local size=$3
4008         shift 3
4009         local opts="$@"
4010
4011         do_facet $facet "$RESIZE2FS $opts $device $size"
4012 }
4013
4014 # verify a directory is shared among nodes.
4015 check_shared_dir() {
4016         local dir=$1
4017         local list=${2:-$(comma_list $(nodes_list))}
4018
4019         [ -z "$dir" ] && return 1
4020         do_rpc_nodes "$list" check_logdir $dir
4021         check_write_access $dir "$list" || return 1
4022         return 0
4023 }
4024
4025 # Run e2fsck on MDT and OST(s) to generate databases used for lfsck.
4026 generate_db() {
4027         local i
4028         local ostidx
4029         local dev
4030         local node
4031
4032         [[ $(lustre_version_code $SINGLEMDS) -ne $(version_code 2.2.0) ]] ||
4033                 { skip "Lustre 2.2.0 lacks the patch for LU-1255"; exit 0; }
4034
4035         check_shared_dir $SHARED_DIRECTORY ||
4036                 error "$SHARED_DIRECTORY isn't a shared directory"
4037
4038         export MDSDB=$SHARED_DIRECTORY/mdsdb
4039         export OSTDB=$SHARED_DIRECTORY/ostdb
4040
4041         # DNE is not supported, so when running e2fsck on a DNE filesystem,
4042         # we only pass master MDS parameters.
4043         run_e2fsck $MDTNODE $MDTDEV "-n --mdsdb $MDSDB"
4044
4045     i=0
4046     ostidx=0
4047     OSTDB_LIST=""
4048     for node in $(osts_nodes); do
4049         for dev in ${OSTDEVS[i]}; do
4050             run_e2fsck $node $dev "-n --mdsdb $MDSDB --ostdb $OSTDB-$ostidx"
4051             OSTDB_LIST="$OSTDB_LIST $OSTDB-$ostidx"
4052             ostidx=$((ostidx + 1))
4053         done
4054         i=$((i + 1))
4055     done
4056 }
4057
4058 # Run lfsck on server node if lfsck can't be found on client (LU-2571)
4059 run_lfsck_remote() {
4060         local cmd="$LFSCK_BIN -c -l --mdsdb $MDSDB --ostdb $OSTDB_LIST $MOUNT"
4061         local client=$1
4062         local mounted=true
4063         local rc=0
4064
4065         #Check if lustre is already mounted
4066         do_rpc_nodes $client is_mounted $MOUNT || mounted=false
4067         if ! $mounted; then
4068                 zconf_mount $client $MOUNT ||
4069                         error "failed to mount Lustre on $client"
4070         fi
4071         #Run lfsck
4072         echo $cmd
4073         do_node $client $cmd || rc=$?
4074         #Umount if necessary
4075         if ! $mounted; then
4076                 zconf_umount $client $MOUNT ||
4077                         error "failed to unmount Lustre on $client"
4078         fi
4079
4080         [ $rc -le $FSCK_MAX_ERR ] ||
4081                 error "$cmd returned $rc, should be <= $FSCK_MAX_ERR"
4082         echo "lfsck finished with rc=$rc"
4083
4084         return $rc
4085 }
4086
4087 run_lfsck() {
4088         local facets="client $SINGLEMDS"
4089         local found=false
4090         local facet
4091         local node
4092         local rc=0
4093
4094         for facet in $facets; do
4095                 node=$(facet_active_host $facet)
4096                 if check_progs_installed $node $LFSCK_BIN; then
4097                         found=true
4098                         break
4099                 fi
4100         done
4101         ! $found && error "None of \"$facets\" supports lfsck"
4102
4103         run_lfsck_remote $node || rc=$?
4104
4105         rm -rvf $MDSDB* $OSTDB* || true
4106         return $rc
4107 }
4108
4109 check_and_cleanup_lustre() {
4110     if [ "$LFSCK_ALWAYS" = "yes" -a "$TESTSUITE" != "lfsck" ]; then
4111         get_svr_devs
4112         generate_db
4113         run_lfsck
4114     fi
4115
4116         if is_mounted $MOUNT; then
4117                 [ -n "$DIR" ] && rm -rf $DIR/[Rdfs][0-9]* ||
4118                         error "remove sub-test dirs failed"
4119                 [ "$ENABLE_QUOTA" ] && restore_quota || true
4120         fi
4121
4122         if [ "$I_UMOUNTED2" = "yes" ]; then
4123                 restore_mount $MOUNT2 || error "restore $MOUNT2 failed"
4124         fi
4125
4126         if [ "$I_MOUNTED2" = "yes" ]; then
4127                 cleanup_mount $MOUNT2
4128         fi
4129
4130         if [ "$I_MOUNTED" = "yes" ]; then
4131                 cleanupall -f || error "cleanup failed"
4132                 unset I_MOUNTED
4133         fi
4134 }
4135
4136 #######
4137 # General functions
4138
4139 wait_for_function () {
4140     local quiet=""
4141
4142     # suppress fn both stderr and stdout
4143     if [ "$1" = "--quiet" ]; then
4144         shift
4145         quiet=" > /dev/null 2>&1"
4146
4147     fi
4148
4149     local fn=$1
4150     local max=${2:-900}
4151     local sleep=${3:-5}
4152
4153     local wait=0
4154
4155     while true; do
4156
4157         eval $fn $quiet && return 0
4158
4159         wait=$((wait + sleep))
4160         [ $wait -lt $max ] || return 1
4161         echo waiting $fn, $((max - wait)) secs left ...
4162         sleep $sleep
4163     done
4164 }
4165
4166 check_network() {
4167     local host=$1
4168     local max=$2
4169     local sleep=${3:-5}
4170
4171     echo `date +"%H:%M:%S (%s)"` waiting for $host network $max secs ...
4172     if ! wait_for_function --quiet "ping -c 1 -w 3 $host" $max $sleep ; then
4173         echo "Network not available!"
4174         exit 1
4175     fi
4176
4177     echo `date +"%H:%M:%S (%s)"` network interface is UP
4178 }
4179
4180 no_dsh() {
4181     shift
4182     eval $@
4183 }
4184
4185 # Convert a space-delimited list to a comma-delimited list.  If the input is
4186 # only whitespace, ensure the output is empty (i.e. "") so [ -n $list ] works
4187 comma_list() {
4188         # echo is used to convert newlines to spaces, since it doesn't
4189         # introduce a trailing space as using "tr '\n' ' '" does
4190         echo $(tr -s " " "\n" <<< $* | sort -b -u) | tr ' ' ','
4191 }
4192
4193 list_member () {
4194     local list=$1
4195     local item=$2
4196     echo $list | grep -qw $item
4197 }
4198
4199 # list, excluded are the comma separated lists
4200 exclude_items_from_list () {
4201     local list=$1
4202     local excluded=$2
4203     local item
4204
4205     list=${list//,/ }
4206     for item in ${excluded//,/ }; do
4207         list=$(echo " $list " | sed -re "s/\s+$item\s+/ /g")
4208     done
4209     echo $(comma_list $list)
4210 }
4211
4212 # list, expand  are the comma separated lists
4213 expand_list () {
4214     local list=${1//,/ }
4215     local expand=${2//,/ }
4216     local expanded=
4217
4218     expanded=$(for i in $list $expand; do echo $i; done | sort -u)
4219     echo $(comma_list $expanded)
4220 }
4221
4222 testslist_filter () {
4223     local script=$LUSTRE/tests/${TESTSUITE}.sh
4224
4225     [ -f $script ] || return 0
4226
4227     local start_at=$START_AT
4228     local stop_at=$STOP_AT
4229
4230     local var=${TESTSUITE//-/_}_START_AT
4231     [ x"${!var}" != x ] && start_at=${!var}
4232     var=${TESTSUITE//-/_}_STOP_AT
4233     [ x"${!var}" != x ] && stop_at=${!var}
4234
4235     sed -n 's/^test_\([^ (]*\).*/\1/p' $script | \
4236         awk ' BEGIN { if ("'${start_at:-0}'" != 0) flag = 1 }
4237             /^'${start_at}'$/ {flag = 0}
4238             {if (flag == 1) print $0}
4239             /^'${stop_at}'$/ { flag = 1 }'
4240 }
4241
4242 absolute_path() {
4243     (cd `dirname $1`; echo $PWD/`basename $1`)
4244 }
4245
4246 get_facets () {
4247     local types=${1:-"OST MDS MGS"}
4248
4249     local list=""
4250
4251     for entry in $types; do
4252         local name=$(echo $entry | tr "[:upper:]" "[:lower:]")
4253         local type=$(echo $entry | tr "[:lower:]" "[:upper:]")
4254
4255         case $type in
4256                 MGS ) list="$list $name";;
4257             MDS|OST|AGT ) local count=${type}COUNT
4258                        for ((i=1; i<=${!count}; i++)) do
4259                           list="$list ${name}$i"
4260                       done;;
4261                   * ) error "Invalid facet type"
4262                  exit 1;;
4263         esac
4264     done
4265     echo $(comma_list $list)
4266 }
4267
4268 ##################################
4269 # Adaptive Timeouts funcs
4270
4271 at_is_enabled() {
4272     # only check mds, we assume at_max is the same on all nodes
4273     local at_max=$(do_facet $SINGLEMDS "lctl get_param -n at_max")
4274     if [ $at_max -eq 0 ]; then
4275         return 1
4276     else
4277         return 0
4278     fi
4279 }
4280
4281 at_get() {
4282     local facet=$1
4283     local at=$2
4284
4285     # suppose that all ost-s have the same $at value set
4286     [ $facet != "ost" ] || facet=ost1
4287
4288     do_facet $facet "lctl get_param -n $at"
4289 }
4290
4291 at_max_get() {
4292     at_get $1 at_max
4293 }
4294
4295 at_min_get() {
4296         at_get $1 at_min
4297 }
4298
4299 at_max_set() {
4300     local at_max=$1
4301     shift
4302
4303     local facet
4304     local hosts
4305     for facet in $@; do
4306         if [ $facet == "ost" ]; then
4307             facet=$(get_facets OST)
4308         elif [ $facet == "mds" ]; then
4309             facet=$(get_facets MDS)
4310         fi
4311         hosts=$(expand_list $hosts $(facets_hosts $facet))
4312     done
4313
4314     do_nodes $hosts lctl set_param at_max=$at_max
4315 }
4316
4317 ##################################
4318 # OBD_FAIL funcs
4319
4320 drop_request() {
4321 # OBD_FAIL_MDS_ALL_REQUEST_NET
4322     RC=0
4323     do_facet $SINGLEMDS lctl set_param fail_loc=0x123
4324     do_facet client "$1" || RC=$?
4325     do_facet $SINGLEMDS lctl set_param fail_loc=0
4326     return $RC
4327 }
4328
4329 drop_reply() {
4330 # OBD_FAIL_MDS_ALL_REPLY_NET
4331         RC=0
4332         do_facet $SINGLEMDS $LCTL set_param fail_loc=0x122
4333         eval "$@" || RC=$?
4334         do_facet $SINGLEMDS $LCTL set_param fail_loc=0
4335         return $RC
4336 }
4337
4338 drop_reint_reply() {
4339 # OBD_FAIL_MDS_REINT_NET_REP
4340         RC=0
4341         do_facet $SINGLEMDS $LCTL set_param fail_loc=0x119
4342         eval "$@" || RC=$?
4343         do_facet $SINGLEMDS $LCTL set_param fail_loc=0
4344         return $RC
4345 }
4346
4347 drop_update_reply() {
4348 # OBD_FAIL_UPDATE_OBJ_NET_REP
4349         local index=$1
4350         shift 1
4351         RC=0
4352         do_facet mds${index} lctl set_param fail_loc=0x1701
4353         do_facet client "$@" || RC=$?
4354         do_facet mds${index} lctl set_param fail_loc=0
4355         return $RC
4356 }
4357
4358 pause_bulk() {
4359 #define OBD_FAIL_OST_BRW_PAUSE_BULK      0x214
4360         RC=0
4361
4362         local timeout=${2:-0}
4363         # default is (obd_timeout / 4) if unspecified
4364         echo "timeout is $timeout/$2"
4365         do_facet ost1 lctl set_param fail_val=$timeout fail_loc=0x80000214
4366         do_facet client "$1" || RC=$?
4367         do_facet client "sync"
4368         do_facet ost1 lctl set_param fail_loc=0
4369         return $RC
4370 }
4371
4372 drop_ldlm_cancel() {
4373 #define OBD_FAIL_LDLM_CANCEL_NET                        0x304
4374         local RC=0
4375         local list=$(comma_list $(mdts_nodes) $(osts_nodes))
4376         do_nodes $list lctl set_param fail_loc=0x304
4377
4378         do_facet client "$@" || RC=$?
4379
4380         do_nodes $list lctl set_param fail_loc=0
4381         return $RC
4382 }
4383
4384 drop_bl_callback_once() {
4385         rc=0
4386         do_facet client lctl set_param ldlm.namespaces.*.early_lock_cancel=0
4387 #define OBD_FAIL_LDLM_BL_CALLBACK_NET                   0x305
4388         do_facet client lctl set_param fail_loc=0x80000305
4389         do_facet client "$@" || rc=$?
4390         do_facet client lctl set_param fail_loc=0
4391         do_facet client lctl set_param ldlm.namespaces.*.early_lock_cancel=1
4392         return $rc
4393 }
4394
4395 drop_bl_callback() {
4396         rc=0
4397         do_facet client lctl set_param ldlm.namespaces.*.early_lock_cancel=0
4398 #define OBD_FAIL_LDLM_BL_CALLBACK_NET                   0x305
4399         do_facet client lctl set_param fail_loc=0x305
4400         do_facet client "$@" || rc=$?
4401         do_facet client lctl set_param fail_loc=0
4402         do_facet client lctl set_param ldlm.namespaces.*.early_lock_cancel=1
4403         return $rc
4404 }
4405
4406 drop_ldlm_reply() {
4407 #define OBD_FAIL_LDLM_REPLY              0x30c
4408     RC=0
4409     local list=$(comma_list $(mdts_nodes) $(osts_nodes))
4410     do_nodes $list lctl set_param fail_loc=0x30c
4411
4412     do_facet client "$@" || RC=$?
4413
4414     do_nodes $list lctl set_param fail_loc=0
4415     return $RC
4416 }
4417
4418 drop_ldlm_reply_once() {
4419 #define OBD_FAIL_LDLM_REPLY              0x30c
4420     RC=0
4421     local list=$(comma_list $(mdts_nodes) $(osts_nodes))
4422     do_nodes $list lctl set_param fail_loc=0x8000030c
4423
4424     do_facet client "$@" || RC=$?
4425
4426     do_nodes $list lctl set_param fail_loc=0
4427     return $RC
4428 }
4429
4430 clear_failloc() {
4431     facet=$1
4432     pause=$2
4433     sleep $pause
4434     echo "clearing fail_loc on $facet"
4435     do_facet $facet "lctl set_param fail_loc=0 2>/dev/null || true"
4436 }
4437
4438 set_nodes_failloc () {
4439         do_nodes $(comma_list $1)  lctl set_param fail_val=0 fail_loc=$2
4440 }
4441
4442 cancel_lru_locks() {
4443     $LCTL mark "cancel_lru_locks $1 start"
4444
4445     if [ $1 != "MGC" ]; then
4446         for d in $(lctl get_param -N ldlm.namespaces.*.lru_size |
4447                  egrep -i $1); do
4448             $LCTL set_param -n $d=clear
4449         done
4450         $LCTL get_param ldlm.namespaces.*.lock_unused_count | egrep -i $1 |
4451                 grep -v '=0'
4452     else
4453         for d in $(find \
4454                 /{proc,sys}/fs/lustre/ldlm/namespaces/*$1*/lru_size \
4455                 2> /dev/null); do
4456             echo "clear" > $d
4457         done
4458
4459         for d in $(find \
4460                 /{proc,sys}/fs/lustre/ldlm/namespaces/*$1*/lock_unused_count \
4461                 2> /dev/null); do
4462             if [ $(cat $d) != 0 ]; then
4463                 echo "ldlm.namespaces.$(echo "$d" |
4464                         cut -f 7 -d'/').lock_unused_count=$(cat $d)"
4465             fi
4466         done
4467     fi
4468
4469     $LCTL mark "cancel_lru_locks $1 stop"
4470 }
4471
4472 default_lru_size()
4473 {
4474         NR_CPU=$(grep -c "processor" /proc/cpuinfo)
4475         DEFAULT_LRU_SIZE=$((100 * NR_CPU))
4476         echo "$DEFAULT_LRU_SIZE"
4477 }
4478
4479 lru_resize_enable()
4480 {
4481     lctl set_param ldlm.namespaces.*$1*.lru_size=0
4482 }
4483
4484 lru_resize_disable()
4485 {
4486     lctl set_param ldlm.namespaces.*$1*.lru_size $(default_lru_size)
4487 }
4488
4489 flock_is_enabled()
4490 {
4491         local RC=0
4492         [ -z "$(mount | grep "$MOUNT.*flock" | grep -v noflock)" ] && RC=1
4493         return $RC
4494 }
4495
4496 pgcache_empty() {
4497     local FILE
4498     for FILE in `lctl get_param -N "llite.*.dump_page_cache"`; do
4499         if [ `lctl get_param -n $FILE | wc -l` -gt 1 ]; then
4500             echo there is still data in page cache $FILE ?
4501             lctl get_param -n $FILE
4502             return 1
4503         fi
4504     done
4505     return 0
4506 }
4507
4508 debugsave() {
4509     DEBUGSAVE="$(lctl get_param -n debug)"
4510 }
4511
4512 debugrestore() {
4513     [ -n "$DEBUGSAVE" ] && \
4514         do_nodes $(comma_list $(nodes_list)) "$LCTL set_param debug=\\\"${DEBUGSAVE}\\\";"
4515     DEBUGSAVE=""
4516 }
4517
4518 debug_size_save() {
4519     DEBUG_SIZE_SAVED="$(lctl get_param -n debug_mb)"
4520 }
4521
4522 debug_size_restore() {
4523     [ -n "$DEBUG_SIZE_SAVED" ] && \
4524         do_nodes $(comma_list $(nodes_list)) "$LCTL set_param debug_mb=$DEBUG_SIZE_SAVED"
4525     DEBUG_SIZE_SAVED=""
4526 }
4527
4528 start_full_debug_logging() {
4529     debugsave
4530     debug_size_save
4531
4532     local FULLDEBUG=-1
4533     local DEBUG_SIZE=150
4534
4535     do_nodes $(comma_list $(nodes_list)) "$LCTL set_param debug_mb=$DEBUG_SIZE"
4536     do_nodes $(comma_list $(nodes_list)) "$LCTL set_param debug=$FULLDEBUG;"
4537 }
4538
4539 stop_full_debug_logging() {
4540     debug_size_restore
4541     debugrestore
4542 }
4543
4544 # prints bash call stack
4545 log_trace_dump() {
4546         echo "  Trace dump:"
4547         for (( i=1; i < ${#BASH_LINENO[*]} ; i++ )) ; do
4548                 local s=${BASH_SOURCE[$i]}
4549                 local l=${BASH_LINENO[$i-1]}
4550                 local f=${FUNCNAME[$i]}
4551                 echo "  = $s:$l:$f()"
4552         done
4553 }
4554
4555 ##################################
4556 # Test interface
4557 ##################################
4558
4559 error_noexit() {
4560         local TYPE=${TYPE:-"FAIL"}
4561
4562         local dump=true
4563         # do not dump logs if $1=false
4564         if [ "x$1" = "xfalse" ]; then
4565                 shift
4566                 dump=false
4567         fi
4568
4569
4570         log " ${TESTSUITE} ${TESTNAME}: @@@@@@ ${TYPE}: $@ "
4571         log_trace_dump
4572
4573         mkdir -p $LOGDIR
4574         # We need to dump the logs on all nodes
4575         if $dump; then
4576                 gather_logs $(comma_list $(nodes_list))
4577         fi
4578
4579         debugrestore
4580         [ "$TESTSUITELOG" ] &&
4581                 echo "$TESTSUITE: $TYPE: $TESTNAME $@" >> $TESTSUITELOG
4582         if [ -z "$*" ]; then
4583                 echo "error() without useful message, please fix" > $LOGDIR/err
4584         else
4585                 if [[ `echo $TYPE | grep ^IGNORE` ]]; then
4586                         echo "$@" > $LOGDIR/ignore
4587                 else
4588                         echo "$@" > $LOGDIR/err
4589                 fi
4590         fi
4591 }
4592
4593 exit_status () {
4594         local status=0
4595         local log=$TESTSUITELOG
4596
4597         [ -f "$log" ] && grep -q FAIL $log && status=1
4598         exit $status
4599 }
4600
4601 error() {
4602         error_noexit "$@"
4603         exit 1
4604 }
4605
4606 error_exit() {
4607         error "$@"
4608 }
4609
4610 # use only if we are ignoring failures for this test, bugno required.
4611 # (like ALWAYS_EXCEPT, but run the test and ignore the results.)
4612 # e.g. error_ignore bz5494 "your message" or
4613 # error_ignore LU-5494 "your message"
4614 error_ignore() {
4615         local TYPE="IGNORE ($1)"
4616         shift
4617         error_noexit "$@"
4618 }
4619
4620 error_and_remount() {
4621         error_noexit "$@"
4622         remount_client $MOUNT
4623         exit 1
4624 }
4625
4626 skip_env () {
4627         $FAIL_ON_SKIP_ENV && error false $@ || skip $@
4628 }
4629
4630 skip() {
4631         echo
4632         log " SKIP: $TESTSUITE $TESTNAME $@"
4633
4634         if [[ -n "$ALWAYS_SKIPPED" ]]; then
4635                 skip_logged $TESTNAME "$@"
4636         else
4637                 mkdir -p $LOGDIR
4638                 echo "$@" > $LOGDIR/skip
4639         fi
4640
4641         [[ -n "$TESTSUITELOG" ]] &&
4642                 echo "$TESTSUITE: SKIP: $TESTNAME $@" >> $TESTSUITELOG || true
4643 }
4644
4645 build_test_filter() {
4646     EXCEPT="$EXCEPT $(testslist_filter)"
4647
4648         for O in $ONLY; do
4649                 if [[ $O = [0-9]*-[0-9]* ]]; then
4650                         for num in $(seq $(echo $O | tr '-' ' ')); do
4651                                 eval ONLY_$num=true
4652                         done
4653                 else
4654                         eval ONLY_${O}=true
4655                 fi
4656         done
4657
4658     [ "$EXCEPT$ALWAYS_EXCEPT" ] && \
4659         log "excepting tests: `echo $EXCEPT $ALWAYS_EXCEPT`"
4660     [ "$EXCEPT_SLOW" ] && \
4661         log "skipping tests SLOW=no: `echo $EXCEPT_SLOW`"
4662     for E in $EXCEPT; do
4663         eval EXCEPT_${E}=true
4664     done
4665     for E in $ALWAYS_EXCEPT; do
4666         eval EXCEPT_ALWAYS_${E}=true
4667     done
4668     for E in $EXCEPT_SLOW; do
4669         eval EXCEPT_SLOW_${E}=true
4670     done
4671     for G in $GRANT_CHECK_LIST; do
4672         eval GCHECK_ONLY_${G}=true
4673         done
4674 }
4675
4676 basetest() {
4677     if [[ $1 = [a-z]* ]]; then
4678         echo $1
4679     else
4680         echo ${1%%[a-z]*}
4681     fi
4682 }
4683
4684 # print a newline if the last test was skipped
4685 export LAST_SKIPPED=
4686 export ALWAYS_SKIPPED=
4687 #
4688 # Main entry into test-framework. This is called with the name and
4689 # description of a test. The name is used to find the function to run
4690 # the test using "test_$name".
4691 #
4692 # This supports a variety of methods of specifying specific test to
4693 # run or not run.  These need to be documented...
4694 #
4695 run_test() {
4696         assert_DIR
4697
4698         export base=$(basetest $1)
4699         if [ -n "$ONLY" ]; then
4700                 testname=ONLY_$1
4701                 if [ ${!testname}x != x ]; then
4702                         [ -n "$LAST_SKIPPED" ] && echo "" && LAST_SKIPPED=
4703                         run_one_logged $1 "$2"
4704                         return $?
4705                 fi
4706                 testname=ONLY_$base
4707                 if [ ${!testname}x != x ]; then
4708                         [ -n "$LAST_SKIPPED" ] && echo "" && LAST_SKIPPED=
4709                         run_one_logged $1 "$2"
4710                         return $?
4711                 fi
4712                 LAST_SKIPPED="y"
4713                 return 0
4714         fi
4715
4716         LAST_SKIPPED="y"
4717         ALWAYS_SKIPPED="y"
4718         testname=EXCEPT_$1
4719         if [ ${!testname}x != x ]; then
4720                 TESTNAME=test_$1 skip "skipping excluded test $1"
4721                 return 0
4722         fi
4723         testname=EXCEPT_$base
4724         if [ ${!testname}x != x ]; then
4725                 TESTNAME=test_$1 skip "skipping excluded test $1 (base $base)"
4726                 return 0
4727         fi
4728         testname=EXCEPT_ALWAYS_$1
4729         if [ ${!testname}x != x ]; then
4730                 TESTNAME=test_$1 skip "skipping ALWAYS excluded test $1"
4731                 return 0
4732         fi
4733         testname=EXCEPT_ALWAYS_$base
4734         if [ ${!testname}x != x ]; then
4735                 TESTNAME=test_$1 skip "skipping ALWAYS excluded test $1 (base $base)"
4736                 return 0
4737         fi
4738         testname=EXCEPT_SLOW_$1
4739         if [ ${!testname}x != x ]; then
4740                 TESTNAME=test_$1 skip "skipping SLOW test $1"
4741                 return 0
4742         fi
4743         testname=EXCEPT_SLOW_$base
4744         if [ ${!testname}x != x ]; then
4745                 TESTNAME=test_$1 skip "skipping SLOW test $1 (base $base)"
4746                 return 0
4747         fi
4748
4749         LAST_SKIPPED=
4750         ALWAYS_SKIPPED=
4751         run_one_logged $1 "$2"
4752
4753         return $?
4754 }
4755
4756 log() {
4757     echo "$*"
4758     module_loaded lnet || load_modules
4759
4760     local MSG="$*"
4761     # Get rid of '
4762     MSG=${MSG//\'/\\\'}
4763     MSG=${MSG//\(/\\\(}
4764     MSG=${MSG//\)/\\\)}
4765     MSG=${MSG//\;/\\\;}
4766     MSG=${MSG//\|/\\\|}
4767     MSG=${MSG//\>/\\\>}
4768     MSG=${MSG//\</\\\<}
4769     MSG=${MSG//\//\\\/}
4770     do_nodes $(comma_list $(nodes_list)) $LCTL mark "$MSG" 2> /dev/null || true
4771 }
4772
4773 trace() {
4774         log "STARTING: $*"
4775         strace -o $TMP/$1.strace -ttt $*
4776         RC=$?
4777         log "FINISHED: $*: rc $RC"
4778         return 1
4779 }
4780
4781 complete () {
4782     local duration=$1
4783
4784     banner test complete, duration $duration sec
4785     [ -f "$TESTSUITELOG" ] && egrep .FAIL $TESTSUITELOG || true
4786     echo duration $duration >>$TESTSUITELOG
4787 }
4788
4789 pass() {
4790         # Set TEST_STATUS here. It will be used for logging the result.
4791         TEST_STATUS="PASS"
4792
4793         if [[ -f $LOGDIR/err ]]; then
4794                 TEST_STATUS="FAIL"
4795         elif [[ -f $LOGDIR/skip ]]; then
4796                 TEST_STATUS="SKIP"
4797         fi
4798         echo "$TEST_STATUS $@" 2>&1 | tee -a $TESTSUITELOG
4799 }
4800
4801 check_mds() {
4802     local FFREE=$(do_node $SINGLEMDS \
4803         lctl get_param -n osd*.*MDT*.filesfree | calc_sum)
4804     local FTOTAL=$(do_node $SINGLEMDS \
4805         lctl get_param -n osd*.*MDT*.filestotal | calc_sum)
4806
4807     [ $FFREE -ge $FTOTAL ] && error "files free $FFREE > total $FTOTAL" || true
4808 }
4809
4810 reset_fail_loc () {
4811     echo -n "Resetting fail_loc on all nodes..."
4812     do_nodes $(comma_list $(nodes_list)) "lctl set_param -n fail_loc=0 \
4813             fail_val=0 2>/dev/null || true"
4814     echo done.
4815 }
4816
4817
4818 #
4819 # Log a message (on all nodes) padded with "=" before and after. 
4820 # Also appends a timestamp and prepends the testsuite name.
4821
4822
4823 EQUALS="===================================================================================================="
4824 banner() {
4825     msg="== ${TESTSUITE} $*"
4826     last=${msg: -1:1}
4827     [[ $last != "=" && $last != " " ]] && msg="$msg "
4828     msg=$(printf '%s%.*s'  "$msg"  $((${#EQUALS} - ${#msg})) $EQUALS )
4829     # always include at least == after the message
4830     log "$msg== $(date +"%H:%M:%S (%s)")"
4831 }
4832
4833 #
4834 # Run a single test function and cleanup after it.
4835 #
4836 # This function should be run in a subshell so the test func can
4837 # exit() without stopping the whole script.
4838 #
4839 run_one() {
4840         local testnum=$1
4841         local message=$2
4842         export tfile=f${testnum}.${TESTSUITE}
4843         export tdir=d${testnum}.${TESTSUITE}
4844         export TESTNAME=test_$testnum
4845         local SAVE_UMASK=`umask`
4846         umask 0022
4847
4848         banner "test $testnum: $message"
4849         test_${testnum} || error "test_$testnum failed with $?"
4850         cd $SAVE_PWD
4851         reset_fail_loc
4852         check_grant ${testnum} || error "check_grant $testnum failed with $?"
4853         check_catastrophe || error "LBUG/LASSERT detected"
4854         if [ "$PARALLEL" != "yes" ]; then
4855                 ps auxww | grep -v grep | grep -q multiop &&
4856                                         error "multiop still running"
4857         fi
4858         unset TESTNAME
4859         unset tdir
4860         unset tfile
4861         umask $SAVE_UMASK
4862         return 0
4863 }
4864
4865 #
4866 # Wrapper around run_one to ensure:
4867 #  - test runs in subshell
4868 #  - output of test is saved to separate log file for error reporting
4869 #  - test result is saved to data file
4870 #
4871 run_one_logged() {
4872         local BEFORE=$(date +%s)
4873         local TEST_ERROR
4874         local name=${TESTSUITE}.test_${1}.test_log.$(hostname -s).log
4875         local test_log=$LOGDIR/$name
4876         rm -rf $LOGDIR/err
4877         rm -rf $LOGDIR/ignore
4878         rm -rf $LOGDIR/skip
4879         local SAVE_UMASK=$(umask)
4880         umask 0022
4881
4882         echo
4883         log_sub_test_begin test_${1}
4884         (run_one $1 "$2") 2>&1 | tee -i $test_log
4885         local RC=${PIPESTATUS[0]}
4886
4887         [ $RC -ne 0 ] && [ ! -f $LOGDIR/err ] &&
4888                 echo "test_$1 returned $RC" | tee $LOGDIR/err
4889
4890         duration=$(($(date +%s) - $BEFORE))
4891         pass "$1" "(${duration}s)"
4892
4893         if [[ -f $LOGDIR/err ]]; then
4894                 TEST_ERROR=$(cat $LOGDIR/err)
4895         elif [[ -f $LOGDIR/ignore ]]; then
4896                 TEST_ERROR=$(cat $LOGDIR/ignore)
4897         elif [[ -f $LOGDIR/skip ]]; then
4898                 TEST_ERROR=$(cat $LOGDIR/skip)
4899         fi
4900         log_sub_test_end $TEST_STATUS $duration "$RC" "$TEST_ERROR"
4901
4902         if [[ "$TEST_STATUS" != "SKIP" ]] && [[ -f $TF_SKIP ]]; then
4903                 rm -f $TF_SKIP
4904         fi
4905
4906         if [ -f $LOGDIR/err ]; then
4907                 $FAIL_ON_ERROR && exit $RC
4908         fi
4909
4910         umask $SAVE_UMASK
4911
4912         return 0
4913 }
4914
4915 #
4916 # Print information of skipped tests to result.yml
4917 #
4918 skip_logged(){
4919         log_sub_test_begin $1
4920         shift
4921         log_sub_test_end "SKIP" "0" "0" "$@"
4922 }
4923
4924 canonical_path() {
4925         (cd $(dirname $1); echo $PWD/$(basename $1))
4926 }
4927
4928
4929 check_grant() {
4930         export base=$(basetest $1)
4931         [ "$CHECK_GRANT" == "no" ] && return 0
4932
4933         testname=GCHECK_ONLY_${base}
4934         [ ${!testname}x == x ] && return 0
4935
4936         echo -n "checking grant......"
4937
4938         local clients=$CLIENTS
4939         [ -z "$clients" ] && clients=$(hostname)
4940
4941         # sync all the data and make sure no pending data on server
4942         do_nodes $clients sync
4943
4944         # get client grant
4945         client_grant=$(do_nodes $clients \
4946                 "$LCTL get_param -n osc.${FSNAME}-*.cur_*grant_bytes" |
4947                 awk '{ total += $1 } END { printf("%0.0f", total) }')
4948
4949         # get server grant
4950         server_grant=$(do_nodes $(comma_list $(osts_nodes)) \
4951                 "$LCTL get_param -n obdfilter.${FSNAME}-OST*.tot_granted" |
4952                 awk '{ total += $1 } END { printf("%0.0f", total) }')
4953
4954         # check whether client grant == server grant
4955         if [[ $client_grant -ne $server_grant ]]; then
4956                 echo "failed: client:${client_grant} server: ${server_grant}."
4957                 do_nodes $(comma_list $(osts_nodes)) \
4958                         "$LCTL get_param obdfilter.${FSNAME}-OST*.tot*"
4959                 do_nodes $clients "$LCTL get_param osc.${FSNAME}-*.cur_*_bytes"
4960                 return 1
4961         else
4962                 echo "pass: client:${client_grant} server: ${server_grant}"
4963         fi
4964 }
4965
4966 ########################
4967 # helper functions
4968
4969 osc_to_ost()
4970 {
4971     osc=$1
4972     ost=`echo $1 | awk -F_ '{print $3}'`
4973     if [ -z $ost ]; then
4974         ost=`echo $1 | sed 's/-osc.*//'`
4975     fi
4976     echo $ost
4977 }
4978
4979 ostuuid_from_index()
4980 {
4981     $LFS osts $2 | sed -ne "/^$1: /s/.* \(.*\) .*$/\1/p"
4982 }
4983
4984 ostname_from_index() {
4985     local uuid=$(ostuuid_from_index $1)
4986     echo ${uuid/_UUID/}
4987 }
4988
4989 index_from_ostuuid()
4990 {
4991     $LFS osts $2 | sed -ne "/${1}/s/\(.*\): .* .*$/\1/p"
4992 }
4993
4994 mdtuuid_from_index()
4995 {
4996     $LFS mdts $2 | sed -ne "/^$1: /s/.* \(.*\) .*$/\1/p"
4997 }
4998
4999 # Description:
5000 #   Return unique identifier for given hostname
5001 host_id() {
5002         local host_name=$1
5003         echo $host_name | md5sum | cut -d' ' -f1
5004 }
5005
5006 # Description:
5007 #   Returns list of ip addresses for each interface
5008 local_addr_list() {
5009         ip addr | awk '/inet\ / {print $2}' | awk -F\/ '{print $1}'
5010 }
5011
5012 is_local_addr() {
5013         local addr=$1
5014         # Cache address list to avoid mutiple execution of local_addr_list
5015         LOCAL_ADDR_LIST=${LOCAL_ADDR_LIST:-$(local_addr_list)}
5016         local i
5017         for i in $LOCAL_ADDR_LIST ; do
5018                 [[ "$i" == "$addr" ]] && return 0
5019         done
5020         return 1
5021 }
5022
5023 local_node() {
5024         local host_name=$1
5025         local is_local="IS_LOCAL_$(host_id $host_name)"
5026         if [ -z "${!is_local-}" ] ; then
5027                 eval $is_local=0
5028                 local host_ip=$($LUSTRE/tests/resolveip $host_name)
5029                 is_local_addr "$host_ip" && eval $is_local=1
5030         fi
5031         [[ "${!is_local}" == "1" ]]
5032 }
5033
5034 remote_node () {
5035         local node=$1
5036         local_node $node && return 1
5037         return 0
5038 }
5039
5040 remote_mds ()
5041 {
5042     local node
5043     for node in $(mdts_nodes); do
5044         remote_node $node && return 0
5045     done
5046     return 1
5047 }
5048
5049 remote_mds_nodsh()
5050 {
5051     [ "$CLIENTONLY" ] && return 0 || true
5052     remote_mds && [ "$PDSH" = "no_dsh" -o -z "$PDSH" -o -z "$mds_HOST" ]
5053 }
5054
5055 require_dsh_mds()
5056 {
5057         remote_mds_nodsh && echo "SKIP: $TESTSUITE: remote MDS with nodsh" && \
5058             MSKIPPED=1 && return 1
5059         return 0
5060 }
5061
5062 remote_ost ()
5063 {
5064     local node
5065     for node in $(osts_nodes) ; do
5066         remote_node $node && return 0
5067     done
5068     return 1
5069 }
5070
5071 remote_ost_nodsh()
5072 {
5073     [ "$CLIENTONLY" ] && return 0 || true 
5074     remote_ost && [ "$PDSH" = "no_dsh" -o -z "$PDSH" -o -z "$ost_HOST" ]
5075 }
5076
5077 require_dsh_ost()
5078 {
5079         remote_ost_nodsh && echo "SKIP: $TESTSUITE: remote OST with nodsh" && \
5080             OSKIPPED=1 && return 1
5081         return 0
5082 }
5083
5084 remote_mgs_nodsh()
5085 {
5086     local MGS 
5087     MGS=$(facet_host mgs)
5088     remote_node $MGS && [ "$PDSH" = "no_dsh" -o -z "$PDSH" -o -z "$ost_HOST" ]
5089 }
5090
5091 local_mode ()
5092 {
5093     remote_mds_nodsh || remote_ost_nodsh || \
5094         $(single_local_node $(comma_list $(nodes_list)))
5095 }
5096
5097 remote_servers () {
5098     remote_ost && remote_mds
5099 }
5100
5101 # Get the active nodes for facets.
5102 facets_nodes () {
5103         local facets=$1
5104         local facet
5105         local nodes
5106         local nodes_sort
5107         local i
5108
5109         for facet in ${facets//,/ }; do
5110                 nodes="$nodes $(facet_active_host $facet)"
5111         done
5112
5113         nodes_sort=$(for i in $nodes; do echo $i; done | sort -u)
5114         echo -n $nodes_sort
5115 }
5116
5117 # Get all of the active MDS nodes.
5118 mdts_nodes () {
5119         echo -n $(facets_nodes $(get_facets MDS))
5120 }
5121
5122 # Get all of the active OSS nodes.
5123 osts_nodes () {
5124         echo -n $(facets_nodes $(get_facets OST))
5125 }
5126
5127 # Get all of the active AGT (HSM agent) nodes.
5128 agts_nodes () {
5129         echo -n $(facets_nodes $(get_facets AGT))
5130 }
5131
5132 # Get all of the client nodes and active server nodes.
5133 nodes_list () {
5134         local nodes=$HOSTNAME
5135         local nodes_sort
5136         local i
5137
5138         # CLIENTS (if specified) contains the local client
5139         [ -n "$CLIENTS" ] && nodes=${CLIENTS//,/ }
5140
5141         if [ "$PDSH" -a "$PDSH" != "no_dsh" ]; then
5142                 nodes="$nodes $(facets_nodes $(get_facets))"
5143         fi
5144
5145         nodes_sort=$(for i in $nodes; do echo $i; done | sort -u)
5146         echo -n $nodes_sort
5147 }
5148
5149 # Get all of the remote client nodes and remote active server nodes.
5150 remote_nodes_list () {
5151         echo -n $(nodes_list) | sed -re "s/\<$HOSTNAME\>//g"
5152 }
5153
5154 # Get all of the MDS nodes, including active and passive nodes.
5155 all_mdts_nodes () {
5156         local host
5157         local failover_host
5158         local nodes
5159         local nodes_sort
5160         local i
5161
5162         for i in $(seq $MDSCOUNT); do
5163                 host=mds${i}_HOST
5164                 failover_host=mds${i}failover_HOST
5165                 nodes="$nodes ${!host} ${!failover_host}"
5166         done
5167
5168         nodes_sort=$(for i in $nodes; do echo $i; done | sort -u)
5169         echo -n $nodes_sort
5170 }
5171
5172 # Get all of the OSS nodes, including active and passive nodes.
5173 all_osts_nodes () {
5174         local host
5175         local failover_host
5176         local nodes
5177         local nodes_sort
5178         local i
5179
5180         for i in $(seq $OSTCOUNT); do
5181                 host=ost${i}_HOST
5182                 failover_host=ost${i}failover_HOST
5183                 nodes="$nodes ${!host} ${!failover_host}"
5184         done
5185
5186         nodes_sort=$(for i in $nodes; do echo $i; done | sort -u)
5187         echo -n $nodes_sort
5188 }
5189
5190 # Get all of the server nodes, including active and passive nodes.
5191 all_server_nodes () {
5192         local nodes
5193         local nodes_sort
5194         local i
5195
5196         nodes="$mgs_HOST $mgsfailover_HOST $(all_mdts_nodes) $(all_osts_nodes)"
5197
5198         nodes_sort=$(for i in $nodes; do echo $i; done | sort -u)
5199         echo -n $nodes_sort
5200 }
5201
5202 # Get all of the client and server nodes, including active and passive nodes.
5203 all_nodes () {
5204         local nodes=$HOSTNAME
5205         local nodes_sort
5206         local i
5207
5208         # CLIENTS (if specified) contains the local client
5209         [ -n "$CLIENTS" ] && nodes=${CLIENTS//,/ }
5210
5211         if [ "$PDSH" -a "$PDSH" != "no_dsh" ]; then
5212                 nodes="$nodes $(all_server_nodes)"
5213         fi
5214
5215         nodes_sort=$(for i in $nodes; do echo $i; done | sort -u)
5216         echo -n $nodes_sort
5217 }
5218
5219 init_clients_lists () {
5220     # Sanity check: exclude the local client from RCLIENTS
5221     local clients=$(hostlist_expand "$RCLIENTS")
5222     local rclients=$(exclude_items_from_list "$clients" $HOSTNAME)
5223
5224     # Sanity check: exclude the dup entries
5225     RCLIENTS=$(for i in ${rclients//,/ }; do echo $i; done | sort -u)
5226
5227     clients="$SINGLECLIENT $HOSTNAME $RCLIENTS"
5228
5229     # Sanity check: exclude the dup entries from CLIENTS
5230     # for those configs which has SINGLCLIENT set to local client
5231     clients=$(for i in $clients; do echo $i; done | sort -u)
5232
5233     CLIENTS=$(comma_list $clients)
5234     local -a remoteclients=($RCLIENTS)
5235     for ((i=0; $i<${#remoteclients[@]}; i++)); do
5236             varname=CLIENT$((i + 2))
5237             eval $varname=${remoteclients[i]}
5238     done
5239
5240     CLIENTCOUNT=$((${#remoteclients[@]} + 1))
5241 }
5242
5243 get_random_entry () {
5244     local rnodes=$1
5245
5246     rnodes=${rnodes//,/ }
5247
5248     local -a nodes=($rnodes)
5249     local num=${#nodes[@]} 
5250     local i=$((RANDOM * num * 2 / 65536))
5251
5252     echo ${nodes[i]}
5253 }
5254
5255 client_only () {
5256     [ "$CLIENTONLY" ] || [ "$CLIENTMODSONLY" = yes ]
5257 }
5258
5259 is_patchless ()
5260 {
5261     lctl get_param version | grep -q patchless
5262 }
5263
5264 check_versions () {
5265     [ "$(lustre_version_code client)" = "$(lustre_version_code $SINGLEMDS)" -a \
5266       "$(lustre_version_code client)" = "$(lustre_version_code ost1)" ]
5267 }
5268
5269 get_node_count() {
5270     local nodes="$@"
5271     echo $nodes | wc -w || true
5272 }
5273
5274 mixed_ost_devs () {
5275     local nodes=$(osts_nodes)
5276     local osscount=$(get_node_count "$nodes")
5277     [ ! "$OSTCOUNT" = "$osscount" ]
5278 }
5279
5280 mixed_mdt_devs () {
5281     local nodes=$(mdts_nodes)
5282     local mdtcount=$(get_node_count "$nodes")
5283     [ ! "$MDSCOUNT" = "$mdtcount" ]
5284 }
5285
5286 generate_machine_file() {
5287     local nodes=${1//,/ }
5288     local machinefile=$2
5289     rm -f $machinefile
5290     for node in $nodes; do
5291         echo $node >>$machinefile || \
5292             { echo "can not generate machinefile $machinefile" && return 1; }
5293     done
5294 }
5295
5296 get_stripe () {
5297         local file=$1/stripe
5298
5299         touch $file
5300         $LFS getstripe -v $file || error "getstripe $file failed"
5301         rm -f $file
5302 }
5303
5304 setstripe_nfsserver () {
5305         local dir=$1
5306
5307         local nfsserver=$(awk '"'$dir'" ~ $2 && $3 ~ "nfs" && $2 != "/" \
5308                 { print $1 }' /proc/mounts | cut -f 1 -d : | head -n1)
5309
5310         [ -z $nfsserver ] && echo "$dir is not nfs mounted" && return 1
5311
5312         do_nodev $nfsserver lfs setstripe "$@"
5313 }
5314
5315 # Check and add a test group.
5316 add_group() {
5317         local group_id=$1
5318         local group_name=$2
5319         local rc=0
5320
5321         local gid=$(getent group $group_name | cut -d: -f3)
5322         if [[ -n "$gid" ]]; then
5323                 [[ "$gid" -eq "$group_id" ]] || {
5324                         error_noexit "inconsistent group ID:" \
5325                                      "new: $group_id, old: $gid"
5326                         rc=1
5327                 }
5328         else
5329                 groupadd -g $group_id $group_name
5330                 rc=${PIPESTATUS[0]}
5331         fi
5332
5333         return $rc
5334 }
5335
5336 # Check and add a test user.
5337 add_user() {
5338         local user_id=$1
5339         shift
5340         local user_name=$1
5341         shift
5342         local group_name=$1
5343         shift
5344         local home=$1
5345         shift
5346         local opts="$@"
5347         local rc=0
5348
5349         local uid=$(getent passwd $user_name | cut -d: -f3)
5350         if [[ -n "$uid" ]]; then
5351                 if [[ "$uid" -eq "$user_id" ]]; then
5352                         local dir=$(getent passwd $user_name | cut -d: -f6)
5353                         if [[ "$dir" != "$home" ]]; then
5354                                 mkdir -p $home
5355                                 usermod -d $home $user_name
5356                                 rc=${PIPESTATUS[0]}
5357                         fi
5358                 else
5359                         error_noexit "inconsistent user ID:" \
5360                                      "new: $user_id, old: $uid"
5361                         rc=1
5362                 fi
5363         else
5364                 mkdir -p $home
5365                 useradd -M -u $user_id -d $home -g $group_name $opts $user_name
5366                 rc=${PIPESTATUS[0]}
5367         fi
5368
5369         return $rc
5370 }
5371
5372 check_runas_id_ret() {
5373     local myRC=0
5374     local myRUNAS_UID=$1
5375     local myRUNAS_GID=$2
5376     shift 2
5377     local myRUNAS=$@
5378     if [ -z "$myRUNAS" ]; then
5379         error_exit "myRUNAS command must be specified for check_runas_id"
5380     fi
5381     if $GSS_KRB5; then
5382         $myRUNAS krb5_login.sh || \
5383             error "Failed to refresh Kerberos V5 TGT for UID $myRUNAS_ID."
5384     fi
5385     mkdir $DIR/d0_runas_test
5386     chmod 0755 $DIR
5387     chown $myRUNAS_UID:$myRUNAS_GID $DIR/d0_runas_test
5388     $myRUNAS touch $DIR/d0_runas_test/f$$ || myRC=$?
5389     rm -rf $DIR/d0_runas_test
5390     return $myRC
5391 }
5392
5393 check_runas_id() {
5394     local myRUNAS_UID=$1
5395     local myRUNAS_GID=$2
5396     shift 2
5397     local myRUNAS=$@
5398     check_runas_id_ret $myRUNAS_UID $myRUNAS_GID $myRUNAS || \
5399         error "unable to write to $DIR/d0_runas_test as UID $myRUNAS_UID.
5400         Please set RUNAS_ID to some UID which exists on MDS and client or
5401         add user $myRUNAS_UID:$myRUNAS_GID on these nodes."
5402 }
5403
5404 # obtain the UID/GID for MPI_USER
5405 get_mpiuser_id() {
5406     local mpi_user=$1
5407
5408     MPI_USER_UID=$(do_facet client "getent passwd $mpi_user | cut -d: -f3;
5409 exit \\\${PIPESTATUS[0]}") || error_exit "failed to get the UID for $mpi_user"
5410
5411     MPI_USER_GID=$(do_facet client "getent passwd $mpi_user | cut -d: -f4;
5412 exit \\\${PIPESTATUS[0]}") || error_exit "failed to get the GID for $mpi_user"
5413 }
5414
5415 # obtain and cache Kerberos ticket-granting ticket
5416 refresh_krb5_tgt() {
5417     local myRUNAS_UID=$1
5418     local myRUNAS_GID=$2
5419     shift 2
5420     local myRUNAS=$@
5421     if [ -z "$myRUNAS" ]; then
5422         error_exit "myRUNAS command must be specified for refresh_krb5_tgt"
5423     fi
5424
5425     CLIENTS=${CLIENTS:-$HOSTNAME}
5426     do_nodes $CLIENTS "set -x
5427 if ! $myRUNAS krb5_login.sh; then
5428     echo "Failed to refresh Krb5 TGT for UID/GID $myRUNAS_UID/$myRUNAS_GID."
5429     exit 1
5430 fi"
5431 }
5432
5433 # Run multiop in the background, but wait for it to print
5434 # "PAUSING" to its stdout before returning from this function.
5435 multiop_bg_pause() {
5436     MULTIOP_PROG=${MULTIOP_PROG:-$MULTIOP}
5437     FILE=$1
5438     ARGS=$2
5439
5440     TMPPIPE=/tmp/multiop_open_wait_pipe.$$
5441     mkfifo $TMPPIPE
5442
5443     echo "$MULTIOP_PROG $FILE v$ARGS"
5444     $MULTIOP_PROG $FILE v$ARGS > $TMPPIPE &
5445
5446     echo "TMPPIPE=${TMPPIPE}"
5447     read -t 60 multiop_output < $TMPPIPE
5448     if [ $? -ne 0 ]; then
5449         rm -f $TMPPIPE
5450         return 1
5451     fi
5452     rm -f $TMPPIPE
5453     if [ "$multiop_output" != "PAUSING" ]; then
5454         echo "Incorrect multiop output: $multiop_output"
5455         kill -9 $PID
5456         return 1
5457     fi
5458
5459     return 0
5460 }
5461
5462 do_and_time () {
5463     local cmd=$1
5464     local rc
5465
5466     SECONDS=0
5467     eval '$cmd'
5468
5469     [ ${PIPESTATUS[0]} -eq 0 ] || rc=1
5470
5471     echo $SECONDS
5472     return $rc
5473 }
5474
5475 inodes_available () {
5476         local IFree=$($LFS df -i $MOUNT | grep ^$FSNAME | awk '{ print $4 }' |
5477                 sort -un | head -n1) || return 1
5478         echo $((IFree))
5479 }
5480
5481 mdsrate_inodes_available () {
5482     local min_inodes=$(inodes_available)
5483     echo $((min_inodes * 99 / 100))
5484 }
5485
5486 # reset llite stat counters
5487 clear_llite_stats(){
5488         lctl set_param -n llite.*.stats 0
5489 }
5490
5491 # sum llite stat items
5492 calc_llite_stats() {
5493         local res=$(lctl get_param -n llite.*.stats |
5494                 awk '/^'"$1"'/ {sum += $2} END { printf("%0.0f", sum) }')
5495         echo $((res))
5496 }
5497
5498 # reset osc stat counters
5499 clear_osc_stats(){
5500         lctl set_param -n osc.*.osc_stats 0
5501 }
5502
5503 # sum osc stat items
5504 calc_osc_stats() {
5505         local res=$(lctl get_param -n osc.*.osc_stats |
5506                 awk '/^'"$1"'/ {sum += $2} END { printf("%0.0f", sum) }')
5507         echo $((res))
5508 }
5509
5510 calc_sum () {
5511         awk '{sum += $1} END { printf("%0.0f", sum) }'
5512 }
5513
5514 calc_osc_kbytes () {
5515         df $MOUNT > /dev/null
5516         $LCTL get_param -n osc.*[oO][sS][cC][-_][0-9a-f]*.$1 | calc_sum
5517 }
5518
5519 # save_lustre_params(comma separated facet list, parameter_mask)
5520 # generate a stream of formatted strings (<facet> <param name>=<param value>)
5521 save_lustre_params() {
5522         local facets=$1
5523         local facet
5524         local nodes
5525         local node
5526
5527         for facet in ${facets//,/ }; do
5528                 node=$(facet_active_host $facet)
5529                 [[ *\ $node\ * = " $nodes " ]] && continue
5530                 nodes="$nodes $node"
5531
5532                 do_node $node "$LCTL get_param $2 |
5533                         while read s; do echo $facet \\\$s; done"
5534         done
5535 }
5536
5537 # restore lustre parameters from input stream, produces by save_lustre_params
5538 restore_lustre_params() {
5539         local facet
5540         local name
5541         local val
5542
5543         while IFS=" =" read facet name val; do
5544                 do_facet $facet "$LCTL set_param -n $name $val"
5545         done
5546 }
5547
5548 check_catastrophe() {
5549         local rnodes=${1:-$(comma_list $(remote_nodes_list))}
5550         VAR=$(lctl get_param -n catastrophe 2>&1)
5551         if [ $? = 0 ] ; then
5552                 if [ $VAR != 0 ]; then
5553                         return 1
5554                 fi
5555         fi
5556
5557         [ -z "$rnodes" ] && return 0
5558
5559         local data
5560         data=$(do_nodes "$rnodes" "rc=\\\$(lctl get_param -n catastrophe);
5561                 if [ \\\$rc -ne 0 ]; then echo \\\$(hostname): \\\$rc; fi
5562                 exit \\\$rc")
5563         local rc=$?
5564         if [ -n "$data" ]; then
5565             echo $data
5566             return $rc
5567         fi
5568         return 0
5569 }
5570
5571 # CMD: determine mds index where directory inode presents
5572 get_mds_dir () {
5573     local dir=$1
5574     local file=$dir/f0.get_mds_dir_tmpfile
5575
5576     mkdir -p $dir
5577     rm -f $file
5578     sleep 1
5579     local iused=$(lfs df -i $dir | grep MDT | awk '{print $3}')
5580     local -a oldused=($iused)
5581
5582     openfile -f O_CREAT:O_LOV_DELAY_CREATE -m 0644 $file > /dev/null
5583     sleep 1
5584     iused=$(lfs df -i $dir | grep MDT | awk '{print $3}')
5585     local -a newused=($iused)
5586
5587     local num=0
5588     for ((i=0; i<${#newused[@]}; i++)); do
5589          if [ ${oldused[$i]} -lt ${newused[$i]} ];  then
5590              echo $(( i + 1 ))
5591              rm -f $file
5592              return 0
5593          fi
5594     done
5595     error "mdt-s : inodes count OLD ${oldused[@]} NEW ${newused[@]}"
5596 }
5597
5598 mdsrate_cleanup () {
5599         if [ -d $4 ]; then
5600                 mpi_run ${MACHINEFILE_OPTION} $2 -np $1 ${MDSRATE} --unlink \
5601                         --nfiles $3 --dir $4 --filefmt $5 $6
5602                 rmdir $4
5603         fi
5604 }
5605
5606 delayed_recovery_enabled () {
5607     local var=${SINGLEMDS}_svc
5608     do_facet $SINGLEMDS lctl get_param -n mdd.${!var}.stale_export_age > /dev/null 2>&1
5609 }
5610
5611 ########################
5612
5613 convert_facet2label() {
5614     local facet=$1
5615
5616     if [ x$facet = xost ]; then
5617        facet=ost1
5618     fi
5619
5620     local varsvc=${facet}_svc
5621
5622     if [ -n ${!varsvc} ]; then
5623         echo ${!varsvc}
5624     else
5625         error "No lablel for $facet!"
5626     fi
5627 }
5628
5629 get_clientosc_proc_path() {
5630     echo "${1}-osc-*"
5631 }
5632
5633 get_lustre_version () {
5634     local facet=${1:-"$SINGLEMDS"}    
5635     do_facet $facet $LCTL get_param -n version | awk '/^lustre:/ {print $2}'
5636 }
5637
5638 lustre_version_code() {
5639     local facet=${1:-"$SINGLEMDS"}
5640     version_code $(get_lustre_version $1)
5641 }
5642
5643 # If the 2.0 MDS was mounted on 1.8 device, then the OSC and LOV names
5644 # used by MDT would not be changed.
5645 # mdt lov: fsname-mdtlov
5646 # mdt osc: fsname-OSTXXXX-osc
5647 mds_on_old_device() {
5648     local mds=${1:-"$SINGLEMDS"}
5649
5650     if [ $(lustre_version_code $mds) -gt $(version_code 1.9.0) ]; then
5651         do_facet $mds "lctl list_param osc.$FSNAME-OST*-osc \
5652             > /dev/null 2>&1" && return 0
5653     fi
5654     return 1
5655 }
5656
5657 get_mdtosc_proc_path() {
5658     local mds_facet=$1
5659     local ost_label=${2:-"*OST*"}
5660
5661     [ "$mds_facet" = "mds" ] && mds_facet=$SINGLEMDS
5662     local mdt_label=$(convert_facet2label $mds_facet)
5663     local mdt_index=$(echo $mdt_label | sed -e 's/^.*-//')
5664
5665     if [ $(lustre_version_code $mds_facet) -le $(version_code 1.8.0) ] ||
5666        mds_on_old_device $mds_facet; then
5667         echo "${ost_label}-osc"
5668     else
5669         echo "${ost_label}-osc-${mdt_index}"
5670     fi
5671 }
5672
5673 get_osc_import_name() {
5674     local facet=$1
5675     local ost=$2
5676     local label=$(convert_facet2label $ost)
5677
5678     if [ "${facet:0:3}" = "mds" ]; then
5679         get_mdtosc_proc_path $facet $label
5680         return 0
5681     fi
5682
5683     get_clientosc_proc_path $label
5684     return 0
5685 }
5686
5687 _wait_import_state () {
5688     local expected=$1
5689     local CONN_PROC=$2
5690     local maxtime=${3:-$(max_recovery_time)}
5691     local CONN_STATE
5692     local i=0
5693
5694         CONN_STATE=$($LCTL get_param -n $CONN_PROC 2>/dev/null | cut -f2 | uniq)
5695     while [ "${CONN_STATE}" != "${expected}" ]; do
5696         if [ "${expected}" == "DISCONN" ]; then
5697             # for disconn we can check after proc entry is removed
5698             [ "x${CONN_STATE}" == "x" ] && return 0
5699             #  with AT enabled, we can have connect request timeout near of
5700             # reconnect timeout and test can't see real disconnect
5701             [ "${CONN_STATE}" == "CONNECTING" ] && return 0
5702         fi
5703         [ $i -ge $maxtime ] && \
5704             error "can't put import for $CONN_PROC into ${expected} state after $i sec, have ${CONN_STATE}" && \
5705             return 1
5706         sleep 1
5707         # Add uniq for multi-mount case
5708         CONN_STATE=$($LCTL get_param -n $CONN_PROC 2>/dev/null | cut -f2 | uniq)
5709         i=$(($i + 1))
5710     done
5711
5712     log "$CONN_PROC in ${CONN_STATE} state after $i sec"
5713     return 0
5714 }
5715
5716 wait_import_state() {
5717     local state=$1
5718     local params=$2
5719     local maxtime=${3:-$(max_recovery_time)}
5720     local param
5721
5722     for param in ${params//,/ }; do
5723         _wait_import_state $state $param $maxtime || return
5724     done
5725 }
5726
5727 wait_import_state_mount() {
5728         if ! is_mounted $MOUNT && ! is_mounted $MOUNT2; then
5729                 return 0
5730         fi
5731
5732         wait_import_state $*
5733 }
5734
5735 # One client request could be timed out because server was not ready
5736 # when request was sent by client.
5737 # The request timeout calculation details :
5738 # ptl_send_rpc ()
5739 #      /* We give the server rq_timeout secs to process the req, and
5740 #      add the network latency for our local timeout. */
5741 #      request->rq_deadline = request->rq_sent + request->rq_timeout +
5742 #           ptlrpc_at_get_net_latency(request) ;
5743 #
5744 # ptlrpc_connect_import ()
5745 #      request->rq_timeout = INITIAL_CONNECT_TIMEOUT
5746 #
5747 # init_imp_at () ->
5748 #   -> at_init(&at->iat_net_latency, 0, 0) -> iat_net_latency=0
5749 # ptlrpc_at_get_net_latency(request) ->
5750 #       at_get (max (iat_net_latency=0, at_min)) = at_min
5751 #
5752 # i.e.:
5753 # request->rq_timeout + ptlrpc_at_get_net_latency(request) =
5754 # INITIAL_CONNECT_TIMEOUT + at_min
5755 #
5756 # We will use obd_timeout instead of INITIAL_CONNECT_TIMEOUT
5757 # because we can not get this value in runtime,
5758 # the value depends on configure options, and it is not stored in /proc.
5759 # obd_support.h:
5760 # #define CONNECTION_SWITCH_MIN 5U
5761 # #define INITIAL_CONNECT_TIMEOUT max(CONNECTION_SWITCH_MIN,obd_timeout/20)
5762
5763 request_timeout () {
5764     local facet=$1
5765
5766     # request->rq_timeout = INITIAL_CONNECT_TIMEOUT
5767     local init_connect_timeout=$TIMEOUT
5768     [[ $init_connect_timeout -ge 5 ]] || init_connect_timeout=5
5769
5770     local at_min=$(at_get $facet at_min)
5771
5772     echo $(( init_connect_timeout + at_min ))
5773 }
5774
5775 _wait_osc_import_state() {
5776         local facet=$1
5777         local ost_facet=$2
5778         local expected=$3
5779         local ost=$(get_osc_import_name $facet $ost_facet)
5780         local param="osc.${ost}.ost_server_uuid"
5781         local params=$param
5782         local i=0
5783
5784         # 1. wait the deadline of client 1st request (it could be skipped)
5785         # 2. wait the deadline of client 2nd request
5786         local maxtime=$(( 2 * $(request_timeout $facet)))
5787
5788         if [[ $facet == client* ]]; then
5789                 # During setup time, the osc might not be setup, it need wait
5790                 # until list_param can return valid value. And also if there
5791                 # are mulitple osc entries we should list all of them before
5792                 # go to wait.
5793                 params=$($LCTL list_param $param 2>/dev/null || true)
5794                 while [ -z "$params" ]; do
5795                         if [ $i -ge $maxtime ]; then
5796                                 echo "can't get $param in $maxtime secs"
5797                                 return 1
5798                         fi
5799                         sleep 1
5800                         i=$((i + 1))
5801                         params=$($LCTL list_param $param 2>/dev/null || true)
5802                 done
5803         fi
5804         if ! do_rpc_nodes "$(facet_active_host $facet)" \
5805                         wait_import_state $expected "$params" $maxtime; then
5806                 error "import is not in ${expected} state"
5807                 return 1
5808         fi
5809
5810         return 0
5811 }
5812
5813 wait_osc_import_state() {
5814         local facet=$1
5815         local ost_facet=$2
5816         local expected=$3
5817         local num
5818
5819         if [[ $facet = mds ]]; then
5820                 for num in $(seq $MDSCOUNT); do
5821                         _wait_osc_import_state mds$num "$ost_facet" "$expected"
5822                 done
5823         else
5824                 _wait_osc_import_state "$facet" "$ost_facet" "$expected"
5825         fi
5826 }
5827
5828 get_clientmdc_proc_path() {
5829     echo "${1}-mdc-*"
5830 }
5831
5832 do_rpc_nodes () {
5833         local list=$1
5834         shift
5835
5836         [ -z "$list" ] && return 0
5837
5838         # Add paths to lustre tests for 32 and 64 bit systems.
5839         local LIBPATH="/usr/lib/lustre/tests:/usr/lib64/lustre/tests:"
5840         local TESTPATH="$RLUSTRE/tests:"
5841         local RPATH="PATH=${TESTPATH}${LIBPATH}${PATH}:/sbin:/bin:/usr/sbin:"
5842         do_nodesv $list "${RPATH} NAME=${NAME} sh rpc.sh $@ "
5843 }
5844
5845 wait_clients_import_state () {
5846     local list=$1
5847     local facet=$2
5848     local expected=$3
5849
5850     local facets=$facet
5851
5852     if [ "$FAILURE_MODE" = HARD ]; then
5853         facets=$(facets_on_host $(facet_active_host $facet))
5854     fi
5855
5856     for facet in ${facets//,/ }; do
5857     local label=$(convert_facet2label $facet)
5858     local proc_path
5859     case $facet in
5860         ost* ) proc_path="osc.$(get_clientosc_proc_path $label).ost_server_uuid" ;;
5861         mds* ) proc_path="mdc.$(get_clientmdc_proc_path $label).mds_server_uuid" ;;
5862         *) error "unknown facet!" ;;
5863     esac
5864     local params=$(expand_list $params $proc_path)
5865     done
5866
5867         if ! do_rpc_nodes "$list" wait_import_state_mount $expected $params; then
5868                 error "import is not in ${expected} state"
5869                 return 1
5870         fi
5871 }
5872
5873 oos_full() {
5874         local -a AVAILA
5875         local -a GRANTA
5876         local -a TOTALA
5877         local OSCFULL=1
5878         AVAILA=($(do_nodes $(comma_list $(osts_nodes)) \
5879                   $LCTL get_param obdfilter.*.kbytesavail))
5880         GRANTA=($(do_nodes $(comma_list $(osts_nodes)) \
5881                   $LCTL get_param -n obdfilter.*.tot_granted))
5882         TOTALA=($(do_nodes $(comma_list $(osts_nodes)) \
5883                   $LCTL get_param -n obdfilter.*.kbytestotal))
5884         for ((i=0; i<${#AVAILA[@]}; i++)); do
5885                 local -a AVAIL1=(${AVAILA[$i]//=/ })
5886                 local -a TOTAL=(${TOTALA[$i]//=/ })
5887                 GRANT=$((${GRANTA[$i]}/1024))
5888                 # allow 1% of total space in bavail because of delayed
5889                 # allocation with ZFS which might release some free space after
5890                 # txg commit.  For small devices, we set a mininum of 8MB
5891                 local LIMIT=$((${TOTAL} / 100 + 8000))
5892                 echo -n $(echo ${AVAIL1[0]} | cut -d"." -f2) avl=${AVAIL1[1]} \
5893                         grnt=$GRANT diff=$((AVAIL1[1] - GRANT)) limit=${LIMIT}
5894                 [ $((AVAIL1[1] - GRANT)) -lt $LIMIT ] && OSCFULL=0 && \
5895                         echo " FULL" || echo
5896         done
5897         return $OSCFULL
5898 }
5899
5900 pool_list () {
5901    do_facet mgs lctl pool_list $1
5902 }
5903
5904 create_pool() {
5905     local fsname=${1%%.*}
5906     local poolname=${1##$fsname.}
5907
5908     do_facet mgs lctl pool_new $1
5909     local RC=$?
5910     # get param should return err unless pool is created
5911     [[ $RC -ne 0 ]] && return $RC
5912
5913     wait_update $HOSTNAME "lctl get_param -n lov.$fsname-*.pools.$poolname \
5914         2>/dev/null || echo foo" "" || RC=1
5915     if [[ $RC -eq 0 ]]; then
5916         add_pool_to_list $1
5917     else
5918         error "pool_new failed $1"
5919     fi
5920     return $RC
5921 }
5922
5923 add_pool_to_list () {
5924     local fsname=${1%%.*}
5925     local poolname=${1##$fsname.}
5926
5927     local listvar=${fsname}_CREATED_POOLS
5928     eval export ${listvar}=$(expand_list ${!listvar} $poolname)
5929 }
5930
5931 remove_pool_from_list () {
5932     local fsname=${1%%.*}
5933     local poolname=${1##$fsname.}
5934
5935     local listvar=${fsname}_CREATED_POOLS
5936     eval export ${listvar}=$(exclude_items_from_list ${!listvar} $poolname)
5937 }
5938
5939 destroy_pool_int() {
5940     local ost
5941     local OSTS=$(do_facet $SINGLEMDS lctl pool_list $1 | \
5942         awk '$1 !~ /^Pool:/ {print $1}')
5943     for ost in $OSTS; do
5944         do_facet mgs lctl pool_remove $1 $ost
5945     done
5946     do_facet mgs lctl pool_destroy $1
5947 }
5948
5949 # <fsname>.<poolname> or <poolname>
5950 destroy_pool() {
5951     local fsname=${1%%.*}
5952     local poolname=${1##$fsname.}
5953
5954     [[ x$fsname = x$poolname ]] && fsname=$FSNAME
5955
5956     local RC
5957
5958     pool_list $fsname.$poolname || return $?
5959
5960     destroy_pool_int $fsname.$poolname
5961     RC=$?
5962     [[ $RC -ne 0 ]] && return $RC
5963
5964     wait_update $HOSTNAME "lctl get_param -n lov.$fsname-*.pools.$poolname \
5965       2>/dev/null || echo foo" "foo" || RC=1
5966
5967     if [[ $RC -eq 0 ]]; then
5968         remove_pool_from_list $fsname.$poolname
5969     else
5970         error "destroy pool failed $1"
5971     fi
5972     return $RC
5973 }
5974
5975 destroy_pools () {
5976     local fsname=${1:-$FSNAME}
5977     local poolname
5978     local listvar=${fsname}_CREATED_POOLS
5979
5980     pool_list $fsname
5981
5982     [ x${!listvar} = x ] && return 0
5983
5984     echo destroy the created pools: ${!listvar}
5985     for poolname in ${!listvar//,/ }; do
5986         destroy_pool $fsname.$poolname
5987     done
5988 }
5989
5990 cleanup_pools () {
5991     local fsname=${1:-$FSNAME}
5992     trap 0
5993     destroy_pools $fsname
5994 }
5995
5996 gather_logs () {
5997     local list=$1
5998
5999     local ts=$(date +%s)
6000     local docp=true
6001
6002     if [[ ! -f "$YAML_LOG" ]]; then
6003         # init_logging is not performed before gather_logs,
6004         # so the $LOGDIR needs to be checked here
6005         check_shared_dir $LOGDIR && touch $LOGDIR/shared
6006     fi
6007
6008     [ -f $LOGDIR/shared ] && docp=false
6009
6010     # dump lustre logs, dmesg
6011
6012     prefix="$TESTLOG_PREFIX.$TESTNAME"
6013     suffix="$ts.log"
6014     echo "Dumping lctl log to ${prefix}.*.${suffix}"
6015
6016     if [ "$CLIENTONLY" -o "$PDSH" == "no_dsh" ]; then
6017         echo "Dumping logs only on local client."
6018         $LCTL dk > ${prefix}.debug_log.$(hostname -s).${suffix}
6019         dmesg > ${prefix}.dmesg.$(hostname -s).${suffix}
6020         return
6021     fi
6022
6023     do_nodesv $list \
6024         "$LCTL dk > ${prefix}.debug_log.\\\$(hostname -s).${suffix};
6025          dmesg > ${prefix}.dmesg.\\\$(hostname -s).${suffix}"
6026     if [ ! -f $LOGDIR/shared ]; then
6027         do_nodes $list rsync -az "${prefix}.*.${suffix}" $HOSTNAME:$LOGDIR
6028     fi
6029 }
6030
6031 do_ls () {
6032     local mntpt_root=$1
6033     local num_mntpts=$2
6034     local dir=$3
6035     local i
6036     local cmd
6037     local pids
6038     local rc=0
6039
6040     for i in $(seq 0 $num_mntpts); do
6041         cmd="ls -laf ${mntpt_root}$i/$dir"
6042         echo + $cmd;
6043         $cmd > /dev/null &
6044         pids="$pids $!"
6045     done
6046     echo pids=$pids
6047     for pid in $pids; do
6048         wait $pid || rc=$?
6049     done
6050
6051     return $rc
6052 }
6053
6054 # target_start_and_reset_recovery_timer()
6055 #        service_time = at_est2timeout(service_time);
6056 #        service_time += 2 * (CONNECTION_SWITCH_MAX + CONNECTION_SWITCH_INC +
6057 #                             INITIAL_CONNECT_TIMEOUT);
6058 # CONNECTION_SWITCH_MAX : min(25U, max(CONNECTION_SWITCH_MIN,obd_timeout))
6059 #define CONNECTION_SWITCH_INC 1
6060 #define INITIAL_CONNECT_TIMEOUT max(CONNECTION_SWITCH_MIN,obd_timeout/20)
6061 #define CONNECTION_SWITCH_MIN 5U
6062
6063 max_recovery_time () {
6064     local init_connect_timeout=$(( TIMEOUT / 20 ))
6065     [[ $init_connect_timeout -ge 5 ]] || init_connect_timeout=5
6066
6067     local service_time=$(( $(at_max_get client) + $(( 2 * $(( 25 + 1  + init_connect_timeout)) )) ))
6068
6069     echo $service_time 
6070 }
6071
6072 get_clients_mount_count () {
6073     local clients=${CLIENTS:-`hostname`}
6074
6075     # we need to take into account the clients mounts and
6076     # exclude mds/ost mounts if any;
6077     do_nodes $clients cat /proc/mounts | grep lustre | grep $MOUNT | wc -l
6078 }
6079
6080 # gss functions
6081 PROC_CLI="srpc_info"
6082
6083 combination()
6084 {
6085     local M=$1
6086     local N=$2
6087     local R=1
6088
6089     if [ $M -lt $N ]; then
6090         R=0
6091     else
6092         N=$((N + 1))
6093         while [ $N -lt $M ]; do
6094             R=$((R * N))
6095             N=$((N + 1))
6096         done
6097     fi
6098
6099     echo $R
6100     return 0
6101 }
6102
6103 calc_connection_cnt() {
6104     local dir=$1
6105
6106     # MDT->MDT = 2 * C(M, 2)
6107     # MDT->OST = M * O
6108     # CLI->OST = C * O
6109     # CLI->MDT = C * M
6110     comb_m2=$(combination $MDSCOUNT 2)
6111
6112     local num_clients=$(get_clients_mount_count)
6113
6114     local cnt_mdt2mdt=$((comb_m2 * 2))
6115     local cnt_mdt2ost=$((MDSCOUNT * OSTCOUNT))
6116     local cnt_cli2ost=$((num_clients * OSTCOUNT))
6117     local cnt_cli2mdt=$((num_clients * MDSCOUNT))
6118     local cnt_all2ost=$((cnt_mdt2ost + cnt_cli2ost))
6119     local cnt_all2mdt=$((cnt_mdt2mdt + cnt_cli2mdt))
6120     local cnt_all2all=$((cnt_mdt2ost + cnt_mdt2mdt + cnt_cli2ost + cnt_cli2mdt))
6121
6122     local var=cnt_$dir
6123     local res=${!var}
6124
6125     echo $res
6126 }
6127
6128 set_rule()
6129 {
6130     local tgt=$1
6131     local net=$2
6132     local dir=$3
6133     local flavor=$4
6134     local cmd="$tgt.srpc.flavor"
6135
6136     if [ $net == "any" ]; then
6137         net="default"
6138     fi
6139     cmd="$cmd.$net"
6140
6141     if [ $dir != "any" ]; then
6142         cmd="$cmd.$dir"
6143     fi
6144
6145     cmd="$cmd=$flavor"
6146     log "Setting sptlrpc rule: $cmd"
6147     do_facet mgs "$LCTL conf_param $cmd"
6148 }
6149
6150 count_flvr()
6151 {
6152     local output=$1
6153     local flavor=$2
6154     local count=0
6155
6156     rpc_flvr=`echo $flavor | awk -F - '{ print $1 }'`
6157     bulkspec=`echo $flavor | awk -F - '{ print $2 }'`
6158
6159     count=`echo "$output" | grep "rpc flavor" | grep $rpc_flvr | wc -l`
6160
6161     if [ "x$bulkspec" != "x" ]; then
6162         algs=`echo $bulkspec | awk -F : '{ print $2 }'`
6163
6164         if [ "x$algs" != "x" ]; then
6165             bulk_count=`echo "$output" | grep "bulk flavor" | grep $algs | wc -l`
6166         else
6167             bulk=`echo $bulkspec | awk -F : '{ print $1 }'`
6168             if [ $bulk == "bulkn" ]; then
6169                 bulk_count=`echo "$output" | grep "bulk flavor" \
6170                             | grep "null/null" | wc -l`
6171             elif [ $bulk == "bulki" ]; then
6172                 bulk_count=`echo "$output" | grep "bulk flavor" \
6173                             | grep "/null" | grep -v "null/" | wc -l`
6174             else
6175                 bulk_count=`echo "$output" | grep "bulk flavor" \
6176                             | grep -v "/null" | grep -v "null/" | wc -l`
6177             fi
6178         fi
6179
6180         [ $bulk_count -lt $count ] && count=$bulk_count
6181     fi
6182
6183     echo $count
6184 }
6185
6186 flvr_cnt_cli2mdt()
6187 {
6188     local flavor=$1
6189     local cnt
6190
6191     local clients=${CLIENTS:-`hostname`}
6192
6193     for c in ${clients//,/ }; do
6194         output=`do_node $c lctl get_param -n mdc.*-MDT*-mdc-*.$PROC_CLI 2>/dev/null`
6195         tmpcnt=`count_flvr "$output" $flavor`
6196         cnt=$((cnt + tmpcnt))
6197     done
6198     echo $cnt
6199 }
6200
6201 flvr_cnt_cli2ost()
6202 {
6203     local flavor=$1
6204     local cnt
6205
6206     local clients=${CLIENTS:-`hostname`}
6207
6208     for c in ${clients//,/ }; do
6209         output=`do_node $c lctl get_param -n osc.*OST*-osc-[^M][^D][^T]*.$PROC_CLI 2>/dev/null`
6210         tmpcnt=`count_flvr "$output" $flavor`
6211         cnt=$((cnt + tmpcnt))
6212     done
6213     echo $cnt
6214 }
6215
6216 flvr_cnt_mdt2mdt()
6217 {
6218     local flavor=$1
6219     local cnt=0
6220
6221     if [ $MDSCOUNT -le 1 ]; then
6222         echo 0
6223         return
6224     fi
6225
6226     for num in `seq $MDSCOUNT`; do
6227         output=`do_facet mds$num lctl get_param -n mdc.*-MDT*-mdc[0-9]*.$PROC_CLI 2>/dev/null`
6228         tmpcnt=`count_flvr "$output" $flavor`
6229         cnt=$((cnt + tmpcnt))
6230     done
6231     echo $cnt;
6232 }
6233
6234 flvr_cnt_mdt2ost()
6235 {
6236     local flavor=$1
6237     local cnt=0
6238     local mdtosc
6239
6240     for num in `seq $MDSCOUNT`; do
6241         mdtosc=$(get_mdtosc_proc_path mds$num)
6242         mdtosc=${mdtosc/-MDT*/-MDT\*}
6243         output=$(do_facet mds$num lctl get_param -n \
6244             osc.$mdtosc.$PROC_CLI 2>/dev/null)
6245         tmpcnt=`count_flvr "$output" $flavor`
6246         cnt=$((cnt + tmpcnt))
6247     done
6248     echo $cnt;
6249 }
6250
6251 flvr_cnt_mgc2mgs()
6252 {
6253     local flavor=$1
6254
6255     output=`do_facet client lctl get_param -n mgc.*.$PROC_CLI 2>/dev/null`
6256     count_flvr "$output" $flavor
6257 }
6258
6259 do_check_flavor()
6260 {
6261     local dir=$1        # from to
6262     local flavor=$2     # flavor expected
6263     local res=0
6264
6265     if [ $dir == "cli2mdt" ]; then
6266         res=`flvr_cnt_cli2mdt $flavor`
6267     elif [ $dir == "cli2ost" ]; then
6268         res=`flvr_cnt_cli2ost $flavor`
6269     elif [ $dir == "mdt2mdt" ]; then
6270         res=`flvr_cnt_mdt2mdt $flavor`
6271     elif [ $dir == "mdt2ost" ]; then
6272         res=`flvr_cnt_mdt2ost $flavor`
6273     elif [ $dir == "all2ost" ]; then
6274         res1=`flvr_cnt_mdt2ost $flavor`
6275         res2=`flvr_cnt_cli2ost $flavor`
6276         res=$((res1 + res2))
6277     elif [ $dir == "all2mdt" ]; then
6278         res1=`flvr_cnt_mdt2mdt $flavor`
6279         res2=`flvr_cnt_cli2mdt $flavor`
6280         res=$((res1 + res2))
6281     elif [ $dir == "all2all" ]; then
6282         res1=`flvr_cnt_mdt2ost $flavor`
6283         res2=`flvr_cnt_cli2ost $flavor`
6284         res3=`flvr_cnt_mdt2mdt $flavor`
6285         res4=`flvr_cnt_cli2mdt $flavor`
6286         res=$((res1 + res2 + res3 + res4))
6287     fi
6288
6289     echo $res
6290 }
6291
6292 wait_flavor()
6293 {
6294     local dir=$1        # from to
6295     local flavor=$2     # flavor expected
6296     local expect=${3:-$(calc_connection_cnt $dir)}     # number expected
6297
6298     local res=0
6299
6300     for ((i=0;i<20;i++)); do
6301         echo -n "checking $dir..."
6302         res=$(do_check_flavor $dir $flavor)
6303         echo "found $res/$expect $flavor connections"
6304         [ $res -ge $expect ] && return 0
6305         sleep 4
6306     done
6307
6308     echo "Error checking $flavor of $dir: expect $expect, actual $res"
6309     return 1
6310 }
6311
6312 restore_to_default_flavor()
6313 {
6314     local proc="mgs.MGS.live.$FSNAME"
6315
6316     echo "restoring to default flavor..."
6317
6318     nrule=`do_facet mgs lctl get_param -n $proc 2>/dev/null | grep ".srpc.flavor." | wc -l`
6319
6320     # remove all existing rules if any
6321     if [ $nrule -ne 0 ]; then
6322         echo "$nrule existing rules"
6323         for rule in `do_facet mgs lctl get_param -n $proc 2>/dev/null | grep ".srpc.flavor."`; do
6324             echo "remove rule: $rule"
6325             spec=`echo $rule | awk -F = '{print $1}'`
6326             do_facet mgs "$LCTL conf_param -d $spec"
6327         done
6328     fi
6329
6330     # verify no rules left
6331     nrule=`do_facet mgs lctl get_param -n $proc 2>/dev/null | grep ".srpc.flavor." | wc -l`
6332     [ $nrule -ne 0 ] && error "still $nrule rules left"
6333
6334     # wait for default flavor to be applied
6335     # currently default flavor for all connections are 'null'
6336     wait_flavor all2all null
6337     echo "now at default flavor settings"
6338 }
6339
6340 set_flavor_all()
6341 {
6342     local flavor=${1:-null}
6343
6344     echo "setting all flavor to $flavor"
6345
6346     # FIXME need parameter to this fn
6347     # and remove global vars
6348     local cnt_all2all=$(calc_connection_cnt all2all)
6349
6350     local res=$(do_check_flavor all2all $flavor)
6351     if [ $res -eq $cnt_all2all ]; then
6352         echo "already have total $res $flavor connections"
6353         return
6354     fi
6355
6356     echo "found $res $flavor out of total $cnt_all2all connections"
6357     restore_to_default_flavor
6358
6359     [[ $flavor = null ]] && return 0
6360
6361     set_rule $FSNAME any any $flavor
6362     wait_flavor all2all $flavor
6363 }
6364
6365
6366 check_logdir() {
6367     local dir=$1
6368     # Checking for shared logdir
6369     if [ ! -d $dir ]; then
6370         # Not found. Create local logdir
6371         mkdir -p $dir
6372     else
6373         touch $dir/check_file.$(hostname -s)
6374     fi
6375     return 0
6376 }
6377
6378 check_write_access() {
6379         local dir=$1
6380         local list=${2:-$(comma_list $(nodes_list))}
6381         local node
6382         local file
6383
6384         for node in ${list//,/ }; do
6385                 file=$dir/check_file.$(short_nodename $node)
6386                 if [[ ! -f "$file" ]]; then
6387                         # Logdir not accessible/writable from this node.
6388                         return 1
6389                 fi
6390                 rm -f $file || return 1
6391         done
6392         return 0
6393 }
6394
6395 init_logging() {
6396     if [[ -n $YAML_LOG ]]; then
6397         return
6398     fi
6399     local SAVE_UMASK=`umask`
6400     umask 0000
6401
6402     export YAML_LOG=${LOGDIR}/results.yml
6403     mkdir -p $LOGDIR
6404     init_clients_lists
6405
6406     if [ ! -f $YAML_LOG ]; then       # If the yaml log already exists then we will just append to it
6407       if check_shared_dir $LOGDIR; then
6408           touch $LOGDIR/shared
6409           echo "Logging to shared log directory: $LOGDIR"
6410       else
6411           echo "Logging to local directory: $LOGDIR"
6412       fi
6413
6414       yml_nodes_file $LOGDIR >> $YAML_LOG
6415       yml_results_file >> $YAML_LOG
6416     fi
6417
6418     umask $SAVE_UMASK
6419 }
6420
6421 log_test() {
6422     yml_log_test $1 >> $YAML_LOG
6423 }
6424
6425 log_test_status() {
6426      yml_log_test_status $@ >> $YAML_LOG
6427 }
6428
6429 log_sub_test_begin() {
6430     yml_log_sub_test_begin "$@" >> $YAML_LOG
6431 }
6432
6433 log_sub_test_end() {
6434     yml_log_sub_test_end "$@" >> $YAML_LOG
6435 }
6436
6437 run_llverdev()
6438 {
6439         local dev=$1
6440         local llverdev_opts=$2
6441         local devname=$(basename $1)
6442         local size=$(grep "$devname"$ /proc/partitions | awk '{print $3}')
6443         # loop devices aren't in /proc/partitions
6444         [ "x$size" == "x" ] && local size=$(ls -l $dev | awk '{print $5}')
6445
6446         size=$(($size / 1024 / 1024)) # Gb
6447
6448         local partial_arg=""
6449         # Run in partial (fast) mode if the size
6450         # of a partition > 1 GB
6451         [ $size -gt 1 ] && partial_arg="-p"
6452
6453         llverdev --force $partial_arg $llverdev_opts $dev
6454 }
6455
6456 run_llverfs()
6457 {
6458         local dir=$1
6459         local llverfs_opts=$2
6460         local use_partial_arg=$3
6461         local partial_arg=""
6462         local size=$(df -B G $dir |tail -n 1 |awk '{print $2}' |sed 's/G//') #GB
6463
6464         # Run in partial (fast) mode if the size
6465         # of a partition > 1 GB
6466         [ "x$use_partial_arg" != "xno" ] && [ $size -gt 1 ] && partial_arg="-p"
6467
6468         llverfs $partial_arg $llverfs_opts $dir
6469 }
6470
6471 #Remove objects from OST
6472 remove_ost_objects() {
6473         local facet=$1
6474         local ostdev=$2
6475         local group=$3
6476         shift 3
6477         local objids="$@"
6478         local mntpt=$(facet_mntpt $facet)
6479         local opts=$OST_MOUNT_OPTS
6480         local i
6481         local rc
6482
6483         echo "removing objects from $ostdev on $facet: $objids"
6484         if ! test -b $ostdev; then
6485                 opts=$(csa_add "$opts" -o loop)
6486         fi
6487         mount -t $(facet_fstype $facet) $opts $ostdev $mntpt ||
6488                 return $?
6489         rc=0
6490         for i in $objids; do
6491                 rm $mntpt/O/$group/d$((i % 32))/$i || { rc=$?; break; }
6492         done
6493         umount -f $mntpt || return $?
6494         return $rc
6495 }
6496
6497 #Remove files from MDT
6498 remove_mdt_files() {
6499         local facet=$1
6500         local mdtdev=$2
6501         shift 2
6502         local files="$@"
6503         local mntpt=$(facet_mntpt $facet)
6504         local opts=$MDS_MOUNT_OPTS
6505
6506         echo "removing files from $mdtdev on $facet: $files"
6507         if [ $(facet_fstype $facet) == ldiskfs ] &&
6508            ! do_facet $facet test -b $mdtdev; then
6509                 opts=$(csa_add "$opts" -o loop)
6510         fi
6511         mount -t $(facet_fstype $facet) $opts $mdtdev $mntpt ||
6512                 return $?
6513         rc=0
6514         for f in $files; do
6515                 rm $mntpt/ROOT/$f || { rc=$?; break; }
6516         done
6517         umount -f $mntpt || return $?
6518         return $rc
6519 }
6520
6521 duplicate_mdt_files() {
6522         local facet=$1
6523         local mdtdev=$2
6524         shift 2
6525         local files="$@"
6526         local mntpt=$(facet_mntpt $facet)
6527         local opts=$MDS_MOUNT_OPTS
6528
6529         echo "duplicating files on $mdtdev on $facet: $files"
6530         mkdir -p $mntpt || return $?
6531         if [ $(facet_fstype $facet) == ldiskfs ] &&
6532            ! do_facet $facet test -b $mdtdev; then
6533                 opts=$(csa_add "$opts" -o loop)
6534         fi
6535         mount -t $(facet_fstype $facet) $opts $mdtdev $mntpt ||
6536                 return $?
6537
6538     do_umount() {
6539         trap 0
6540         popd > /dev/null
6541         rm $tmp
6542         umount -f $mntpt
6543     }
6544     trap do_umount EXIT
6545
6546     tmp=$(mktemp $TMP/setfattr.XXXXXXXXXX)
6547     pushd $mntpt/ROOT > /dev/null || return $?
6548     rc=0
6549     for f in $files; do
6550         touch $f.bad || return $?
6551         getfattr -n trusted.lov $f | sed "s#$f#&.bad#" > $tmp
6552         rc=${PIPESTATUS[0]}
6553         [ $rc -eq 0 ] || return $rc
6554         setfattr --restore $tmp || return $?
6555     done
6556     do_umount
6557 }
6558
6559 run_sgpdd () {
6560     local devs=${1//,/ }
6561     shift
6562     local params=$@
6563     local rslt=$TMP/sgpdd_survey
6564
6565     # sgpdd-survey cleanups ${rslt}.* files
6566
6567     local cmd="rslt=$rslt $params scsidevs=\"$devs\" $SGPDDSURVEY"
6568     echo + $cmd
6569     eval $cmd
6570     cat ${rslt}.detail
6571 }
6572
6573 # returns the canonical name for an ldiskfs device
6574 ldiskfs_canon() {
6575         local dev="$1"
6576         local facet="$2"
6577
6578         do_facet $facet "dv=\\\$(lctl get_param -n $dev);
6579 if foo=\\\$(lvdisplay -c \\\$dv 2>/dev/null); then
6580     echo dm-\\\${foo##*:};
6581 else
6582     echo \\\$(basename \\\$dv);
6583 fi;"
6584 }
6585
6586 is_sanity_benchmark() {
6587     local benchmarks="dbench bonnie iozone fsx"
6588     local suite=$1
6589     for b in $benchmarks; do
6590         if [ "$b" == "$suite" ]; then
6591             return 0
6592         fi
6593     done
6594     return 1
6595 }
6596
6597 min_ost_size () {
6598     $LCTL get_param -n osc.*.kbytesavail | sort -n | head -n1
6599 }
6600
6601 #
6602 # Get the available size (KB) of a given obd target.
6603 #
6604 get_obd_size() {
6605         local facet=$1
6606         local obd=$2
6607         local size
6608
6609         [[ $facet != client ]] || return 0
6610
6611         size=$(do_facet $facet $LCTL get_param -n *.$obd.kbytesavail | head -n1)
6612         echo -n $size
6613 }
6614
6615 #
6616 # Get the page size (bytes) on a given facet node.
6617 #
6618 get_page_size() {
6619         local facet=$1
6620         local size
6621
6622         size=$(do_facet $facet getconf PAGE_SIZE)
6623         [[ ${PIPESTATUS[0]} = 0 && -n "$size" ]] || size=4096
6624         echo -n $size
6625 }
6626
6627 #
6628 # Get the block count of the filesystem.
6629 #
6630 get_block_count() {
6631         local facet=$1
6632         local device=$2
6633         local count
6634
6635         count=$(do_facet $facet "$DUMPE2FS -h $device 2>&1" |
6636                 awk '/^Block count:/ {print $3}')
6637         echo -n $count
6638 }
6639
6640 # Get the block size of the filesystem.
6641 get_block_size() {
6642     local facet=$1
6643     local device=$2
6644     local size
6645
6646     size=$(do_facet $facet "$DUMPE2FS -h $device 2>&1" |
6647            awk '/^Block size:/ {print $3}')
6648     echo $size
6649 }
6650
6651 # Check whether the "large_xattr" feature is enabled or not.
6652 large_xattr_enabled() {
6653         [[ $(facet_fstype $SINGLEMDS) == zfs ]] && return 0
6654
6655         local mds_dev=$(mdsdevname ${SINGLEMDS//mds/})
6656
6657         do_facet $SINGLEMDS "$DUMPE2FS -h $mds_dev 2>&1 |
6658                 grep -E -q '(ea_inode|large_xattr)'"
6659         return ${PIPESTATUS[0]}
6660 }
6661
6662 # Get the maximum xattr size supported by the filesystem.
6663 max_xattr_size() {
6664     local size
6665
6666     if large_xattr_enabled; then
6667         # include/linux/limits.h: #define XATTR_SIZE_MAX 65536
6668         size=65536
6669     else
6670         local mds_dev=$(mdsdevname ${SINGLEMDS//mds/})
6671         local block_size=$(get_block_size $SINGLEMDS $mds_dev)
6672
6673         # maximum xattr size = size of block - size of header -
6674         #                      size of 1 entry - 4 null bytes
6675         size=$((block_size - 32 - 32 - 4))
6676     fi
6677
6678     echo $size
6679 }
6680
6681 # Dump the value of the named xattr from a file.
6682 get_xattr_value() {
6683     local xattr_name=$1
6684     local file=$2
6685
6686     echo "$(getfattr -n $xattr_name --absolute-names --only-values $file)"
6687 }
6688
6689 # Generate a string with size of $size bytes.
6690 generate_string() {
6691     local size=${1:-1024} # in bytes
6692
6693     echo "$(head -c $size < /dev/zero | tr '\0' y)"
6694 }
6695
6696 reformat_external_journal() {
6697         local facet=$1
6698
6699         if [ ! -z ${EJOURNAL} ]; then
6700                 local rcmd="do_facet $facet"
6701
6702                 echo "reformat external journal on $facet:${EJOURNAL}"
6703                 ${rcmd} mke2fs -O journal_dev ${EJOURNAL} || return 1
6704         fi
6705 }
6706
6707 # MDT file-level backup/restore
6708 mds_backup_restore() {
6709         local facet=$1
6710         local igif=$2
6711         local devname=$(mdsdevname $(facet_number $facet))
6712         local mntpt=$(facet_mntpt brpt)
6713         local rcmd="do_facet $facet"
6714         local metaea=${TMP}/backup_restore.ea
6715         local metadata=${TMP}/backup_restore.tgz
6716         local opts=${MDS_MOUNT_OPTS}
6717         local svc=${facet}_svc
6718
6719         if ! ${rcmd} test -b ${devname}; then
6720                 opts=$(csa_add "$opts" -o loop)
6721         fi
6722
6723         echo "file-level backup/restore on $facet:${devname}"
6724
6725         # step 1: build mount point
6726         ${rcmd} mkdir -p $mntpt
6727         # step 2: cleanup old backup
6728         ${rcmd} rm -f $metaea $metadata
6729         # step 3: mount dev
6730         ${rcmd} mount -t ldiskfs $opts $devname $mntpt || return 1
6731         if [ ! -z $igif ]; then
6732                 # step 3.5: rm .lustre
6733                 ${rcmd} rm -rf $mntpt/ROOT/.lustre || return 1
6734         fi
6735         # step 4: backup metaea
6736         echo "backup EA"
6737         ${rcmd} "cd $mntpt && getfattr -R -d -m '.*' -P . > $metaea && cd -" ||
6738                 return 2
6739         # step 5: backup metadata
6740         echo "backup data"
6741         ${rcmd} tar zcf $metadata -C $mntpt/ . > /dev/null 2>&1 || return 3
6742         # step 6: umount
6743         ${rcmd} umount -d $mntpt || return 4
6744         # step 7: reformat external journal if needed
6745         reformat_external_journal $facet || return 5
6746         # step 8: reformat dev
6747         echo "reformat new device"
6748         add $facet $(mkfs_opts $facet ${devname}) --backfstype ldiskfs \
6749                 --reformat ${devname} $(mdsvdevname $(facet_number $facet)) \
6750                 > /dev/null || exit 6
6751         # step 9: mount dev
6752         ${rcmd} mount -t ldiskfs $opts $devname $mntpt || return 7
6753         # step 10: restore metadata
6754         echo "restore data"
6755         ${rcmd} tar zxfp $metadata -C $mntpt > /dev/null 2>&1 || return 8
6756         # step 11: restore metaea
6757         echo "restore EA"
6758         ${rcmd} "cd $mntpt && setfattr --restore=$metaea && cd - " || return 9
6759         # step 12: remove recovery logs
6760         echo "remove recovery logs"
6761         ${rcmd} rm -fv $mntpt/OBJECTS/* $mntpt/CATALOGS
6762         # step 13: umount dev
6763         ${rcmd} umount -d $mntpt || return 10
6764         # step 14: cleanup tmp backup
6765         ${rcmd} rm -f $metaea $metadata
6766         # step 15: reset device label - it's not virgin on
6767         ${rcmd} e2label $devname ${!svc}
6768 }
6769
6770 # remove OI files
6771 mds_remove_ois() {
6772         local facet=$1
6773         local idx=$2
6774         local devname=$(mdsdevname $(facet_number $facet))
6775         local mntpt=$(facet_mntpt brpt)
6776         local rcmd="do_facet $facet"
6777         local opts=${MDS_MOUNT_OPTS}
6778
6779         if ! ${rcmd} test -b ${devname}; then
6780                 opts=$(csa_add "$opts" -o loop)
6781         fi
6782
6783         echo "removing OI files on $facet: idx=${idx}"
6784
6785         # step 1: build mount point
6786         ${rcmd} mkdir -p $mntpt
6787         # step 2: mount dev
6788         ${rcmd} mount -t ldiskfs $opts $devname $mntpt || return 1
6789         if [ -z $idx ]; then
6790                 # step 3: remove all OI files
6791                 ${rcmd} rm -fv $mntpt/oi.16*
6792         elif [ $idx -lt 2 ]; then
6793                 ${rcmd} rm -fv $mntpt/oi.16.${idx}
6794         else
6795                 local i
6796
6797                 # others, rm oi.16.[idx, idx * idx, idx ** ...]
6798                 for ((i=${idx}; i<64; i=$((i * idx)))); do
6799                         ${rcmd} rm -fv $mntpt/oi.16.${i}
6800                 done
6801         fi
6802         # step 4: umount
6803         ${rcmd} umount -d $mntpt || return 2
6804         # OI files will be recreated when mounted as lustre next time.
6805 }
6806
6807 # generate maloo upload-able log file name
6808 # \param logname specify unique part of file name
6809 generate_logname() {
6810         local logname=${1:-"default_logname"}
6811
6812         echo "$TESTLOG_PREFIX.$TESTNAME.$logname.$(hostname -s).log"
6813 }
6814
6815 # make directory on different MDTs
6816 test_mkdir() {
6817         local option
6818         local parent
6819         local child
6820         local path
6821         local p_option
6822         local option2
6823         local stripe_count=2
6824         local rc=0
6825
6826         case $# in
6827                 1) path=$1;;
6828                 2) option=$1
6829                    path=$2;;
6830                 3) option=$1
6831                    option2=$2
6832                    path=$3;;
6833                 *) error "Only creating single directory is supported";;
6834         esac
6835
6836         child=$(basename $path)
6837         parent=$(dirname $path)
6838
6839         if [ "$option" == "-p" -o "$option2" == "-p" ]; then
6840                 if [ -d $parent/$child ]; then
6841                         return $rc
6842                 fi
6843                 p_option="-p"
6844         fi
6845
6846         if [ "${option:0:2}" == "-c" ]; then
6847                 stripe_count=$(echo $option | sed 's/^-c//')
6848         fi
6849
6850         if [ "${option2:0:2}" == "-c" ]; then
6851                 stripe_count=$(echo $option2 | sed 's/^-c//')
6852         fi
6853
6854         if [ ! -d ${parent} ]; then
6855                 if [ "$p_option" == "-p" ]; then
6856                         mkdir -p ${parent}
6857                 else
6858                         return 1
6859                 fi
6860         fi
6861
6862         if [ $MDSCOUNT -le 1 ]; then
6863                 mkdir $p_option $parent/$child || rc=$?
6864         else
6865                 local mdt_idx=$($LFS getstripe -M $parent)
6866                 local test_num=$(echo $testnum | sed -e 's/[^0-9]*//g')
6867
6868                 mdt_idx=$((test_num % MDSCOUNT))
6869                 echo "striped dir -i$mdt_idx -c$stripe_count $path"
6870                 $LFS setdirstripe -i$mdt_idx -c$stripe_count $path || rc=$?
6871         fi
6872         return $rc
6873 }
6874
6875 # find the smallest and not in use file descriptor
6876 free_fd()
6877 {
6878         local max_fd=$(ulimit -n)
6879         local fd=3
6880         while [[ $fd -le $max_fd && -e /proc/self/fd/$fd ]]; do
6881                 ((++fd))
6882         done
6883         [ $fd -lt $max_fd ] || error "finding free file descriptor failed"
6884         echo $fd
6885 }
6886
6887 check_mount_and_prep()
6888 {
6889         is_mounted $MOUNT || setupall
6890
6891         rm -rf $DIR/[df][0-9]* || error "Fail to cleanup the env!"
6892         mkdir $DIR/$tdir || error "Fail to mkdir $DIR/$tdir."
6893 }
6894
6895 # calcule how many ost-objects to be created.
6896 precreated_ost_obj_count()
6897 {
6898         local mdt_idx=$1
6899         local ost_idx=$2
6900         local mdt_name="MDT$(printf '%04x' $mdt_idx)"
6901         local ost_name="OST$(printf '%04x' $ost_idx)"
6902         local proc_path="${FSNAME}-${ost_name}-osc-${mdt_name}"
6903         local last_id=$(do_facet mds${mdt_idx} lctl get_param -n \
6904                         osp.$proc_path.prealloc_last_id)
6905         local next_id=$(do_facet mds${mdt_idx} lctl get_param -n \
6906                         osp.$proc_path.prealloc_next_id)
6907
6908         echo $((last_id - next_id + 1))
6909 }
6910
6911 check_file_in_pool()
6912 {
6913         local file=$1
6914         local pool=$2
6915         local tlist="$3"
6916         local res=$($GETSTRIPE $file | grep 0x | cut -f2)
6917         for i in $res
6918         do
6919                 for t in $tlist ; do
6920                         [ "$i" -eq "$t" ] && continue 2
6921                 done
6922
6923                 echo "pool list: $tlist"
6924                 echo "striping: $res"
6925                 error_noexit "$file not allocated in $pool"
6926                 return 1
6927         done
6928         return 0
6929 }
6930
6931 pool_add() {
6932         echo "Creating new pool"
6933         local pool=$1
6934
6935         create_pool $FSNAME.$pool ||
6936                 { error_noexit "No pool created, result code $?"; return 1; }
6937         [ $($LFS pool_list $FSNAME | grep -c $pool) -eq 1 ] ||
6938                 { error_noexit "$pool not in lfs pool_list"; return 2; }
6939 }
6940
6941 pool_add_targets() {
6942         echo "Adding targets to pool"
6943         local pool=$1
6944         local first=$2
6945         local last=$3
6946         local step=${4:-1}
6947
6948         local list=$(seq $first $step $last)
6949
6950         local t=$(for i in $list; do printf "$FSNAME-OST%04x_UUID " $i; done)
6951         do_facet mgs $LCTL pool_add \
6952                         $FSNAME.$pool $FSNAME-OST[$first-$last/$step]
6953         wait_update $HOSTNAME "lctl get_param -n lov.$FSNAME-*.pools.$pool \
6954                         | sort -u | tr '\n' ' ' " "$t" || {
6955                 error_noexit "Add to pool failed"
6956                 return 1
6957         }
6958         local lfscount=$($LFS pool_list $FSNAME.$pool | grep -c "\-OST")
6959         local addcount=$(((last - first) / step + 1))
6960         [ $lfscount -eq $addcount ] || {
6961                 error_noexit "lfs pool_list bad ost count" \
6962                                                 "$lfscount != $addcount"
6963                 return 2
6964         }
6965 }
6966
6967 pool_set_dir() {
6968         local pool=$1
6969         local tdir=$2
6970         echo "Setting pool on directory $tdir"
6971
6972         $SETSTRIPE -c 2 -p $pool $tdir && return 0
6973
6974         error_noexit "Cannot set pool $pool to $tdir"
6975         return 1
6976 }
6977
6978 pool_check_dir() {
6979         local pool=$1
6980         local tdir=$2
6981         echo "Checking pool on directory $tdir"
6982
6983         local res=$($GETSTRIPE --pool $tdir | sed "s/\s*$//")
6984         [ "$res" = "$pool" ] && return 0
6985
6986         error_noexit "Pool on '$tdir' is '$res', not '$pool'"
6987         return 1
6988 }
6989
6990 pool_dir_rel_path() {
6991         echo "Testing relative path works well"
6992         local pool=$1
6993         local tdir=$2
6994         local root=$3
6995
6996         mkdir -p $root/$tdir/$tdir
6997         cd $root/$tdir
6998         pool_set_dir $pool $tdir          || return 1
6999         pool_set_dir $pool ./$tdir        || return 2
7000         pool_set_dir $pool ../$tdir       || return 3
7001         pool_set_dir $pool ../$tdir/$tdir || return 4
7002         rm -rf $tdir; cd - > /dev/null
7003 }
7004
7005 pool_alloc_files() {
7006         echo "Checking files allocation from directory pool"
7007         local pool=$1
7008         local tdir=$2
7009         local count=$3
7010         local tlist="$4"
7011
7012         local failed=0
7013         for i in $(seq -w 1 $count)
7014         do
7015                 local file=$tdir/file-$i
7016                 touch $file
7017                 check_file_in_pool $file $pool "$tlist" || \
7018                         failed=$((failed + 1))
7019         done
7020         [ "$failed" = 0 ] && return 0
7021
7022         error_noexit "$failed files not allocated in $pool"
7023         return 1
7024 }
7025
7026 pool_create_files() {
7027         echo "Creating files in pool"
7028         local pool=$1
7029         local tdir=$2
7030         local count=$3
7031         local tlist="$4"
7032
7033         mkdir -p $tdir
7034         local failed=0
7035         for i in $(seq -w 1 $count)
7036         do
7037                 local file=$tdir/spoo-$i
7038                 $SETSTRIPE -p $pool $file
7039                 check_file_in_pool $file $pool "$tlist" || \
7040                         failed=$((failed + 1))
7041         done
7042         [ "$failed" = 0 ] && return 0
7043
7044         error_noexit "$failed files not allocated in $pool"
7045         return 1
7046 }
7047
7048 pool_lfs_df() {
7049         echo "Checking 'lfs df' output"
7050         local pool=$1
7051
7052         local t=$($LCTL get_param -n lov.$FSNAME-clilov-*.pools.$pool |
7053                         tr '\n' ' ')
7054         local res=$($LFS df --pool $FSNAME.$pool |
7055                         awk '{print $1}' |
7056                         grep "$FSNAME-OST" |
7057                         tr '\n' ' ')
7058         [ "$res" = "$t" ] && return 0
7059
7060         error_noexit "Pools OSTs '$t' is not '$res' that lfs df reports"
7061         return 1
7062 }
7063
7064 pool_file_rel_path() {
7065         echo "Creating files in a pool with relative pathname"
7066         local pool=$1
7067         local tdir=$2
7068
7069         mkdir -p $tdir ||
7070                 { error_noexit "unable to create $tdir"; return 1 ; }
7071         local file="/..$tdir/$tfile-1"
7072         $SETSTRIPE -p $pool $file ||
7073                 { error_noexit "unable to create $file" ; return 2 ; }
7074
7075         cd $tdir
7076         $SETSTRIPE -p $pool $tfile-2 || {
7077                 error_noexit "unable to create $tfile-2 in $tdir"
7078                 return 3
7079         }
7080 }
7081
7082 pool_remove_first_target() {
7083         echo "Removing first target from a pool"
7084         local pool=$1
7085
7086         local pname="lov.$FSNAME-*.pools.$pool"
7087         local t=$($LCTL get_param -n $pname | head -1)
7088         do_facet mgs $LCTL pool_remove $FSNAME.$pool $t
7089         wait_update $HOSTNAME "lctl get_param -n $pname | grep $t" "" || {
7090                 error_noexit "$t not removed from $FSNAME.$pool"
7091                 return 1
7092         }
7093 }
7094
7095 pool_remove_all_targets() {
7096         echo "Removing all targets from pool"
7097         local pool=$1
7098         local file=$2
7099         local pname="lov.$FSNAME-*.pools.$pool"
7100         for t in $($LCTL get_param -n $pname | sort -u)
7101         do
7102                 do_facet mgs $LCTL pool_remove $FSNAME.$pool $t
7103         done
7104         wait_update $HOSTNAME "lctl get_param -n $pname" "" || {
7105                 error_noexit "Pool $FSNAME.$pool cannot be drained"
7106                 return 1
7107         }
7108         # striping on an empty/nonexistant pool should fall back
7109         # to "pool of everything"
7110         touch $file || {
7111                 error_noexit "failed to use fallback striping for empty pool"
7112                 return 2
7113         }
7114         # setstripe on an empty pool should fail
7115         $SETSTRIPE -p $pool $file 2>/dev/null && {
7116                 error_noexit "expected failure when creating file" \
7117                                                         "with empty pool"
7118                 return 3
7119         }
7120         return 0
7121 }
7122
7123 pool_remove() {
7124         echo "Destroying pool"
7125         local pool=$1
7126         local file=$2
7127
7128         do_facet mgs $LCTL pool_destroy $FSNAME.$pool
7129
7130         sleep 2
7131         # striping on an empty/nonexistant pool should fall back
7132         # to "pool of everything"
7133         touch $file || {
7134                 error_noexit "failed to use fallback striping for missing pool"
7135                 return 1
7136         }
7137         # setstripe on an empty pool should fail
7138         $SETSTRIPE -p $pool $file 2>/dev/null && {
7139                 error_noexit "expected failure when creating file" \
7140                                                         "with missing pool"
7141                 return 2
7142         }
7143
7144         # get param should return err once pool is gone
7145         if wait_update $HOSTNAME "lctl get_param -n \
7146                 lov.$FSNAME-*.pools.$pool 2>/dev/null || echo foo" "foo"
7147         then
7148                 remove_pool_from_list $FSNAME.$pool
7149                 return 0
7150         fi
7151         error_noexit "Pool $FSNAME.$pool is not destroyed"
7152         return 3
7153 }