Whamcloud - gitweb
LU-4843 mdt: disallow old clients access striped dir
[fs/lustre-release.git] / lustre / tests / test-framework.sh
old mode 100644 (file)
new mode 100755 (executable)
index 97b7aad..d26cb56
@@ -5,6 +5,7 @@ trap 'print_summary && touch $TF_FAIL && \
 set -e
 #set -x
 
+export LANG=en_US
 export EJOURNAL=${EJOURNAL:-""}
 export REFORMAT=${REFORMAT:-""}
 export WRITECONF=${WRITECONF:-""}
@@ -23,6 +24,7 @@ export JOBID_VAR=${JOBID_VAR:-"procname_uid"}  # or "existing" or "disable"
 export LOAD_LLOOP=${LOAD_LLOOP:-false}
 
 #export PDSH="pdsh -S -Rssh -w"
+export MOUNT_CMD=${MOUNT_CMD:-"mount -t lustre"}
 
 # function used by scripts run on remote nodes
 LUSTRE=${LUSTRE:-$(cd $(dirname $0)/..; echo $PWD)}
@@ -89,16 +91,21 @@ print_summary () {
         local total=
         local status=Unfinished
         if [ -f $log ]; then
-            skipped=$(grep excluded $log | awk '{ printf " %s", $3 }' | sed 's/test_//g')
-            slow=$(egrep "^PASS|^FAIL" $log | tr -d "("| sed s/s\)$//g | sort -nr -k 3  | head -5 |  awk '{ print $2":"$3"s" }')
-            total=$(grep duration $log | awk '{ print $2}')
-            if [ "${!O}" = "done" ]; then
-                status=Done
-            fi
-            if $DDETAILS; then
-                local durations=$(egrep "^PASS|^FAIL" $log |  tr -d "("| sed s/s\)$//g | awk '{ print $2":"$3"|" }')
-                details=$(printf "%s\n%s %s %s\n" "$details" "DDETAILS" "$O" "$(echo $durations)")
-            fi
+               skipped=$(grep excluded $log | awk '{ printf " %s", $3 }' |
+                       sed 's/test_//g')
+               slow=$(egrep "^PASS|^FAIL" $log | tr -d "("| sed s/s\)$//g |
+                       sort -nr -k 3  | head -n5 |  awk '{ print $2":"$3"s" }')
+               total=$(grep duration $log | awk '{ print $2 }')
+               if [ "${!O}" = "done" ]; then
+                       status=Done
+               fi
+               if $DDETAILS; then
+                       local durations=$(egrep "^PASS|^FAIL" $log |
+                               tr -d "("| sed s/s\)$//g |
+                               awk '{ print $2":"$3"|" }')
+                       details=$(printf "%s\n%s %s %s\n" "$details" \
+                               "DDETAILS" "$O" "$(echo $durations)")
+               fi
         fi
         printf "$form" $status "$O" "${total}" "E=$skipped"
         printf "$form" "-" "-" "-" "S=$(echo $slow)"
@@ -178,6 +185,15 @@ init_test_env() {
         fi
     fi
 
+       export RESIZE2FS=$RESIZE2FS
+       if [ -z "$RESIZE2FS" ]; then
+               if which resizefs.ldiskfs >/dev/null 2>&1; then
+                       export RESIZE2FS=resizefs.ldiskfs
+               else
+                       export RESIZE2FS=resize2fs
+               fi
+       fi
+
     export LFSCK_BIN=${LFSCK_BIN:-lfsck}
     export LFSCK_ALWAYS=${LFSCK_ALWAYS:-"no"} # check fs after each test suite
     export FSCK_MAX_ERR=4   # File system errors left uncorrected
@@ -185,6 +201,7 @@ init_test_env() {
        export ZFS=${ZFS:-zfs}
        export ZPOOL=${ZPOOL:-zpool}
        export ZDB=${ZDB:-zdb}
+       export PARTPROBE=${PARTPROBE:-partprobe}
 
     #[ -d /r ] && export ROOT=${ROOT:-/r}
     export TMP=${TMP:-$ROOT/tmp}
@@ -290,13 +307,14 @@ init_test_env() {
     export RLUSTRE=${RLUSTRE:-$LUSTRE}
     export RPWD=${RPWD:-$PWD}
     export I_MOUNTED=${I_MOUNTED:-"no"}
-    if [ ! -f /lib/modules/$(uname -r)/kernel/fs/lustre/mdt.ko -a \
-        ! -f /lib/modules/$(uname -r)/updates/kernel/fs/lustre/mdt.ko -a \
-        ! -f `dirname $0`/../mdt/mdt.ko ]; then
-        export CLIENTMODSONLY=yes
-    fi
+       if [ ! -f /lib/modules/$(uname -r)/kernel/fs/lustre/mdt.ko -a \
+            ! -f /lib/modules/$(uname -r)/updates/kernel/fs/lustre/mdt.ko -a \
+            ! -f /lib/modules/$(uname -r)/extra/kernel/fs/lustre/mdt.ko -a \
+            ! -f $LUSTRE/mdt/mdt.ko ]; then
+           export CLIENTMODSONLY=yes
+       fi
 
-    export SHUTDOWN_ATTEMPTS=${SHUTDOWN_ATTEMPTS:-3}
+       export SHUTDOWN_ATTEMPTS=${SHUTDOWN_ATTEMPTS:-3}
        export OSD_TRACK_DECLARES_LBUG=${OSD_TRACK_DECLARES_LBUG:-"yes"}
 
     # command line
@@ -343,7 +361,7 @@ version_code() {
     echo -n "$((($1 << 16) | ($2 << 8) | $3))"
 }
 
-export LINUX_VERSION=$(uname -r | sed -e "s/[-.]/ /3" -e "s/ .*//")
+export LINUX_VERSION=$(uname -r | sed -e "s/\([0-9]*\.[0-9]*\.[0-9]*\).*/\1/")
 export LINUX_VERSION_CODE=$(version_code ${LINUX_VERSION//\./ })
 
 module_loaded () {
@@ -474,7 +492,6 @@ load_modules_local() {
     load_module ../lnet/lnet/lnet
     LNETLND=${LNETLND:-"socklnd/ksocklnd"}
     load_module ../lnet/klnds/$LNETLND
-    load_module lvfs/lvfs
     load_module obdclass/obdclass
     load_module ptlrpc/ptlrpc
     load_module ptlrpc/gss/ptlrpc_gss
@@ -497,19 +514,15 @@ load_modules_local() {
                        modprobe zfs
                        load_module osd-zfs/osd_zfs
                fi
-               load_module mgs/mgs
-               load_module mdd/mdd
                if [[ $(node_fstypes $HOSTNAME) == *ldiskfs* ]]; then
-                       #
-                       # This block shall be moved up beside osd-zfs as soon
-                       # as osd-ldiskfs stops using mdd symbols.
-                       #
                        grep -q exportfs_decode_fh $SYMLIST ||
                                { modprobe exportfs 2> /dev/null || true; }
-                       load_module ../ldiskfs/ldiskfs/ldiskfs
-                       load_module lvfs/fsfilt_ldiskfs
+                       load_module ../ldiskfs/ldiskfs
                        load_module osd-ldiskfs/osd_ldiskfs
                fi
+               load_module nodemap/nodemap
+               load_module mgs/mgs
+               load_module mdd/mdd
                load_module mdt/mdt
                load_module ost/ost
                load_module lod/lod
@@ -518,20 +531,25 @@ load_modules_local() {
                load_module osp/osp
     fi
 
+       load_module llite/lustre
+       llite_lloop_enabled && load_module llite/llite_lloop
+       [ -d /r ] && OGDB=${OGDB:-"/r/tmp"}
+       OGDB=${OGDB:-$TMP}
+       rm -f $OGDB/ogdb-$HOSTNAME
+       $LCTL modules > $OGDB/ogdb-$HOSTNAME
 
-    load_module llite/lustre
-    llite_lloop_enabled && load_module llite/llite_lloop
-    [ -d /r ] && OGDB=${OGDB:-"/r/tmp"}
-    OGDB=${OGDB:-$TMP}
-    rm -f $OGDB/ogdb-$HOSTNAME
-    $LCTL modules > $OGDB/ogdb-$HOSTNAME
-
-    # 'mount' doesn't look in $PATH, just sbin
-    if [ -f $LUSTRE/utils/mount.lustre ] && \
-       ! grep -qe "/sbin/mount\.lustre " /proc/mounts; then
-        [ ! -f /sbin/mount.lustre ] && touch /sbin/mount.lustre
-        mount --bind $LUSTRE/utils/mount.lustre /sbin/mount.lustre || true
-    fi
+       # 'mount' doesn't look in $PATH, just sbin
+       local MOUNT_LUSTRE=$LUSTRE/utils/mount.lustre
+       if [ -f $MOUNT_LUSTRE ]; then
+               if grep -qe "/sbin/mount\.lustre " /proc/mounts; then
+                       cmp $MOUNT_LUSTRE /sbin/mount.lustre ||
+                               umount /sbin/mount.lustre
+               fi
+               if ! grep -qe "/sbin/mount\.lustre " /proc/mounts; then
+                       [ ! -f /sbin/mount.lustre ] && touch /sbin/mount.lustre
+                       mount --bind $MOUNT_LUSTRE /sbin/mount.lustre
+               fi
+       fi
 }
 
 load_modules () {
@@ -642,7 +660,6 @@ start_gss_daemons() {
     fi
 
     local list=$(comma_list $(mdts_nodes))
-
     echo "Starting gss daemon on mds: $list"
     do_nodes $list "$LSVCGSSD -v" || return 1
     if $GSS_PIPEFS; then
@@ -679,7 +696,7 @@ start_gss_daemons() {
 
 stop_gss_daemons() {
     local list=$(comma_list $(mdts_nodes))
-    
+
     send_sigint $list lsvcgssd lgssd
 
     list=$(comma_list $(osts_nodes))
@@ -696,7 +713,9 @@ init_gss() {
             module_loaded ptlrpc_gss ||
                 error_exit "init_gss : GSS=$GSS, but gss/krb5 is not supported!"
         fi
-        start_gss_daemons || error_exit "start gss daemon failed! rc=$?"
+        if $GSS_KRB5; then
+                start_gss_daemons || error_exit "start gss daemon failed! rc=$?"
+        fi
 
         if [ -n "$LGSS_KEYRING_DEBUG" ]; then
             echo $LGSS_KEYRING_DEBUG > /proc/fs/lustre/sptlrpc/gss/lgss_keyring/debug_level
@@ -711,6 +730,13 @@ cleanup_gss() {
     fi
 }
 
+facet_svc() {
+       local facet=$1
+       local var=${facet}_svc
+
+       echo -n ${!var}
+}
+
 facet_type() {
        local facet=$1
 
@@ -810,6 +836,183 @@ ostdevlabel() {
 }
 
 #
+# Get the device of a facet.
+#
+facet_device() {
+       local facet=$1
+       local device
+
+       case $facet in
+               mgs) device=$(mgsdevname) ;;
+               mds*) device=$(mdsdevname $(facet_number $facet)) ;;
+               ost*) device=$(ostdevname $(facet_number $facet)) ;;
+               fs2mds) device=$(mdsdevname 1_2) ;;
+               fs2ost) device=$(ostdevname 1_2) ;;
+               fs3ost) device=$(ostdevname 2_2) ;;
+               *) ;;
+       esac
+
+       echo -n $device
+}
+
+#
+# Get the virtual device of a facet.
+#
+facet_vdevice() {
+       local facet=$1
+       local device
+
+       case $facet in
+               mgs) device=$(mgsvdevname) ;;
+               mds*) device=$(mdsvdevname $(facet_number $facet)) ;;
+               ost*) device=$(ostvdevname $(facet_number $facet)) ;;
+               fs2mds) device=$(mdsvdevname 1_2) ;;
+               fs2ost) device=$(ostvdevname 1_2) ;;
+               fs3ost) device=$(ostvdevname 2_2) ;;
+               *) ;;
+       esac
+
+       echo -n $device
+}
+
+#
+# Re-read the partition table on failover partner host.
+# After a ZFS storage pool is created on a shared device, the partition table
+# on the device may change. However, the operating system on the failover
+# host may not notice the change automatically. Without the up-to-date partition
+# block devices, 'zpool import ..' cannot find the labels, whose positions are
+# relative to partition rather than disk beginnings.
+#
+# This function performs partprobe on the failover host to make it re-read the
+# partition table.
+#
+refresh_partition_table() {
+       local facet=$1
+       local device=$2
+       local host
+
+       host=$(facet_passive_host $facet)
+       if [[ -n "$host" ]]; then
+               do_node $host "$PARTPROBE $device"
+       fi
+}
+
+#
+# Get ZFS storage pool name.
+#
+zpool_name() {
+       local facet=$1
+       local device
+       local poolname
+
+       device=$(facet_device $facet)
+       # poolname is string before "/"
+       poolname="${device%%/*}"
+
+       echo -n $poolname
+}
+
+#
+# Create ZFS storage pool.
+#
+create_zpool() {
+       local facet=$1
+       local poolname=$2
+       local vdev=$3
+       shift 3
+       local opts=${@:-"-o cachefile=none"}
+
+       do_facet $facet "$ZPOOL list -H $poolname >/dev/null 2>&1 ||
+               $ZPOOL create -f $opts $poolname $vdev"
+}
+
+#
+# Create ZFS file system.
+#
+create_zfs() {
+       local facet=$1
+       local dataset=$2
+       shift 2
+       local opts=${@:-"-o mountpoint=legacy"}
+
+       do_facet $facet "$ZFS list -H $dataset >/dev/null 2>&1 ||
+               $ZFS create $opts $dataset"
+}
+
+#
+# Export ZFS storage pool.
+# Before exporting the pool, all datasets within the pool should be unmounted.
+#
+export_zpool() {
+       local facet=$1
+       shift
+       local opts="$@"
+       local poolname
+
+       poolname=$(zpool_name $facet)
+
+       if [[ -n "$poolname" ]]; then
+               do_facet $facet "! $ZPOOL list -H $poolname >/dev/null 2>&1 ||
+                       grep -q ^$poolname/ /proc/mounts ||
+                       $ZPOOL export $opts $poolname"
+       fi
+}
+
+#
+# Destroy ZFS storage pool.
+# Destroy the given pool and free up any devices for other use. This command
+# tries to unmount any active datasets before destroying the pool.
+# -f    Force any active datasets contained within the pool to be unmounted.
+#
+destroy_zpool() {
+       local facet=$1
+       local poolname=${2:-$(zpool_name $facet)}
+
+       if [[ -n "$poolname" ]]; then
+               do_facet $facet "! $ZPOOL list -H $poolname >/dev/null 2>&1 ||
+                       $ZPOOL destroy -f $poolname"
+       fi
+}
+
+#
+# Import ZFS storage pool.
+# Force importing, even if the pool appears to be potentially active.
+#
+import_zpool() {
+       local facet=$1
+       shift
+       local opts=${@:-"-o cachefile=none"}
+       local poolname
+
+       poolname=$(zpool_name $facet)
+
+       if [[ -n "$poolname" ]]; then
+               opts+=" -d $(dirname $(facet_vdevice $facet))"
+               do_facet $facet "$ZPOOL list -H $poolname >/dev/null 2>&1 ||
+                       $ZPOOL import -f $opts $poolname"
+       fi
+}
+
+#
+# Set the "cachefile=none" property on ZFS storage pool so that the pool
+# is not automatically imported on system startup.
+#
+# In a failover environment, this will provide resource level fencing which
+# will ensure that the same ZFS storage pool will not be imported concurrently
+# on different nodes.
+#
+disable_zpool_cache() {
+       local facet=$1
+       local poolname
+
+       poolname=$(zpool_name $facet)
+
+       if [[ -n "$poolname" ]]; then
+               do_facet $facet "$ZPOOL set cachefile=none $poolname"
+       fi
+}
+
+#
 # This and set_osd_param() shall be used to access OSD parameters
 # once existed under "obdfilter":
 #
@@ -937,12 +1140,17 @@ mount_facet() {
                opts=$(csa_add "$opts" -o loop)
        fi
 
+       if [[ $(facet_fstype $facet) == zfs ]]; then
+               # import ZFS storage pool
+               import_zpool $facet || return ${PIPESTATUS[0]}
+       fi
+
        echo "Starting ${facet}: $opts ${!dev} $mntpt"
        # for testing LU-482 error handling in mount_facets() and test_0a()
        if [ -f $TMP/test-lu482-trigger ]; then
                RC=2
        else
-               do_facet ${facet} "mkdir -p $mntpt; mount -t lustre $opts \
+               do_facet ${facet} "mkdir -p $mntpt; $MOUNT_CMD $opts \
                                   ${!dev} $mntpt"
                RC=${PIPESTATUS[0]}
        fi
@@ -975,45 +1183,19 @@ start() {
         eval export ${facet}failover_dev=$device
     fi
 
-    local mntpt=$(facet_mntpt $facet)
-    do_facet ${facet} mkdir -p $mntpt
-    eval export ${facet}_MOUNT=$mntpt
-    mount_facet ${facet}
-    RC=$?
-    return $RC
-}
-
-#
-# When a ZFS OSD is made read-only by replay_barrier(), its pool is "freezed".
-# Because stopping corresponding target may not clear this in-memory state, we
-# need to zap the pool from memory by exporting and reimporting the pool.
-#
-# Although the uberblocks are not updated when a pool is freezed, transactions
-# are still written to the disks.  Modified blocks may be cached in memory when
-# tests try reading them back.  The export-and-reimport process also evicts any
-# cached pool data from memory to provide the correct "data loss" semantics.
-#
-refresh_disk() {
-       local facet=$1
-       local fstype=$(facet_fstype $facet)
-       local _dev
-       local dev
-       local poolname
-
-       if [ "${fstype}" == "zfs" ]; then
-               _dev=$(facet_active $facet)_dev
-               dev=${!_dev} # expand _dev to its value, e.g. ${mds1_dev}
-               poolname="${dev%%/*}" # poolname is string before "/"
+       local mntpt=$(facet_mntpt $facet)
+       do_facet ${facet} mkdir -p $mntpt
+       eval export ${facet}_MOUNT=$mntpt
+       mount_facet ${facet}
+       RC=$?
 
-               if [ "${poolname}" == "" ]; then
-                       echo "invalid dataset name: $dev"
-                       return
-               fi
-               do_facet $facet "cp /etc/zfs/zpool.cache /tmp/zpool.cache.back"
-               do_facet $facet "$ZPOOL export ${poolname}"
-               do_facet $facet "$ZPOOL import -f -c /tmp/zpool.cache.back \
-                                ${poolname}"
+       if [[ $facet == mds* ]]; then
+               do_facet $facet \
+                       lctl set_param -n mdt.${FSNAME}*.enable_remote_dir=1 \
+                               2>/dev/null
        fi
+
+       return $RC
 }
 
 stop() {
@@ -1030,9 +1212,14 @@ stop() {
         do_facet ${facet} umount -d $@ $mntpt
     fi
 
-    # umount should block, but we should wait for unrelated obd's
-    # like the MGS or MGC to also stop.
-    wait_exit_ST ${facet}
+       # umount should block, but we should wait for unrelated obd's
+       # like the MGS or MGC to also stop.
+       wait_exit_ST ${facet} || return ${PIPESTATUS[0]}
+
+       if [[ $(facet_fstype $facet) == zfs ]]; then
+               # export ZFS storage pool
+               export_zpool $facet
+       fi
 }
 
 # save quota version (both administrative and operational quotas)
@@ -1072,7 +1259,7 @@ quota_type() {
                rc=$?
        do_nodes $(comma_list $(osts_nodes)) \
                lctl get_param obdfilter.${fsname}-OST*.quota_type || rc=$?
-       return $rc 
+       return $rc
 }
 
 # XXX This function is kept for interoperability with old server (< 2.3.50),
@@ -1178,6 +1365,23 @@ lfs_df() {
        $LFS df $* | sed -e 's/filesystem /filesystem_/'
 }
 
+# Get free inodes on the MDT specified by mdt index, free indoes on
+# the whole filesystem will be returned when index == -1.
+mdt_free_inodes() {
+       local index=$1
+       local free_inodes
+       local mdt_uuid
+
+       if [ $index -eq -1 ]; then
+               mdt_uuid="summary"
+       else
+               mdt_uuid=$(mdtuuid_from_index $index)
+       fi
+
+       free_inodes=$(lfs_df -i $MOUNT | grep $mdt_uuid | awk '{print $4}')
+       echo $free_inodes
+}
+
 setup_quota(){
        if [ $(lustre_version_code $SINGLEMDS) -lt $(version_code 2.3.50) ]; then
                setup_quota_old $1
@@ -1244,7 +1448,7 @@ zconf_mount() {
 
     echo "Starting client: $client: $OPTIONS $device $mnt"
     do_node $client mkdir -p $mnt
-    do_node $client mount -t lustre $OPTIONS $device $mnt || return 1
+    do_node $client $MOUNT_CMD $OPTIONS $device $mnt || return 1
 
     set_default_debug_nodes $client
 
@@ -1355,7 +1559,7 @@ running=\\\$(mount | grep -c $mnt' ');
 rc=0;
 if [ \\\$running -eq 0 ] ; then
     mkdir -p $mnt;
-    mount -t lustre $OPTIONS $device $mnt;
+    $MOUNT_CMD $OPTIONS $device $mnt;
     rc=\\\$?;
 fi;
 exit \\\$rc" || return ${PIPESTATUS[0]}
@@ -1445,7 +1649,7 @@ facet_up() {
        local host=${2:-$(facet_host $facet)}
 
        local label=$(convert_facet2label $facet)
-       do_node $host $LCTL dl | awk '{print $4}' | grep -q -x $label
+       do_node $host $LCTL dl | awk '{ print $4 }' | grep -q "^$label\$"
 }
 
 facets_up_on_host () {
@@ -1490,7 +1694,6 @@ reboot_facet() {
        if [ "$FAILURE_MODE" = HARD ]; then
                reboot_node $(facet_active_host $facet)
        else
-               refresh_disk ${facet}
                sleep 10
        fi
 }
@@ -1553,6 +1756,7 @@ TESTLOG_PREFIX=$TESTLOG_PREFIX \
 TESTNAME=$TESTNAME \
 DBENCH_LIB=$DBENCH_LIB \
 DBENCH_SRC=$DBENCH_SRC \
+CLIENT_COUNT=$((CLIENTCOUNT - 1)) \
 LFS=$LFS \
 run_${load}.sh" &
     local ppid=$!
@@ -1738,18 +1942,18 @@ stop_client_loads() {
 
 # verify that lustre actually cleaned up properly
 cleanup_check() {
-    [ -f $CATASTROPHE ] && [ `cat $CATASTROPHE` -ne 0 ] && \
-        error "LBUG/LASSERT detected"
-    BUSY=`dmesg | grep -i destruct || true`
-    if [ "$BUSY" ]; then
-        echo "$BUSY" 1>&2
-        [ -e $TMP/debug ] && mv $TMP/debug $TMP/debug-busy.`date +%s`
-        exit 205
-    fi
+       [ -f "$CATASTROPHE" ] && [[ $(< $CATASTROPHE) -ne 0 ]] &&
+               error "LBUG/LASSERT detected"
+       BUSY=$(dmesg | grep -i destruct || true)
+       if [ -n "$BUSY" ]; then
+               echo "$BUSY" 1>&2
+               [ -e $TMP/debug ] && mv $TMP/debug $TMP/debug-busy.$(date +%s)
+               exit 205
+       fi
 
-    check_mem_leak || exit 204
+       check_mem_leak || exit 204
 
-       [ "`lctl dl 2> /dev/null | wc -l`" -gt 0 ] && lctl dl &&
+       [[ $($LCTL dl 2>/dev/null | wc -l) -gt 0 ]] && $LCTL dl &&
                echo "$TESTSUITE: lustre didn't clean up..." 1>&2 &&
                return 202 || true
 
@@ -1762,30 +1966,44 @@ cleanup_check() {
 }
 
 wait_update () {
-    local node=$1
-    local TEST=$2
-    local FINAL=$3
-    local MAX=${4:-90}
-
-        local RESULT
-        local WAIT=0
-        local sleep=1
-        local print=10
-        while [ true ]; do
-            RESULT=$(do_node $node "$TEST")
-            if [ "$RESULT" == "$FINAL" ]; then
-                [ -z "$RESULT" -o $WAIT -le $sleep ] ||
-                    echo "Updated after ${WAIT}s: wanted '$FINAL' got '$RESULT'"
-                return 0
-            fi
-            [ $WAIT -ge $MAX ] && break
-            [ $((WAIT % print)) -eq 0 ] &&
-                echo "Waiting $((MAX - WAIT)) secs for update"
-            WAIT=$((WAIT + sleep))
-            sleep $sleep
-        done
-        echo "Update not seen after ${MAX}s: wanted '$FINAL' got '$RESULT'"
-        return 3
+       local verbose=false
+       if [[ "$1" == "--verbose" ]]; then
+               shift
+               verbose=true
+       fi
+
+       local node=$1
+       local TEST=$2
+       local FINAL=$3
+       local MAX=${4:-90}
+       local RESULT
+       local PREV_RESULT
+       local WAIT=0
+       local sleep=1
+       local print=10
+
+       PREV_RESULT=$(do_node $node "$TEST")
+       while [ true ]; do
+               RESULT=$(do_node $node "$TEST")
+               if [[ "$RESULT" == "$FINAL" ]]; then
+                       [[ -z "$RESULT" || $WAIT -le $sleep ]] ||
+                               echo "Updated after ${WAIT}s: wanted '$FINAL'"\
+                                    "got '$RESULT'"
+                       return 0
+               fi
+               if [[ $verbose && "$RESULT" != "$PREV_RESULT" ]]; then
+                       echo "Changed after ${WAIT}s: from '$PREV_RESULT'"\
+                            "to '$RESULT'"
+                       PREV_RESULT=$RESULT
+               fi
+               [[ $WAIT -ge $MAX ]] && break
+               [[ $((WAIT % print)) -eq 0 ]] &&
+                       echo "Waiting $((MAX - WAIT)) secs for update"
+               WAIT=$((WAIT + sleep))
+               sleep $sleep
+       done
+       echo "Update not seen after ${MAX}s: wanted '$FINAL' got '$RESULT'"
+       return 3
 }
 
 wait_update_facet() {
@@ -1805,39 +2023,39 @@ sync_all_data() {
 wait_delete_completed_mds() {
        local MAX_WAIT=${1:-20}
        local mds2sync=""
-       local stime=`date +%s`
+       local stime=$(date +%s)
        local etime
        local node
        local changes
 
        # find MDS with pending deletions
        for node in $(mdts_nodes); do
-               changes=$(do_node $node "lctl get_param -n osc.*MDT*.sync_*" \
+               changes=$(do_node $node "$LCTL get_param -n osc.*MDT*.sync_*" \
                        2>/dev/null | calc_sum)
-               if [ -z "$changes" ] || [ $changes -eq 0 ]; then
+               if [[ $changes -eq 0 ]]; then
                        continue
                fi
                mds2sync="$mds2sync $node"
        done
-       if [ "$mds2sync" == "" ]; then
+       if [ -z "$mds2sync" ]; then
                return
        fi
        mds2sync=$(comma_list $mds2sync)
 
        # sync MDS transactions
-       do_nodes $mds2sync "lctl set_param -n osd*.*MD*.force_sync 1"
+       do_nodes $mds2sync "$LCTL set_param -n osd*.*MD*.force_sync 1"
 
        # wait till all changes are sent and commmitted by OSTs
        # for ldiskfs space is released upon execution, but DMU
        # do this upon commit
 
        local WAIT=0
-       while [ "$WAIT" -ne "$MAX_WAIT" ]; do
-               changes=$(do_nodes $mds2sync "lctl get_param -n osc.*MDT*.sync_*" \
-                       | calc_sum)
+       while [[ $WAIT -ne $MAX_WAIT ]]; do
+               changes=$(do_nodes $mds2sync \
+                       "$LCTL get_param -n osc.*MDT*.sync_*" | calc_sum)
                #echo "$node: $changes changes on all"
-               if [ "$changes" -eq "0" ]; then
-                       etime=`date +%s`
+               if [[ $changes -eq 0 ]]; then
+                       etime=$(date +%s)
                        #echo "delete took $((etime - stime)) seconds"
                        return
                fi
@@ -1845,9 +2063,9 @@ wait_delete_completed_mds() {
                WAIT=$(( WAIT + 1))
        done
 
-       etime=`date +%s`
+       etime=$(date +%s)
        echo "Delete is not completed in $((etime - stime)) seconds"
-       do_nodes $mds2sync "lctl get_param osc.*MDT*.sync_*"
+       do_nodes $mds2sync "$LCTL get_param osc.*MDT*.sync_*"
 }
 
 wait_for_host() {
@@ -1919,6 +2137,7 @@ wait_mds_ost_sync () {
        echo "Waiting for orphan cleanup..."
        # MAX value includes time needed for MDS-OST reconnection
        local MAX=$(( TIMEOUT * 2 ))
+       local WAIT_TIMEOUT=${1:-$MAX}
        local WAIT=0
        local new_wait=true
        local list=$(comma_list $(mdts_nodes))
@@ -1931,7 +2150,9 @@ wait_mds_ost_sync () {
                list=$(comma_list $(osts_nodes))
                cmd="$LCTL get_param -n obdfilter.*.mds_sync"
        fi
-       while [ $WAIT -lt $MAX ]; do
+
+       echo "wait $WAIT_TIMEOUT secs maximumly for $list mds-ost sync done."
+       while [ $WAIT -lt $WAIT_TIMEOUT ]; do
                local -a sync=($(do_nodes $list "$cmd"))
                local con=1
                local i
@@ -1947,10 +2168,13 @@ wait_mds_ost_sync () {
                done
                sleep 2 # increase waiting time and cover statfs cache
                [ ${con} -eq 1 ] && return 0
-               echo "Waiting $WAIT secs for $facet mds-ost sync done."
+               echo "Waiting $WAIT secs for $list $i mds-ost sync done."
                WAIT=$((WAIT + 2))
        done
-       echo "$facet recovery not done in $MAX sec. $STATUS"
+
+       # show which nodes are not finished.
+       do_nodes $list "$cmd"
+       echo "$facet recovery node $i not done in $WAIT_TIMEOUT sec. $STATUS"
        return 1
 }
 
@@ -2064,7 +2288,7 @@ client_evicted() {
     ! client_up $1
 }
 
-client_reconnect() {
+client_reconnect_try() {
     uname -n >> $MOUNT/recon
     if [ -z "$CLIENTS" ]; then
         df $MOUNT; uname -n >> $MOUNT/recon
@@ -2077,6 +2301,14 @@ client_reconnect() {
     rm $MOUNT/recon
 }
 
+client_reconnect() {
+       # one client_reconnect_try call does not always do the job...
+       while true ; do
+               client_reconnect_try && break
+               sleep 1
+       done
+}
+
 affected_facets () {
     local facet=$1
 
@@ -2153,7 +2385,7 @@ replay_barrier() {
        do_facet $facet "sync; sync; sync"
        df $MOUNT
 
-        # make sure there will be no seq change
+       # make sure there will be no seq change
        local clients=${CLIENTS:-$HOSTNAME}
        local f=fsa-\\\$\(hostname\)
        do_nodes $clients "mcreate $MOUNT/$f; rm $MOUNT/$f"
@@ -2161,6 +2393,21 @@ replay_barrier() {
 
        local svc=${facet}_svc
        do_facet $facet $LCTL --device ${!svc} notransno
+       #
+       # If a ZFS OSD is made read-only here, its pool is "freezed". This
+       # in-memory state has to be cleared by either rebooting the host or
+       # exporting and reimporting the pool.
+       #
+       # Although the uberblocks are not updated when a pool is freezed,
+       # transactions are still written to the disks. Modified blocks may be
+       # cached in memory when tests try reading them back. The
+       # export-and-reimport process also evicts any cached pool data from
+       # memory to provide the correct "data loss" semantics.
+       #
+       # In the test framework, the exporting and importing operations are
+       # handled by stop() and mount_facet() separately, which are used
+       # inside fail() and fail_abort().
+       #
        do_facet $facet $LCTL --device ${!svc} readonly
        do_facet $facet $LCTL mark "$facet REPLAY BARRIER on ${!svc}"
        $LCTL mark "local REPLAY BARRIER on ${!svc}"
@@ -2187,14 +2434,32 @@ replay_barrier_nosync() {
        $LCTL mark "local REPLAY BARRIER on ${!svc}"
 }
 
+#
+# Get Lustre client uuid for a given Lustre mount point.
+#
+get_client_uuid() {
+       local mntpnt=${1:-$MOUNT}
+
+       local name=$($LFS getname $mntpnt | cut -d' ' -f1)
+       local uuid=$($LCTL get_param -n llite.$name.uuid)
+
+       echo -n $uuid
+}
+
 mds_evict_client() {
-    UUID=`lctl get_param -n mdc.${mds1_svc}-mdc-*.uuid`
-    do_facet mds1 "lctl set_param -n mdt.${mds1_svc}.evict_client $UUID"
+       local mntpnt=${1:-$MOUNT}
+       local uuid=$(get_client_uuid $mntpnt)
+
+       do_facet $SINGLEMDS \
+               "$LCTL set_param -n mdt.${mds1_svc}.evict_client $uuid"
 }
 
 ost_evict_client() {
-    UUID=`lctl get_param -n devices| grep ${ost1_svc}-osc- | egrep -v 'MDT' | awk '{print $5}'`
-    do_facet ost1 "lctl set_param -n obdfilter.${ost1_svc}.evict_client $UUID"
+       local mntpnt=${1:-$MOUNT}
+       local uuid=$(get_client_uuid $mntpnt)
+
+       do_facet ost1 \
+               "$LCTL set_param -n obdfilter.${ost1_svc}.evict_client $uuid"
 }
 
 fail() {
@@ -2214,7 +2479,6 @@ fail_nodf() {
 fail_abort() {
        local facet=$1
        stop $facet
-       refresh_disk ${facet}
        change_active $facet
        wait_for_facet $facet
        mount_facet $facet -o abort_recovery
@@ -2240,42 +2504,43 @@ host_nids_address() {
 }
 
 h2name_or_ip() {
-    if [ "$1" = "client" -o "$1" = "'*'" ]; then echo \'*\'; else
-        echo $1"@$2"
-    fi
+       if [ "$1" = "'*'" ]; then echo \'*\'; else
+               echo $1"@$2"
+       fi
 }
 
 h2ptl() {
-   if [ "$1" = "client" -o "$1" = "'*'" ]; then echo \'*\'; else
-       ID=`xtprocadmin -n $1 2>/dev/null | egrep -v 'NID' | awk '{print $1}'`
-       if [ -z "$ID" ]; then
-           echo "Could not get a ptl id for $1..."
-           exit 1
-       fi
-       echo $ID"@ptl"
-   fi
+       if [ "$1" = "'*'" ]; then echo \'*\'; else
+               ID=`xtprocadmin -n $1 2>/dev/null | egrep -v 'NID' | \
+                                                       awk '{print $1}'`
+               if [ -z "$ID" ]; then
+                       echo "Could not get a ptl id for $1..."
+                       exit 1
+               fi
+               echo $ID"@ptl"
+       fi
 }
 declare -fx h2ptl
 
 h2tcp() {
-    h2name_or_ip "$1" "tcp"
+       h2name_or_ip "$1" "tcp"
 }
 declare -fx h2tcp
 
 h2elan() {
-    if [ "$1" = "client" -o "$1" = "'*'" ]; then echo \'*\'; else
-        if type __h2elan >/dev/null 2>&1; then
-            ID=$(__h2elan $1)
-        else
-            ID=`echo $1 | sed 's/[^0-9]*//g'`
-        fi
-        echo $ID"@elan"
-    fi
+       if [ "$1" = "'*'" ]; then echo \'*\'; else
+               if type __h2elan >/dev/null 2>&1; then
+                       ID=$(__h2elan $1)
+               else
+                       ID=`echo $1 | sed 's/[^0-9]*//g'`
+               fi
+               echo $ID"@elan"
+       fi
 }
 declare -fx h2elan
 
 h2o2ib() {
-    h2name_or_ip "$1" "o2ib"
+       h2name_or_ip "$1" "o2ib"
 }
 declare -fx h2o2ib
 
@@ -2376,7 +2641,11 @@ facet_host() {
        varname=${facet}_HOST
        if [ -z "${!varname}" ]; then
                if [ "${facet:0:3}" == "ost" ]; then
-                       eval export ${facet}_HOST=${ost_HOST}
+                       local fh=${facet%failover}_HOST
+                       eval export ${facet}_HOST=${!fh}
+                       if [ -z "${!varname}" ]; then
+                               eval export ${facet}_HOST=${ost_HOST}
+                       fi
                elif [ "${facet:0:3}" == "mdt" -o \
                        "${facet:0:3}" == "mds" -o \
                        "${facet:0:3}" == "mgs" ]; then
@@ -2640,18 +2909,32 @@ do_nodesv() {
 }
 
 add() {
-    local facet=$1
-    shift
-    # make sure its not already running
-    stop ${facet} -f
-    rm -f $TMP/${facet}active
-    [[ $facet = mds1 ]] && combined_mgs_mds && rm -f $TMP/mgsactive
-    do_facet ${facet} $MKFS $*
+       local facet=$1
+       shift
+       # make sure its not already running
+       stop ${facet} -f
+       rm -f $TMP/${facet}active
+       [[ $facet = mds1 ]] && combined_mgs_mds && rm -f $TMP/mgsactive
+       do_facet ${facet} $MKFS $* || return ${PIPESTATUS[0]}
+
+       if [[ $(facet_fstype $facet) == zfs ]]; then
+               #
+               # After formatting a ZFS target, "cachefile=none" property will
+               # be set on the ZFS storage pool so that the pool is not
+               # automatically imported on system startup. And then the pool
+               # will be exported so as to leave the importing and exporting
+               # operations handled by mount_facet() and stop() separately.
+               #
+               refresh_partition_table $facet $(facet_vdevice $facet)
+               disable_zpool_cache $facet
+               export_zpool $facet
+       fi
 }
 
+# Device formatted as ost
 ostdevname() {
-    num=$1
-    DEVNAME=OSTDEV$num
+       local num=$1
+       local DEVNAME=OSTDEV$num
 
        local fstype=$(facet_fstype ost$num)
 
@@ -2660,8 +2943,9 @@ ostdevname() {
                        #if $OSTDEVn isn't defined, default is $OSTDEVBASE + num
                        eval DEVPTR=${!DEVNAME:=${OSTDEVBASE}${num}};;
                zfs )
-                       #dataset name is independent of vdev device names
-                       eval DEVPTR=${FSNAME}-ost${num}/ost${num};;
+                       #try $OSTZFSDEVn - independent of vdev
+                       DEVNAME=OSTZFSDEV$num
+                       eval DEVPTR=${!DEVNAME:=${FSNAME}-ost${num}/ost${num}};;
                * )
                        error "unknown fstype!";;
        esac
@@ -2669,9 +2953,11 @@ ostdevname() {
     echo -n $DEVPTR
 }
 
+# Physical device location of data
 ostvdevname() {
-       num=$1
-       DEVNAME=OSTDEV$num
+       local num=$1
+       local DEVNAME
+       local VDEVPTR
 
        local fstype=$(facet_fstype ost$num)
 
@@ -2680,7 +2966,9 @@ ostvdevname() {
                        # vdevs are not supported by ldiskfs
                        eval VDEVPTR="";;
                zfs )
-                       #if $OSTDEVn isn't defined, default is $OSTDEVBASE + num
+                       #if $OSTDEVn isn't defined, default is $OSTDEVBASE{n}
+                       # Device formated by zfs
+                       DEVNAME=OSTDEV$num
                        eval VDEVPTR=${!DEVNAME:=${OSTDEVBASE}${num}};;
                * )
                        error "unknown fstype!";;
@@ -2689,19 +2977,21 @@ ostvdevname() {
        echo -n $VDEVPTR
 }
 
+# Logical device formated for lustre
 mdsdevname() {
-    num=$1
-    DEVNAME=MDSDEV$num
+       local num=$1
+       local DEVNAME=MDSDEV$num
 
        local fstype=$(facet_fstype mds$num)
 
        case $fstype in
                ldiskfs )
-                       #if $MDSDEVn isn't defined, default is $MDSDEVBASE + num
+                       #if $MDSDEVn isn't defined, default is $MDSDEVBASE{n}
                        eval DEVPTR=${!DEVNAME:=${MDSDEVBASE}${num}};;
                zfs )
-                       #dataset name is independent of vdev device names
-                       eval DEVPTR=${FSNAME}-mdt${num}/mdt${num};;
+                       # try $MDSZFSDEVn - independent of vdev
+                       DEVNAME=MDSZFSDEV$num
+                       eval DEVPTR=${!DEVNAME:=${FSNAME}-mdt${num}/mdt${num}};;
                * )
                        error "unknown fstype!";;
        esac
@@ -2709,10 +2999,10 @@ mdsdevname() {
        echo -n $DEVPTR
 }
 
+# Physical location of data
 mdsvdevname() {
-       num=$1
-       DEVNAME=MDSDEV$num
-
+       local VDEVPTR=""
+       local num=$1
        local fstype=$(facet_fstype mds$num)
 
        case $fstype in
@@ -2720,7 +3010,9 @@ mdsvdevname() {
                        # vdevs are not supported by ldiskfs
                        eval VDEVPTR="";;
                zfs )
-                       #if $MDSDEVn isn't defined, default is $MDSDEVBASE + num
+                       # if $MDSDEVn isn't defined, default is $MDSDEVBASE{n}
+                       # Device formated by ZFS
+                       local DEVNAME=MDSDEV$num
                        eval VDEVPTR=${!DEVNAME:=${MDSDEVBASE}${num}};;
                * )
                        error "unknown fstype!";;
@@ -2743,10 +3035,11 @@ mgsdevname() {
                fi;;
        zfs )
                if [ $(facet_host mgs) = $(facet_host mds1) ] &&
-                  ( [ -z "$MGSDEV" ] || [ $MGSDEV = $(mdsvdevname 1) ] ); then
+                   ( [ -z "$MGSZFSDEV" ] &&
+                       [ -z "$MGSDEV" -o "$MGSDEV" = $(mdsvdevname 1) ] ); then
                        DEVPTR=$(mdsdevname 1)
                else
-                       DEVPTR=${FSNAME}-mgs/mgs
+                       DEVPTR=${MGSZFSDEV:-${FSNAME}-mgs/mgs}
                fi;;
        * )
                error "unknown fstype!";;
@@ -2756,8 +3049,7 @@ mgsdevname() {
 }
 
 mgsvdevname() {
-       local VDEVPTR
-       DEVNAME=MGSDEV
+       local VDEVPTR=""
 
        local fstype=$(facet_fstype mgs)
 
@@ -2767,9 +3059,10 @@ mgsvdevname() {
                ;;
        zfs )
                if [ $(facet_host mgs) = $(facet_host mds1) ] &&
-                  ( [ -z "$MGSDEV" ] || [ $MGSDEV = $(mdsvdevname 1) ] ); then
+                  ( [ -z "$MGSDEV" ] &&
+                      [ -z "$MGSZFSDEV" -o "$MGSZFSDEV" = $(mdsdevname 1) ]); then
                        VDEVPTR=$(mdsvdevname 1)
-               else
+               elif [ -n "$MGSDEV" ]; then
                        VDEVPTR=$MGSDEV
                fi;;
        * )
@@ -2789,6 +3082,84 @@ facet_mntpt () {
     echo -n $mntpt
 }
 
+mount_ldiskfs() {
+       local facet=$1
+       local dev=$(facet_device $facet)
+       local mnt=$(facet_mntpt $facet)
+       local opts
+
+       if ! do_facet $facet test -b $dev; then
+               opts="-o loop"
+       fi
+       do_facet $facet mount -t ldiskfs $opts $dev $mnt
+}
+
+unmount_ldiskfs() {
+       local facet=$1
+       local dev=$(facet_device $facet)
+       local mnt=$(facet_mntpt $facet)
+
+       do_facet $facet umount -d $mnt
+}
+
+var_name() {
+       echo -n "$1" | tr -c '[:alnum:]\n' '_'
+}
+
+mount_zfs() {
+       local facet=$1
+       local ds=$(facet_device $facet)
+       local mnt=$(facet_mntpt $facet)
+       local canmnt
+       local mntpt
+
+       import_zpool $facet
+       canmnt=$(do_facet $facet $ZFS get -H -o value canmount $ds)
+       mntpt=$(do_facet $facet $ZFS get -H -o value mountpoint $ds)
+       do_facet $facet $ZFS set canmount=noauto $ds
+       #
+       # The "legacy" mount method is used here because "zfs unmount $mnt"
+       # calls stat(2) on $mnt/../*, which may include $MOUNT.  If certain
+       # targets are not available at the time, the stat(2) on $MOUNT will
+       # hang.
+       #
+       do_facet $facet $ZFS set mountpoint=legacy $ds
+       do_facet $facet mount -t zfs $ds $mnt
+       eval export mz_$(var_name ${facet}_$ds)_canmount=$canmnt
+       eval export mz_$(var_name ${facet}_$ds)_mountpoint=$mntpt
+}
+
+unmount_zfs() {
+       local facet=$1
+       local ds=$(facet_device $facet)
+       local mnt=$(facet_mntpt $facet)
+       local var_mntpt=mz_$(var_name ${facet}_$ds)_mountpoint
+       local var_canmnt=mz_$(var_name ${facet}_$ds)_canmount
+       local mntpt=${!var_mntpt}
+       local canmnt=${!var_canmnt}
+
+       unset $var_mntpt
+       unset $var_canmnt
+       do_facet $facet umount $mnt
+       do_facet $facet $ZFS set mountpoint=$mntpt $ds
+       do_facet $facet $ZFS set canmount=$canmnt $ds
+       export_zpool $facet
+}
+
+mount_fstype() {
+       local facet=$1
+       local fstype=$(facet_fstype $facet)
+
+       mount_$fstype $facet
+}
+
+unmount_fstype() {
+       local facet=$1
+       local fstype=$(facet_fstype $facet)
+
+       unmount_$fstype $facet
+}
+
 ########
 ## MountConf setup
 
@@ -2905,6 +3276,12 @@ mkfs_opts() {
                opts+=${L_GETIDENTITY:+" --param=mdt.identity_upcall=$L_GETIDENTITY"}
 
                if [ $fstype == ldiskfs ]; then
+                       # Check for wide striping
+                       if [ $OSTCOUNT -gt 160 ]; then
+                               MDSJOURNALSIZE=${MDSJOURNALSIZE:-4096}
+                               fs_mkfs_opts+="-O large_xattr"
+                       fi
+
                        fs_mkfs_opts+=${MDSJOURNALSIZE:+" -J size=$MDSJOURNALSIZE"}
                        if [ ! -z $EJOURNAL ]; then
                                fs_mkfs_opts+=${MDSJOURNALSIZE:+" device=$EJOURNAL"}
@@ -3395,10 +3772,17 @@ is_empty_dir() {
 
 # empty lustre filesystem may have empty directories lost+found and .lustre
 is_empty_fs() {
+       # exclude .lustre & lost+found
        [ $(find $1 -maxdepth 1 -name lost+found -o -name .lustre -prune -o \
                -print | wc -l) = 1 ] || return 1
        [ ! -d $1/lost+found ] || is_empty_dir $1/lost+found || return 1
-       [ ! -d $1/.lustre ] || is_empty_dir $1/.lustre || return 1
+       if [ $(lustre_version_code $SINGLEMDS) -gt $(version_code 2.4.0) ]; then
+               # exclude .lustre/fid (LU-2780)
+               [ $(find $1/.lustre -maxdepth 1 -name fid -prune -o \
+                       -print | wc -l) = 1 ] || return 1
+       else
+               [ ! -d $1/.lustre ] || is_empty_dir $1/.lustre || return 1
+       fi
        return 0
 }
 
@@ -3461,7 +3845,13 @@ check_and_setup_lustre() {
     fi
 
        if [ $(lower $OSD_TRACK_DECLARES_LBUG) == 'yes' ] ; then
-               local facets="$(get_facets OST),$(get_facets MDS),mgs"
+               local facets=""
+               [ "$(facet_fstype ost1)" = "ldiskfs" ] &&
+                       facets="$(get_facets OST)"
+               [ "$(facet_fstype mds1)" = "ldiskfs" ] &&
+                       facets="$facets,$(get_facets MDS)"
+               [ "$(facet_fstype mgs)" = "ldiskfs" ] &&
+                       facets="$facets,mgs"
                local nodes="$(facets_hosts ${facets})"
                if [ -n "$nodes" ] ; then
                        do_nodes $nodes "$LCTL set_param \
@@ -3474,6 +3864,13 @@ check_and_setup_lustre() {
                set_flavor_all $SEC
        fi
 
+       #Enable remote MDT create for testing
+       for num in $(seq $MDSCOUNT); do
+               do_facet mds$num \
+                       lctl set_param -n mdt.${FSNAME}*.enable_remote_dir=1 \
+                               2>/dev/null
+       done
+
        if [ "$ONLY" == "setup" ]; then
                exit 0
        fi
@@ -3487,10 +3884,10 @@ restore_mount () {
 }
 
 cleanup_mount () {
-    local clients=${CLIENTS:-$HOSTNAME}
-    local mntpt=$1
+       local clients=${CLIENTS:-$HOSTNAME}
+       local mntpt=$1
 
-    zconf_umount_clients $clients $mntpt    
+       zconf_umount_clients $clients $mntpt
 }
 
 cleanup_and_setup_lustre() {
@@ -3514,8 +3911,7 @@ get_mnt_devs() {
        if [ "$type" == ost ]; then
                devs=$(get_osd_param $node "" mntdev)
        else
-               devs=$(do_node $node \
-                      "lctl get_param -n osd-*.$FSNAME-M*.mntdev")
+               devs=$(do_node $node $LCTL get_param -n osd-*.$FSNAME-M*.mntdev)
        fi
        for dev in $devs; do
                case $dev in
@@ -3528,63 +3924,101 @@ get_mnt_devs() {
 
 # Get all of the server target devices.
 get_svr_devs() {
-    local i
+       local node
+       local i
 
-    # MDT device
-    MDTDEV=$(get_mnt_devs $(mdts_nodes) mdt)
+       # Master MDS parameters used by lfsck
+       MDTNODE=$(facet_active_host $SINGLEMDS)
+       MDTDEV=$(echo $(get_mnt_devs $MDTNODE mdt) | awk '{print $1}')
 
-    # OST devices
-    i=0
-    for node in $(osts_nodes); do
-        OSTDEVS[i]=$(get_mnt_devs $node ost)
-        i=$((i + 1))
-    done
+       # MDT devices
+       i=0
+       for node in $(mdts_nodes); do
+               MDTDEVS[i]=$(get_mnt_devs $node mdt)
+               i=$((i + 1))
+       done
+
+       # OST devices
+       i=0
+       for node in $(osts_nodes); do
+               OSTDEVS[i]=$(get_mnt_devs $node ost)
+               i=$((i + 1))
+       done
 }
 
 # Run e2fsck on MDT or OST device.
 run_e2fsck() {
-    local node=$1
-    local target_dev=$2
-    local extra_opts=$3
+       local node=$1
+       local target_dev=$2
+       local extra_opts=$3
+       local cmd="$E2FSCK -d -v -t -t -f $extra_opts $target_dev"
+       local log=$TMP/e2fsck.log
+       local rc=0
 
-    df > /dev/null      # update statfs data on disk
-    local cmd="$E2FSCK -d -v -t -t -f $extra_opts $target_dev"
-    echo $cmd
-    local rc=0
-    do_node $node $cmd || rc=$?
-    [ $rc -le $FSCK_MAX_ERR ] || \
-        error "$cmd returned $rc, should be <= $FSCK_MAX_ERR"
-    return 0
+       echo $cmd
+       do_node $node $cmd 2>&1 | tee $log
+       rc=${PIPESTATUS[0]}
+       if [ -n "$(grep "DNE mode isn't supported" $log)" ]; then
+               rm -f $log
+               if [ $MDSCOUNT -gt 1 ]; then
+                       skip "DNE mode isn't supported!"
+                       cleanupall
+                       exit_status
+               else
+                       error "It's not DNE mode."
+               fi
+       fi
+       rm -f $log
+
+       [ $rc -le $FSCK_MAX_ERR ] ||
+               error "$cmd returned $rc, should be <= $FSCK_MAX_ERR"
+
+       return 0
+}
+
+#
+# Run resize2fs on MDT or OST device.
+#
+run_resize2fs() {
+       local facet=$1
+       local device=$2
+       local size=$3
+       shift 3
+       local opts="$@"
+
+       do_facet $facet "$RESIZE2FS $opts $device $size"
 }
 
 # verify a directory is shared among nodes.
 check_shared_dir() {
        local dir=$1
+       local list=${2:-$(comma_list $(nodes_list))}
 
        [ -z "$dir" ] && return 1
-       do_rpc_nodes "$(comma_list $(nodes_list))" check_logdir $dir
-       check_write_access $dir || return 1
+       do_rpc_nodes "$list" check_logdir $dir
+       check_write_access $dir "$list" || return 1
        return 0
 }
 
 # Run e2fsck on MDT and OST(s) to generate databases used for lfsck.
 generate_db() {
-    local i
-    local ostidx
-    local dev
+       local i
+       local ostidx
+       local dev
+       local node
 
        [[ $(lustre_version_code $SINGLEMDS) -ne $(version_code 2.2.0) ]] ||
                { skip "Lustre 2.2.0 lacks the patch for LU-1255"; exit 0; }
 
-    check_shared_dir $SHARED_DIRECTORY ||
-        error "$SHARED_DIRECTORY isn't a shared directory"
-
-    export MDSDB=$SHARED_DIRECTORY/mdsdb
-    export OSTDB=$SHARED_DIRECTORY/ostdb
+       check_shared_dir $SHARED_DIRECTORY ||
+               error "$SHARED_DIRECTORY isn't a shared directory"
 
-    [ $MDSCOUNT -eq 1 ] || error "CMD is not supported"
+       export MDSDB=$SHARED_DIRECTORY/mdsdb
+       export OSTDB=$SHARED_DIRECTORY/ostdb
 
-    run_e2fsck $(mdts_nodes) $MDTDEV "-n --mdsdb $MDSDB"
+       # DNE is not supported, so when running e2fsck on a DNE filesystem,
+       # we only pass master MDS parameters.
+       run_e2fsck $MDTNODE $MDTDEV "-n --mdsdb $MDSDB"
 
     i=0
     ostidx=0
@@ -3614,7 +4048,7 @@ run_lfsck_remote() {
        fi
        #Run lfsck
        echo $cmd
-       do_node $node $cmd || rc=$?
+       do_node $client $cmd || rc=$?
        #Umount if necessary
        if ! $mounted; then
                zconf_umount $client $MOUNT ||
@@ -3663,18 +4097,22 @@ check_and_cleanup_lustre() {
                [ "$ENABLE_QUOTA" ] && restore_quota || true
        fi
 
-    if [ "$I_UMOUNTED2" = "yes" ]; then
-        restore_mount $MOUNT2 || error "restore $MOUNT2 failed"
-    fi
+       if [ "$I_UMOUNTED2" = "yes" ]; then
+               restore_mount $MOUNT2 || error "restore $MOUNT2 failed"
+       fi
 
-    if [ "$I_MOUNTED2" = "yes" ]; then
-        cleanup_mount $MOUNT2
-    fi
+       if [ "$I_MOUNTED2" = "yes" ]; then
+               cleanup_mount $MOUNT2
+       fi
 
-    if [ "$I_MOUNTED" = "yes" ]; then
-        cleanupall -f || error "cleanup failed"
-        unset I_MOUNTED
-    fi
+       if [ "$I_MOUNTED" = "yes" ]; then
+               cleanupall -f || error "cleanup failed"
+               unset I_MOUNTED
+       fi
+
+       if grep -qe "/sbin/mount\.lustre " /proc/mounts; then
+               umount /sbin/mount.lustre
+       fi
 }
 
 #######
@@ -3798,7 +4236,7 @@ get_facets () {
 
         case $type in
                 MGS ) list="$list $name";;
-            MDS|OST ) local count=${type}COUNT
+            MDS|OST|AGT ) local count=${type}COUNT
                        for ((i=1; i<=${!count}; i++)) do
                           list="$list ${name}$i"
                       done;;
@@ -3901,12 +4339,16 @@ drop_update_reply() {
 
 pause_bulk() {
 #define OBD_FAIL_OST_BRW_PAUSE_BULK      0x214
-    RC=0
-    do_facet ost1 lctl set_param fail_loc=0x214
-    do_facet client "$1" || RC=$?
-    do_facet client "sync"
-    do_facet ost1 lctl set_param fail_loc=0
-    return $RC
+       RC=0
+
+       local timeout=${2:-0}
+       # default is (obd_timeout / 4) if unspecified
+       echo "timeout is $timeout/$2"
+       do_facet ost1 lctl set_param fail_val=$timeout fail_loc=0x80000214
+       do_facet client "$1" || RC=$?
+       do_facet client "sync"
+       do_facet ost1 lctl set_param fail_loc=0
+       return $RC
 }
 
 drop_ldlm_cancel() {
@@ -3948,7 +4390,7 @@ clear_failloc() {
 }
 
 set_nodes_failloc () {
-    do_nodes $(comma_list $1)  lctl set_param fail_loc=$2
+       do_nodes $(comma_list $1)  lctl set_param fail_val=0 fail_loc=$2
 }
 
 cancel_lru_locks() {
@@ -3977,6 +4419,13 @@ lru_resize_disable()
     lctl set_param ldlm.namespaces.*$1*.lru_size $(default_lru_size)
 }
 
+flock_is_enabled()
+{
+       local RC=0
+       [ -z "$(mount | grep "$MOUNT.*flock" | grep -v noflock)" ] && RC=1
+       return $RC
+}
+
 pgcache_empty() {
     local FILE
     for FILE in `lctl get_param -N "llite.*.dump_page_cache"`; do
@@ -4066,7 +4515,11 @@ error_noexit() {
        if [ -z "$*" ]; then
                echo "error() without useful message, please fix" > $LOGDIR/err
        else
-               echo "$@" > $LOGDIR/err
+               if [[ `echo $TYPE | grep ^IGNORE` ]]; then
+                       echo "$@" > $LOGDIR/ignore
+               else
+                       echo "$@" > $LOGDIR/err
+               fi
        fi
 }
 
@@ -4089,9 +4542,10 @@ error_exit() {
 
 # use only if we are ignoring failures for this test, bugno required.
 # (like ALWAYS_EXCEPT, but run the test and ignore the results.)
-# e.g. error_ignore 5494 "your message"
+# e.g. error_ignore bz5494 "your message" or
+# error_ignore LU-5494 "your message"
 error_ignore() {
-       local TYPE="IGNORE (bz$1)"
+       local TYPE="IGNORE ($1)"
        shift
        error_noexit "$@"
 }
@@ -4124,10 +4578,16 @@ skip() {
 build_test_filter() {
     EXCEPT="$EXCEPT $(testslist_filter)"
 
-    [ "$ONLY" ] && log "only running test `echo $ONLY`"
-    for O in $ONLY; do
-        eval ONLY_${O}=true
-    done
+       for O in $ONLY; do
+               if [[ $O = [0-9]*-[0-9]* ]]; then
+                       for num in $(seq $(echo $O | tr '-' ' ')); do
+                               eval ONLY_$num=true
+                       done
+               else
+                       eval ONLY_${O}=true
+               fi
+       done
+
     [ "$EXCEPT$ALWAYS_EXCEPT" ] && \
         log "excepting tests: `echo $EXCEPT $ALWAYS_EXCEPT`"
     [ "$EXCEPT_SLOW" ] && \
@@ -4166,64 +4626,64 @@ export ALWAYS_SKIPPED=
 # run or not run.  These need to be documented...
 #
 run_test() {
-    assert_DIR
-
-    export base=`basetest $1`
-    if [ ! -z "$ONLY" ]; then
-        testname=ONLY_$1
-        if [ ${!testname}x != x ]; then
-            [ "$LAST_SKIPPED" ] && echo "" && LAST_SKIPPED=
-            run_one_logged $1 "$2"
-            return $?
-        fi
-        testname=ONLY_$base
-        if [ ${!testname}x != x ]; then
-            [ "$LAST_SKIPPED" ] && echo "" && LAST_SKIPPED=
-            run_one_logged $1 "$2"
-            return $?
-        fi
-        LAST_SKIPPED="y"
-        return 0
-    fi
+       assert_DIR
+
+       export base=$(basetest $1)
+       if [ -n "$ONLY" ]; then
+               testname=ONLY_$1
+               if [ ${!testname}x != x ]; then
+                       [ -n "$LAST_SKIPPED" ] && echo "" && LAST_SKIPPED=
+                       run_one_logged $1 "$2"
+                       return $?
+               fi
+               testname=ONLY_$base
+               if [ ${!testname}x != x ]; then
+                       [ -n "$LAST_SKIPPED" ] && echo "" && LAST_SKIPPED=
+                       run_one_logged $1 "$2"
+                       return $?
+               fi
+               LAST_SKIPPED="y"
+               return 0
+       fi
 
        LAST_SKIPPED="y"
        ALWAYS_SKIPPED="y"
-    testname=EXCEPT_$1
-    if [ ${!testname}x != x ]; then
-        TESTNAME=test_$1 skip "skipping excluded test $1"
-        return 0
-    fi
-    testname=EXCEPT_$base
-    if [ ${!testname}x != x ]; then
-        TESTNAME=test_$1 skip "skipping excluded test $1 (base $base)"
-        return 0
-    fi
-    testname=EXCEPT_ALWAYS_$1
-    if [ ${!testname}x != x ]; then
-        TESTNAME=test_$1 skip "skipping ALWAYS excluded test $1"
-        return 0
-    fi
-    testname=EXCEPT_ALWAYS_$base
-    if [ ${!testname}x != x ]; then
-        TESTNAME=test_$1 skip "skipping ALWAYS excluded test $1 (base $base)"
-        return 0
-    fi
-    testname=EXCEPT_SLOW_$1
-    if [ ${!testname}x != x ]; then
-        TESTNAME=test_$1 skip "skipping SLOW test $1"
-        return 0
-    fi
-    testname=EXCEPT_SLOW_$base
-    if [ ${!testname}x != x ]; then
-        TESTNAME=test_$1 skip "skipping SLOW test $1 (base $base)"
-        return 0
-    fi
+       testname=EXCEPT_$1
+       if [ ${!testname}x != x ]; then
+               TESTNAME=test_$1 skip "skipping excluded test $1"
+               return 0
+       fi
+       testname=EXCEPT_$base
+       if [ ${!testname}x != x ]; then
+               TESTNAME=test_$1 skip "skipping excluded test $1 (base $base)"
+               return 0
+       fi
+       testname=EXCEPT_ALWAYS_$1
+       if [ ${!testname}x != x ]; then
+               TESTNAME=test_$1 skip "skipping ALWAYS excluded test $1"
+               return 0
+       fi
+       testname=EXCEPT_ALWAYS_$base
+       if [ ${!testname}x != x ]; then
+               TESTNAME=test_$1 skip "skipping ALWAYS excluded test $1 (base $base)"
+               return 0
+       fi
+       testname=EXCEPT_SLOW_$1
+       if [ ${!testname}x != x ]; then
+               TESTNAME=test_$1 skip "skipping SLOW test $1"
+               return 0
+       fi
+       testname=EXCEPT_SLOW_$base
+       if [ ${!testname}x != x ]; then
+               TESTNAME=test_$1 skip "skipping SLOW test $1 (base $base)"
+               return 0
+       fi
 
-    LAST_SKIPPED=
-    ALWAYS_SKIPPED=
-    run_one_logged $1 "$2"
+       LAST_SKIPPED=
+       ALWAYS_SKIPPED=
+       run_one_logged $1 "$2"
 
-    return $?
+       return $?
 }
 
 log() {
@@ -4303,34 +4763,35 @@ banner() {
 }
 
 #
-# Run a single test function and cleanup after it.  
+# Run a single test function and cleanup after it.
 #
 # This function should be run in a subshell so the test func can
 # exit() without stopping the whole script.
 #
 run_one() {
-    local testnum=$1
-    local message=$2
-    tfile=f.${TESTSUITE}.${testnum}
-    export tdir=d0.${TESTSUITE}/d${base}
-    export TESTNAME=test_$testnum
-    local SAVE_UMASK=`umask`
-    umask 0022
-
-    banner "test $testnum: $message"
-    test_${testnum} || error "test_$testnum failed with $?"
-    cd $SAVE_PWD
-    reset_fail_loc
-    check_grant ${testnum} || error "check_grant $testnum failed with $?"
-    check_catastrophe || error "LBUG/LASSERT detected"
+       local testnum=$1
+       local message=$2
+       export tfile=f${testnum}.${TESTSUITE}
+       export tdir=d${testnum}.${TESTSUITE}
+       export TESTNAME=test_$testnum
+       local SAVE_UMASK=`umask`
+       umask 0022
+
+       banner "test $testnum: $message"
+       test_${testnum} || error "test_$testnum failed with $?"
+       cd $SAVE_PWD
+       reset_fail_loc
+       check_grant ${testnum} || error "check_grant $testnum failed with $?"
+       check_catastrophe || error "LBUG/LASSERT detected"
        if [ "$PARALLEL" != "yes" ]; then
                ps auxww | grep -v grep | grep -q multiop &&
                                        error "multiop still running"
        fi
-    unset TESTNAME
-    unset tdir
-    umask $SAVE_UMASK
-    return 0
+       unset TESTNAME
+       unset tdir
+       unset tfile
+       umask $SAVE_UMASK
+       return 0
 }
 
 #
@@ -4340,13 +4801,14 @@ run_one() {
 #  - test result is saved to data file
 #
 run_one_logged() {
-       local BEFORE=`date +%s`
+       local BEFORE=$(date +%s)
        local TEST_ERROR
        local name=${TESTSUITE}.test_${1}.test_log.$(hostname -s).log
        local test_log=$LOGDIR/$name
        rm -rf $LOGDIR/err
+       rm -rf $LOGDIR/ignore
        rm -rf $LOGDIR/skip
-       local SAVE_UMASK=`umask`
+       local SAVE_UMASK=$(umask)
        umask 0022
 
        echo
@@ -4354,19 +4816,25 @@ run_one_logged() {
        (run_one $1 "$2") 2>&1 | tee -i $test_log
        local RC=${PIPESTATUS[0]}
 
-       [ $RC -ne 0 ] && [ ! -f $LOGDIR/err ] && \
+       [ $RC -ne 0 ] && [ ! -f $LOGDIR/err ] &&
                echo "test_$1 returned $RC" | tee $LOGDIR/err
 
-       duration=$((`date +%s` - $BEFORE))
+       duration=$(($(date +%s) - $BEFORE))
        pass "$1" "(${duration}s)"
 
        if [[ -f $LOGDIR/err ]]; then
                TEST_ERROR=$(cat $LOGDIR/err)
+       elif [[ -f $LOGDIR/ignore ]]; then
+               TEST_ERROR=$(cat $LOGDIR/ignore)
        elif [[ -f $LOGDIR/skip ]]; then
                TEST_ERROR=$(cat $LOGDIR/skip)
        fi
        log_sub_test_end $TEST_STATUS $duration "$RC" "$TEST_ERROR"
 
+       if [[ "$TEST_STATUS" != "SKIP" ]] && [[ -f $TF_SKIP ]]; then
+               rm -f $TF_SKIP
+       fi
+
        if [ -f $LOGDIR/err ]; then
                $FAIL_ON_ERROR && exit $RC
        fi
@@ -4386,46 +4854,45 @@ skip_logged(){
 }
 
 canonical_path() {
-    (cd `dirname $1`; echo $PWD/`basename $1`)
+       (cd $(dirname $1); echo $PWD/$(basename $1))
 }
 
 
 check_grant() {
-    export base=`basetest $1`
-    [ "$CHECK_GRANT" == "no" ] && return 0
+       export base=$(basetest $1)
+       [ "$CHECK_GRANT" == "no" ] && return 0
 
-        testname=GCHECK_ONLY_${base}
-        [ ${!testname}x == x ] && return 0
+       testname=GCHECK_ONLY_${base}
+       [ ${!testname}x == x ] && return 0
 
-    echo -n "checking grant......"
+       echo -n "checking grant......"
 
-        local clients=$CLIENTS
-        [ -z $clients ] && clients=$(hostname)
+       local clients=$CLIENTS
+       [ -z "$clients" ] && clients=$(hostname)
 
-    # sync all the data and make sure no pending data on server
-    do_nodes $clients sync
-
-    # get client grant
-    client_grant=`do_nodes $clients \
-                    "$LCTL get_param -n osc.${FSNAME}-*.cur_*grant_bytes" | \
-                    awk '{total += $1} END{print total}'`
-
-    # get server grant
-    server_grant=`do_nodes $(comma_list $(osts_nodes)) \
-                    "$LCTL get_param -n obdfilter.${FSNAME}-OST*.tot_granted" |
-                    awk '{total += $1} END{print total}'`
-
-    # check whether client grant == server grant
-    if [ $client_grant -ne $server_grant ]; then
-        echo "failed: client:${client_grant} server: ${server_grant}."
-        do_nodes $(comma_list $(osts_nodes)) \
-                   "$LCTL get_param obdfilter.${FSNAME}-OST*.tot*"
-        do_nodes $clients "$LCTL get_param osc.${FSNAME}-*.cur_*_bytes"
-        return 1
-    else
-        echo "pass: client:${client_grant} server: ${server_grant}"
-    fi
+       # sync all the data and make sure no pending data on server
+       do_nodes $clients sync
 
+       # get client grant
+       client_grant=$(do_nodes $clients \
+               "$LCTL get_param -n osc.${FSNAME}-*.cur_*grant_bytes" |
+               awk '{ total += $1 } END { printf("%0.0f", total) }')
+
+       # get server grant
+       server_grant=$(do_nodes $(comma_list $(osts_nodes)) \
+               "$LCTL get_param -n obdfilter.${FSNAME}-OST*.tot_granted" |
+               awk '{ total += $1 } END { printf("%0.0f", total) }')
+
+       # check whether client grant == server grant
+       if [[ $client_grant -ne $server_grant ]]; then
+               echo "failed: client:${client_grant} server: ${server_grant}."
+               do_nodes $(comma_list $(osts_nodes)) \
+                       "$LCTL get_param obdfilter.${FSNAME}-OST*.tot*"
+               do_nodes $clients "$LCTL get_param osc.${FSNAME}-*.cur_*_bytes"
+               return 1
+       else
+               echo "pass: client:${client_grant} server: ${server_grant}"
+       fi
 }
 
 ########################
@@ -4589,6 +5056,11 @@ osts_nodes () {
        echo -n $(facets_nodes $(get_facets OST))
 }
 
+# Get all of the active AGT (HSM agent) nodes.
+agts_nodes () {
+       echo -n $(facets_nodes $(get_facets AGT))
+}
+
 # Get all of the client nodes and active server nodes.
 nodes_list () {
        local nodes=$HOSTNAME
@@ -4762,14 +5234,14 @@ get_stripe () {
 }
 
 setstripe_nfsserver () {
-    local dir=$1
+       local dir=$1
 
-    local nfsserver=$(awk '"'$dir'" ~ $2 && $3 ~ "nfs" && $2 != "/" \
-                { print $1 }' /proc/mounts | cut -f 1 -d : | head -1)
+       local nfsserver=$(awk '"'$dir'" ~ $2 && $3 ~ "nfs" && $2 != "/" \
+               { print $1 }' /proc/mounts | cut -f 1 -d : | head -n1)
 
-    [ -z $nfsserver ] && echo "$dir is not nfs mounted" && return 1
+       [ -z $nfsserver ] && echo "$dir is not nfs mounted" && return 1
 
-    do_nodev $nfsserver lfs setstripe "$@"
+       do_nodev $nfsserver lfs setstripe "$@"
 }
 
 # Check and add a test group.
@@ -4925,7 +5397,7 @@ do_and_time () {
 
     SECONDS=0
     eval '$cmd'
-    
+
     [ ${PIPESTATUS[0]} -eq 0 ] || rc=1
 
     echo $SECONDS
@@ -4933,8 +5405,9 @@ do_and_time () {
 }
 
 inodes_available () {
-    local IFree=$($LFS df -i $MOUNT | grep ^$FSNAME | awk '{print $4}' | sort -un | head -1) || return 1
-    echo $IFree
+       local IFree=$($LFS df -i $MOUNT | grep ^$FSNAME | awk '{ print $4 }' |
+               sort -un | head -n1) || return 1
+       echo $((IFree))
 }
 
 mdsrate_inodes_available () {
@@ -4949,25 +5422,25 @@ clear_llite_stats(){
 
 # sum llite stat items
 calc_llite_stats() {
-        local res=$(lctl get_param -n llite.*.stats |
-                    awk 'BEGIN {s = 0} END {print s} /^'"$1"'/ {s += $2}')
-        echo $res
+       local res=$(lctl get_param -n llite.*.stats |
+               awk '/^'"$1"'/ {sum += $2} END { printf("%0.0f", sum) }')
+       echo $((res))
 }
 
 # reset osc stat counters
 clear_osc_stats(){
-        lctl set_param -n osc.*.osc_stats 0
+       lctl set_param -n osc.*.osc_stats 0
 }
 
 # sum osc stat items
 calc_osc_stats() {
-        local res=$(lctl get_param -n osc.*.osc_stats |
-                    awk 'BEGIN {s = 0} END {print s} /^'"$1"'/ {s += $2}')
-        echo $res
+       local res=$(lctl get_param -n osc.*.osc_stats |
+               awk '/^'"$1"'/ {sum += $2} END { printf("%0.0f", sum) }')
+       echo $((res))
 }
 
 calc_sum () {
-        awk 'BEGIN {s = 0}; {s += $1}; END {print s}'
+       awk '{sum += $1} END { printf("%0.0f", sum) }'
 }
 
 calc_osc_kbytes () {
@@ -5053,7 +5526,7 @@ get_mds_dir () {
 
 mdsrate_cleanup () {
        if [ -d $4 ]; then
-               mpi_run -np $1 ${MACHINEFILE_OPTION} $2 ${MDSRATE} --unlink \
+               mpi_run ${MACHINEFILE_OPTION} $2 -np $1 ${MDSRATE} --unlink \
                        --nfiles $3 --dir $4 --filefmt $5 $6
                rmdir $4
        fi
@@ -5066,7 +5539,7 @@ delayed_recovery_enabled () {
 
 ########################
 
-convert_facet2label() { 
+convert_facet2label() {
     local facet=$1
 
     if [ x$facet = xost ]; then
@@ -5077,7 +5550,7 @@ convert_facet2label() {
 
     if [ -n ${!varsvc} ]; then
         echo ${!varsvc}
-    else  
+    else
         error "No lablel for $facet!"
     fi
 }
@@ -5229,39 +5702,34 @@ request_timeout () {
 }
 
 _wait_osc_import_state() {
-    local facet=$1
-    local ost_facet=$2
-    local expected=$3
-    local ost=$(get_osc_import_name $facet $ost_facet)
-
+       local facet=$1
+       local ost_facet=$2
+       local expected=$3
+       local ost=$(get_osc_import_name $facet $ost_facet)
        local param="osc.${ost}.ost_server_uuid"
+       local params=$param
        local i=0
 
-    # 1. wait the deadline of client 1st request (it could be skipped)
-    # 2. wait the deadline of client 2nd request
-    local maxtime=$(( 2 * $(request_timeout $facet)))
-
-       #During setup time, the osc might not be setup, it need wait
-       #until list_param can return valid value. And also if there
-       #are mulitple osc entries we should list all of them before
-       #go to wait.
-       local params=$($LCTL list_param $param 2>/dev/null || true)
-       while [ -z "$params" ]; do
-               if [ $i -ge $maxtime ]; then
-                       echo "can't get $param by list_param in $maxtime secs"
-                       if [[ $facet != client* ]]; then
-                               echo "Go with $param directly"
-                               params=$param
-                               break
-                       else
+       # 1. wait the deadline of client 1st request (it could be skipped)
+       # 2. wait the deadline of client 2nd request
+       local maxtime=$(( 2 * $(request_timeout $facet)))
+
+       if [[ $facet == client* ]]; then
+               # During setup time, the osc might not be setup, it need wait
+               # until list_param can return valid value. And also if there
+               # are mulitple osc entries we should list all of them before
+               # go to wait.
+               params=$($LCTL list_param $param 2>/dev/null || true)
+               while [ -z "$params" ]; do
+                       if [ $i -ge $maxtime ]; then
+                               echo "can't get $param in $maxtime secs"
                                return 1
                        fi
-               fi
-               sleep 1
-               i=$((i + 1))
-               params=$($LCTL list_param $param 2>/dev/null || true)
-       done
-
+                       sleep 1
+                       i=$((i + 1))
+                       params=$($LCTL list_param $param 2>/dev/null || true)
+               done
+       fi
        if ! do_rpc_nodes "$(facet_active_host $facet)" \
                        wait_import_state $expected "$params" $maxtime; then
                error "import is not in ${expected} state"
@@ -5837,19 +6305,20 @@ check_logdir() {
 }
 
 check_write_access() {
-    local dir=$1
-    local node
-    local file
+       local dir=$1
+       local list=${2:-$(comma_list $(nodes_list))}
+       local node
+       local file
 
-    for node in $(nodes_list); do
-        file=$dir/check_file.$(short_hostname $node)
-        if [[ ! -f "$file" ]]; then
-            # Logdir not accessible/writable from this node.
-            return 1
-        fi
-        rm -f $file || return 1
-    done
-    return 0
+       for node in ${list//,/ }; do
+               file=$dir/check_file.$(short_nodename $node)
+               if [[ ! -f "$file" ]]; then
+                       # Logdir not accessible/writable from this node.
+                       return 1
+               fi
+               rm -f $file || return 1
+       done
+       return 0
 }
 
 init_logging() {
@@ -5946,7 +6415,7 @@ remove_ost_objects() {
        fi
        mount -t $(facet_fstype $facet) $opts $ostdev $mntpt ||
                return $?
-       rc=0;
+       rc=0
        for i in $objids; do
                rm $mntpt/O/$group/d$((i % 32))/$i || { rc=$?; break; }
        done
@@ -5970,7 +6439,7 @@ remove_mdt_files() {
        fi
        mount -t $(facet_fstype $facet) $opts $mdtdev $mntpt ||
                return $?
-       rc=0;
+       rc=0
        for f in $files; do
                rm $mntpt/ROOT/$f || { rc=$?; break; }
        done
@@ -6058,6 +6527,45 @@ min_ost_size () {
     $LCTL get_param -n osc.*.kbytesavail | sort -n | head -n1
 }
 
+#
+# Get the available size (KB) of a given obd target.
+#
+get_obd_size() {
+       local facet=$1
+       local obd=$2
+       local size
+
+       [[ $facet != client ]] || return 0
+
+       size=$(do_facet $facet $LCTL get_param -n *.$obd.kbytesavail | head -n1)
+       echo -n $size
+}
+
+#
+# Get the page size (bytes) on a given facet node.
+#
+get_page_size() {
+       local facet=$1
+       local size
+
+       size=$(do_facet $facet getconf PAGE_SIZE)
+       [[ ${PIPESTATUS[0]} = 0 && -n "$size" ]] || size=4096
+       echo -n $size
+}
+
+#
+# Get the block count of the filesystem.
+#
+get_block_count() {
+       local facet=$1
+       local device=$2
+       local count
+
+       count=$(do_facet $facet "$DUMPE2FS -h $device 2>&1" |
+               awk '/^Block count:/ {print $3}')
+       echo -n $count
+}
+
 # Get the block size of the filesystem.
 get_block_size() {
     local facet=$1
@@ -6075,7 +6583,8 @@ large_xattr_enabled() {
 
        local mds_dev=$(mdsdevname ${SINGLEMDS//mds/})
 
-       do_facet $SINGLEMDS "$DUMPE2FS -h $mds_dev 2>&1 | grep -q large_xattr"
+       do_facet $SINGLEMDS "$DUMPE2FS -h $mds_dev 2>&1 |
+               grep -E -q '(ea_inode|large_xattr)'"
        return ${PIPESTATUS[0]}
 }
 
@@ -6114,30 +6623,33 @@ generate_string() {
 }
 
 reformat_external_journal() {
+       local facet=$1
+
        if [ ! -z ${EJOURNAL} ]; then
-               local rcmd="do_facet ${SINGLEMDS}"
+               local rcmd="do_facet $facet"
 
-               echo "reformat external journal on ${SINGLEMDS}:${EJOURNAL}"
+               echo "reformat external journal on $facet:${EJOURNAL}"
                ${rcmd} mke2fs -O journal_dev ${EJOURNAL} || return 1
        fi
 }
 
 # MDT file-level backup/restore
 mds_backup_restore() {
-       local devname=$(mdsdevname ${SINGLEMDS//mds/})
+       local facet=$1
+       local igif=$2
+       local devname=$(mdsdevname $(facet_number $facet))
        local mntpt=$(facet_mntpt brpt)
-       local rcmd="do_facet ${SINGLEMDS}"
+       local rcmd="do_facet $facet"
        local metaea=${TMP}/backup_restore.ea
        local metadata=${TMP}/backup_restore.tgz
        local opts=${MDS_MOUNT_OPTS}
-       local svc=${SINGLEMDS}_svc
-       local igif=$1
+       local svc=${facet}_svc
 
        if ! ${rcmd} test -b ${devname}; then
                opts=$(csa_add "$opts" -o loop)
        fi
 
-       echo "file-level backup/restore on ${SINGLEMDS}:${devname}"
+       echo "file-level backup/restore on $facet:${devname}"
 
        # step 1: build mount point
        ${rcmd} mkdir -p $mntpt
@@ -6159,12 +6671,12 @@ mds_backup_restore() {
        # step 6: umount
        ${rcmd} umount -d $mntpt || return 4
        # step 7: reformat external journal if needed
-       reformat_external_journal || return 5
+       reformat_external_journal $facet || return 5
        # step 8: reformat dev
        echo "reformat new device"
-       add ${SINGLEMDS} $(mkfs_opts ${SINGLEMDS} ${devname}) --backfstype \
-               ldiskfs --reformat ${devname} $(mdsvdevname 1) > /dev/null ||
-               exit 6
+       add $facet $(mkfs_opts $facet ${devname}) --backfstype ldiskfs \
+               --reformat ${devname} $(mdsvdevname $(facet_number $facet)) \
+               > /dev/null || exit 6
        # step 9: mount dev
        ${rcmd} mount -t ldiskfs $opts $devname $mntpt || return 7
        # step 10: restore metadata
@@ -6186,17 +6698,18 @@ mds_backup_restore() {
 
 # remove OI files
 mds_remove_ois() {
-       local devname=$(mdsdevname ${SINGLEMDS//mds/})
+       local facet=$1
+       local idx=$2
+       local devname=$(mdsdevname $(facet_number $facet))
        local mntpt=$(facet_mntpt brpt)
-       local rcmd="do_facet ${SINGLEMDS}"
-       local idx=$1
+       local rcmd="do_facet $facet"
        local opts=${MDS_MOUNT_OPTS}
 
        if ! ${rcmd} test -b ${devname}; then
                opts=$(csa_add "$opts" -o loop)
        fi
 
-       echo "remove OI files: idx=${idx}"
+       echo "removing OI files on $facet: idx=${idx}"
 
        # step 1: build mount point
        ${rcmd} mkdir -p $mntpt
@@ -6234,24 +6747,41 @@ test_mkdir() {
        local parent
        local child
        local path
+       local p_option
+       local option2
+       local stripe_count=2
        local rc=0
 
        case $# in
                1) path=$1;;
                2) option=$1
                   path=$2;;
+               3) option=$1
+                  option2=$2
+                  path=$3;;
                *) error "Only creating single directory is supported";;
        esac
 
        child=$(basename $path)
        parent=$(dirname $path)
 
-       if [ "$option" == "-p" -a -d $parent/$child ]; then
-               return $rc
+       if [ "$option" == "-p" -o "$option2" == "-p" ]; then
+               if [ -d $parent/$child ]; then
+                       return $rc
+               fi
+               p_option="-p"
+       fi
+
+       if [ "${option:0:2}" == "-c" ]; then
+               stripe_count=$(echo $option | sed 's/^-c//')
+       fi
+
+       if [ "${option2:0:2}" == "-c" ]; then
+               stripe_count=$(echo $option2 | sed 's/^-c//')
        fi
 
        if [ ! -d ${parent} ]; then
-               if [ "$option" == "-p" ]; then
+               if [ "$p_option" == "-p" ]; then
                        mkdir -p ${parent}
                else
                        return 1
@@ -6259,18 +6789,50 @@ test_mkdir() {
        fi
 
        if [ $MDSCOUNT -le 1 ]; then
-               mkdir $option $parent/$child || rc=$?
+               mkdir $p_option $parent/$child || rc=$?
        else
                local mdt_idx=$($LFS getstripe -M $parent)
                local test_num=$(echo $testnum | sed -e 's/[^0-9]*//g')
 
-               if [ "$mdt_idx" -ne 0 ]; then
-                       mkdir $option $parent/$child || rc=$?
-               else
-                       mdt_idx=$((test_num % MDSCOUNT))
-                       echo "mkdir $mdt_idx for $parent/$child"
-                       $LFS setdirstripe -i $mdt_idx $parent/$child || rc=$?
-               fi
+               mdt_idx=$((test_num % MDSCOUNT))
+               echo "striped dir -i$mdt_idx -c$stripe_count $path"
+               $LFS setdirstripe -i$mdt_idx -c$stripe_count $path || rc=$?
        fi
        return $rc
 }
+
+# find the smallest and not in use file descriptor
+free_fd()
+{
+        local max_fd=$(ulimit -n)
+        local fd=3
+        while [[ $fd -le $max_fd && -e /proc/self/fd/$fd ]]; do
+                ((++fd))
+        done
+        [ $fd -lt $max_fd ] || error "finding free file descriptor failed"
+        echo $fd
+}
+
+check_mount_and_prep()
+{
+       is_mounted $MOUNT || setupall
+
+       rm -rf $DIR/[df][0-9]* || error "Fail to cleanup the env!"
+       mkdir $DIR/$tdir || error "Fail to mkdir $DIR/$tdir."
+}
+
+# calcule how many ost-objects to be created.
+precreated_ost_obj_count()
+{
+       local mdt_idx=$1
+       local ost_idx=$2
+       local mdt_name="MDT$(printf '%04x' $mdt_idx)"
+       local ost_name="OST$(printf '%04x' $ost_idx)"
+       local proc_path="${FSNAME}-${ost_name}-osc-${mdt_name}"
+       local last_id=$(do_facet mds${mdt_idx} lctl get_param -n \
+                       osp.$proc_path.prealloc_last_id)
+       local next_id=$(do_facet mds${mdt_idx} lctl get_param -n \
+                       osp.$proc_path.prealloc_next_id)
+
+       echo $((last_id - next_id + 1))
+}