Whamcloud - gitweb
LU-15931 tests: Escape * in log()
[fs/lustre-release.git] / lustre / tests / test-framework.sh
1 #!/bin/bash
2
3 trap 'print_summary && print_stack_trace | tee $TF_FAIL && \
4     echo "$TESTSUITE: FAIL: test-framework exiting on error"' ERR
5 set -e
6
7 export LANG=en_US
8 export REFORMAT=${REFORMAT:-""}
9 export WRITECONF=${WRITECONF:-""}
10 export VERBOSE=${VERBOSE:-false}
11 export GSS=${GSS:-false}
12 export GSS_SK=${GSS_SK:-false}
13 export GSS_KRB5=false
14 export GSS_PIPEFS=false
15 export SHARED_KEY=${SHARED_KEY:-false}
16 export SK_PATH=${SK_PATH:-/tmp/test-framework-keys}
17 export SK_OM_PATH=$SK_PATH'/tmp-request-mount'
18 export SK_MOUNTED=${SK_MOUNTED:-false}
19 export SK_FLAVOR=${SK_FLAVOR:-ski}
20 export SK_NO_KEY=${SK_NO_KEY:-true}
21 export SK_UNIQUE_NM=${SK_UNIQUE_NM:-false}
22 export SK_S2S=${SK_S2S:-false}
23 export SK_S2SNM=${SK_S2SNM:-TestFrameNM}
24 export SK_S2SNMCLI=${SK_S2SNMCLI:-TestFrameNMCli}
25 export SK_SKIPFIRST=${SK_SKIPFIRST:-true}
26 export IDENTITY_UPCALL=default
27 export QUOTA_AUTO=1
28 export FLAKEY=${FLAKEY:-true}
29 # specify environment variable containing batch job name for server statistics
30 export JOBID_VAR=${JOBID_VAR:-"procname_uid"}  # or "existing" or "disable"
31
32 #export PDSH="pdsh -S -Rssh -w"
33 export MOUNT_CMD=${MOUNT_CMD:-"mount -t lustre"}
34 export UMOUNT=${UMOUNT:-"umount -d"}
35
36 export LSNAPSHOT_CONF="/etc/ldev.conf"
37 export LSNAPSHOT_LOG="/var/log/lsnapshot.log"
38
39 # sles12 umount has a issue with -d option
40 [ -e /etc/SuSE-release ] && grep -w VERSION /etc/SuSE-release | grep -wq 12 && {
41         export UMOUNT="umount"
42 }
43
44 # function used by scripts run on remote nodes
45 LUSTRE=${LUSTRE:-$(cd $(dirname $0)/..; echo $PWD)}
46 . $LUSTRE/tests/functions.sh
47 . $LUSTRE/tests/yaml.sh
48
49 export LD_LIBRARY_PATH=${LUSTRE}/utils/.libs:${LUSTRE}/utils:${LD_LIBRARY_PATH}
50
51 LUSTRE_TESTS_CFG_DIR=${LUSTRE_TESTS_CFG_DIR:-${LUSTRE}/tests/cfg}
52
53 EXCEPT_LIST_FILE=${EXCEPT_LIST_FILE:-${LUSTRE_TESTS_CFG_DIR}/tests-to-skip.sh}
54
55 if [ -f "$EXCEPT_LIST_FILE" ]; then
56     echo "Reading test skip list from $EXCEPT_LIST_FILE"
57     cat $EXCEPT_LIST_FILE
58     . $EXCEPT_LIST_FILE
59 fi
60
61 # check config files for options in decreasing order of preference
62 [ -z "$MODPROBECONF" -a -f /etc/modprobe.d/lustre.conf ] &&
63     MODPROBECONF=/etc/modprobe.d/lustre.conf
64 [ -z "$MODPROBECONF" -a -f /etc/modprobe.d/Lustre ] &&
65     MODPROBECONF=/etc/modprobe.d/Lustre
66 [ -z "$MODPROBECONF" -a -f /etc/modprobe.conf ] &&
67     MODPROBECONF=/etc/modprobe.conf
68
69 sanitize_parameters() {
70         for i in DIR DIR1 DIR2 MOUNT MOUNT1 MOUNT2
71         do
72                 local path=${!i}
73                 if [ -d "$path" ]; then
74                         eval export $i=$(echo $path | sed -r 's/\/+$//g')
75                 fi
76         done
77 }
78 assert_DIR () {
79         local failed=""
80         [[ $DIR/ = $MOUNT/* ]] ||
81                 { failed=1 && echo "DIR=$DIR not in $MOUNT. Aborting."; }
82         [[ $DIR1/ = $MOUNT1/* ]] ||
83                 { failed=1 && echo "DIR1=$DIR1 not in $MOUNT1. Aborting."; }
84         [[ $DIR2/ = $MOUNT2/* ]] ||
85                 { failed=1 && echo "DIR2=$DIR2 not in $MOUNT2. Aborting"; }
86
87         [ -n "$failed" ] && exit 99 || true
88 }
89
90 usage() {
91     echo "usage: $0 [-r] [-f cfgfile]"
92     echo "       -r: reformat"
93
94     exit
95 }
96
97 print_summary () {
98         trap 0
99         [ -z "$DEFAULT_SUITES" ] && return 0
100         [ -n "$ONLY" ] && echo "WARNING: ONLY is set to $(echo $ONLY)"
101         local details
102         local form="%-13s %-17s %-9s %s %s\n"
103
104         printf "$form" "status" "script" "Total(sec)" "E(xcluded) S(low)"
105         echo "---------------------------------------------------------------"
106     for O in $DEFAULT_SUITES; do
107         O=$(echo $O  | tr "-" "_" | tr "[:lower:]" "[:upper:]")
108         [ "${!O}" = "no" ] && continue || true
109         local o=$(echo $O  | tr "[:upper:]_" "[:lower:]-")
110         local log=${TMP}/${o}.log
111         if is_sanity_benchmark $o; then
112             log=${TMP}/sanity-benchmark.log
113         fi
114         local slow=
115         local skipped=
116         local total=
117         local status=Unfinished
118         if [ -f $log ]; then
119                 skipped=$(grep excluded $log | awk '{ printf " %s", $3 }' |
120                         sed 's/test_//g')
121                 slow=$(egrep "^PASS|^FAIL" $log | tr -d "("| sed s/s\)$//g |
122                         sort -nr -k 3  | head -n5 |  awk '{ print $2":"$3"s" }')
123                 total=$(grep duration $log | awk '{ print $2 }')
124                 if [ "${!O}" = "done" ]; then
125                         status=Done
126                 fi
127                 if $DDETAILS; then
128                         local durations=$(egrep "^PASS|^FAIL" $log |
129                                 tr -d "("| sed s/s\)$//g |
130                                 awk '{ print $2":"$3"|" }')
131                         details=$(printf "%s\n%s %s %s\n" "$details" \
132                                 "DDETAILS" "$O" "$(echo $durations)")
133                 fi
134         fi
135         printf "$form" $status "$O" "${total}" "E=$skipped"
136         printf "$form" "-" "-" "-" "S=$(echo $slow)"
137     done
138
139     for O in $DEFAULT_SUITES; do
140         O=$(echo $O  | tr "-" "_" | tr "[:lower:]" "[:upper:]")
141         if [ "${!O}" = "no" ]; then
142             printf "$form" "Skipped" "$O" ""
143         fi
144     done
145
146     # print the detailed tests durations if DDETAILS=true
147     if $DDETAILS; then
148         echo "$details"
149     fi
150 }
151
152 # Get information about the Lustre environment. The information collected
153 # will be used in Lustre tests.
154 # usage: get_lustre_env
155 # input: No required or optional arguments
156 # output: No return values, environment variables are exported
157
158 get_lustre_env() {
159         if ! $RPC_MODE; then
160                 export mds1_FSTYPE=${mds1_FSTYPE:-$(facet_fstype mds1)}
161                 export ost1_FSTYPE=${ost1_FSTYPE:-$(facet_fstype ost1)}
162
163                 export MGS_VERSION=$(lustre_version_code mgs)
164                 export MDS1_VERSION=$(lustre_version_code mds1)
165                 export OST1_VERSION=$(lustre_version_code ost1)
166                 export CLIENT_VERSION=$(lustre_version_code client)
167         fi
168
169         # Prefer using "mds1" directly instead of SINGLEMDS.
170         # Keep this for compat until it is removed from scripts.
171         export SINGLEMDS=${SINGLEMDS:-mds1}
172 }
173
174 init_test_env() {
175         export LUSTRE=$(absolute_path $LUSTRE)
176         export TESTSUITE=$(basename $0 .sh)
177         export TEST_FAILED=false
178         export FAIL_ON_SKIP_ENV=${FAIL_ON_SKIP_ENV:-false}
179         export RPC_MODE=${RPC_MODE:-false}
180         export DO_CLEANUP=${DO_CLEANUP:-true}
181         export KEEP_ZPOOL=${KEEP_ZPOOL:-false}
182         export CLEANUP_DM_DEV=false
183         export PAGE_SIZE=$(get_page_size client)
184
185         export MKE2FS=$MKE2FS
186         if [ -z "$MKE2FS" ]; then
187                 if which mkfs.ldiskfs >/dev/null 2>&1; then
188                         export MKE2FS=mkfs.ldiskfs
189                 else
190                         export MKE2FS=mke2fs
191                 fi
192         fi
193
194         export DEBUGFS=$DEBUGFS
195         if [ -z "$DEBUGFS" ]; then
196                 if which debugfs.ldiskfs >/dev/null 2>&1; then
197                         export DEBUGFS=debugfs.ldiskfs
198                 else
199                         export DEBUGFS=debugfs
200                 fi
201         fi
202
203         export TUNE2FS=$TUNE2FS
204         if [ -z "$TUNE2FS" ]; then
205                 if which tunefs.ldiskfs >/dev/null 2>&1; then
206                         export TUNE2FS=tunefs.ldiskfs
207                 else
208                         export TUNE2FS=tune2fs
209                 fi
210         fi
211
212         export E2LABEL=$E2LABEL
213         if [ -z "$E2LABEL" ]; then
214                 if which label.ldiskfs >/dev/null 2>&1; then
215                         export E2LABEL=label.ldiskfs
216                 else
217                         export E2LABEL=e2label
218                 fi
219         fi
220
221         export DUMPE2FS=$DUMPE2FS
222         if [ -z "$DUMPE2FS" ]; then
223                 if which dumpfs.ldiskfs >/dev/null 2>&1; then
224                         export DUMPE2FS=dumpfs.ldiskfs
225                 else
226                         export DUMPE2FS=dumpe2fs
227                 fi
228         fi
229
230         export E2FSCK=$E2FSCK
231         if [ -z "$E2FSCK" ]; then
232                 if which fsck.ldiskfs >/dev/null 2>&1; then
233                         export E2FSCK=fsck.ldiskfs
234                 else
235                          export E2FSCK=e2fsck
236                 fi
237         fi
238
239         export RESIZE2FS=$RESIZE2FS
240         if [ -z "$RESIZE2FS" ]; then
241                 if which resizefs.ldiskfs >/dev/null 2>&1; then
242                         export RESIZE2FS=resizefs.ldiskfs
243                 else
244                         export RESIZE2FS=resize2fs
245                 fi
246         fi
247
248         export LFSCK_ALWAYS=${LFSCK_ALWAYS:-"no"} # check fs after test suite
249         export FSCK_MAX_ERR=4   # File system errors left uncorrected
250
251         export ZFS=${ZFS:-zfs}
252         export ZPOOL=${ZPOOL:-zpool}
253         export ZDB=${ZDB:-zdb}
254         export PARTPROBE=${PARTPROBE:-partprobe}
255
256         #[ -d /r ] && export ROOT=${ROOT:-/r}
257         export TMP=${TMP:-$ROOT/tmp}
258         export TESTSUITELOG=${TMP}/${TESTSUITE}.log
259         export LOGDIR=${LOGDIR:-${TMP}/test_logs/$(date +%s)}
260         export TESTLOG_PREFIX=$LOGDIR/$TESTSUITE
261
262         export HOSTNAME=${HOSTNAME:-$(hostname -s)}
263         if ! echo $PATH | grep -q $LUSTRE/utils; then
264                 export PATH=$LUSTRE/utils:$PATH
265         fi
266         if ! echo $PATH | grep -q $LUSTRE/utils/gss; then
267                 export PATH=$LUSTRE/utils/gss:$PATH
268         fi
269         if ! echo $PATH | grep -q $LUSTRE/tests; then
270                 export PATH=$LUSTRE/tests:$PATH
271         fi
272         if ! echo $PATH | grep -q $LUSTRE/../lustre-iokit/sgpdd-survey; then
273                 export PATH=$LUSTRE/../lustre-iokit/sgpdd-survey:$PATH
274         fi
275         export LST=${LST:-"$LUSTRE/../lnet/utils/lst"}
276         [ ! -f "$LST" ] && export LST=$(which lst)
277         export SGPDDSURVEY=${SGPDDSURVEY:-"$LUSTRE/../lustre-iokit/sgpdd-survey/sgpdd-survey")}
278         [ ! -f "$SGPDDSURVEY" ] && export SGPDDSURVEY=$(which sgpdd-survey)
279         export MCREATE=${MCREATE:-mcreate}
280         export MULTIOP=${MULTIOP:-multiop}
281         export MMAP_CAT=${MMAP_CAT:-mmap_cat}
282         export STATX=${STATX:-statx}
283         # Ubuntu, at least, has a truncate command in /usr/bin
284         # so fully path our truncate command.
285         export TRUNCATE=${TRUNCATE:-$LUSTRE/tests/truncate}
286         export FSX=${FSX:-$LUSTRE/tests/fsx}
287         export MDSRATE=${MDSRATE:-"$LUSTRE/tests/mpi/mdsrate"}
288         [ ! -f "$MDSRATE" ] && export MDSRATE=$(which mdsrate 2> /dev/null)
289         if ! echo $PATH | grep -q $LUSTRE/tests/racer; then
290                 export PATH=$LUSTRE/tests/racer:$PATH:
291         fi
292         if ! echo $PATH | grep -q $LUSTRE/tests/mpi; then
293                 export PATH=$LUSTRE/tests/mpi:$PATH
294         fi
295         export RSYNC_RSH=${RSYNC_RSH:-rsh}
296
297         export LNETCTL=${LNETCTL:-"$LUSTRE/../lnet/utils/lnetctl"}
298         [ ! -f "$LNETCTL" ] && export LNETCTL=$(which lnetctl 2> /dev/null)
299         export LCTL=${LCTL:-"$LUSTRE/utils/lctl"}
300         [ ! -f "$LCTL" ] && export LCTL=$(which lctl)
301         export LFS=${LFS:-"$LUSTRE/utils/lfs"}
302         [ ! -f "$LFS" ] && export LFS=$(which lfs)
303         export KSOCKLND_CONFIG=${KSOCKLND_CONFIG:-"$LUSTRE/scripts/ksocklnd-config"}
304         [ ! -f "$KSOCKLND_CONFIG" ] &&
305                 export KSOCKLND_CONFIG=$(which ksocklnd-config 2> /dev/null)
306
307         export PERM_CMD=$(echo ${PERM_CMD:-"$LCTL conf_param"})
308
309         export L_GETIDENTITY=${L_GETIDENTITY:-"$LUSTRE/utils/l_getidentity"}
310         if [ ! -f "$L_GETIDENTITY" ]; then
311                 if `which l_getidentity > /dev/null 2>&1`; then
312                         export L_GETIDENTITY=$(which l_getidentity)
313                 else
314                         export L_GETIDENTITY=NONE
315                 fi
316         fi
317         export LL_DECODE_FILTER_FID=${LL_DECODE_FILTER_FID:-"$LUSTRE/utils/ll_decode_filter_fid"}
318         [ ! -f "$LL_DECODE_FILTER_FID" ] && export LL_DECODE_FILTER_FID="ll_decode_filter_fid"
319         export LL_DECODE_LINKEA=${LL_DECODE_LINKEA:-"$LUSTRE/utils/ll_decode_linkea"}
320         [ ! -f "$LL_DECODE_LINKEA" ] && export LL_DECODE_LINKEA="ll_decode_linkea"
321         export MKFS=${MKFS:-"$LUSTRE/utils/mkfs.lustre"}
322         [ ! -f "$MKFS" ] && export MKFS="mkfs.lustre"
323         export TUNEFS=${TUNEFS:-"$LUSTRE/utils/tunefs.lustre"}
324         [ ! -f "$TUNEFS" ] && export TUNEFS="tunefs.lustre"
325         export CHECKSTAT="${CHECKSTAT:-"checkstat -v"} "
326         export LUSTRE_RMMOD=${LUSTRE_RMMOD:-$LUSTRE/scripts/lustre_rmmod}
327         [ ! -f "$LUSTRE_RMMOD" ] &&
328                 export LUSTRE_RMMOD=$(which lustre_rmmod 2> /dev/null)
329         export LUSTRE_ROUTES_CONVERSION=${LUSTRE_ROUTES_CONVERSION:-$LUSTRE/scripts/lustre_routes_conversion}
330         [ ! -f "$LUSTRE_ROUTES_CONVERSION" ] &&
331                 export LUSTRE_ROUTES_CONVERSION=$(which lustre_routes_conversion 2> /dev/null)
332         export LFS_MIGRATE=${LFS_MIGRATE:-$LUSTRE/scripts/lfs_migrate}
333         [ ! -f "$LFS_MIGRATE" ] &&
334                 export LFS_MIGRATE=$(which lfs_migrate 2> /dev/null)
335         export LR_READER=${LR_READER:-"$LUSTRE/utils/lr_reader"}
336         [ ! -f "$LR_READER" ] &&
337                 export LR_READER=$(which lr_reader 2> /dev/null)
338         [ -z "$LR_READER" ] && export LR_READER="/usr/sbin/lr_reader"
339         export LSOM_SYNC=${LSOM_SYNC:-"$LUSTRE/utils/llsom_sync"}
340         [ ! -f "$LSOM_SYNC" ] &&
341                 export LSOM_SYNC=$(which llsom_sync 2> /dev/null)
342         [ -z "$LSOM_SYNC" ] && export LSOM_SYNC="/usr/sbin/llsom_sync"
343         export NAME=${NAME:-local}
344         export LGSSD=${LGSSD:-"$LUSTRE/utils/gss/lgssd"}
345         [ "$GSS_PIPEFS" = "true" ] && [ ! -f "$LGSSD" ] &&
346                 export LGSSD=$(which lgssd)
347         export LSVCGSSD=${LSVCGSSD:-"$LUSTRE/utils/gss/lsvcgssd"}
348         [ ! -f "$LSVCGSSD" ] && export LSVCGSSD=$(which lsvcgssd 2> /dev/null)
349         export KRB5DIR=${KRB5DIR:-"/usr/kerberos"}
350         export DIR2
351         export SAVE_PWD=${SAVE_PWD:-$LUSTRE/tests}
352         export AT_MAX_PATH
353         export LDEV=${LDEV:-"$LUSTRE/scripts/ldev"}
354         [ ! -f "$LDEV" ] && export LDEV=$(which ldev 2> /dev/null)
355
356         export DMSETUP=${DMSETUP:-dmsetup}
357         export DM_DEV_PATH=${DM_DEV_PATH:-/dev/mapper}
358         export LOSETUP=${LOSETUP:-losetup}
359
360         if [ "$ACCEPTOR_PORT" ]; then
361                 export PORT_OPT="--port $ACCEPTOR_PORT"
362         fi
363
364         if $SHARED_KEY; then
365                 $RPC_MODE || echo "Using GSS shared-key feature"
366                 which lgss_sk > /dev/null 2>&1 ||
367                         error_exit "built with lgss_sk disabled! SEC=$SEC"
368                 GSS=true
369                 GSS_SK=true
370                 SEC=$SK_FLAVOR
371         fi
372
373         case "x$SEC" in
374                 xkrb5*)
375                 $RPC_MODE || echo "Using GSS/krb5 ptlrpc security flavor"
376                 which lgss_keyring > /dev/null 2>&1 ||
377                         error_exit "built with gss disabled! SEC=$SEC"
378                 GSS=true
379                 GSS_KRB5=true
380                 ;;
381         esac
382
383         case "x$IDUP" in
384                 xtrue)
385                         IDENTITY_UPCALL=true
386                         ;;
387                 xfalse)
388                         IDENTITY_UPCALL=false
389                         ;;
390         esac
391
392         export LOAD_MODULES_REMOTE=${LOAD_MODULES_REMOTE:-false}
393
394         # Paths on remote nodes, if different
395         export RLUSTRE=${RLUSTRE:-$LUSTRE}
396         export RPWD=${RPWD:-$PWD}
397         export I_MOUNTED=${I_MOUNTED:-"no"}
398         export AUSTER_CLEANUP=${AUSTER_CLEANUP:-false}
399         if [ ! -f /lib/modules/$(uname -r)/kernel/fs/lustre/mdt.ko -a \
400              ! -f /lib/modules/$(uname -r)/updates/kernel/fs/lustre/mdt.ko -a \
401              ! -f /lib/modules/$(uname -r)/extra/kernel/fs/lustre/mdt.ko -a \
402              ! -f $LUSTRE/mdt/mdt.ko ]; then
403             export CLIENTMODSONLY=yes
404         fi
405
406         export SHUTDOWN_ATTEMPTS=${SHUTDOWN_ATTEMPTS:-3}
407         export OSD_TRACK_DECLARES_LBUG=${OSD_TRACK_DECLARES_LBUG:-"yes"}
408
409         # command line
410
411         while getopts "rvwf:" opt $*; do
412                 case $opt in
413                         f) CONFIG=$OPTARG;;
414                         r) REFORMAT=yes;;
415                         v) VERBOSE=true;;
416                         w) WRITECONF=writeconf;;
417                         \?) usage;;
418                 esac
419         done
420
421         shift $((OPTIND - 1))
422         ONLY=${ONLY:-$*}
423
424         # print the durations of each test if "true"
425         DDETAILS=${DDETAILS:-false}
426         [ "$TESTSUITELOG" ] && rm -f $TESTSUITELOG || true
427         if ! $RPC_MODE; then
428                 rm -f $TMP/*active
429         fi
430
431         export TF_FAIL=${TF_FAIL:-$TMP/tf.fail}
432
433         # Constants used in more than one test script
434         export LOV_MAX_STRIPE_COUNT=2000
435         export DELETE_OLD_POOLS=${DELETE_OLD_POOLS:-false}
436         export KEEP_POOLS=${KEEP_POOLS:-false}
437         export PARALLEL=${PARALLEL:-"no"}
438
439         export MACHINEFILE=${MACHINEFILE:-$TMP/$(basename $0 .sh).machines}
440         . ${CONFIG:=$LUSTRE/tests/cfg/$NAME.sh}
441         get_lustre_env
442
443         # use localrecov to enable recovery for local clients, LU-12722
444         [[ $MDS1_VERSION -lt $(version_code 2.13.52) ]] || {
445                 export MDS_MOUNT_OPTS=${MDS_MOUNT_OPTS:-"-o localrecov"}
446                 export MGS_MOUNT_OPTS=${MGS_MOUNT_OPTS:-"-o localrecov"}
447         }
448
449         [[ $OST1_VERSION -lt $(version_code 2.13.52) ]] ||
450                 export OST_MOUNT_OPTS=${OST_MOUNT_OPTS:-"-o localrecov"}
451 }
452
453 check_cpt_number() {
454         local facet=$1
455         local ncpts
456
457         ncpts=$(do_facet $facet "lctl get_param -n " \
458                 "cpu_partition_table 2>/dev/null| wc -l" || echo 1)
459
460         if [ $ncpts -eq 0 ]; then
461                 echo "1"
462         else
463                 echo $ncpts
464         fi
465 }
466
467 # Return a numeric version code based on a version string.  The version
468 # code is useful for comparison two version strings to see which is newer.
469 version_code() {
470         # split arguments like "1.8.6-wc3" into "1", "8", "6", "3"
471         eval set -- $(tr "[:punct:][a-zA-Z]" " " <<< $*)
472
473         echo -n $(((${1:-0}<<24) | (${2:-0}<<16) | (${3:-0}<<8) | (${4:-0})))
474 }
475
476 export LINUX_VERSION=$(uname -r | sed -e "s/\([0-9]*\.[0-9]*\.[0-9]*\).*/\1/")
477 export LINUX_VERSION_CODE=$(version_code ${LINUX_VERSION//\./ })
478
479 # Report the Lustre build version string (e.g. 1.8.7.3 or 2.4.1).
480 #
481 # usage: lustre_build_version
482 #
483 # All Lustre versions support "lctl get_param" to report the version of the
484 # code running in the kernel (what our tests are interested in), but it
485 # doesn't work without modules loaded.  After 2.9.53 and in upstream kernels
486 # the "version" parameter doesn't include "lustre: " at the beginning.
487 # If that fails, call "lctl lustre_build_version" which prints either (or both)
488 # the userspace and kernel build versions, but until 2.8.55 required root
489 # access to get the Lustre kernel version.  If that also fails, fall back to
490 # using "lctl --version", which is easy to parse and works without the kernel
491 # modules, but was only added in 2.6.50 and only prints the lctl tool version,
492 # not the module version, though they are usually the same.
493 #
494 # Various commands and their output format for different Lustre versions:
495 # lctl get_param version:       2.9.55
496 # lctl get_param version:       lustre: 2.8.53
497 # lctl get_param version:       lustre: 2.6.52
498 #                               kernel: patchless_client
499 #                               build: v2_6_92_0-2.6.32-431.el6_lustre.x86_64
500 # lctl lustre_build_version:    Lustre version: 2.8.53_27_gae67fc01
501 # lctl lustre_build_version:    error: lustre_build_version: Permission denied
502 #       (as non-root user)      lctl   version: v2_6_92_0-2.6.32-431.el6.x86_64
503 # lctl lustre_build_version:    Lustre version: 2.5.3-2.6.32.26-175.fc12.x86_64
504 #                               lctl   version: 2.5.3-2.6.32..26-175fc12.x86_64
505 # lctl --version:               lctl 2.6.50
506 #
507 # output: prints version string to stdout in (up to 4) dotted-decimal values
508 lustre_build_version() {
509         local facet=${1:-client}
510         local facet_version=${facet}_VERSION
511
512         # if the global variable is already set, then use that
513         [ -n "${!facet_version}" ] && echo ${!facet_version} && return
514
515         # this is the currently-running version of the kernel modules
516         local ver=$(do_facet $facet "$LCTL get_param -n version 2>/dev/null")
517         # we mostly test 2.10+ systems, only try others if the above fails
518         if [ -z "$ver" ]; then
519                 ver=$(do_facet $facet "$LCTL lustre_build_version 2>/dev/null")
520         fi
521         if [ -z "$ver" ]; then
522                 ver=$(do_facet $facet "$LCTL --version 2>/dev/null" |
523                       cut -d' ' -f2)
524         fi
525         local lver=$(egrep -i "lustre: |version: " <<<"$ver" | head -n 1)
526         [ -n "$lver" ] && ver="$lver"
527
528         lver=$(sed -e 's/[^:]*: //' -e 's/^v//' -e 's/[ -].*//' <<<$ver |
529                tr _ . | cut -d. -f1-4)
530
531         # save in global variable for the future
532         export $facet_version=$lver
533
534         echo $lver
535 }
536
537 # Report the Lustre numeric build version code for the supplied facet.
538 lustre_version_code() {
539         version_code $(lustre_build_version $1)
540 }
541
542 module_loaded () {
543         /sbin/lsmod | grep -q "^\<$1\>"
544 }
545
546 check_lfs_df_ret_val() {
547         # Ignore only EOPNOTSUPP (which is 95; Operation not supported) error
548         # returned by 'lfs df' for valid dentry but not a lustrefs.
549         #
550         # 'lfs df' historically always returned success(0) instead of
551         # EOPNOTSUPP. This function for compatibility reason, ignores and
552         # masquerades EOPNOTSUPP as success.
553         [[ $1 -eq 95 ]] && return 0
554         return $1
555 }
556
557 PRLFS=false
558 lustre_insmod() {
559         local module=$1
560         shift
561         local args="$@"
562         local msg
563         local rc=0
564
565         if ! $PRLFS; then
566                 msg="$(insmod $module $args 2>&1)" && return 0 || rc=$?
567         fi
568
569         # parallels can't load modules directly from prlfs, use /tmp instead
570         if $PRLFS || [[ "$(stat -f -c%t $module)" == "7c7c6673" ]]; then
571                 local target="$(mktemp)"
572
573                 cp "$module" "$target"
574                 insmod $target $args
575                 rc=$?
576                 [[ $rc == 0 ]] && PRLFS=true
577                 rm -f $target
578         else
579                 echo "$msg"
580         fi
581         return $rc
582 }
583
584 # Load a module on the system where this is running.
585 #
586 # usage: load_module module_name [module arguments for insmod/modprobe]
587 #
588 # If module arguments are not given but MODOPTS_<MODULE> is set, then its value
589 # will be used as the arguments.  Otherwise arguments will be obtained from
590 # /etc/modprobe.conf, from /etc/modprobe.d/Lustre, or else none will be used.
591 #
592 load_module() {
593         local module=$1 # '../libcfs/libcfs/libcfs', 'obdclass/obdclass', ...
594         shift
595         local ext=".ko"
596         local base=$(basename $module $ext)
597         local path
598         local -A module_is_loaded_aa
599         local optvar
600         local mod
601
602         for mod in $(lsmod | awk '{ print $1; }'); do
603                 module_is_loaded_aa[${mod//-/_}]=true
604         done
605
606         module_is_loaded() {
607                 ${module_is_loaded_aa[${1//-/_}]:-false}
608         }
609
610         if module_is_loaded $base; then
611                 return
612         fi
613
614         if [[ -f $LUSTRE/$module$ext ]]; then
615                 path=$LUSTRE/$module$ext
616         elif [[ "$base" == lnet_selftest ]] &&
617              [[ -f $LUSTRE/../lnet/selftest/$base$ext ]]; then
618                 path=$LUSTRE/../lnet/selftest/$base$ext
619         else
620                 path=''
621         fi
622
623         if [[ -n "$path" ]]; then
624                 # Try to load any non-Lustre modules that $module depends on.
625                 for mod in $(modinfo --field=depends $path | tr ',' ' '); do
626                         if ! module_is_loaded $mod; then
627                                 modprobe $mod
628                         fi
629                 done
630         fi
631
632         # If no module arguments were passed then get them from
633         # $MODOPTS_<MODULE>, otherwise from modprobe.conf.
634         if [ $# -eq 0 ]; then
635                 # $MODOPTS_<MODULE>; we could use associative arrays, but that's
636                 # not in Bash until 4.x, so we resort to eval.
637                 optvar="MODOPTS_$(basename $module | tr a-z A-Z)"
638                 eval set -- \$$optvar
639                 if [ $# -eq 0 -a -n "$MODPROBECONF" ]; then
640                         # Nothing in $MODOPTS_<MODULE>; try modprobe.conf
641                         local opt
642                         opt=$(awk -v var="^options $base" '$0 ~ var \
643                               {gsub("'"options $base"'",""); print}' \
644                                 $MODPROBECONF)
645                         set -- $(echo -n $opt)
646
647                         # Ensure we have accept=all for lnet
648                         if [[ "$base" == lnet ]]; then
649                                 # OK, this is a bit wordy...
650                                 local arg accept_all_present=false
651
652                                 for arg in "$@"; do
653                                         [[ "$arg" == accept=all ]] &&
654                                                 accept_all_present=true
655                                 done
656
657                                 $accept_all_present || set -- "$@" accept=all
658                         fi
659
660                         export $optvar="$*"
661                 fi
662         fi
663
664         [ $# -gt 0 ] && echo "${module} options: '$*'"
665
666         # Note that insmod will ignore anything in modprobe.conf, which is why
667         # we're passing options on the command-line. If $path does not exist
668         # then we must be testing a "make install" or"rpm" installation. Also
669         # note that failing to load ptlrpc_gss is not considered fatal.
670         if [[ -n "$path" ]]; then
671                 lustre_insmod $path "$@"
672         elif [[ "$base" == ptlrpc_gss ]]; then
673                 if ! modprobe $base "$@" 2>/dev/null; then
674                         echo "gss/krb5 is not supported"
675                 fi
676         else
677                 modprobe $base "$@"
678         fi
679 }
680
681 do_lnetctl() {
682         $LCTL mark "$LNETCTL $*"
683         echo "$LNETCTL $*"
684         $LNETCTL "$@"
685 }
686
687 load_lnet() {
688         # For kmemleak-enabled kernels we need clear all past state
689         # that obviously has nothing to do with this Lustre run
690         # Disable automatic memory scanning to avoid perf hit.
691         if [ -f /sys/kernel/debug/kmemleak ] ; then
692                 echo scan=off > /sys/kernel/debug/kmemleak || true
693                 echo scan > /sys/kernel/debug/kmemleak || true
694                 echo clear > /sys/kernel/debug/kmemleak || true
695         fi
696
697         echo Loading modules from $LUSTRE
698
699         local ncpus
700
701         if [ -f /sys/devices/system/cpu/online ]; then
702                 ncpus=$(($(cut -d "-" -f 2 /sys/devices/system/cpu/online) + 1))
703                 echo "detected $ncpus online CPUs by sysfs"
704         else
705                 ncpus=$(getconf _NPROCESSORS_CONF 2>/dev/null)
706                 local rc=$?
707                 if [ $rc -eq 0 ]; then
708                         echo "detected $ncpus online CPUs by getconf"
709                 else
710                         echo "Can't detect number of CPUs"
711                         ncpus=1
712                 fi
713         fi
714
715         # if there is only one CPU core, libcfs can only create one partition
716         # if there is more than 4 CPU cores, libcfs should create multiple CPU
717         # partitions. So we just force libcfs to create 2 partitions for
718         # system with 2 or 4 cores
719         local saved_opts="$MODOPTS_LIBCFS"
720         if [ $ncpus -le 4 ] && [ $ncpus -gt 1 ]; then
721                 # force to enable multiple CPU partitions
722                 echo "Force libcfs to create 2 CPU partitions"
723                 MODOPTS_LIBCFS="cpu_npartitions=2 $MODOPTS_LIBCFS"
724         else
725                 echo "libcfs will create CPU partition based on online CPUs"
726         fi
727
728         load_module ../libcfs/libcfs/libcfs
729         # Prevent local MODOPTS_LIBCFS being passed as part of environment
730         # variable to remote nodes
731         unset MODOPTS_LIBCFS
732
733         set_default_debug "neterror net nettrace malloc"
734         if [ "$1" = "config_on_load=1" ]; then
735                 load_module ../lnet/lnet/lnet
736         else
737                 load_module ../lnet/lnet/lnet "$@"
738         fi
739
740         LNDPATH=${LNDPATH:-"../lnet/klnds"}
741         if [ -z "$LNETLND" ]; then
742                 case $NETTYPE in
743                 o2ib*)  LNETLND="o2iblnd/ko2iblnd" ;;
744                 tcp*)   LNETLND="socklnd/ksocklnd" ;;
745                 *)      local lnd="${NETTYPE%%[0-9]}lnd"
746                         [ -f "$LNDPATH/$lnd/k$lnd.ko" ] &&
747                                 LNETLND="$lnd/k$lnd" ||
748                                 LNETLND="socklnd/ksocklnd"
749                 esac
750         fi
751         load_module ../lnet/klnds/$LNETLND
752
753         if [ "$1" = "config_on_load=1" ]; then
754                 do_lnetctl lnet configure --all ||
755                         return $?
756         fi
757 }
758
759 load_modules_local() {
760         if [ -n "$MODPROBE" ]; then
761                 # use modprobe
762                 echo "Using modprobe to load modules"
763                 return 0
764         fi
765
766         # Create special udev test rules on every node
767         if [ -f $LUSTRE/lustre/conf/99-lustre.rules ]; then {
768                 sed -e 's|/usr/sbin/lctl|$LCTL|g' $LUSTRE/lustre/conf/99-lustre.rules > /etc/udev/rules.d/99-lustre-test.rules
769         } else {
770                 echo "SUBSYSTEM==\"lustre\", ACTION==\"change\", ENV{PARAM}==\"?*\", RUN+=\"$LCTL set_param '\$env{PARAM}=\$env{SETTING}'\"" > /etc/udev/rules.d/99-lustre-test.rules
771         } fi
772         udevadm control --reload-rules
773         udevadm trigger
774
775         load_lnet
776
777         load_module obdclass/obdclass
778         if ! client_only; then
779                 MODOPTS_PTLRPC=${MODOPTS_PTLRPC:-"lbug_on_grant_miscount=1"}
780         fi
781         load_module ptlrpc/ptlrpc
782         load_module ptlrpc/gss/ptlrpc_gss
783         load_module fld/fld
784         load_module fid/fid
785         load_module lmv/lmv
786         load_module osc/osc
787         load_module lov/lov
788         load_module mdc/mdc
789         load_module mgc/mgc
790         load_module obdecho/obdecho
791         if ! client_only; then
792                 load_module lfsck/lfsck
793                 [ "$LQUOTA" != "no" ] &&
794                         load_module quota/lquota $LQUOTAOPTS
795                 if [[ $(node_fstypes $HOSTNAME) == *zfs* ]]; then
796                         load_module osd-zfs/osd_zfs
797                 elif [[ $(node_fstypes $HOSTNAME) == *ldiskfs* ]]; then
798                         load_module ../ldiskfs/ldiskfs
799                         load_module osd-ldiskfs/osd_ldiskfs
800                 fi
801                 load_module mgs/mgs
802                 load_module mdd/mdd
803                 load_module mdt/mdt
804                 load_module ost/ost
805                 load_module lod/lod
806                 load_module osp/osp
807                 load_module ofd/ofd
808                 load_module osp/osp
809         fi
810
811         load_module llite/lustre
812         [ -d /r ] && OGDB=${OGDB:-"/r/tmp"}
813         OGDB=${OGDB:-$TMP}
814         rm -f $OGDB/ogdb-$HOSTNAME
815         $LCTL modules > $OGDB/ogdb-$HOSTNAME
816
817         # 'mount' doesn't look in $PATH, just sbin
818         local mount_lustre=$LUSTRE/utils/mount.lustre
819         if [ -f $mount_lustre ]; then
820                 local sbin_mount=$(readlink -f /sbin)/mount.lustre
821                 if grep -qw "$sbin_mount" /proc/mounts; then
822                         cmp -s $mount_lustre $sbin_mount || umount $sbin_mount
823                 fi
824                 if ! grep -qw "$sbin_mount" /proc/mounts; then
825                         [ ! -f "$sbin_mount" ] && touch "$sbin_mount"
826                         if [ ! -s "$sbin_mount" -a -w "$sbin_mount" ]; then
827                                 cat <<- EOF > "$sbin_mount"
828                                 #!/bin/sh
829                                 #STUB MARK
830                                 echo "This $sbin_mount just a mountpoint." 1>&2
831                                 echo "It is never supposed to be run." 1>&2
832                                 logger -p emerg -- "using stub $sbin_mount $@"
833                                 exit 1
834                                 EOF
835                                 chmod a+x $sbin_mount
836                         fi
837                         mount --bind $mount_lustre $sbin_mount ||
838                                 error "can't bind $mount_lustre to $sbin_mount"
839                 fi
840         fi
841 }
842
843 load_modules () {
844         local facets
845         local facet
846         local failover
847         load_modules_local
848         # bug 19124
849         # load modules on remote nodes optionally
850         # lustre-tests have to be installed on these nodes
851         if $LOAD_MODULES_REMOTE; then
852                 local list=$(comma_list $(remote_nodes_list))
853
854                 # include failover nodes in case they are not in the list yet
855                 facets=$(get_facets)
856                 for facet in ${facets//,/ }; do
857                         failover=$(facet_failover_host $facet)
858                         [ -n "$list" ] && [[ ! "$list" =~ "$failover" ]] &&
859                                 list="$list,$failover"
860                 done
861
862                 if [ -n "$list" ]; then
863                         echo "loading modules on: '$list'"
864                         do_rpc_nodes "$list" load_modules_local
865                 fi
866         fi
867 }
868
869 check_mem_leak () {
870         LEAK_LUSTRE=$(dmesg | tail -n 30 | grep "obd_memory.*leaked" || true)
871         LEAK_PORTALS=$(dmesg | tail -n 20 | egrep -i "libcfs.*memory leaked" || true)
872         if [ "$LEAK_LUSTRE" -o "$LEAK_PORTALS" ]; then
873                 echo "$LEAK_LUSTRE" 1>&2
874                 echo "$LEAK_PORTALS" 1>&2
875                 mv $TMP/debug $TMP/debug-leak.`date +%s` || true
876                 echo "Memory leaks detected"
877                 [ -n "$IGNORE_LEAK" ] && { echo "ignoring leaks" && return 0; } || true
878                 return 1
879         fi
880 }
881
882 unload_modules_local() {
883         $LUSTRE_RMMOD ldiskfs || return 2
884
885         [ -f /etc/udev/rules.d/99-lustre-test.rules ] &&
886                 rm /etc/udev/rules.d/99-lustre-test.rules
887         udevadm control --reload-rules
888         udevadm trigger
889
890         check_mem_leak || return 254
891
892         return 0
893 }
894
895 unload_modules() {
896         local rc=0
897
898         wait_exit_ST client # bug 12845
899
900         unload_modules_local || rc=$?
901
902         if $LOAD_MODULES_REMOTE; then
903                 local list=$(comma_list $(remote_nodes_list))
904                 if [ -n "$list" ]; then
905                         echo "unloading modules on: '$list'"
906                         do_rpc_nodes "$list" unload_modules_local
907                 fi
908         fi
909
910         local sbin_mount=$(readlink -f /sbin)/mount.lustre
911         if grep -qe "$sbin_mount " /proc/mounts; then
912                 umount $sbin_mount || true
913                 [ -s $sbin_mount ] && ! grep -q "STUB MARK" $sbin_mount ||
914                         rm -f $sbin_mount
915         fi
916
917         [[ $rc -eq 0 ]] && echo "modules unloaded."
918
919         return $rc
920 }
921
922 fs_log_size() {
923         local facet=${1:-$SINGLEMDS}
924         local size=0
925
926         case $(facet_fstype $facet) in
927                 ldiskfs) size=72;; # largest seen is 64, leave some headroom
928                 # grant_block_size is in bytes, allow at least 2x max blocksize
929                 zfs)     size=$(lctl get_param osc.$FSNAME*.import |
930                                 awk '/grant_block_size:/ {print $2/512; exit;}')
931                           ;;
932         esac
933
934         echo -n $((size * MDSCOUNT))
935 }
936
937 fs_inode_ksize() {
938         local facet=${1:-$SINGLEMDS}
939         local fstype=$(facet_fstype $facet)
940         local size=0
941         case $fstype in
942                 ldiskfs) size=4;;  # ~4KB per inode
943                 zfs)     size=11;; # 10 to 11KB per inode
944         esac
945
946         echo -n $size
947 }
948
949 check_gss_daemon_nodes() {
950     local list=$1
951     dname=$2
952
953     do_nodesv $list "num=\\\$(ps -o cmd -C $dname | grep $dname | wc -l);
954 if [ \\\"\\\$num\\\" -ne 1 ]; then
955     echo \\\$num instance of $dname;
956     exit 1;
957 fi; "
958 }
959
960 check_gss_daemon_facet() {
961     facet=$1
962     dname=$2
963
964     num=`do_facet $facet ps -o cmd -C $dname | grep $dname | wc -l`
965     if [ $num -ne 1 ]; then
966         echo "$num instance of $dname on $facet"
967         return 1
968     fi
969     return 0
970 }
971
972 send_sigint() {
973     local list=$1
974     shift
975     echo Stopping $@ on $list
976     do_nodes $list "killall -2 $@ 2>/dev/null || true"
977 }
978
979 # start gss daemons on all nodes, or "daemon" on "nodes" if set
980 start_gss_daemons() {
981         local nodes=$1
982         local daemon=$2
983
984         if [ "$nodes" ] && [ "$daemon" ] ; then
985                 echo "Starting gss daemon on nodes: $nodes"
986                 do_nodes $nodes "$daemon" || return 8
987                 return 0
988         fi
989
990         nodes=$(comma_list $(mdts_nodes))
991         echo "Starting gss daemon on mds: $nodes"
992         if $GSS_SK; then
993                 # Start all versions, in case of switching
994                 do_nodes $nodes "$LSVCGSSD -vvv -s -m -o -z" || return 1
995         else
996                 do_nodes $nodes "$LSVCGSSD -v" || return 1
997         fi
998         if $GSS_PIPEFS; then
999                 do_nodes $nodes "$LGSSD -v" || return 2
1000         fi
1001
1002         nodes=$(comma_list $(osts_nodes))
1003         echo "Starting gss daemon on ost: $nodes"
1004         if $GSS_SK; then
1005                 # Start all versions, in case of switching
1006                 do_nodes $nodes "$LSVCGSSD -vvv -s -m -o -z" || return 3
1007         else
1008                 do_nodes $nodes "$LSVCGSSD -v" || return 3
1009         fi
1010         # starting on clients
1011
1012         local clients=${CLIENTS:-$HOSTNAME}
1013         if $GSS_PIPEFS; then
1014                 echo "Starting $LGSSD on clients $clients "
1015                 do_nodes $clients  "$LGSSD -v" || return 4
1016         fi
1017
1018         # wait daemons entering "stable" status
1019         sleep 5
1020
1021         #
1022         # check daemons are running
1023         #
1024         nodes=$(comma_list $(mdts_nodes) $(osts_nodes))
1025         check_gss_daemon_nodes $nodes lsvcgssd || return 5
1026         if $GSS_PIPEFS; then
1027                 nodes=$(comma_list $(mdts_nodes))
1028                 check_gss_daemon_nodes $nodes lgssd || return 6
1029         fi
1030         if $GSS_PIPEFS; then
1031                 check_gss_daemon_nodes $clients lgssd || return 7
1032         fi
1033 }
1034
1035 stop_gss_daemons() {
1036         local nodes=$(comma_list $(mdts_nodes))
1037
1038         send_sigint $nodes lsvcgssd lgssd
1039
1040         nodes=$(comma_list $(osts_nodes))
1041         send_sigint $nodes lsvcgssd
1042
1043         nodes=${CLIENTS:-$HOSTNAME}
1044         send_sigint $nodes lgssd
1045 }
1046
1047 add_sk_mntflag() {
1048         # Add mount flags for shared key
1049         local mt_opts=$@
1050         if grep -q skpath <<< "$mt_opts" ; then
1051                 mt_opts=$(echo $mt_opts |
1052                         sed -e "s#skpath=[^ ,]*#skpath=$SK_PATH#")
1053         else
1054                 if [ -z "$mt_opts" ]; then
1055                         mt_opts="-o skpath=$SK_PATH"
1056                 else
1057                         mt_opts="$mt_opts,skpath=$SK_PATH"
1058                 fi
1059         fi
1060         echo -n $mt_opts
1061 }
1062
1063 from_build_tree() {
1064         local from_tree
1065
1066         case $LUSTRE in
1067         /usr/lib/lustre/* | /usr/lib64/lustre/* | /usr/lib/lustre | \
1068         /usr/lib64/lustre )
1069                 from_tree=false
1070                 ;;
1071         *)
1072                 from_tree=true
1073                 ;;
1074         esac
1075
1076         [ $from_tree = true ]
1077 }
1078
1079 init_gss() {
1080         if $SHARED_KEY; then
1081                 GSS=true
1082                 GSS_SK=true
1083         fi
1084
1085         if ! $GSS; then
1086                 return
1087         fi
1088
1089         if ! module_loaded ptlrpc_gss; then
1090                 load_module ptlrpc/gss/ptlrpc_gss
1091                 module_loaded ptlrpc_gss ||
1092                         error_exit "init_gss: GSS=$GSS, but gss/krb5 missing"
1093         fi
1094
1095         if $GSS_KRB5 || $GSS_SK; then
1096                 start_gss_daemons || error_exit "start gss daemon failed! rc=$?"
1097         fi
1098
1099         if $GSS_SK && ! $SK_NO_KEY; then
1100                 echo "Loading basic SSK keys on all servers"
1101                 do_nodes $(comma_list $(all_server_nodes)) \
1102                         "lgss_sk -t server -l $SK_PATH/$FSNAME.key || true"
1103                 do_nodes $(comma_list $(all_server_nodes)) \
1104                                 "keyctl show | grep lustre | cut -c1-11 |
1105                                 sed -e 's/ //g;' |
1106                                 xargs -IX keyctl setperm X 0x3f3f3f3f"
1107         fi
1108
1109         if $GSS_SK && $SK_NO_KEY; then
1110                 local numclients=${1:-$CLIENTCOUNT}
1111                 local clients=${CLIENTS:-$HOSTNAME}
1112
1113                 # security ctx config for keyring
1114                 SK_NO_KEY=false
1115                 local lgssc_conf_file="/etc/request-key.d/lgssc.conf"
1116
1117                 if from_build_tree; then
1118                         mkdir -p $SK_OM_PATH
1119                         if grep -q request-key /proc/mounts > /dev/null; then
1120                                 echo "SSK: Request key already mounted."
1121                         else
1122                                 mount -o bind $SK_OM_PATH /etc/request-key.d/
1123                         fi
1124                         local lgssc_conf_line='create lgssc * * '
1125                         lgssc_conf_line+=$(which lgss_keyring)
1126                         lgssc_conf_line+=' %o %k %t %d %c %u %g %T %P %S'
1127                         echo "$lgssc_conf_line" > $lgssc_conf_file
1128                 fi
1129
1130                 [ -e $lgssc_conf_file ] ||
1131                         error_exit "Could not find key options in $lgssc_conf_file"
1132                 echo "$lgssc_conf_file content is:"
1133                 cat $lgssc_conf_file
1134
1135                 if ! local_mode; then
1136                         if from_build_tree; then
1137                                 do_nodes $(comma_list $(all_nodes)) "mkdir -p \
1138                                         $SK_OM_PATH"
1139                                 do_nodes $(comma_list $(all_nodes)) "mount \
1140                                         -o bind $SK_OM_PATH \
1141                                         /etc/request-key.d/"
1142                                 do_nodes $(comma_list $(all_nodes)) "rsync \
1143                                         -aqv $HOSTNAME:$lgssc_conf_file \
1144                                         $lgssc_conf_file >/dev/null 2>&1"
1145                         else
1146                                 do_nodes $(comma_list $(all_nodes)) \
1147                                         "echo $lgssc_conf_file: ; \
1148                                         cat $lgssc_conf_file"
1149                         fi
1150                 fi
1151
1152                 # create shared key on all nodes
1153                 mkdir -p $SK_PATH/nodemap
1154                 rm -f $SK_PATH/$FSNAME.key $SK_PATH/nodemap/c*.key \
1155                         $SK_PATH/$FSNAME-*.key
1156                 # for nodemap testing each client may need own key,
1157                 # and S2S now requires keys as well, both for "client"
1158                 # and for "server"
1159                 if $SK_S2S; then
1160                         lgss_sk -t server -f$FSNAME -n $SK_S2SNMCLI \
1161                                 -w $SK_PATH/$FSNAME-nmclient.key \
1162                                 -d /dev/urandom >/dev/null 2>&1
1163                         lgss_sk -t mgs,server -f$FSNAME -n $SK_S2SNM \
1164                                 -w $SK_PATH/$FSNAME-s2s-server.key \
1165                                 -d /dev/urandom >/dev/null 2>&1
1166                 fi
1167                 # basic key create
1168                 lgss_sk -t server -f$FSNAME -w $SK_PATH/$FSNAME.key \
1169                         -d /dev/urandom >/dev/null 2>&1
1170                 # per-nodemap keys
1171                 for i in $(seq 0 $((numclients - 1))); do
1172                         lgss_sk -t server -f$FSNAME -n c$i \
1173                                 -w $SK_PATH/nodemap/c$i.key -d /dev/urandom \
1174                                 >/dev/null 2>&1
1175                 done
1176                 # Distribute keys
1177                 if ! local_mode; then
1178                         for lnode in $(all_nodes); do
1179                                 scp -r $SK_PATH ${lnode}:$(dirname $SK_PATH)/
1180                         done
1181                 fi
1182                 # Set client keys to client type to generate prime P
1183                 if local_mode; then
1184                         do_nodes $(all_nodes) "lgss_sk -t client,server -m \
1185                                 $SK_PATH/$FSNAME.key >/dev/null 2>&1"
1186                 else
1187                         do_nodes $clients "lgss_sk -t client -m \
1188                                 $SK_PATH/$FSNAME.key >/dev/null 2>&1"
1189                         do_nodes $clients "find $SK_PATH/nodemap -name \*.key | \
1190                                 xargs -IX lgss_sk -t client -m X >/dev/null 2>&1"
1191                 fi
1192                 # This is required for servers as well, if S2S in use
1193                 if $SK_S2S; then
1194                         do_nodes $(comma_list $(mdts_nodes)) \
1195                                 "cp $SK_PATH/$FSNAME-s2s-server.key \
1196                                 $SK_PATH/$FSNAME-s2s-client.key; lgss_sk \
1197                                 -t client -m $SK_PATH/$FSNAME-s2s-client.key \
1198                                 >/dev/null 2>&1"
1199                         do_nodes $(comma_list $(osts_nodes)) \
1200                                 "cp $SK_PATH/$FSNAME-s2s-server.key \
1201                                 $SK_PATH/$FSNAME-s2s-client.key; lgss_sk \
1202                                 -t client -m $SK_PATH/$FSNAME-s2s-client.key \
1203                                 >/dev/null 2>&1"
1204                         do_nodes $clients "lgss_sk -t client \
1205                                 -m $SK_PATH/$FSNAME-nmclient.key \
1206                                  >/dev/null 2>&1"
1207                 fi
1208         fi
1209         if $GSS_SK; then
1210                 # mount options for servers and clients
1211                 MGS_MOUNT_OPTS=$(add_sk_mntflag $MGS_MOUNT_OPTS)
1212                 MDS_MOUNT_OPTS=$(add_sk_mntflag $MDS_MOUNT_OPTS)
1213                 OST_MOUNT_OPTS=$(add_sk_mntflag $OST_MOUNT_OPTS)
1214                 MOUNT_OPTS=$(add_sk_mntflag $MOUNT_OPTS)
1215                 SEC=$SK_FLAVOR
1216                 if [ -z "$LGSS_KEYRING_DEBUG" ]; then
1217                         LGSS_KEYRING_DEBUG=4
1218                 fi
1219         fi
1220
1221         if [ -n "$LGSS_KEYRING_DEBUG" ] && \
1222                ( local_mode || from_build_tree ); then
1223                 lctl set_param -n \
1224                      sptlrpc.gss.lgss_keyring.debug_level=$LGSS_KEYRING_DEBUG
1225         elif [ -n "$LGSS_KEYRING_DEBUG" ]; then
1226                 do_nodes $(comma_list $(all_nodes)) "modprobe ptlrpc_gss && \
1227                 lctl set_param -n \
1228                    sptlrpc.gss.lgss_keyring.debug_level=$LGSS_KEYRING_DEBUG"
1229         fi
1230 }
1231
1232 cleanup_gss() {
1233         if $GSS; then
1234                 stop_gss_daemons
1235                 # maybe cleanup credential cache?
1236         fi
1237 }
1238
1239 cleanup_sk() {
1240         if $GSS_SK; then
1241                 if $SK_S2S; then
1242                         do_node $(mgs_node) "$LCTL nodemap_del $SK_S2SNM"
1243                         do_node $(mgs_node) "$LCTL nodemap_del $SK_S2SNMCLI"
1244                         $RPC_MODE || echo "Sleeping for 10 sec for Nodemap.."
1245                         sleep 10
1246                 fi
1247                 stop_gss_daemons
1248                 $RPC_MODE || echo "Cleaning up Shared Key.."
1249                 do_nodes $(comma_list $(all_nodes)) "rm -f \
1250                         $SK_PATH/$FSNAME*.key $SK_PATH/nodemap/$FSNAME*.key"
1251                 do_nodes $(comma_list $(all_nodes)) "keyctl show | \
1252                   awk '/lustre/ { print \\\$1 }' | xargs -IX keyctl unlink X"
1253                 if from_build_tree; then
1254                         # Remove the mount and clean up the files we added to
1255                         # SK_PATH
1256                         do_nodes $(comma_list $(all_nodes)) "while grep -q \
1257                                 request-key.d /proc/mounts; do umount \
1258                                 /etc/request-key.d/; done"
1259                         do_nodes $(comma_list $(all_nodes)) "rm -f \
1260                                 $SK_OM_PATH/lgssc.conf"
1261                         do_nodes $(comma_list $(all_nodes)) "rmdir $SK_OM_PATH"
1262                 fi
1263                 SK_NO_KEY=true
1264         fi
1265 }
1266
1267 facet_svc() {
1268         local facet=$1
1269         local var=${facet}_svc
1270
1271         echo -n ${!var}
1272 }
1273
1274 facet_type() {
1275         local facet=$1
1276
1277         echo -n $facet | sed -e 's/^fs[0-9]\+//' -e 's/[0-9_]\+//' |
1278                 tr '[:lower:]' '[:upper:]'
1279 }
1280
1281 facet_number() {
1282         local facet=$1
1283
1284         if [ $facet == mgs ] || [ $facet == client ]; then
1285                 return 1
1286         fi
1287
1288         echo -n $facet | sed -e 's/^fs[0-9]\+//' | sed -e 's/^[a-z]\+//'
1289 }
1290
1291 facet_fstype() {
1292         local facet=$1
1293         local var
1294
1295         var=${facet}_FSTYPE
1296         if [ -n "${!var}" ]; then
1297                 echo -n ${!var}
1298                 return
1299         fi
1300
1301         var=$(facet_type $facet)FSTYPE
1302         if [ -n "${!var}" ]; then
1303                 echo -n ${!var}
1304                 return
1305         fi
1306
1307         if [ -n "$FSTYPE" ]; then
1308                 echo -n $FSTYPE
1309                 return
1310         fi
1311
1312         if [[ $facet == mgs ]] && combined_mgs_mds; then
1313                 facet_fstype mds1
1314                 return
1315         fi
1316
1317         return 1
1318 }
1319
1320 node_fstypes() {
1321         local node=$1
1322         local fstypes
1323         local fstype
1324         local facets=$(get_facets)
1325         local facet
1326
1327         for facet in ${facets//,/ }; do
1328                 if [ $node == $(facet_host $facet) ] ||
1329                    [ $node == "$(facet_failover_host $facet)" ]; then
1330                         fstype=$(facet_fstype $facet)
1331                         if [[ $fstypes != *$fstype* ]]; then
1332                                 fstypes+="${fstypes:+,}$fstype"
1333                         fi
1334                 fi
1335         done
1336         echo -n $fstypes
1337 }
1338
1339 facet_index() {
1340         local facet=$1
1341         local num=$(facet_number $facet)
1342         local index
1343
1344         if [[ $(facet_type $facet) = OST ]]; then
1345                 index=OSTINDEX${num}
1346                 if [[ -n "${!index}" ]]; then
1347                         echo -n ${!index}
1348                         return
1349                 fi
1350
1351                 index=${OST_INDICES[num - 1]}
1352         fi
1353
1354         [[ -n "$index" ]] || index=$((num - 1))
1355         echo -n $index
1356 }
1357
1358 devicelabel() {
1359         local facet=$1
1360         local dev=$2
1361         local label
1362         local fstype=$(facet_fstype $facet)
1363
1364         case $fstype in
1365         ldiskfs)
1366                 label=$(do_facet ${facet} "$E2LABEL ${dev} 2>/dev/null");;
1367         zfs)
1368                 label=$(do_facet ${facet} "$ZFS get -H -o value lustre:svname \
1369                                            ${dev} 2>/dev/null");;
1370         *)
1371                 error "unknown fstype!";;
1372         esac
1373
1374         echo -n $label
1375 }
1376
1377 #
1378 # Get the device of a facet.
1379 #
1380 facet_device() {
1381         local facet=$1
1382         local device
1383
1384         case $facet in
1385                 mgs) device=$(mgsdevname) ;;
1386                 mds*) device=$(mdsdevname $(facet_number $facet)) ;;
1387                 ost*) device=$(ostdevname $(facet_number $facet)) ;;
1388                 fs2mds) device=$(mdsdevname 1_2) ;;
1389                 fs2ost) device=$(ostdevname 1_2) ;;
1390                 fs3ost) device=$(ostdevname 2_2) ;;
1391                 *) ;;
1392         esac
1393
1394         echo -n $device
1395 }
1396
1397 #
1398 # Get the virtual device of a facet.
1399 #
1400 facet_vdevice() {
1401         local facet=$1
1402         local device
1403
1404         case $facet in
1405                 mgs) device=$(mgsvdevname) ;;
1406                 mds*) device=$(mdsvdevname $(facet_number $facet)) ;;
1407                 ost*) device=$(ostvdevname $(facet_number $facet)) ;;
1408                 fs2mds) device=$(mdsvdevname 1_2) ;;
1409                 fs2ost) device=$(ostvdevname 1_2) ;;
1410                 fs3ost) device=$(ostvdevname 2_2) ;;
1411                 *) ;;
1412         esac
1413
1414         echo -n $device
1415 }
1416
1417 running_in_vm() {
1418         local virt=$(virt-what 2> /dev/null)
1419
1420         [ $? -eq 0 ] && [ -n "$virt" ] && { echo $virt; return; }
1421
1422         virt=$(dmidecode -s system-product-name | awk '{print $1}')
1423
1424         case $virt in
1425                 VMware|KVM|VirtualBox|Parallels|Bochs)
1426                         echo $virt | tr '[A-Z]' '[a-z]' ;;
1427                 *) ;;
1428         esac
1429 }
1430
1431 #
1432 # Re-read the partition table on failover partner host.
1433 # After a ZFS storage pool is created on a shared device, the partition table
1434 # on the device may change. However, the operating system on the failover
1435 # host may not notice the change automatically. Without the up-to-date partition
1436 # block devices, 'zpool import ..' cannot find the labels, whose positions are
1437 # relative to partition rather than disk beginnings.
1438 #
1439 # This function performs partprobe on the failover host to make it re-read the
1440 # partition table.
1441 #
1442 refresh_partition_table() {
1443         local facet=$1
1444         local device=$2
1445         local host
1446
1447         host=$(facet_passive_host $facet)
1448         if [[ -n "$host" ]]; then
1449                 do_node $host "$PARTPROBE $device"
1450         fi
1451 }
1452
1453 #
1454 # Get ZFS storage pool name.
1455 #
1456 zpool_name() {
1457         local facet=$1
1458         local device
1459         local poolname
1460
1461         device=$(facet_device $facet)
1462         # poolname is string before "/"
1463         poolname="${device%%/*}"
1464
1465         echo -n $poolname
1466 }
1467
1468 #
1469 #
1470 # Get ZFS local fsname.
1471 #
1472 zfs_local_fsname() {
1473         local facet=$1
1474         local lfsname=$(basename $(facet_device $facet))
1475
1476         echo -n $lfsname
1477 }
1478
1479 #
1480 # Create ZFS storage pool.
1481 #
1482 create_zpool() {
1483         local facet=$1
1484         local poolname=$2
1485         local vdev=$3
1486         shift 3
1487         local opts=${@:-"-o cachefile=none"}
1488
1489         do_facet $facet "lsmod | grep zfs >&/dev/null || modprobe zfs;
1490                 $ZPOOL list -H $poolname >/dev/null 2>&1 ||
1491                 $ZPOOL create -f $opts $poolname $vdev"
1492 }
1493
1494 #
1495 # Create ZFS file system.
1496 #
1497 create_zfs() {
1498         local facet=$1
1499         local dataset=$2
1500         shift 2
1501         local opts=${@:-"-o mountpoint=legacy"}
1502
1503         do_facet $facet "$ZFS list -H $dataset >/dev/null 2>&1 ||
1504                 $ZFS create $opts $dataset"
1505 }
1506
1507 #
1508 # Export ZFS storage pool.
1509 # Before exporting the pool, all datasets within the pool should be unmounted.
1510 #
1511 export_zpool() {
1512         local facet=$1
1513         shift
1514         local opts="$@"
1515         local poolname
1516
1517         poolname=$(zpool_name $facet)
1518
1519         if [[ -n "$poolname" ]]; then
1520                 do_facet $facet "! $ZPOOL list -H $poolname >/dev/null 2>&1 ||
1521                         grep -q ^$poolname/ /proc/mounts ||
1522                         $ZPOOL export $opts $poolname"
1523         fi
1524 }
1525
1526 #
1527 # Destroy ZFS storage pool.
1528 # Destroy the given pool and free up any devices for other use. This command
1529 # tries to unmount any active datasets before destroying the pool.
1530 # -f    Force any active datasets contained within the pool to be unmounted.
1531 #
1532 destroy_zpool() {
1533         local facet=$1
1534         local poolname=${2:-$(zpool_name $facet)}
1535
1536         if [[ -n "$poolname" ]]; then
1537                 do_facet $facet "! $ZPOOL list -H $poolname >/dev/null 2>&1 ||
1538                         $ZPOOL destroy -f $poolname"
1539         fi
1540 }
1541
1542 #
1543 # Import ZFS storage pool.
1544 # Force importing, even if the pool appears to be potentially active.
1545 #
1546 import_zpool() {
1547         local facet=$1
1548         shift
1549         local opts=${@:-"-o cachefile=none -o failmode=panic"}
1550         local poolname
1551
1552         poolname=$(zpool_name $facet)
1553
1554         if [[ -n "$poolname" ]]; then
1555                 opts+=" -d $(dirname $(facet_vdevice $facet))"
1556                 do_facet $facet "lsmod | grep zfs >&/dev/null || modprobe zfs;
1557                         $ZPOOL list -H $poolname >/dev/null 2>&1 ||
1558                         $ZPOOL import -f $opts $poolname"
1559         fi
1560 }
1561
1562 #
1563 # Reimport ZFS storage pool with new name
1564 #
1565 reimport_zpool() {
1566         local facet=$1
1567         local newpool=$2
1568         local opts="-o cachefile=none"
1569         local poolname=$(zpool_name $facet)
1570
1571         opts+=" -d $(dirname $(facet_vdevice $facet))"
1572         do_facet $facet "$ZPOOL export $poolname;
1573                          $ZPOOL import $opts $poolname $newpool"
1574 }
1575
1576 #
1577 # Set the "cachefile=none" property on ZFS storage pool so that the pool
1578 # is not automatically imported on system startup.
1579 #
1580 # In a failover environment, this will provide resource level fencing which
1581 # will ensure that the same ZFS storage pool will not be imported concurrently
1582 # on different nodes.
1583 #
1584 disable_zpool_cache() {
1585         local facet=$1
1586         local poolname
1587
1588         poolname=$(zpool_name $facet)
1589
1590         if [[ -n "$poolname" ]]; then
1591                 do_facet $facet "$ZPOOL set cachefile=none $poolname"
1592         fi
1593 }
1594
1595 #
1596 # This and set_osd_param() shall be used to access OSD parameters
1597 # once existed under "obdfilter":
1598 #
1599 #   mntdev
1600 #   stats
1601 #   read_cache_enable
1602 #   writethrough_cache_enable
1603 #
1604 get_osd_param() {
1605         local nodes=$1
1606         local device=${2:-$FSNAME-OST*}
1607         local name=$3
1608
1609         do_nodes $nodes "$LCTL get_param -n osd-*.$device.$name"
1610 }
1611
1612 set_osd_param() {
1613         local nodes=$1
1614         local device=${2:-$FSNAME-OST*}
1615         local name=$3
1616         local value=$4
1617
1618         do_nodes $nodes "$LCTL set_param -n osd-*.$device.$name=$value"
1619 }
1620
1621 set_debug_size () {
1622     local dz=${1:-$DEBUG_SIZE}
1623
1624     if [ -f /sys/devices/system/cpu/possible ]; then
1625         local cpus=$(($(cut -d "-" -f 2 /sys/devices/system/cpu/possible)+1))
1626     else
1627         local cpus=$(getconf _NPROCESSORS_CONF 2>/dev/null)
1628     fi
1629
1630     # bug 19944, adjust size to be -gt num_possible_cpus()
1631     # promise 2MB for every cpu at least
1632     if [ -n "$cpus" ] && [ $((cpus * 2)) -gt $dz ]; then
1633         dz=$((cpus * 2))
1634     fi
1635     lctl set_param debug_mb=$dz
1636 }
1637
1638 set_default_debug () {
1639         local debug=${1:-"$PTLDEBUG"}
1640         local subsys=${2:-"$SUBSYSTEM"}
1641         local debug_size=${3:-$DEBUG_SIZE}
1642
1643         [ -n "$debug" ] && lctl set_param debug="$debug" >/dev/null
1644         [ -n "$subsys" ] && lctl set_param subsystem_debug="${subsys# }" >/dev/null
1645
1646         [ -n "$debug_size" ] && set_debug_size $debug_size > /dev/null
1647 }
1648
1649 set_default_debug_nodes () {
1650         local nodes="$1"
1651         local debug="${2:-"$PTLDEBUG"}"
1652         local subsys="${3:-"$SUBSYSTEM"}"
1653         local debug_size="${4:-$DEBUG_SIZE}"
1654
1655         if [[ ,$nodes, = *,$HOSTNAME,* ]]; then
1656                 nodes=$(exclude_items_from_list "$nodes" "$HOSTNAME")
1657                 set_default_debug
1658         fi
1659
1660         [[ -z "$nodes" ]] ||
1661                 do_rpc_nodes "$nodes" set_default_debug \
1662                         \\\"$debug\\\" \\\"$subsys\\\" $debug_size || true
1663 }
1664
1665 set_default_debug_facet () {
1666         local facet=$1
1667         local debug="${2:-"$PTLDEBUG"}"
1668         local subsys="${3:-"$SUBSYSTEM"}"
1669         local debug_size="${4:-$DEBUG_SIZE}"
1670         local node=$(facet_active_host $facet)
1671
1672         [ -n "$node" ] || error "No host defined for facet $facet"
1673
1674         set_default_debug_nodes $node "$debug" "$subsys" $debug_size
1675 }
1676
1677 set_params_nodes () {
1678         [[ $# -ge 2 ]] || return 0
1679
1680         local nodes=$1
1681         shift
1682         do_nodes $nodes $LCTL set_param $@
1683 }
1684
1685 set_params_clients () {
1686         local clients=${1:-$CLIENTS}
1687         local params=${2:-$CLIENT_LCTL_SETPARAM_PARAM}
1688
1689         [[ -n $params ]] || return 0
1690         set_params_nodes $clients $params
1691 }
1692
1693 set_hostid () {
1694     local hostid=${1:-$(hostid)}
1695
1696     if [ ! -s /etc/hostid ]; then
1697         printf $(echo -n $hostid |
1698             sed 's/\(..\)\(..\)\(..\)\(..\)/\\x\4\\x\3\\x\2\\x\1/') >/etc/hostid
1699     fi
1700 }
1701
1702 # Facet functions
1703 mount_facets () {
1704         local facets=${1:-$(get_facets)}
1705         local facet
1706         local -a mountpids
1707         local total=0
1708         local ret=0
1709
1710         for facet in ${facets//,/ }; do
1711                 mount_facet $facet &
1712                 mountpids[total]=$!
1713                 total=$((total+1))
1714         done
1715         for ((index=0; index<$total; index++)); do
1716                 wait ${mountpids[index]}
1717                 local RC=$?
1718                 [ $RC -eq 0 ] && continue
1719
1720                 if [ "$TESTSUITE.$TESTNAME" = "replay-dual.test_0a" ]; then
1721                         skip_noexit "Restart of $facet failed!." &&
1722                                 touch $LU482_FAILED
1723                 else
1724                         error "Restart of $facet failed!"
1725                 fi
1726                 ret=$RC
1727         done
1728         return $ret
1729 }
1730
1731 #
1732 # Add argument "arg" (e.g., "loop") to the comma-separated list
1733 # of arguments for option "opt" (e.g., "-o") on command
1734 # line "opts" (e.g., "-o flock").
1735 #
1736 csa_add() {
1737         local opts=$1
1738         local opt=$2
1739         local arg=$3
1740         local opt_pattern="\([[:space:]]\+\|^\)$opt"
1741
1742         if echo "$opts" | grep -q $opt_pattern; then
1743                 opts=$(echo "$opts" | sed -e \
1744                         "s/$opt_pattern[[:space:]]*[^[:space:]]\+/&,$arg/")
1745         else
1746                 opts+="${opts:+ }$opt $arg"
1747         fi
1748         echo -n "$opts"
1749 }
1750
1751 #
1752 # Associate loop device with a given regular file.
1753 # Return the loop device.
1754 #
1755 setup_loop_device() {
1756         local facet=$1
1757         local file=$2
1758
1759         do_facet $facet "loop_dev=\\\$($LOSETUP -j $file | cut -d : -f 1);
1760                          if [[ -z \\\$loop_dev ]]; then
1761                                 loop_dev=\\\$($LOSETUP -f);
1762                                 $LOSETUP \\\$loop_dev $file || loop_dev=;
1763                          fi;
1764                          echo -n \\\$loop_dev"
1765 }
1766
1767 #
1768 # Detach a loop device.
1769 #
1770 cleanup_loop_device() {
1771         local facet=$1
1772         local loop_dev=$2
1773
1774         do_facet $facet "! $LOSETUP $loop_dev >/dev/null 2>&1 ||
1775                          $LOSETUP -d $loop_dev"
1776 }
1777
1778 #
1779 # Check if a given device is a block device.
1780 #
1781 is_blkdev() {
1782         local facet=$1
1783         local dev=$2
1784         local size=${3:-""}
1785
1786         [[ -n "$dev" ]] || return 1
1787         do_facet $facet "test -b $dev" || return 1
1788         if [[ -n "$size" ]]; then
1789                 local in=$(do_facet $facet "dd if=$dev of=/dev/null bs=1k \
1790                                             count=1 skip=$size 2>&1" |
1791                                             awk '($3 == "in") { print $1 }')
1792                 [[ "$in" = "1+0" ]] || return 1
1793         fi
1794 }
1795
1796 #
1797 # Check if a given device is a device-mapper device.
1798 #
1799 is_dm_dev() {
1800         local facet=$1
1801         local dev=$2
1802
1803         [[ -n "$dev" ]] || return 1
1804         do_facet $facet "$DMSETUP status $dev >/dev/null 2>&1"
1805 }
1806
1807 #
1808 # Check if a given device is a device-mapper flakey device.
1809 #
1810 is_dm_flakey_dev() {
1811         local facet=$1
1812         local dev=$2
1813         local type
1814
1815         [[ -n "$dev" ]] || return 1
1816
1817         type=$(do_facet $facet "$DMSETUP status $dev 2>&1" |
1818                awk '{print $3}')
1819         [[ $type = flakey ]] && return 0 || return 1
1820 }
1821
1822 #
1823 # Check if device-mapper flakey device is supported by the kernel
1824 # of $facet node or not.
1825 #
1826 dm_flakey_supported() {
1827         local facet=$1
1828
1829         $FLAKEY || return 1
1830         do_facet $facet "modprobe dm-flakey;
1831                          $DMSETUP targets | grep -q flakey" &> /dev/null
1832 }
1833
1834 #
1835 # Get the device-mapper flakey device name of a given facet.
1836 #
1837 dm_facet_devname() {
1838         local facet=$1
1839         [[ $facet = mgs ]] && combined_mgs_mds && facet=mds1
1840
1841         echo -n ${facet}_flakey
1842 }
1843
1844 #
1845 # Get the device-mapper flakey device of a given facet.
1846 # A device created by dmsetup will appear as /dev/mapper/<device-name>.
1847 #
1848 dm_facet_devpath() {
1849         local facet=$1
1850
1851         echo -n $DM_DEV_PATH/$(dm_facet_devname $facet)
1852 }
1853
1854 #
1855 # Set a device-mapper device with a new table.
1856 #
1857 # The table has the following format:
1858 # <logical_start_sector> <num_sectors> <target_type> <target_args>
1859 #
1860 # flakey <target_args> includes:
1861 # <destination_device> <offset> <up_interval> <down_interval> \
1862 # [<num_features> [<feature_arguments>]]
1863 #
1864 # linear <target_args> includes:
1865 # <destination_device> <start_sector>
1866 #
1867 dm_set_dev_table() {
1868         local facet=$1
1869         local dm_dev=$2
1870         local target_type=$3
1871         local num_sectors
1872         local real_dev
1873         local tmp
1874         local table
1875
1876         read tmp num_sectors tmp real_dev tmp \
1877                 <<< $(do_facet $facet "$DMSETUP table $dm_dev")
1878
1879         case $target_type in
1880         flakey)
1881                 table="0 $num_sectors flakey $real_dev 0 0 1800 1 drop_writes"
1882                 ;;
1883         linear)
1884                 table="0 $num_sectors linear $real_dev 0"
1885                 ;;
1886         *) error "invalid target type $target_type" ;;
1887         esac
1888
1889         do_facet $facet "$DMSETUP suspend --nolockfs --noflush $dm_dev" ||
1890                 error "failed to suspend $dm_dev"
1891         do_facet $facet "$DMSETUP load $dm_dev --table \\\"$table\\\"" ||
1892                 error "failed to load $target_type table into $dm_dev"
1893         do_facet $facet "$DMSETUP resume $dm_dev" ||
1894                 error "failed to resume $dm_dev"
1895 }
1896
1897 #
1898 # Set a device-mapper flakey device as "read-only" by using the "drop_writes"
1899 # feature parameter.
1900 #
1901 # drop_writes:
1902 #       All write I/O is silently ignored.
1903 #       Read I/O is handled correctly.
1904 #
1905 dm_set_dev_readonly() {
1906         local facet=$1
1907         local dm_dev=${2:-$(dm_facet_devpath $facet)}
1908
1909         dm_set_dev_table $facet $dm_dev flakey
1910 }
1911
1912 #
1913 # Set a device-mapper device to traditional linear mapping mode.
1914 #
1915 dm_clear_dev_readonly() {
1916         local facet=$1
1917         local dm_dev=${2:-$(dm_facet_devpath $facet)}
1918
1919         dm_set_dev_table $facet $dm_dev linear
1920 }
1921
1922 #
1923 # Set the device of a given facet as "read-only".
1924 #
1925 set_dev_readonly() {
1926         local facet=$1
1927         local svc=${facet}_svc
1928
1929         if [[ $(facet_fstype $facet) = zfs ]] ||
1930            ! dm_flakey_supported $facet; then
1931                 do_facet $facet $LCTL --device ${!svc} readonly
1932         else
1933                 dm_set_dev_readonly $facet
1934         fi
1935 }
1936
1937 #
1938 # Get size in 512-byte sectors (BLKGETSIZE64 / 512) of a given device.
1939 #
1940 get_num_sectors() {
1941         local facet=$1
1942         local dev=$2
1943         local num_sectors
1944
1945         num_sectors=$(do_facet $facet "blockdev --getsz $dev 2>/dev/null")
1946         [[ ${PIPESTATUS[0]} = 0 && -n "$num_sectors" ]] || num_sectors=0
1947         echo -n $num_sectors
1948 }
1949
1950 #
1951 # Create a device-mapper device with a given block device or regular file (will
1952 # be associated with loop device).
1953 # Return the full path of the device-mapper device.
1954 #
1955 dm_create_dev() {
1956         local facet=$1
1957         local real_dev=$2                                  # destination device
1958         local dm_dev_name=${3:-$(dm_facet_devname $facet)} # device name
1959         local dm_dev=$DM_DEV_PATH/$dm_dev_name            # device-mapper device
1960
1961         # check if the device-mapper device to be created already exists
1962         if is_dm_dev $facet $dm_dev; then
1963                 # if the existing device was set to "read-only", then clear it
1964                 ! is_dm_flakey_dev $facet $dm_dev ||
1965                         dm_clear_dev_readonly $facet $dm_dev
1966
1967                 echo -n $dm_dev
1968                 return 0
1969         fi
1970
1971         # check if the destination device is a block device, and if not,
1972         # associate it with a loop device
1973         is_blkdev $facet $real_dev ||
1974                 real_dev=$(setup_loop_device $facet $real_dev)
1975         [[ -n "$real_dev" ]] || { echo -n $real_dev; return 2; }
1976
1977         # now create the device-mapper device
1978         local num_sectors=$(get_num_sectors $facet $real_dev)
1979         local table="0 $num_sectors linear $real_dev 0"
1980         local rc=0
1981
1982         do_facet $facet "$DMSETUP create $dm_dev_name --table \\\"$table\\\"" ||
1983                 { rc=${PIPESTATUS[0]}; dm_dev=; }
1984         do_facet $facet "$DMSETUP mknodes >/dev/null 2>&1"
1985
1986         echo -n $dm_dev
1987         return $rc
1988 }
1989
1990 #
1991 # Map the facet name to its device variable name.
1992 #
1993 facet_device_alias() {
1994         local facet=$1
1995         local dev_alias=$facet
1996
1997         case $facet in
1998                 fs2mds) dev_alias=mds1_2 ;;
1999                 fs2ost) dev_alias=ost1_2 ;;
2000                 fs3ost) dev_alias=ost2_2 ;;
2001                 *) ;;
2002         esac
2003
2004         echo -n $dev_alias
2005 }
2006
2007 #
2008 # Save the original value of the facet device and export the new value.
2009 #
2010 export_dm_dev() {
2011         local facet=$1
2012         local dm_dev=$2
2013
2014         local active_facet=$(facet_active $facet)
2015         local dev_alias=$(facet_device_alias $active_facet)
2016         local dev_name=${dev_alias}_dev
2017         local dev=${!dev_name}
2018
2019         if [[ $active_facet = $facet ]]; then
2020                 local failover_dev=${dev_alias}failover_dev
2021                 if [[ ${!failover_dev} = $dev ]]; then
2022                         eval export ${failover_dev}_saved=$dev
2023                         eval export ${failover_dev}=$dm_dev
2024                 fi
2025         else
2026                 dev_alias=$(facet_device_alias $facet)
2027                 local facet_dev=${dev_alias}_dev
2028                 if [[ ${!facet_dev} = $dev ]]; then
2029                         eval export ${facet_dev}_saved=$dev
2030                         eval export ${facet_dev}=$dm_dev
2031                 fi
2032         fi
2033
2034         eval export ${dev_name}_saved=$dev
2035         eval export ${dev_name}=$dm_dev
2036 }
2037
2038 #
2039 # Restore the saved value of the facet device.
2040 #
2041 unexport_dm_dev() {
2042         local facet=$1
2043
2044         [[ $facet = mgs ]] && combined_mgs_mds && facet=mds1
2045         local dev_alias=$(facet_device_alias $facet)
2046
2047         local saved_dev=${dev_alias}_dev_saved
2048         [[ -z ${!saved_dev} ]] ||
2049                 eval export ${dev_alias}_dev=${!saved_dev}
2050
2051         saved_dev=${dev_alias}failover_dev_saved
2052         [[ -z ${!saved_dev} ]] ||
2053                 eval export ${dev_alias}failover_dev=${!saved_dev}
2054 }
2055
2056 #
2057 # Remove a device-mapper device.
2058 # If the destination device is a loop device, then also detach it.
2059 #
2060 dm_cleanup_dev() {
2061         local facet=$1
2062         local dm_dev=${2:-$(dm_facet_devpath $facet)}
2063         local major
2064         local minor
2065
2066         is_dm_dev $facet $dm_dev || return 0
2067
2068         read major minor <<< $(do_facet $facet "$DMSETUP table $dm_dev" |
2069                 awk '{ print $4 }' | awk -F: '{ print $1" "$2 }')
2070
2071         do_facet $facet "$DMSETUP remove $dm_dev"
2072         do_facet $facet "$DMSETUP mknodes >/dev/null 2>&1"
2073
2074         unexport_dm_dev $facet
2075
2076         # detach a loop device
2077         [[ $major -ne 7 ]] || cleanup_loop_device $facet /dev/loop$minor
2078
2079         # unload dm-flakey module
2080         do_facet $facet "modprobe -r dm-flakey" || true
2081 }
2082
2083 mount_facet() {
2084         local facet=$1
2085         shift
2086         local active_facet=$(facet_active $facet)
2087         local dev_alias=$(facet_device_alias $active_facet)
2088         local dev=${dev_alias}_dev
2089         local opt=${facet}_opt
2090         local mntpt=$(facet_mntpt $facet)
2091         local opts="${!opt} $@"
2092         local fstype=$(facet_fstype $facet)
2093         local devicelabel
2094         local dm_dev=${!dev}
2095
2096         [[ $dev == "mgsfailover_dev" ]] && combined_mgs_mds &&
2097                 dev=mds1failover_dev
2098
2099         module_loaded lustre || load_modules
2100
2101         case $fstype in
2102         ldiskfs)
2103                 if dm_flakey_supported $facet; then
2104                         dm_dev=$(dm_create_dev $facet ${!dev})
2105                         [[ -n "$dm_dev" ]] || dm_dev=${!dev}
2106                 fi
2107
2108                 is_blkdev $facet $dm_dev || opts=$(csa_add "$opts" -o loop)
2109
2110                 devicelabel=$(do_facet ${facet} "$E2LABEL $dm_dev");;
2111         zfs)
2112                 # import ZFS storage pool
2113                 import_zpool $facet || return ${PIPESTATUS[0]}
2114
2115                 devicelabel=$(do_facet ${facet} "$ZFS get -H -o value \
2116                                                 lustre:svname $dm_dev");;
2117         *)
2118                 error "unknown fstype!";;
2119         esac
2120
2121         echo "Starting ${facet}: $opts $dm_dev $mntpt"
2122         # for testing LU-482 error handling in mount_facets() and test_0a()
2123         if [ -f $TMP/test-lu482-trigger ]; then
2124                 RC=2
2125         else
2126                 do_facet ${facet} \
2127                         "mkdir -p $mntpt; $MOUNT_CMD $opts $dm_dev $mntpt"
2128                 RC=${PIPESTATUS[0]}
2129         fi
2130
2131         if [ $RC -ne 0 ]; then
2132                 echo "Start of $dm_dev on ${facet} failed ${RC}"
2133                 return $RC
2134         fi
2135
2136         health=$(do_facet ${facet} "$LCTL get_param -n health_check")
2137         if [[ "$health" != "healthy" ]]; then
2138                 error "$facet is in a unhealthy state"
2139         fi
2140
2141         set_default_debug_facet $facet
2142
2143         if [[ $opts =~ .*nosvc.* ]]; then
2144                 echo "Start $dm_dev without service"
2145         else
2146
2147                 case $fstype in
2148                 ldiskfs)
2149                         wait_update_facet ${facet} "$E2LABEL $dm_dev \
2150                                 2>/dev/null | grep -E ':[a-zA-Z]{3}[0-9]{4}'" \
2151                                 "" || error "$dm_dev failed to initialize!";;
2152                 zfs)
2153                         wait_update_facet ${facet} "$ZFS get -H -o value \
2154                                 lustre:svname $dm_dev 2>/dev/null | \
2155                                 grep -E ':[a-zA-Z]{3}[0-9]{4}'" "" ||
2156                                 error "$dm_dev failed to initialize!";;
2157
2158                 *)
2159                         error "unknown fstype!";;
2160                 esac
2161         fi
2162
2163         # commit the device label change to disk
2164         if [[ $devicelabel =~ (:[a-zA-Z]{3}[0-9]{4}) ]]; then
2165                 echo "Commit the device label on ${!dev}"
2166                 do_facet $facet "sync; sleep 1; sync"
2167         fi
2168
2169
2170         label=$(devicelabel ${facet} $dm_dev)
2171         [ -z "$label" ] && echo no label for $dm_dev && exit 1
2172         eval export ${facet}_svc=${label}
2173         echo Started ${label}
2174
2175         export_dm_dev $facet $dm_dev
2176
2177         return $RC
2178 }
2179
2180 # start facet device options
2181 start() {
2182         local facet=$1
2183         shift
2184         local device=$1
2185         shift
2186         local dev_alias=$(facet_device_alias $facet)
2187
2188         eval export ${dev_alias}_dev=${device}
2189         eval export ${facet}_opt=\"$@\"
2190
2191         combined_mgs_mds && [[ ${dev_alias} == mds1 ]] &&
2192                 eval export mgs_dev=${device}
2193
2194         local varname=${dev_alias}failover_dev
2195         if [ -n "${!varname}" ] ; then
2196                 eval export ${dev_alias}failover_dev=${!varname}
2197         else
2198                 eval export ${dev_alias}failover_dev=$device
2199                 combined_mgs_mds && [[ ${dev_alias} == mds1 ]] &&
2200                         eval export mgsfailover_dev=${device}
2201
2202         fi
2203
2204         local mntpt=$(facet_mntpt $facet)
2205         do_facet ${facet} mkdir -p $mntpt
2206         eval export ${facet}_MOUNT=$mntpt
2207         mount_facet ${facet}
2208         RC=$?
2209
2210         return $RC
2211 }
2212
2213 stop() {
2214         local running
2215         local facet=$1
2216         shift
2217         local HOST=$(facet_active_host $facet)
2218         [[ -z $HOST ]] && echo stop: no host for $facet && return 0
2219
2220         local mntpt=$(facet_mntpt $facet)
2221         running=$(do_facet ${facet} "grep -c $mntpt' ' /proc/mounts || true")
2222         if [ ${running} -ne 0 ]; then
2223                 echo "Stopping $mntpt (opts:$@) on $HOST"
2224                 do_facet ${facet} $UMOUNT $@ $mntpt
2225         fi
2226
2227         # umount should block, but we should wait for unrelated obd's
2228         # like the MGS or MGC to also stop.
2229         wait_exit_ST ${facet} || return ${PIPESTATUS[0]}
2230
2231         if [[ $(facet_fstype $facet) == zfs ]]; then
2232                 # export ZFS storage pool
2233                 [ "$KEEP_ZPOOL" = "true" ] || export_zpool $facet
2234         elif dm_flakey_supported $facet; then
2235                 local host=${facet}_HOST
2236                 local failover_host=${facet}failover_HOST
2237                 if [[ -n ${!failover_host} && ${!failover_host} != ${!host} ]]||
2238                         $CLEANUP_DM_DEV || [[ $facet = fs* ]]; then
2239                         dm_cleanup_dev $facet
2240                 fi
2241         fi
2242 }
2243
2244 # get mdt quota type
2245 mdt_quota_type() {
2246         local varsvc=${SINGLEMDS}_svc
2247         do_facet $SINGLEMDS $LCTL get_param -n \
2248                 osd-$(facet_fstype $SINGLEMDS).${!varsvc}.quota_slave.enabled
2249 }
2250
2251 # get ost quota type
2252 ost_quota_type() {
2253         # All OSTs should have same quota type
2254         local varsvc=ost1_svc
2255         do_facet ost1 $LCTL get_param -n \
2256                 osd-$(facet_fstype ost1).${!varsvc}.quota_slave.enabled
2257 }
2258
2259 # restore old quota type settings
2260 restore_quota() {
2261         if [ "$old_MDT_QUOTA_TYPE" ]; then
2262                 if [[ $PERM_CMD == *"set_param -P"* ]]; then
2263                         do_facet mgs $PERM_CMD \
2264                                 osd-*.$FSNAME-MDT*.quota_slave.enabled = \
2265                                 $old_MDT_QUOTA_TYPE
2266                 else
2267                         do_facet mgs $PERM_CMD \
2268                                 $FSNAME.quota.mdt=$old_MDT_QUOTA_TYPE
2269                 fi
2270         fi
2271         if [ "$old_OST_QUOTA_TYPE" ]; then
2272                 if [[ $PERM_CMD == *"set_param -P"* ]]; then
2273                         do_facet mgs $PERM_CMD \
2274                                 osd-*.$FSNAME-OST*.quota_slave.enabled = \
2275                                 $old_OST_QUOTA_TYPE
2276                 else
2277                         do_facet mgs $LCTL conf_param \
2278                                 $FSNAME.quota.ost=$old_OST_QUOTA_TYPE
2279                 fi
2280         fi
2281 }
2282
2283 # Handle the case when there is a space in the lfs df
2284 # "filesystem summary" line the same as when there is no space.
2285 # This will allow fixing the "lfs df" summary line in the future.
2286 lfs_df() {
2287         $LFS df $* | sed -e 's/filesystem /filesystem_/'
2288         check_lfs_df_ret_val $?
2289 }
2290
2291 # Get free inodes on the MDT specified by mdt index, free indoes on
2292 # the whole filesystem will be returned when index == -1.
2293 mdt_free_inodes() {
2294         local index=$1
2295         local free_inodes
2296         local mdt_uuid
2297
2298         if [ $index -eq -1 ]; then
2299                 mdt_uuid="summary"
2300         else
2301                 mdt_uuid=$(mdtuuid_from_index $index)
2302         fi
2303
2304         free_inodes=$(lfs_df -i $MOUNT | grep $mdt_uuid | awk '{print $4}')
2305         echo $free_inodes
2306 }
2307
2308 #
2309 # Get the OST device status from 'lfs df' with a given OST index.
2310 #
2311 ost_dev_status() {
2312         local ost_idx=$1
2313         local mnt_pnt=${2:-$MOUNT}
2314         local opts=$3
2315         local ost_uuid
2316
2317         ost_uuid=$(ostuuid_from_index $ost_idx $mnt_pnt)
2318         lfs_df $opts $mnt_pnt | awk '/'$ost_uuid'/ { print $7 }'
2319 }
2320
2321 setup_quota(){
2322         local mntpt=$1
2323
2324         # save old quota type & set new quota type
2325         local mdt_qtype=$(mdt_quota_type)
2326         local ost_qtype=$(ost_quota_type)
2327
2328         echo "[HOST:$HOSTNAME] [old_mdt_qtype:$mdt_qtype]" \
2329                 "[old_ost_qtype:$ost_qtype] [new_qtype:$QUOTA_TYPE]"
2330
2331         export old_MDT_QUOTA_TYPE=$mdt_qtype
2332         export old_OST_QUOTA_TYPE=$ost_qtype
2333
2334         if [[ $PERM_CMD == *"set_param -P"* ]]; then
2335                 do_facet mgs $PERM_CMD \
2336                         osd-*.$FSNAME-MDT*.quota_slave.enabled=$QUOTA_TYPE
2337                 do_facet mgs $PERM_CMD \
2338                         osd-*.$FSNAME-OST*.quota_slave.enabled=$QUOTA_TYPE
2339         else
2340                 do_facet mgs $PERM_CMD $FSNAME.quota.mdt=$QUOTA_TYPE ||
2341                         error "set mdt quota type failed"
2342                 do_facet mgs $PERM_CMD $FSNAME.quota.ost=$QUOTA_TYPE ||
2343                         error "set ost quota type failed"
2344         fi
2345
2346         local quota_usrs=$QUOTA_USERS
2347
2348         # get_filesystem_size
2349         local disksz=$(lfs_df $mntpt | grep "summary" | awk '{print $2}')
2350         local blk_soft=$((disksz + 1024))
2351         local blk_hard=$((blk_soft + blk_soft / 20)) # Go 5% over
2352
2353         local inodes=$(lfs_df -i $mntpt | grep "summary" | awk '{print $2}')
2354         local i_soft=$inodes
2355         local i_hard=$((i_soft + i_soft / 20))
2356
2357         echo "Total disk size: $disksz  block-softlimit: $blk_soft" \
2358                 "block-hardlimit: $blk_hard inode-softlimit: $i_soft" \
2359                 "inode-hardlimit: $i_hard"
2360
2361         local cmd
2362         for usr in $quota_usrs; do
2363                 echo "Setting up quota on $HOSTNAME:$mntpt for $usr..."
2364                 for type in u g; do
2365                         cmd="$LFS setquota -$type $usr -b $blk_soft"
2366                         cmd="$cmd -B $blk_hard -i $i_soft -I $i_hard $mntpt"
2367                         echo "+ $cmd"
2368                         eval $cmd || error "$cmd FAILED!"
2369                 done
2370                 # display the quota status
2371                 echo "Quota settings for $usr : "
2372                 $LFS quota -v -u $usr $mntpt || true
2373         done
2374 }
2375
2376 zconf_mount() {
2377         local client=$1
2378         local mnt=$2
2379         local opts=${3:-$MOUNT_OPTS}
2380         opts=${opts:+-o $opts}
2381         local flags=${4:-$MOUNT_FLAGS}
2382
2383         local device=$MGSNID:/$FSNAME$FILESET
2384         if [ -z "$mnt" -o -z "$FSNAME" ]; then
2385                 echo "Bad mount command: opt=$flags $opts dev=$device " \
2386                      "mnt=$mnt"
2387                 exit 1
2388         fi
2389
2390         if $GSS_SK; then
2391                 # update mount option with skpath
2392                 opts=$(add_sk_mntflag $opts)
2393         fi
2394
2395         echo "Starting client: $client: $flags $opts $device $mnt"
2396         do_node $client mkdir -p $mnt
2397         if [ -n "$FILESET" -a -z "$SKIP_FILESET" ];then
2398                 do_node $client $MOUNT_CMD $flags $opts $MGSNID:/$FSNAME \
2399                         $mnt || return 1
2400                 #disable FILESET if not supported
2401                 do_nodes $client lctl get_param -n \
2402                         mdc.$FSNAME-MDT0000*.import | grep -q subtree ||
2403                                 device=$MGSNID:/$FSNAME
2404                 do_node $client mkdir -p $mnt/$FILESET
2405                 do_node $client "! grep -q $mnt' ' /proc/mounts ||
2406                         umount $mnt"
2407         fi
2408         if $GSS_SK && ($SK_UNIQUE_NM || $SK_S2S); then
2409                 # Mount using nodemap key
2410                 local mountkey=$SK_PATH/$FSNAME-nmclient.key
2411                 if $SK_UNIQUE_NM; then
2412                         mountkey=$SK_PATH/nodemap/c0.key
2413                 fi
2414                 local prunedopts=$(echo $opts |
2415                                 sed -e "s#skpath=[^,^ ]*#skpath=$mountkey#g")
2416                 do_node $client $MOUNT_CMD $flags $prunedopts $device $mnt ||
2417                                 return 1
2418         else
2419                 do_node $client $MOUNT_CMD $flags $opts $device $mnt ||
2420                                 return 1
2421         fi
2422
2423         set_default_debug_nodes $client
2424         set_params_clients $client
2425
2426         return 0
2427 }
2428
2429 zconf_umount() {
2430         local client=$1
2431         local mnt=$2
2432         local force
2433         local busy
2434         local need_kill
2435         local running=$(do_node $client "grep -c $mnt' ' /proc/mounts") || true
2436
2437         [ "$3" ] && force=-f
2438         [ $running -eq 0 ] && return 0
2439
2440         echo "Stopping client $client $mnt (opts:$force)"
2441         do_node $client lsof -t $mnt || need_kill=no
2442         if [ "x$force" != "x" ] && [ "x$need_kill" != "xno" ]; then
2443                 pids=$(do_node $client lsof -t $mnt | sort -u);
2444                 if [ -n "$pids" ]; then
2445                         do_node $client kill -9 $pids || true
2446                 fi
2447         fi
2448
2449         busy=$(do_node $client "umount $force $mnt 2>&1" | grep -c "busy") ||
2450                 true
2451         if [ $busy -ne 0 ] ; then
2452                 echo "$mnt is still busy, wait one second" && sleep 1
2453                 do_node $client umount $force $mnt
2454         fi
2455 }
2456
2457 # Mount the file system on the MDS
2458 mount_mds_client() {
2459         local host=$(facet_active_host $SINGLEMDS)
2460         echo $host
2461         zconf_mount $host $MOUNT2 $MOUNT_OPTS ||
2462                 error "unable to mount $MOUNT2 on $host"
2463 }
2464
2465 # Unmount the file system on the MDS
2466 umount_mds_client() {
2467         local host=$(facet_active_host $SINGLEMDS)
2468         zconf_umount $host $MOUNT2
2469         do_facet $SINGLEMDS "rmdir $MOUNT2"
2470 }
2471
2472 # nodes is comma list
2473 sanity_mount_check_nodes () {
2474     local nodes=$1
2475     shift
2476     local mnts="$@"
2477     local mnt
2478
2479     # FIXME: assume that all cluster nodes run the same os
2480     [ "$(uname)" = Linux ] || return 0
2481
2482     local rc=0
2483     for mnt in $mnts ; do
2484         do_nodes $nodes "running=\\\$(grep -c $mnt' ' /proc/mounts);
2485 mpts=\\\$(mount | grep -c $mnt' ');
2486 if [ \\\$running -ne \\\$mpts ]; then
2487     echo \\\$(hostname) env are INSANE!;
2488     exit 1;
2489 fi"
2490     [ $? -eq 0 ] || rc=1
2491     done
2492     return $rc
2493 }
2494
2495 sanity_mount_check_servers () {
2496     [ -n "$CLIENTONLY" ] &&
2497         { echo "CLIENTONLY mode, skip mount_check_servers"; return 0; } || true
2498     echo Checking servers environments
2499
2500     # FIXME: modify get_facets to display all facets wo params
2501     local facets="$(get_facets OST),$(get_facets MDS),mgs"
2502     local node
2503     local mntpt
2504     local facet
2505     for facet in ${facets//,/ }; do
2506         node=$(facet_host ${facet})
2507         mntpt=$(facet_mntpt $facet)
2508         sanity_mount_check_nodes $node $mntpt ||
2509             { error "server $node environments are insane!"; return 1; }
2510     done
2511 }
2512
2513 sanity_mount_check_clients () {
2514     local clients=${1:-$CLIENTS}
2515     local mntpt=${2:-$MOUNT}
2516     local mntpt2=${3:-$MOUNT2}
2517
2518     [ -z $clients ] && clients=$(hostname)
2519     echo Checking clients $clients environments
2520
2521     sanity_mount_check_nodes $clients $mntpt $mntpt2 ||
2522        error "clients environments are insane!"
2523 }
2524
2525 sanity_mount_check () {
2526     sanity_mount_check_servers || return 1
2527     sanity_mount_check_clients || return 2
2528 }
2529
2530 # mount clients if not mouted
2531 zconf_mount_clients() {
2532         local clients=$1
2533         local mnt=$2
2534         local opts=${3:-$MOUNT_OPTS}
2535         opts=${opts:+-o $opts}
2536         local flags=${4:-$MOUNT_FLAGS}
2537         local device=$MGSNID:/$FSNAME$FILESET
2538         if [ -z "$mnt" -o -z "$FSNAME" ]; then
2539                 echo "Bad conf mount command: opt=$flags $opts dev=$device " \
2540                      "mnt=$mnt"
2541                 exit 1
2542         fi
2543
2544         echo "Starting client $clients: $flags $opts $device $mnt"
2545         do_nodes $clients mkdir -p $mnt
2546         if [ -n "$FILESET" -a -z "$SKIP_FILESET" ]; then
2547                 if $GSS_SK && ($SK_UNIQUE_NM || $SK_S2S); then
2548                         # Mount with own nodemap key
2549                         local i=0
2550                         # Mount all server nodes first with per-NM keys
2551                         for nmclient in ${clients//,/ }; do
2552 #                               do_nodes $(comma_list $(all_server_nodes)) "lgss_sk -t server -l $SK_PATH/nodemap/c$i.key -n c$i"
2553                                 do_nodes $(comma_list $(all_server_nodes)) "lgss_sk -t server -l $SK_PATH/nodemap/c$i.key"
2554                                 i=$((i + 1))
2555                         done
2556                         # set perms for per-nodemap keys else permission denied
2557                         do_nodes $(comma_list $(all_nodes)) \
2558                                 "keyctl show | grep lustre | cut -c1-11 |
2559                                 sed -e 's/ //g;' |
2560                                 xargs -IX keyctl setperm X 0x3f3f3f3f"
2561                         local mountkey=$SK_PATH/$FSNAME-nmclient.key
2562                         i=0
2563                         for nmclient in ${clients//,/ }; do
2564                                 if $SK_UNIQUE_NM; then
2565                                         mountkey=$SK_PATH/nodemap/c$i.key
2566                                 fi
2567                                 do_node $nmclient "! grep -q $mnt' ' \
2568                                         /proc/mounts || umount $mnt"
2569                                 local prunedopts=$(add_sk_mntflag $prunedopts);
2570                                 prunedopts=$(echo $prunedopts | sed -e \
2571                                         "s#skpath=[^ ^,]*#skpath=$mountkey#g")
2572                                 set -x
2573                                 do_nodes $(comma_list $(all_server_nodes)) \
2574                                         "keyctl show"
2575                                 set +x
2576                                 do_node $nmclient $MOUNT_CMD $flags \
2577                                         $prunedopts $MGSNID:/$FSNAME $mnt ||
2578                                         return 1
2579                                 i=$((i + 1))
2580                         done
2581                 else
2582                         do_nodes $clients "! grep -q $mnt' ' /proc/mounts ||
2583                                         umount $mnt"
2584                         do_nodes $clients $MOUNT_CMD $flags $opts \
2585                                         $MGSNID:/$FSNAME $mnt || return 1
2586                 fi
2587                 #disable FILESET if not supported
2588                 do_nodes $clients lctl get_param -n \
2589                         mdc.$FSNAME-MDT0000*.import | grep -q subtree ||
2590                                 device=$MGSNID:/$FSNAME
2591                 do_nodes $clients mkdir -p $mnt/$FILESET
2592                 do_nodes $clients "! grep -q $mnt' ' /proc/mounts ||
2593                         umount $mnt"
2594         fi
2595
2596         if $GSS_SK && ($SK_UNIQUE_NM || $SK_S2S); then
2597                 # Mount with nodemap key
2598                 local i=0
2599                 local mountkey=$SK_PATH/$FSNAME-nmclient.key
2600                 for nmclient in ${clients//,/ }; do
2601                         if $SK_UNIQUE_NM; then
2602                                 mountkey=$SK_PATH/nodemap/c$i.key
2603                         fi
2604                         local prunedopts=$(echo $opts | sed -e \
2605                                 "s#skpath=[^ ^,]*#skpath=$mountkey#g");
2606                         do_node $nmclient "! grep -q $mnt' ' /proc/mounts ||
2607                                 umount $mnt"
2608                         do_node $nmclient "
2609                 running=\\\$(mount | grep -c $mnt' ');
2610                 rc=0;
2611                 if [ \\\$running -eq 0 ] ; then
2612                         mkdir -p $mnt;
2613                         $MOUNT_CMD $flags $prunedopts $device $mnt;
2614                         rc=\\\$?;
2615                 else
2616                         lustre_mnt_count=\\\$(mount | grep $mnt' ' | \
2617                                 grep 'type lustre' | wc -l);
2618                         if [ \\\$running -ne \\\$lustre_mnt_count ] ; then
2619                                 echo zconf_mount_clients FAILED: \
2620                                         mount count \\\$running, not matching \
2621                                         with mount count of 'type lustre' \
2622                                         \\\$lustre_mnt_count;
2623                                 rc=1;
2624                         fi;
2625                 fi;
2626         exit \\\$rc" || return ${PIPESTATUS[0]}
2627
2628                         i=$((i + 1))
2629                 done
2630         else
2631
2632                 local tmpopts=$opts
2633                 if $SHARED_KEY; then
2634                         tmpopts=$(add_sk_mntflag $opts)
2635                 fi
2636                 do_nodes $clients "
2637 running=\\\$(mount | grep -c $mnt' ');
2638 rc=0;
2639 if [ \\\$running -eq 0 ] ; then
2640         mkdir -p $mnt;
2641         $MOUNT_CMD $flags $tmpopts $device $mnt;
2642         rc=\\\$?;
2643 fi;
2644 exit \\\$rc" || return ${PIPESTATUS[0]}
2645         fi
2646
2647         echo "Started clients $clients: "
2648         do_nodes $clients "mount | grep $mnt' '"
2649
2650         set_default_debug_nodes $clients
2651         set_params_clients $clients
2652
2653         return 0
2654 }
2655
2656 zconf_umount_clients() {
2657     local clients=$1
2658     local mnt=$2
2659     local force
2660
2661     [ "$3" ] && force=-f
2662
2663     echo "Stopping clients: $clients $mnt (opts:$force)"
2664     do_nodes $clients "running=\\\$(grep -c $mnt' ' /proc/mounts);
2665 if [ \\\$running -ne 0 ] ; then
2666 echo Stopping client \\\$(hostname) $mnt opts:$force;
2667 lsof $mnt || need_kill=no;
2668 if [ "x$force" != "x" -a "x\\\$need_kill" != "xno" ]; then
2669     pids=\\\$(lsof -t $mnt | sort -u);
2670     if [ -n \\\"\\\$pids\\\" ]; then
2671              kill -9 \\\$pids;
2672     fi
2673 fi;
2674 while umount $force $mnt 2>&1 | grep -q "busy"; do
2675     echo "$mnt is still busy, wait one second" && sleep 1;
2676 done;
2677 fi"
2678 }
2679
2680 shutdown_node () {
2681     local node=$1
2682     echo + $POWER_DOWN $node
2683     $POWER_DOWN $node
2684 }
2685
2686 shutdown_node_hard () {
2687     local host=$1
2688     local attempts=$SHUTDOWN_ATTEMPTS
2689
2690     for i in $(seq $attempts) ; do
2691         shutdown_node $host
2692         sleep 1
2693         wait_for_function --quiet "! ping -w 3 -c 1 $host" 5 1 && return 0
2694         echo "waiting for $host to fail attempts=$attempts"
2695         [ $i -lt $attempts ] || \
2696             { echo "$host still pingable after power down! attempts=$attempts" && return 1; }
2697     done
2698 }
2699
2700 shutdown_client() {
2701     local client=$1
2702     local mnt=${2:-$MOUNT}
2703     local attempts=3
2704
2705     if [ "$FAILURE_MODE" = HARD ]; then
2706         shutdown_node_hard $client
2707     else
2708        zconf_umount_clients $client $mnt -f
2709     fi
2710 }
2711
2712 facets_on_host () {
2713     local host=$1
2714     local facets="$(get_facets OST),$(get_facets MDS)"
2715     local affected
2716
2717     combined_mgs_mds || facets="$facets,mgs"
2718
2719     for facet in ${facets//,/ }; do
2720         if [ $(facet_active_host $facet) == $host ]; then
2721            affected="$affected $facet"
2722         fi
2723     done
2724
2725     echo $(comma_list $affected)
2726 }
2727
2728 facet_up() {
2729         local facet=$1
2730         local host=${2:-$(facet_host $facet)}
2731
2732         local label=$(convert_facet2label $facet)
2733         do_node $host $LCTL dl | awk '{ print $4 }' | grep -q "^$label\$"
2734 }
2735
2736 facets_up_on_host () {
2737     local host=$1
2738     local facets=$(facets_on_host $host)
2739     local affected_up
2740
2741     for facet in ${facets//,/ }; do
2742         if $(facet_up $facet $host); then
2743             affected_up="$affected_up $facet"
2744         fi
2745     done
2746
2747     echo $(comma_list $affected_up)
2748 }
2749
2750 shutdown_facet() {
2751         local facet=$1
2752         local affected_facet
2753         local affected_facets
2754
2755         if [[ "$FAILURE_MODE" = HARD ]]; then
2756                 if [[ $(facet_fstype $facet) = ldiskfs ]] &&
2757                         dm_flakey_supported $facet; then
2758                         affected_facets=$(affected_facets $facet)
2759                         for affected_facet in ${affected_facets//,/ }; do
2760                                 unexport_dm_dev $affected_facet
2761                         done
2762                 fi
2763
2764                 shutdown_node_hard $(facet_active_host $facet)
2765         else
2766                 stop $facet
2767         fi
2768 }
2769
2770 reboot_node() {
2771     local node=$1
2772     echo + $POWER_UP $node
2773     $POWER_UP $node
2774 }
2775
2776 remount_facet() {
2777     local facet=$1
2778
2779     stop $facet
2780     mount_facet $facet
2781 }
2782
2783 reboot_facet() {
2784         local facet=$1
2785         local node=$(facet_active_host $facet)
2786         local sleep_time=${2:-10}
2787
2788         if [ "$FAILURE_MODE" = HARD ]; then
2789                 boot_node $node
2790         else
2791                 sleep $sleep_time
2792         fi
2793 }
2794
2795 boot_node() {
2796         local node=$1
2797
2798         if [ "$FAILURE_MODE" = HARD ]; then
2799                 reboot_node $node
2800                 wait_for_host $node
2801                 if $LOAD_MODULES_REMOTE; then
2802                         echo "loading modules on $node: $facet"
2803                         do_rpc_nodes $node load_modules_local
2804                 fi
2805         fi
2806 }
2807
2808 facets_hosts () {
2809     local facets=$1
2810     local hosts
2811
2812     for facet in ${facets//,/ }; do
2813         hosts=$(expand_list $hosts $(facet_host $facet) )
2814     done
2815
2816     echo $hosts
2817 }
2818
2819 _check_progs_installed () {
2820     local progs=$@
2821     local rc=0
2822
2823     for prog in $progs; do
2824         if ! [ "$(which $prog)"  -o  "${!prog}" ]; then
2825            echo $prog missing on $(hostname)
2826            rc=1
2827         fi
2828     done
2829     return $rc
2830 }
2831
2832 check_progs_installed () {
2833         local nodes=$1
2834         shift
2835
2836         do_rpc_nodes "$nodes" _check_progs_installed $@
2837 }
2838
2839 # recovery-scale functions
2840 node_var_name() {
2841     echo __$(echo $1 | tr '-' '_' | tr '.' '_')
2842 }
2843
2844 start_client_load() {
2845         local client=$1
2846         local load=$2
2847         local var=$(node_var_name $client)_load
2848         eval export ${var}=$load
2849
2850         do_node $client "PATH=$PATH MOUNT=$MOUNT ERRORS_OK=$ERRORS_OK \
2851                         BREAK_ON_ERROR=$BREAK_ON_ERROR \
2852                         END_RUN_FILE=$END_RUN_FILE \
2853                         LOAD_PID_FILE=$LOAD_PID_FILE \
2854                         TESTLOG_PREFIX=$TESTLOG_PREFIX \
2855                         TESTNAME=$TESTNAME \
2856                         DBENCH_LIB=$DBENCH_LIB \
2857                         DBENCH_SRC=$DBENCH_SRC \
2858                         CLIENT_COUNT=$((CLIENTCOUNT - 1)) \
2859                         LFS=$LFS \
2860                         LCTL=$LCTL \
2861                         FSNAME=$FSNAME \
2862                         MPIRUN=$MPIRUN \
2863                         MPIRUN_OPTIONS=\\\"$MPIRUN_OPTIONS\\\" \
2864                         MACHINEFILE_OPTION=\\\"$MACHINEFILE_OPTION\\\" \
2865                         num_clients=$(get_node_count ${CLIENTS//,/ }) \
2866                         ior_THREADS=$ior_THREADS ior_iteration=$ior_iteration \
2867                         ior_blockSize=$ior_blockSize \
2868                         ior_blockUnit=$ior_blockUnit \
2869                         ior_xferSize=$ior_xferSize ior_type=$ior_type \
2870                         ior_DURATION=$ior_DURATION \
2871                         ior_stripe_params=\\\"$ior_stripe_params\\\" \
2872                         ior_custom_params=\\\"$ior_custom_param\\\" \
2873                         mpi_ior_custom_threads=$mpi_ior_custom_threads \
2874                         run_${load}.sh" &
2875         local ppid=$!
2876         log "Started client load: ${load} on $client"
2877
2878         # get the children process IDs
2879         local pids=$(ps --ppid $ppid -o pid= | xargs)
2880         CLIENT_LOAD_PIDS="$CLIENT_LOAD_PIDS $ppid $pids"
2881         return 0
2882 }
2883
2884 start_client_loads () {
2885         local -a clients=(${1//,/ })
2886         local numloads=${#CLIENT_LOADS[@]}
2887
2888         for ((nodenum=0; nodenum < ${#clients[@]}; nodenum++ )); do
2889                 local load=$((nodenum % numloads))
2890                 start_client_load ${clients[nodenum]} ${CLIENT_LOADS[load]}
2891         done
2892         # bug 22169: wait the background threads to start
2893         sleep 2
2894 }
2895
2896 # only for remote client
2897 check_client_load () {
2898         local client=$1
2899         local var=$(node_var_name $client)_load
2900         local testload=run_${!var}.sh
2901
2902         ps auxww | grep -v grep | grep $client | grep -q $testload || return 1
2903
2904         # bug 18914: try to connect several times not only when
2905         # check ps, but  while check_node_health also
2906
2907         local tries=3
2908         local RC=254
2909         while [ $RC = 254 -a $tries -gt 0 ]; do
2910                 let tries=$tries-1
2911                 # assume success
2912                 RC=0
2913                 if ! check_node_health $client; then
2914                         RC=${PIPESTATUS[0]}
2915                         if [ $RC -eq 254 ]; then
2916                                 # FIXME: not sure how long we shuold sleep here
2917                                 sleep 10
2918                                 continue
2919                         fi
2920                         echo "check node health failed: RC=$RC "
2921                         return $RC
2922                 fi
2923         done
2924         # We can continue try to connect if RC=254
2925         # Just print the warning about this
2926         if [ $RC = 254 ]; then
2927                 echo "got a return status of $RC from do_node while checking " \
2928                 "node health on $client"
2929         fi
2930
2931         # see if the load is still on the client
2932         tries=3
2933         RC=254
2934         while [ $RC = 254 -a $tries -gt 0 ]; do
2935                 let tries=$tries-1
2936                 # assume success
2937                 RC=0
2938                 if ! do_node $client \
2939                         "ps auxwww | grep -v grep | grep -q $testload"; then
2940                         RC=${PIPESTATUS[0]}
2941                         sleep 30
2942                 fi
2943         done
2944         if [ $RC = 254 ]; then
2945                 echo "got a return status of $RC from do_node while checking " \
2946                 "(node health and 'ps') the client load on $client"
2947                 # see if we can diagnose a bit why this is
2948         fi
2949
2950         return $RC
2951 }
2952 check_client_loads () {
2953    local clients=${1//,/ }
2954    local client=
2955    local rc=0
2956
2957    for client in $clients; do
2958       check_client_load $client
2959       rc=${PIPESTATUS[0]}
2960       if [ "$rc" != 0 ]; then
2961         log "Client load failed on node $client, rc=$rc"
2962         return $rc
2963       fi
2964    done
2965 }
2966
2967 restart_client_loads () {
2968     local clients=${1//,/ }
2969     local expectedfail=${2:-""}
2970     local client=
2971     local rc=0
2972
2973     for client in $clients; do
2974         check_client_load $client
2975         rc=${PIPESTATUS[0]}
2976         if [ "$rc" != 0 -a "$expectedfail" ]; then
2977             local var=$(node_var_name $client)_load
2978             start_client_load $client ${!var}
2979             echo "Restarted client load ${!var}: on $client. Checking ..."
2980             check_client_load $client
2981             rc=${PIPESTATUS[0]}
2982             if [ "$rc" != 0 ]; then
2983                 log "Client load failed to restart on node $client, rc=$rc"
2984                 # failure one client load means test fail
2985                 # we do not need to check other
2986                 return $rc
2987             fi
2988         else
2989             return $rc
2990         fi
2991     done
2992 }
2993
2994 # Start vmstat and save its process ID in a file.
2995 start_vmstat() {
2996     local nodes=$1
2997     local pid_file=$2
2998
2999     [ -z "$nodes" -o -z "$pid_file" ] && return 0
3000
3001     do_nodes $nodes \
3002         "vmstat 1 > $TESTLOG_PREFIX.$TESTNAME.vmstat.\\\$(hostname -s).log \
3003         2>/dev/null </dev/null & echo \\\$! > $pid_file"
3004 }
3005
3006 # Display the nodes on which client loads failed.
3007 print_end_run_file() {
3008     local file=$1
3009     local node
3010
3011     [ -s $file ] || return 0
3012
3013     echo "Found the END_RUN_FILE file: $file"
3014     cat $file
3015
3016     # A client load will stop if it finds the END_RUN_FILE file.
3017     # That does not mean the client load actually failed though.
3018     # The first node in END_RUN_FILE is the one we are interested in.
3019     read node < $file
3020
3021     if [ -n "$node" ]; then
3022         local var=$(node_var_name $node)_load
3023
3024         local prefix=$TESTLOG_PREFIX
3025         [ -n "$TESTNAME" ] && prefix=$prefix.$TESTNAME
3026         local stdout_log=$prefix.run_${!var}_stdout.$node.log
3027         local debug_log=$(echo $stdout_log | sed 's/\(.*\)stdout/\1debug/')
3028
3029         echo "Client load ${!var} failed on node $node:"
3030         echo "$stdout_log"
3031         echo "$debug_log"
3032     fi
3033 }
3034
3035 # Stop the process which had its PID saved in a file.
3036 stop_process() {
3037     local nodes=$1
3038     local pid_file=$2
3039
3040     [ -z "$nodes" -o -z "$pid_file" ] && return 0
3041
3042     do_nodes $nodes "test -f $pid_file &&
3043         { kill -s TERM \\\$(cat $pid_file); rm -f $pid_file; }" || true
3044 }
3045
3046 # Stop all client loads.
3047 stop_client_loads() {
3048     local nodes=${1:-$CLIENTS}
3049     local pid_file=$2
3050
3051     # stop the client loads
3052     stop_process $nodes $pid_file
3053
3054     # clean up the processes that started them
3055     [ -n "$CLIENT_LOAD_PIDS" ] && kill -9 $CLIENT_LOAD_PIDS 2>/dev/null || true
3056 }
3057 # End recovery-scale functions
3058
3059 ##
3060 # wait for a command to return the expected result
3061 #
3062 # This will run @check on @node repeatedly until the output matches @expect
3063 # based on the supplied condition, or until @max_wait seconds have elapsed,
3064 # whichever comes first.  @cond may be one of the normal bash operators,
3065 # "-gt", "-ge", "-eq", "-le", "-lt", "==", "!=", or "=~", and must be quoted
3066 # in the caller to avoid unintentional evaluation by the shell in the caller.
3067 #
3068 # If @max_wait is not specified, the condition will be checked for up to 90s.
3069 #
3070 # If --verbose is passed as the first argument, the result is printed on each
3071 # value change, otherwise it is only printed after every 10s interval.
3072 #
3073 # If --quiet is passed as the first/second argument, the do_node() command
3074 # will not print the remote command before executing it each time.
3075 #
3076 # Using wait_update_cond() or related helper function is preferable to adding
3077 # a "long enough" wait for some state to change in the background, since
3078 # "long enough" may be too short due to tunables, system config, or running in
3079 # a VM, and must by necessity wait too long for most cases or risk failure.
3080 #
3081 # usage: wait_update_cond [--verbose] [--quiet] node check cond expect [max_wait]
3082 wait_update_cond() {
3083         local verbose
3084         local quiet
3085
3086         [[ "$1" == "--verbose" ]] && verbose="$1" && shift
3087         [[ "$1" == "--quiet" || "$1" == "-q" ]] && quiet="$1" && shift
3088
3089         local node=$1
3090         local check="$2"
3091         local cond="$3"
3092         local expect="$4"
3093         local max_wait=${5:-90}
3094         local result
3095         local prev_result
3096         local waited=0
3097         local begin=$SECONDS
3098         local sleep=1
3099         local print=10
3100
3101         while (( $waited <= $max_wait )); do
3102                 result=$(do_node $quiet $node "$check")
3103
3104                 eval [[ "'$result'" $cond "'$expect'" ]]
3105                 if [[ $? == 0 ]]; then
3106                         [[ -z "$result" || $waited -le $sleep ]] ||
3107                                 echo "Updated after ${waited}s: want '$expect' got '$result'"
3108                         return 0
3109                 fi
3110                 if [[ -n "$verbose" && "$result" != "$prev_result" ]]; then
3111                         [[ -n "$prev_result" ]] &&
3112                                 echo "Changed after ${waited}s: from '$prev_result' to '$result'"
3113                         prev_result="$result"
3114                 fi
3115                 (( $waited % $print == 0 )) &&
3116                         echo "Waiting $((max_wait - waited))s for '$expect'"
3117                 sleep $sleep
3118                 waited=$((SECONDS - begin))
3119         done
3120         echo "Update not seen after ${max_wait}s: want '$expect' got '$result'"
3121         return 3
3122 }
3123
3124 # usage: wait_update [--verbose] [--quiet] node check expect [max_wait]
3125 wait_update() {
3126         local verbose
3127         local quiet
3128
3129         [[ "$1" == "--verbose" ]] && verbose="$1" && shift
3130         [[ "$1" == "--quiet" || "$1" == "-q" ]] && quiet="$1" && shift
3131
3132         local node="$1"
3133         local check="$2"
3134         local expect="$3"
3135         local max_wait=$4
3136
3137         wait_update_cond $verbose $quiet $node "$check" "==" "$expect" $max_wait
3138 }
3139
3140 # usage: wait_update_facet_cond [--verbose] facet check cond expect [max_wait]
3141 wait_update_facet_cond() {
3142         local verbose
3143         local quiet
3144
3145         [[ "$1" == "--verbose" ]] && verbose="$1" && shift
3146         [[ "$1" == "--quiet" || "$1" == "-q" ]] && quiet="$1" && shift
3147
3148         local node=$(facet_active_host $1)
3149         local check="$2"
3150         local cond="$3"
3151         local expect="$4"
3152         local max_wait=$5
3153
3154         wait_update_cond $verbose $quiet $node "$check" "$cond" "$expect" $max_wait
3155 }
3156
3157 # usage: wait_update_facet [--verbose] facet check expect [max_wait]
3158 wait_update_facet() {
3159         local verbose
3160         local quiet
3161
3162         [[ "$1" == "--verbose" ]] && verbose="$1" && shift
3163         [[ "$1" == "--quiet" || "$1" == "-q" ]] && quiet="$1" && shift
3164
3165         local node=$(facet_active_host $1)
3166         local check="$2"
3167         local expect="$3"
3168         local max_wait=$4
3169
3170         wait_update_cond $verbose $quiet $node "$check" "==" "$expect" $max_wait
3171 }
3172
3173 sync_all_data() {
3174         do_nodes $(comma_list $(mdts_nodes)) \
3175             "lctl set_param -n os[cd]*.*MDT*.force_sync=1"
3176         do_nodes $(comma_list $(osts_nodes)) \
3177             "lctl set_param -n osd*.*OS*.force_sync=1" 2>&1 |
3178                 grep -v 'Found no match'
3179 }
3180
3181 wait_zfs_commit() {
3182         local zfs_wait=${2:-5}
3183
3184         # the occupied disk space will be released
3185         # only after TXGs are committed
3186         if [[ $(facet_fstype $1) == zfs ]]; then
3187                 echo "sleep $zfs_wait for ZFS $(facet_fstype $1)"
3188                 sleep $zfs_wait
3189         fi
3190 }
3191
3192 fill_ost() {
3193         local filename=$1
3194         local ost_idx=$2
3195         local lwm=$3  #low watermark
3196         local size_mb #how many MB should we write to pass watermark
3197         local ost_name=$(ostname_from_index $ost_idx)
3198
3199         free_kb=$($LFS df $MOUNT | awk "/$ost_name/ { print \$4 }")
3200         size_mb=0
3201         if (( $free_kb / 1024 > lwm )); then
3202                 size_mb=$((free_kb / 1024 - lwm))
3203         fi
3204         #If 10% of free space cross low watermark use it
3205         if (( $free_kb / 10240 > size_mb )); then
3206                 size_mb=$((free_kb / 10240))
3207         else
3208                 #At least we need to store 1.1 of difference between
3209                 #free space and low watermark
3210                 size_mb=$((size_mb + size_mb / 10))
3211         fi
3212         if (( lwm <= $free_kb / 1024 )) ||
3213            [ ! -f $DIR/${filename}.fill_ost$ost_idx ]; then
3214                 $LFS setstripe -i $ost_idx -c1 $DIR/${filename}.fill_ost$ost_idx
3215                 dd if=/dev/zero of=$DIR/${filename}.fill_ost$ost_idx bs=1M \
3216                         count=$size_mb oflag=append conv=notrunc
3217         fi
3218
3219         sleep_maxage
3220
3221         free_kb=$($LFS df $MOUNT | awk "/$ost_name/ { print \$4 }")
3222         echo "OST still has $((free_kb / 1024)) MB free"
3223 }
3224
3225 # This checks only the primary MDS
3226 ost_watermarks_get() {
3227         local ost_idx=$1
3228         local ost_name=$(ostname_from_index $ost_idx)
3229         local mdtosc_proc=$(get_mdtosc_proc_path $SINGLEMDS $ost_name)
3230
3231         local hwm=$(do_facet $SINGLEMDS $LCTL get_param -n \
3232                         osp.$mdtosc_proc.reserved_mb_high)
3233         local lwm=$(do_facet $SINGLEMDS $LCTL get_param -n \
3234                         osp.$mdtosc_proc.reserved_mb_low)
3235
3236         echo "$lwm $hwm"
3237 }
3238
3239 # Note that we set watermarks on all MDSes (necessary for striped dirs)
3240 ost_watermarks_set() {
3241         local ost_idx=$1
3242         local lwm=$2
3243         local hwm=$3
3244         local ost_name=$(ostname_from_index $ost_idx)
3245         local facets=$(get_facets MDS)
3246
3247         do_nodes $(comma_list $(mdts_nodes)) $LCTL set_param -n \
3248                 osp.*$ost_name*.reserved_mb_low=$lwm \
3249                 osp.*$ost_name*.reserved_mb_high=$hwm > /dev/null
3250
3251         # sleep to ensure we see the change
3252         sleep_maxage
3253 }
3254
3255 ost_watermarks_set_low_space() {
3256         local ost_idx=$1
3257         local wms=$(ost_watermarks_get $ost_idx)
3258         local ost_name=$(ostname_from_index $ost_idx)
3259
3260         local old_lwm=$(echo $wms | awk '{ print $1 }')
3261         local old_hwm=$(echo $wms | awk '{ print $2 }')
3262
3263         local blocks=$($LFS df $MOUNT | awk "/$ost_name/ { print \$4 }")
3264         # minimal extension size is 64M
3265         local new_lwm=50
3266         if (( $blocks / 1024 > 50 )); then
3267                 new_lwm=$((blocks / 1024 - 50))
3268         fi
3269         local new_hwm=$((new_lwm + 5))
3270
3271         ost_watermarks_set $ost_idx $new_lwm $new_hwm
3272         echo "watermarks: $old_lwm $old_hwm $new_lwm $new_hwm"
3273 }