X-Git-Url: https://git.whamcloud.com/?p=fs%2Flustre-release.git;a=blobdiff_plain;f=lustre%2Ftests%2Ftest-framework.sh;h=40239de3d73f3dc2ea5c6a2584b5254a1a27bd57;hp=f1d54fb541116e5b68088106771ac3f95fce4ac6;hb=979203503af2f77d51bcf27375a1a09f5f28a4a3;hpb=8d8f071648d64f8a16591481064e13f590629caa diff --git a/lustre/tests/test-framework.sh b/lustre/tests/test-framework.sh old mode 100644 new mode 100755 index f1d54fb..40239de --- a/lustre/tests/test-framework.sh +++ b/lustre/tests/test-framework.sh @@ -5,11 +5,11 @@ trap 'print_summary && touch $TF_FAIL && \ set -e #set -x +export LANG=en_US export EJOURNAL=${EJOURNAL:-""} export REFORMAT=${REFORMAT:-""} export WRITECONF=${WRITECONF:-""} export VERBOSE=${VERBOSE:-false} -export CATASTROPHE=${CATASTROPHE:-/proc/sys/lnet/catastrophe} export GSS=false export GSS_KRB5=false export GSS_PIPEFS=false @@ -23,6 +23,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 +90,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 +184,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 @@ -210,6 +225,7 @@ init_test_env() { [ ! -f "$LST" ] && export LST=$(which lst) export SGPDDSURVEY=${SGPDDSURVEY:-"$LUSTRE/../lustre-iokit/sgpdd-survey/sgpdd-survey")} [ ! -f "$SGPDDSURVEY" ] && export SGPDDSURVEY=$(which sgpdd-survey) + export MCREATE=${MCREATE:-mcreate} # Ubuntu, at least, has a truncate command in /usr/bin # so fully path our truncate command. export TRUNCATE=${TRUNCATE:-$LUSTRE/tests/truncate} @@ -291,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 @@ -344,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 () { @@ -475,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 @@ -498,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 @@ -519,20 +531,37 @@ 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 + local sbin_mount=/sbin/mount.lustre + if grep -qe "$sbin_mount " /proc/mounts; then + cmp $mount_lustre $sbin_mount || umount $sbin_mount + fi + if ! grep -qe "$sbin_mount " /proc/mounts; then + [ ! -f "$sbin_mount" ] && touch "$sbin_mount" + if [ ! -s "$sbin_mount" -a -w "$sbin_mount" ]; then + cat <<- EOF > "$sbin_mount" + #!/bin/sh + #STUB MARK + echo "This $sbin_mount just a mountpoint." 1>&2 + echo "It is never supposed to be run." 1>&2 + logger -p emerg -- "using stub $sbin_mount $@" + exit 1 + EOF + chmod a+x $sbin_mount + fi + mount --bind $mount_lustre $sbin_mount || + error "can't bind $mount_lustre to $sbin_mount" + fi + fi } load_modules () { @@ -576,16 +605,17 @@ unload_modules() { fi fi - if grep -qe "/sbin/mount\.lustre" /proc/mounts; then - umount /sbin/mount.lustre || true - [ -w /sbin/mount.lustre -a ! -s /sbin/mount.lustre ] && \ - rm -f /sbin/mount.lustre || true - fi + local sbin_mount=/sbin/mount.lustre + if grep -qe "$sbin_mount " /proc/mounts; then + umount $sbin_mount || true + [ -s $sbin_mount ] && ! grep -q "STUB MARK" $sbin_mount || + rm -f $sbin_mount + fi - check_mem_leak || return 254 + check_mem_leak || return 254 - echo "modules unloaded." - return 0 + echo "modules unloaded." + return 0 } fs_log_size() { @@ -643,7 +673,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 @@ -680,7 +709,7 @@ start_gss_daemons() { stop_gss_daemons() { local list=$(comma_list $(mdts_nodes)) - + send_sigint $list lsvcgssd lgssd list=$(comma_list $(osts_nodes)) @@ -697,10 +726,13 @@ 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 + lctl set_param -n \ + sptlrpc.gss.lgss_keyring.debug_level=$LGSS_KEYRING_DEBUG fi fi } @@ -784,6 +816,25 @@ node_fstypes() { echo -n $fstypes } +facet_index() { + local facet=$1 + local num=$(facet_number $facet) + local index + + if [[ $(facet_type $facet) = OST ]]; then + index=OSTINDEX${num} + if [[ -n "${!index}" ]]; then + echo -n ${!index} + return + fi + + index=${OST_INDICES[num - 1]} + fi + + [[ -n "$index" ]] || index=$((num - 1)) + echo -n $index +} + devicelabel() { local facet=$1 local dev=$2 @@ -895,6 +946,33 @@ zpool_name() { } # +# 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. # @@ -914,6 +992,22 @@ export_zpool() { } # +# 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. # @@ -1089,7 +1183,7 @@ mount_facet() { 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 @@ -1122,12 +1216,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 + local mntpt=$(facet_mntpt $facet) + do_facet ${facet} mkdir -p $mntpt + eval export ${facet}_MOUNT=$mntpt + mount_facet ${facet} + RC=$? + + if [[ $facet == mds* ]]; then + do_facet $facet \ + lctl set_param -n mdt.${FSNAME}*.enable_remote_dir=1 \ + 2>/dev/null + fi + + return $RC } stop() { @@ -1191,7 +1292,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), @@ -1297,6 +1398,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 @@ -1353,17 +1471,19 @@ setup_quota(){ zconf_mount() { local client=$1 local mnt=$2 - local OPTIONS=${3:-$MOUNTOPT} + local opts=${3:-$MOUNT_OPTS} + opts=${opts:+-o $opts} + local flags=${4:-$MOUNT_FLAGS} local device=$MGSNID:/$FSNAME if [ -z "$mnt" -o -z "$FSNAME" ]; then - echo Bad zconf mount command: opt=$OPTIONS dev=$device mnt=$mnt + echo Bad zconf mount command: opt=$flags $opts dev=$device mnt=$mnt exit 1 fi - echo "Starting client: $client: $OPTIONS $device $mnt" + echo "Starting client: $client: $flags $opts $device $mnt" do_node $client mkdir -p $mnt - do_node $client mount -t lustre $OPTIONS $device $mnt || return 1 + do_node $client $MOUNT_CMD $flags $opts $device $mnt || return 1 set_default_debug_nodes $client @@ -1459,22 +1579,24 @@ sanity_mount_check () { zconf_mount_clients() { local clients=$1 local mnt=$2 - local OPTIONS=${3:-$MOUNTOPT} + local opts=${3:-$MOUNT_OPTS} + opts=${opts:+-o $opts} + local flags=${4:-$MOUNT_FLAGS} local device=$MGSNID:/$FSNAME if [ -z "$mnt" -o -z "$FSNAME" ]; then - echo Bad zconf mount command: opt=$OPTIONS dev=$device mnt=$mnt + echo Bad zconf mount command: opt=$flags $opts dev=$device mnt=$mnt exit 1 fi - echo "Starting client $clients: $OPTIONS $device $mnt" + echo "Starting client $clients: $flags $opts $device $mnt" do_nodes $clients " running=\\\$(mount | grep -c $mnt' '); rc=0; if [ \\\$running -eq 0 ] ; then mkdir -p $mnt; - mount -t lustre $OPTIONS $device $mnt; + $MOUNT_CMD $flags $opts $device $mnt; rc=\\\$?; fi; exit \\\$rc" || return ${PIPESTATUS[0]} @@ -1564,7 +1686,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 () { @@ -1857,18 +1979,22 @@ 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 + VAR=$(lctl get_param -n catastrophe 2>&1) + if [ $? = 0 ] ; then + if [ $VAR != 0 ]; then + error "LBUG/LASSERT detected" + fi + fi + 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 @@ -1897,6 +2023,7 @@ wait_update () { local sleep=1 local print=10 + PREV_RESULT=$(do_node $node "$TEST") while [ true ]; do RESULT=$(do_node $node "$TEST") if [[ "$RESULT" == "$FINAL" ]]; then @@ -1937,39 +2064,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 @@ -1977,9 +2104,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() { @@ -2051,6 +2178,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)) @@ -2063,7 +2191,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 @@ -2079,10 +2209,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 } @@ -2196,7 +2329,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 @@ -2209,6 +2342,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 @@ -2404,42 +2545,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 @@ -2540,7 +2682,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 @@ -2708,7 +2854,7 @@ get_env_vars() { local facet for var in ${!MODOPTS_*}; do - value=${!var} + value=${!var//\"/\\\"} echo -n " ${var}=\"$value\"" done @@ -2826,9 +2972,10 @@ add() { fi } +# Device formatted as ost ostdevname() { - num=$1 - DEVNAME=OSTDEV$num + local num=$1 + local DEVNAME=OSTDEV$num local fstype=$(facet_fstype ost$num) @@ -2837,8 +2984,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 @@ -2846,9 +2994,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) @@ -2857,7 +3007,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!";; @@ -2866,19 +3018,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 @@ -2886,10 +3040,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 @@ -2897,7 +3051,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!";; @@ -2920,10 +3076,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!";; @@ -2933,8 +3090,7 @@ mgsdevname() { } mgsvdevname() { - local VDEVPTR - DEVNAME=MGSDEV + local VDEVPTR="" local fstype=$(facet_fstype mgs) @@ -2944,9 +3100,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;; * ) @@ -2966,6 +3123,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 @@ -3042,7 +3277,7 @@ mkfs_opts() { local dev=$2 local fsname=${3:-"$FSNAME"} local type=$(facet_type $facet) - local index=$(($(facet_number $facet) - 1)) + local index=$(facet_index $facet) local fstype=$(facet_fstype $facet) local host=$(facet_host $facet) local opts @@ -3082,6 +3317,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"} @@ -3122,6 +3363,24 @@ mkfs_opts() { echo -n "$opts" } +check_ost_indices() { + local index_count=${#OST_INDICES[@]} + [[ $index_count -eq 0 || $OSTCOUNT -le $index_count ]] && return 0 + + # OST count is greater than the index count in $OST_INDEX_LIST. + # We need check whether there are duplicate indices. + local i + local j + local index + for i in $(seq $((index_count + 1)) $OSTCOUNT); do + index=$(facet_index ost$i) + for j in $(seq 0 $((index_count - 1))); do + [[ $index -ne ${OST_INDICES[j]} ]] || + error "ost$i has the same index $index as ost$((j+1))" + done + done +} + formatall() { local quiet @@ -3148,6 +3407,8 @@ formatall() { ${quiet:+>/dev/null} || exit 10 done + export OST_INDICES=($(hostlist_expand "$OST_INDEX_LIST")) + check_ost_indices for num in $(seq $OSTCOUNT); do echo "Format ost$num: $(ostdevname $num)" add ost$num $(mkfs_opts ost$num $(ostdevname ${num})) \ @@ -3645,7 +3906,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 \ @@ -3658,6 +3925,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 @@ -3671,10 +3945,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() { @@ -3698,8 +3972,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 @@ -3712,33 +3985,69 @@ 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. @@ -3754,22 +4063,23 @@ check_shared_dir() { # 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 @@ -3799,7 +4109,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 || @@ -3835,6 +4145,60 @@ run_lfsck() { return $rc } +dump_file_contents() { + local nodes=$1 + local dir=$2 + local logname=$3 + local node + + if [ -z "$nodes" -o -z "$dir" -o -z "$logname" ]; then + error_noexit false \ + "Invalid parameters for dump_file_contents()" + return 1 + fi + for node in ${nodes}; do + do_node $node "for i in \\\$(find $dir -type f); do + echo ====\\\${i}=======================; + cat \\\${i}; + done" >> ${logname}.${node}.log + done +} + +dump_command_output() { + local nodes=$1 + local cmd=$2 + local logname=$3 + local node + + if [ -z "$nodes" -o -z "$cmd" -o -z "$logname" ]; then + error_noexit false \ + "Invalid parameters for dump_command_output()" + return 1 + fi + + for node in ${nodes}; do + do_node $node "echo ====${cmd}=======================; + $cmd" >> ${logname}.${node}.log + done +} + +log_zfs_info() { + local logname=$1 + + # dump file contents from /proc/spl in case of zfs test + if [ "$(facet_fstype ost1)" = "zfs" ]; then + dump_file_contents "$(osts_nodes)" "/proc/spl" "${logname}" + dump_command_output \ + "$(osts_nodes)" "zpool events -v" "${logname}" + fi + + if [ "$(facet_fstype $SINGLEMDS)" = "zfs" ]; then + dump_file_contents "$(mdts_nodes)" "/proc/spl" "${logname}" + dump_command_output \ + "$(mdts_nodes)" "zpool events -v" "${logname}" + fi +} + check_and_cleanup_lustre() { if [ "$LFSCK_ALWAYS" = "yes" -a "$TESTSUITE" != "lfsck" ]; then get_svr_devs @@ -3848,18 +4212,18 @@ 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 } ####### @@ -4057,20 +4421,20 @@ drop_request() { drop_reply() { # OBD_FAIL_MDS_ALL_REPLY_NET - RC=0 - do_facet $SINGLEMDS lctl set_param fail_loc=0x122 - do_facet client "$@" || RC=$? - do_facet $SINGLEMDS lctl set_param fail_loc=0 - return $RC + RC=0 + do_facet $SINGLEMDS $LCTL set_param fail_loc=0x122 + eval "$@" || RC=$? + do_facet $SINGLEMDS $LCTL set_param fail_loc=0 + return $RC } drop_reint_reply() { # OBD_FAIL_MDS_REINT_NET_REP - RC=0 - do_facet $SINGLEMDS lctl set_param fail_loc=0x119 - do_facet client "$@" || RC=$? - do_facet $SINGLEMDS lctl set_param fail_loc=0 - return $RC + RC=0 + do_facet $SINGLEMDS $LCTL set_param fail_loc=0x119 + eval "$@" || RC=$? + do_facet $SINGLEMDS $LCTL set_param fail_loc=0 + return $RC } drop_update_reply() { @@ -4086,12 +4450,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() { @@ -4106,21 +4474,49 @@ drop_ldlm_cancel() { return $RC } -drop_bl_callback() { +drop_bl_callback_once() { + rc=0 + do_facet client lctl set_param ldlm.namespaces.*.early_lock_cancel=0 #define OBD_FAIL_LDLM_BL_CALLBACK_NET 0x305 - RC=0 do_facet client lctl set_param fail_loc=0x80000305 - do_facet client "$@" || RC=$? + do_facet client "$@" || rc=$? do_facet client lctl set_param fail_loc=0 - return $RC + do_facet client lctl set_param ldlm.namespaces.*.early_lock_cancel=1 + return $rc +} + +drop_bl_callback() { + rc=0 + do_facet client lctl set_param ldlm.namespaces.*.early_lock_cancel=0 +#define OBD_FAIL_LDLM_BL_CALLBACK_NET 0x305 + do_facet client lctl set_param fail_loc=0x305 + do_facet client "$@" || rc=$? + do_facet client lctl set_param fail_loc=0 + do_facet client lctl set_param ldlm.namespaces.*.early_lock_cancel=1 + return $rc } drop_ldlm_reply() { #define OBD_FAIL_LDLM_REPLY 0x30c RC=0 - do_facet $SINGLEMDS lctl set_param fail_loc=0x30c + local list=$(comma_list $(mdts_nodes) $(osts_nodes)) + do_nodes $list lctl set_param fail_loc=0x30c + do_facet client "$@" || RC=$? - do_facet $SINGLEMDS lctl set_param fail_loc=0 + + do_nodes $list lctl set_param fail_loc=0 + return $RC +} + +drop_ldlm_reply_once() { +#define OBD_FAIL_LDLM_REPLY 0x30c + RC=0 + local list=$(comma_list $(mdts_nodes) $(osts_nodes)) + do_nodes $list lctl set_param fail_loc=0x8000030c + + do_facet client "$@" || RC=$? + + do_nodes $list lctl set_param fail_loc=0 return $RC } @@ -4133,15 +4529,36 @@ 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() { $LCTL mark "cancel_lru_locks $1 start" - for d in `lctl get_param -N ldlm.namespaces.*.lru_size | egrep -i $1`; do - $LCTL set_param -n $d=clear - done - $LCTL get_param ldlm.namespaces.*.lock_unused_count | egrep -i $1 | grep -v '=0' + + if [ $1 != "MGC" ]; then + for d in $(lctl get_param -N ldlm.namespaces.*.lru_size | + egrep -i $1); do + $LCTL set_param -n $d=clear + done + $LCTL get_param ldlm.namespaces.*.lock_unused_count | egrep -i $1 | + grep -v '=0' + else + for d in $(find \ + /{proc,sys}/fs/lustre/ldlm/namespaces/*$1*/lru_size \ + 2> /dev/null); do + echo "clear" > $d + done + + for d in $(find \ + /{proc,sys}/fs/lustre/ldlm/namespaces/*$1*/lock_unused_count \ + 2> /dev/null); do + if [ $(cat $d) != 0 ]; then + echo "ldlm.namespaces.$(echo "$d" | + cut -f 7 -d'/').lock_unused_count=$(cat $d)" + fi + done + fi + $LCTL mark "cancel_lru_locks $1 stop" } @@ -4162,6 +4579,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 @@ -4251,7 +4675,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 } @@ -4274,9 +4702,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 "$@" } @@ -4309,10 +4738,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" ] && \ @@ -4351,64 +4786,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() { @@ -4467,7 +4902,8 @@ check_mds() { reset_fail_loc () { echo -n "Resetting fail_loc on all nodes..." - do_nodes $(comma_list $(nodes_list)) "lctl set_param -n fail_loc=0 2>/dev/null || true" + do_nodes $(comma_list $(nodes_list)) "lctl set_param -n fail_loc=0 \ + fail_val=0 2>/dev/null || true" echo done. } @@ -4488,34 +4924,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 } # @@ -4525,13 +4962,16 @@ 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 + local zfs_log_name=${TESTSUITE}.test_${1}.zfs_log + local zfs_debug_log=$LOGDIR/$zfs_log_name rm -rf $LOGDIR/err + rm -rf $LOGDIR/ignore rm -rf $LOGDIR/skip - local SAVE_UMASK=`umask` + local SAVE_UMASK=$(umask) umask 0022 echo @@ -4539,20 +4979,27 @@ 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 + log_zfs_info "$zfs_debug_log" $FAIL_ON_ERROR && exit $RC fi @@ -4571,46 +5018,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 } ######################## @@ -4952,14 +5398,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. @@ -5115,7 +5561,7 @@ do_and_time () { SECONDS=0 eval '$cmd' - + [ ${PIPESTATUS[0]} -eq 0 ] || rc=1 echo $SECONDS @@ -5123,8 +5569,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 () { @@ -5139,25 +5586,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 () { @@ -5196,14 +5643,17 @@ restore_lustre_params() { check_catastrophe() { local rnodes=${1:-$(comma_list $(remote_nodes_list))} - local C=$CATASTROPHE - [ -f $C ] && [ $(cat $C) -ne 0 ] && return 1 + VAR=$(lctl get_param -n catastrophe 2>&1) + if [ $? = 0 ] ; then + if [ $VAR != 0 ]; then + return 1 + fi + fi [ -z "$rnodes" ] && return 0 local data - data=$(do_nodes "$rnodes" "rc=\\\$([ -f $C ] && - echo \\\$(< $C) || echo 0); + data=$(do_nodes "$rnodes" "rc=\\\$(lctl get_param -n catastrophe); if [ \\\$rc -ne 0 ]; then echo \\\$(hostname): \\\$rc; fi exit \\\$rc") local rc=$? @@ -5215,35 +5665,29 @@ check_catastrophe() { } # CMD: determine mds index where directory inode presents -get_mds_dir () { +get_mds_dir() { local dir=$1 - local file=$dir/f0.get_mds_dir_tmpfile + local SEQ - mkdir -p $dir - rm -f $file - sleep 1 - local iused=$(lfs df -i $dir | grep MDT | awk '{print $3}') - local -a oldused=($iused) + SEQ=$(lfs path2fid $dir | tr '[:]' ' '|cut -f2 -d ' ') + if [ "$SEQ" == "" ]; then + error "can't get sequence for $dir" + return 1 + fi + export SEQ - openfile -f O_CREAT:O_LOV_DELAY_CREATE -m 0644 $file > /dev/null - sleep 1 - iused=$(lfs df -i $dir | grep MDT | awk '{print $3}') - local -a newused=($iused) - - local num=0 - for ((i=0; i<${#newused[@]}; i++)); do - if [ ${oldused[$i]} -lt ${newused[$i]} ]; then - echo $(( i + 1 )) - rm -f $file - return 0 - fi - done - error "mdt-s : inodes count OLD ${oldused[@]} NEW ${newused[@]}" + do_facet mds1 "cat /proc/fs/lustre/fld/srv-*-MDT0000/fldb" | \ + tr '[)]:-' ' ' | \ + while read SS EE IDX TYP; do \ + if let "SEQ >= SS && SEQ < EE"; then \ + echo $IDX; \ + fi; \ + done } 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 @@ -5256,7 +5700,7 @@ delayed_recovery_enabled () { ######################## -convert_facet2label() { +convert_facet2label() { local facet=$1 if [ x$facet = xost ]; then @@ -5267,7 +5711,7 @@ convert_facet2label() { if [ -n ${!varsvc} ]; then echo ${!varsvc} - else + else error "No lablel for $facet!" fi } @@ -5419,39 +5863,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" @@ -6033,7 +6472,7 @@ check_write_access() { local file for node in ${list//,/ }; do - file=$dir/check_file.$(short_hostname $node) + file=$dir/check_file.$(short_nodename $node) if [[ ! -f "$file" ]]; then # Logdir not accessible/writable from this node. return 1 @@ -6249,6 +6688,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 @@ -6430,24 +6908,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 @@ -6455,18 +6950,356 @@ 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." + for idx in $(seq $MDSCOUNT); do + local name="MDT$(printf '%04x' $((idx - 1)))" + rm -rf $MOUNT/.lustre/lost+found/$name/* + done +} + +# 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)) +} + +check_file_in_pool() +{ + local file=$1 + local pool=$2 + local tlist="$3" + local res=$($GETSTRIPE $file | grep 0x | cut -f2) + for i in $res + do + for t in $tlist ; do + [ "$i" -eq "$t" ] && continue 2 + done + + echo "pool list: $tlist" + echo "striping: $res" + error_noexit "$file not allocated in $pool" + return 1 + done + return 0 +} + +pool_add() { + echo "Creating new pool" + local pool=$1 + + create_pool $FSNAME.$pool || + { error_noexit "No pool created, result code $?"; return 1; } + [ $($LFS pool_list $FSNAME | grep -c $pool) -eq 1 ] || + { error_noexit "$pool not in lfs pool_list"; return 2; } +} + +pool_add_targets() { + echo "Adding targets to pool" + local pool=$1 + local first=$2 + local last=$3 + local step=${4:-1} + + local list=$(seq $first $step $last) + + local t=$(for i in $list; do printf "$FSNAME-OST%04x_UUID " $i; done) + do_facet mgs $LCTL pool_add \ + $FSNAME.$pool $FSNAME-OST[$first-$last/$step] + wait_update $HOSTNAME "lctl get_param -n lov.$FSNAME-*.pools.$pool \ + | sort -u | tr '\n' ' ' " "$t" || { + error_noexit "Add to pool failed" + return 1 + } + local lfscount=$($LFS pool_list $FSNAME.$pool | grep -c "\-OST") + local addcount=$(((last - first) / step + 1)) + [ $lfscount -eq $addcount ] || { + error_noexit "lfs pool_list bad ost count" \ + "$lfscount != $addcount" + return 2 + } +} + +pool_set_dir() { + local pool=$1 + local tdir=$2 + echo "Setting pool on directory $tdir" + + $SETSTRIPE -c 2 -p $pool $tdir && return 0 + + error_noexit "Cannot set pool $pool to $tdir" + return 1 +} + +pool_check_dir() { + local pool=$1 + local tdir=$2 + echo "Checking pool on directory $tdir" + + local res=$($GETSTRIPE --pool $tdir | sed "s/\s*$//") + [ "$res" = "$pool" ] && return 0 + + error_noexit "Pool on '$tdir' is '$res', not '$pool'" + return 1 +} + +pool_dir_rel_path() { + echo "Testing relative path works well" + local pool=$1 + local tdir=$2 + local root=$3 + + mkdir -p $root/$tdir/$tdir + cd $root/$tdir + pool_set_dir $pool $tdir || return 1 + pool_set_dir $pool ./$tdir || return 2 + pool_set_dir $pool ../$tdir || return 3 + pool_set_dir $pool ../$tdir/$tdir || return 4 + rm -rf $tdir; cd - > /dev/null +} + +pool_alloc_files() { + echo "Checking files allocation from directory pool" + local pool=$1 + local tdir=$2 + local count=$3 + local tlist="$4" + + local failed=0 + for i in $(seq -w 1 $count) + do + local file=$tdir/file-$i + touch $file + check_file_in_pool $file $pool "$tlist" || \ + failed=$((failed + 1)) + done + [ "$failed" = 0 ] && return 0 + + error_noexit "$failed files not allocated in $pool" + return 1 +} + +pool_create_files() { + echo "Creating files in pool" + local pool=$1 + local tdir=$2 + local count=$3 + local tlist="$4" + + mkdir -p $tdir + local failed=0 + for i in $(seq -w 1 $count) + do + local file=$tdir/spoo-$i + $SETSTRIPE -p $pool $file + check_file_in_pool $file $pool "$tlist" || \ + failed=$((failed + 1)) + done + [ "$failed" = 0 ] && return 0 + + error_noexit "$failed files not allocated in $pool" + return 1 +} + +pool_lfs_df() { + echo "Checking 'lfs df' output" + local pool=$1 + + local t=$($LCTL get_param -n lov.$FSNAME-clilov-*.pools.$pool | + tr '\n' ' ') + local res=$($LFS df --pool $FSNAME.$pool | + awk '{print $1}' | + grep "$FSNAME-OST" | + tr '\n' ' ') + [ "$res" = "$t" ] && return 0 + + error_noexit "Pools OSTs '$t' is not '$res' that lfs df reports" + return 1 +} + +pool_file_rel_path() { + echo "Creating files in a pool with relative pathname" + local pool=$1 + local tdir=$2 + + mkdir -p $tdir || + { error_noexit "unable to create $tdir"; return 1 ; } + local file="/..$tdir/$tfile-1" + $SETSTRIPE -p $pool $file || + { error_noexit "unable to create $file" ; return 2 ; } + + cd $tdir + $SETSTRIPE -p $pool $tfile-2 || { + error_noexit "unable to create $tfile-2 in $tdir" + return 3 + } +} + +pool_remove_first_target() { + echo "Removing first target from a pool" + local pool=$1 + + local pname="lov.$FSNAME-*.pools.$pool" + local t=$($LCTL get_param -n $pname | head -1) + do_facet mgs $LCTL pool_remove $FSNAME.$pool $t + wait_update $HOSTNAME "lctl get_param -n $pname | grep $t" "" || { + error_noexit "$t not removed from $FSNAME.$pool" + return 1 + } +} + +pool_remove_all_targets() { + echo "Removing all targets from pool" + local pool=$1 + local file=$2 + local pname="lov.$FSNAME-*.pools.$pool" + for t in $($LCTL get_param -n $pname | sort -u) + do + do_facet mgs $LCTL pool_remove $FSNAME.$pool $t + done + wait_update $HOSTNAME "lctl get_param -n $pname" "" || { + error_noexit "Pool $FSNAME.$pool cannot be drained" + return 1 + } + # striping on an empty/nonexistant pool should fall back + # to "pool of everything" + touch $file || { + error_noexit "failed to use fallback striping for empty pool" + return 2 + } + # setstripe on an empty pool should fail + $SETSTRIPE -p $pool $file 2>/dev/null && { + error_noexit "expected failure when creating file" \ + "with empty pool" + return 3 + } + return 0 +} + +pool_remove() { + echo "Destroying pool" + local pool=$1 + local file=$2 + + do_facet mgs $LCTL pool_destroy $FSNAME.$pool + + sleep 2 + # striping on an empty/nonexistant pool should fall back + # to "pool of everything" + touch $file || { + error_noexit "failed to use fallback striping for missing pool" + return 1 + } + # setstripe on an empty pool should fail + $SETSTRIPE -p $pool $file 2>/dev/null && { + error_noexit "expected failure when creating file" \ + "with missing pool" + return 2 + } + + # get param should return err once pool is gone + if wait_update $HOSTNAME "lctl get_param -n \ + lov.$FSNAME-*.pools.$pool 2>/dev/null || echo foo" "foo" + then + remove_pool_from_list $FSNAME.$pool + return 0 + fi + error_noexit "Pool $FSNAME.$pool is not destroyed" + return 3 +} + +# Get and check the actual stripe count of one file. +# Usage: check_stripe_count +check_stripe_count() { + local file=$1 + local expected=$2 + local actual + + [[ -z "$file" || -z "$expected" ]] && + error "check_stripe_count: invalid argument" + + local cmd="$GETSTRIPE -c $file" + actual=$($cmd) || error "$cmd failed" + actual=${actual%% *} + + if [[ $actual -ne $expected ]]; then + [[ $expected -eq -1 ]] || + error "$cmd wrong: found $actual, expected $expected" + [[ $actual -eq $OSTCOUNT ]] || + error "$cmd wrong: found $actual, expected $OSTCOUNT" + fi +} + +# Get and check the actual list of OST indices on one file. +# Usage: check_obdidx +check_obdidx() { + local file=$1 + local expected=$2 + local obdidx + + [[ -z "$file" || -z "$expected" ]] && + error "check_obdidx: invalid argument!" + + obdidx=$(comma_list $($GETSTRIPE $file | grep -A $OSTCOUNT obdidx | + grep -v obdidx | awk '{print $1}' | xargs)) + + [[ $obdidx = $expected ]] || + error "list of OST indices on $file is $obdidx," \ + "should be $expected" +} + +# Get and check the actual OST index of the first stripe on one file. +# Usage: check_start_ost_idx +check_start_ost_idx() { + local file=$1 + local expected=$2 + local start_ost_idx + + [[ -z "$file" || -z "$expected" ]] && + error "check_start_ost_idx: invalid argument!" + + start_ost_idx=$($GETSTRIPE $file | grep -A 1 obdidx | grep -v obdidx | + awk '{print $1}') + + [[ $start_ost_idx = $expected ]] || + error "OST index of the first stripe on $file is" \ + "$start_ost_idx, should be $expected" +}