X-Git-Url: https://git.whamcloud.com/?p=fs%2Flustre-release.git;a=blobdiff_plain;f=lustre%2Ftests%2Ftest-framework.sh;h=9037f7e215423cd21ce57159256dacdc78d917b1;hp=b4a5ade7cfd62efc7c2bf108c2714b5bf7ed088c;hb=5764a8ce591e7f62cad2ee95b7041c115a1cd0f6;hpb=de5977c6967e5ff9155c6709373932048df5f3ad diff --git a/lustre/tests/test-framework.sh b/lustre/tests/test-framework.sh old mode 100644 new mode 100755 index b4a5ade..9037f7e --- a/lustre/tests/test-framework.sh +++ b/lustre/tests/test-framework.sh @@ -6,11 +6,9 @@ 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 @@ -24,6 +22,12 @@ 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"} +export UMOUNT=${UMOUNT:-"umount -d"} +# sles12 umount has a issue with -d option +[ -e /etc/SuSE-release ] && grep -w VERSION /etc/SuSE-release | grep -wq 12 && { + export UMOUNT="umount" +} # function used by scripts run on remote nodes LUSTRE=${LUSTRE:-$(cd $(dirname $0)/..; echo $PWD)} @@ -71,7 +75,7 @@ usage() { print_summary () { trap 0 - [ "$TESTSUITE" == "lfsck" ] && return 0 + [ -z "$DEFAULT_SUITES"] && return 0 [ -n "$ONLY" ] && echo "WARNING: ONLY is set to $(echo $ONLY)" local details local form="%-13s %-17s %-9s %s %s\n" @@ -90,16 +94,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)" @@ -188,9 +197,8 @@ init_test_env() { 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 + export LFSCK_ALWAYS=${LFSCK_ALWAYS:-"no"} # check fs after test suite + export FSCK_MAX_ERR=4 # File system errors left uncorrected export ZFS=${ZFS:-zfs} export ZPOOL=${ZPOOL:-zpool} @@ -220,9 +228,11 @@ 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} + export FSX=${FSX:-$LUSTRE/tests/fsx} export MDSRATE=${MDSRATE:-"$LUSTRE/tests/mpi/mdsrate"} [ ! -f "$MDSRATE" ] && export MDSRATE=$(which mdsrate 2> /dev/null) if ! echo $PATH | grep -q $LUSTRE/tests/racer; then @@ -261,6 +271,9 @@ init_test_env() { export LFS_MIGRATE=${LFS_MIGRATE:-$LUSTRE/scripts/lfs_migrate} [ ! -f "$LFS_MIGRATE" ] && export LFS_MIGRATE=$(which lfs_migrate 2> /dev/null) + export LR_READER=${LR_READER:-"$LUSTRE/utils/lr_reader"} + [ ! -f "$LR_READER" ] && export LR_READER=$(which lr_reader 2> /dev/null) + [ -z "$LR_READER" ] && export LR_READER="/usr/sbin/lr_reader" export NAME=${NAME:-local} export LGSSD=${LGSSD:-"$LUSTRE/utils/gss/lgssd"} [ "$GSS_PIPEFS" = "true" ] && [ ! -f "$LGSSD" ] && \ @@ -332,6 +345,8 @@ init_test_env() { if ! $RPC_MODE; then rm -f $TMP/*active fi + + export TF_FAIL=${TF_FAIL:-$TMP/tf.fail} } check_cpt_number() { @@ -348,23 +363,62 @@ check_cpt_number() { fi } +# Return a numeric version code based on a version string. The version +# code is useful for comparison two version strings to see which is newer. version_code() { - # split arguments like "1.8.6-wc3" into "1", "8", "6", "wc3" - eval set -- $(tr "[:punct:]" " " <<< $*) + # split arguments like "1.8.6-wc3" into "1", "8", "6", "wc3" + eval set -- $(tr "[:punct:]" " " <<< $*) - echo -n "$((($1 << 16) | ($2 << 8) | $3))" + 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//\./ }) +# Report the Lustre build version string (e.g. 1.8.7.3 or 2.4.1). +# +# usage: lustre_build_version +# +# All Lustre versions support "lctl get_param" to report the version of the +# code running in the kernel (what our tests are interested in), but it +# doesn't work without modules loaded. If that fails, use "lctl version" +# instead, which is easy to parse and works without the kernel modules, +# but was only added in 2.6.50. If that also fails, fall back to calling +# "lctl lustre_build_version" which prints either (or both) the userspace +# and kernel build versions, but is deprecated and should eventually be +# removed. +# +# output: prints version string to stdout in dotted-decimal format +lustre_build_version() { + local facet=${1:-client} + + # lustre: 2.6.52 + # kernel: patchless_client + # build: v2_6_92_0-gadb3ee4-2.6.32-431.29.2.el6_lustre.x86_64 + local VER=$(do_facet $facet $LCTL get_param -n version 2> /dev/null | + awk '/lustre: / { print $2 }') + # lctl 2.6.50 + [ -z "$VER" ] && VER=$(do_facet $facet $LCTL --version 2>/dev/null | + awk '{ print $2 }') + # Lustre version: 2.5.3-gfcfd782-CHANGED-2.6.32.26-175.fc12.x86_64 + # lctl version: 2.5.3-gfcfd782-CHANGED-2.6.32.26-175.fc12.x86_64 + [ -z "$VER" ] && VER=$(do_facet $facet $LCTL lustre_build_version | + awk '/version:/ { print $3; exit; }') + sed -e 's/^v//' -e 's/-.*//' -e 's/_/./g' <<<$VER +} + +# Report the Lustre numeric build version code for the supplied facet. +lustre_version_code() { + version_code $(lustre_build_version $1) +} + module_loaded () { - /sbin/lsmod | grep -q "^\<$1\>" + /sbin/lsmod | grep -q "^\<$1\>" } # Load a module on the system where this is running. # -# Synopsis: load_module module_name [module arguments for insmod/modprobe] +# usage: load_module module_name [module arguments for insmod/modprobe] # # If module arguments are not given but MODOPTS_ is set, then its value # will be used as the arguments. Otherwise arguments will be obtained from @@ -375,12 +429,12 @@ load_module() { EXT=".ko" module=$1 shift - BASE=`basename $module $EXT` + BASE=$(basename $module $EXT) module_loaded ${BASE} && return - # If no module arguments were passed, get them from $MODOPTS_, else from - # modprobe.conf + # If no module arguments were passed, get them from $MODOPTS_, + # else from modprobe.conf if [ $# -eq 0 ]; then # $MODOPTS_; we could use associative arrays, but that's not in # Bash until 4.x, so we resort to eval. @@ -410,22 +464,24 @@ load_module() { [ $# -gt 0 ] && echo "${module} options: '$*'" - # Note that insmod will ignore anything in modprobe.conf, which is why we're - # passing options on the command-line. - if [ "$BASE" == "lnet_selftest" ] && \ - [ -f ${LUSTRE}/../lnet/selftest/${module}${EXT} ]; then - insmod ${LUSTRE}/../lnet/selftest/${module}${EXT} - elif [ -f ${LUSTRE}/${module}${EXT} ]; then - insmod ${LUSTRE}/${module}${EXT} "$@" - else - # must be testing a "make install" or "rpm" installation - # note failed to load ptlrpc_gss is considered not fatal - if [ "$BASE" == "ptlrpc_gss" ]; then - modprobe $BASE "$@" 2>/dev/null || echo "gss/krb5 is not supported" - else - modprobe $BASE "$@" - fi - fi + # Note that insmod will ignore anything in modprobe.conf, which is why + # we're passing options on the command-line. + if [[ "$BASE" == "lnet_selftest" ]] && + [[ -f ${LUSTRE}/../lnet/selftest/${module}${EXT} ]]; then + insmod ${LUSTRE}/../lnet/selftest/${module}${EXT} + elif [[ -f ${LUSTRE}/${module}${EXT} ]]; then + [[ "$BASE" != "ptlrpc_gss" ]] || modprobe sunrpc + insmod ${LUSTRE}/${module}${EXT} "$@" + else + # must be testing a "make install" or "rpm" installation + # note failed to load ptlrpc_gss is considered not fatal + if [[ "$BASE" == "ptlrpc_gss" ]]; then + modprobe $BASE "$@" 2>/dev/null || + echo "gss/krb5 is not supported" + else + modprobe $BASE "$@" + fi + fi } llite_lloop_enabled() { @@ -484,6 +540,13 @@ load_modules_local() { [ "$PTLDEBUG" ] && lctl set_param debug="$PTLDEBUG" [ "$SUBSYSTEM" ] && lctl set_param subsystem_debug="${SUBSYSTEM# }" load_module ../lnet/lnet/lnet + case $NETTYPE in + o2ib) + LNETLND="o2iblnd/ko2iblnd" + ;; + *) + ;; + esac LNETLND=${LNETLND:-"socklnd/ksocklnd"} load_module ../lnet/klnds/$LNETLND load_module obdclass/obdclass @@ -514,7 +577,6 @@ load_modules_local() { 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 @@ -525,20 +587,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 - - # '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 + 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 + local mount_lustre=$LUSTRE/utils/mount.lustre + if [ -f $mount_lustre ]; then + local sbin_mount=$(readlink -f /sbin)/mount.lustre + if grep -qw "$sbin_mount" /proc/mounts; then + cmp -s $mount_lustre $sbin_mount || umount $sbin_mount + fi + if ! grep -qw "$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 () { @@ -582,16 +661,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=$(readlink -f /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() { @@ -649,7 +729,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 @@ -686,7 +765,7 @@ start_gss_daemons() { stop_gss_daemons() { local list=$(comma_list $(mdts_nodes)) - + send_sigint $list lsvcgssd lgssd list=$(comma_list $(osts_nodes)) @@ -703,10 +782,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 } @@ -735,7 +817,7 @@ facet_type() { facet_number() { local facet=$1 - if [ $facet == mgs ]; then + if [ $facet == mgs ] || [ $facet == client ]; then return 1 fi @@ -790,6 +872,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 @@ -1015,7 +1116,7 @@ get_osd_param() { local name=$3 do_nodes $nodes "$LCTL get_param -n obdfilter.$device.$name \ - osd-*.$device.$name 2>&1" | grep -v 'Found no match' + osd-*.$device.$name 2>&1" | grep -v 'error:' } set_osd_param() { @@ -1025,7 +1126,7 @@ set_osd_param() { local value=$4 do_nodes $nodes "$LCTL set_param -n obdfilter.$device.$name=$value \ - osd-*.$device.$name=$value 2>&1" | grep -v 'Found no match' + osd-*.$device.$name=$value 2>&1" | grep -v 'error:' } set_debug_size () { @@ -1122,6 +1223,10 @@ mount_facet() { local opt=${facet}_opt local mntpt=$(facet_mntpt $facet) local opts="${!opt} $@" + local fstype=$(facet_fstype $facet) + local devicelabel + + module_loaded lustre || load_modules if [ $(facet_fstype $facet) == ldiskfs ] && ! do_facet $facet test -b ${!dev}; then @@ -1133,50 +1238,101 @@ mount_facet() { import_zpool $facet || return ${PIPESTATUS[0]} fi + case $fstype in + ldiskfs) + devicelabel=$(do_facet ${facet} "$E2LABEL ${!dev}");; + zfs) + devicelabel=$(do_facet ${facet} "$ZFS get -H -o value \ + lustre:svname ${!dev}");; + *) + error "unknown fstype!";; + esac + 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 + if [ $RC -ne 0 ]; then echo "Start of ${!dev} on ${facet} failed ${RC}" - else - set_default_debug_facet $facet + return $RC + fi - label=$(devicelabel ${facet} ${!dev}) - [ -z "$label" ] && echo no label for ${!dev} && exit 1 - eval export ${facet}_svc=${label} - echo Started ${label} - fi - return $RC + set_default_debug_facet $facet + + if [[ $facet == mds* ]]; then + do_facet $facet \ + lctl set_param -n mdt.${FSNAME}*.enable_remote_dir=1 2>/dev/null + fi + + if [[ $opts =~ .*nosvc.* ]]; then + echo "Start ${!dev} without service" + else + + case $fstype in + ldiskfs) + wait_update_facet ${facet} "$E2LABEL ${!dev} \ + 2>/dev/null | grep -E ':[a-zA-Z]{3}[0-9]{4}'" \ + "" || error "${!dev} failed to initialize!";; + zfs) + wait_update_facet ${facet} "$ZFS get -H -o value \ + lustre:svname ${!dev} 2>/dev/null | \ + grep -E ':[a-zA-Z]{3}[0-9]{4}'" "" || + error "${!dev} failed to initialize!";; + + *) + error "unknown fstype!";; + esac + fi + + # commit the device label change to disk + if [[ $devicelabel =~ (:[a-zA-Z]{3}[0-9]{4}) ]]; then + do_facet $facet "sync; sync; sync" + fi + + + label=$(devicelabel ${facet} ${!dev}) + [ -z "$label" ] && echo no label for ${!dev} && exit 1 + eval export ${facet}_svc=${label} + echo Started ${label} + + return $RC } # start facet device options start() { - local facet=$1 - shift - local device=$1 - shift - eval export ${facet}_dev=${device} - eval export ${facet}_opt=\"$@\" + local facet=$1 + shift + local device=$1 + shift + eval export ${facet}_dev=${device} + eval export ${facet}_opt=\"$@\" - local varname=${facet}failover_dev - if [ -n "${!varname}" ] ; then - eval export ${facet}failover_dev=${!varname} - else - eval export ${facet}failover_dev=$device - fi + local varname=${facet}failover_dev + if [ -n "${!varname}" ] ; then + eval export ${facet}failover_dev=${!varname} + else + 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() { @@ -1190,7 +1346,7 @@ stop() { running=$(do_facet ${facet} "grep -c $mntpt' ' /proc/mounts") || true if [ ${running} -ne 0 ]; then echo "Stopping $mntpt (opts:$@) on $HOST" - do_facet ${facet} umount -d $@ $mntpt + do_facet ${facet} $UMOUNT $@ $mntpt fi # umount should block, but we should wait for unrelated obd's @@ -1240,71 +1396,7 @@ quota_type() { rc=$? do_nodes $(comma_list $(osts_nodes)) \ lctl get_param obdfilter.${fsname}-OST*.quota_type || rc=$? - return $rc -} - -# XXX This function is kept for interoperability with old server (< 2.3.50), -# it should be removed whenever we drop the interoperability for such -# server. -restore_quota_old() { - local mntpt=${1:-$MOUNT} - local quota_type=$(quota_type $FSNAME | grep MDT | cut -d "=" -f2) - if [ ! "$old_QUOTA_TYPE" ] || - [ "$quota_type" = "$old_QUOTA_TYPE" ]; then - return - fi - quota_save_version $old_QUOTA_TYPE -} - -# XXX This function is kept for interoperability with old server (< 2.3.50), -# it should be removed whenever we drop the interoperability for such -# server. -setup_quota_old(){ - local mntpt=$1 - - # no quota enforcement for now and accounting works out of the box - return - - # We need save the original quota_type params, and restore them after testing - - # Suppose that quota type the same on mds and ost - local quota_type=$(quota_type | grep MDT | cut -d "=" -f2) - [ ${PIPESTATUS[0]} -eq 0 ] || error "quota_type failed!" - echo "[HOST:$HOSTNAME] [old_quota_type:$quota_type] [new_quota_type:$QUOTA_TYPE]" - if [ "$quota_type" != "$QUOTA_TYPE" ]; then - export old_QUOTA_TYPE=$quota_type - quota_save_version $QUOTA_TYPE - else - qtype=$(tr -c -d "ug" <<< $QUOTA_TYPE) - $LFS quotacheck -$qtype $mntpt || error "quotacheck has failed for $type" - fi - - local quota_usrs=$QUOTA_USERS - - # get_filesystem_size - local disksz=$(lfs_df $mntpt | grep "summary" | awk '{print $2}') - local blk_soft=$((disksz + 1024)) - local blk_hard=$((blk_soft + blk_soft / 20)) # Go 5% over - - local Inodes=$(lfs_df -i $mntpt | grep "summary" | awk '{print $2}') - local i_soft=$Inodes - local i_hard=$((i_soft + i_soft / 20)) - - echo "Total disk size: $disksz block-softlimit: $blk_soft block-hardlimit: - $blk_hard inode-softlimit: $i_soft inode-hardlimit: $i_hard" - - local cmd - for usr in $quota_usrs; do - echo "Setting up quota on $HOSTNAME:$mntpt for $usr..." - for type in u g; do - cmd="$LFS setquota -$type $usr -b $blk_soft -B $blk_hard -i $i_soft -I $i_hard $mntpt" - echo "+ $cmd" - eval $cmd || error "$cmd FAILED!" - done - # display the quota status - echo "Quota settings for $usr : " - $LFS quota -v -u $usr $mntpt || true - done + return $rc } # get mdt quota type @@ -1324,11 +1416,6 @@ ost_quota_type() { # restore old quota type settings restore_quota() { - if [ $(lustre_version_code $SINGLEMDS) -lt $(version_code 2.3.50) ]; then - restore_quota_old - return - fi - if [ "$old_MDT_QUOTA_TYPE" ]; then do_facet mgs $LCTL conf_param \ $FSNAME.quota.mdt=$old_MDT_QUOTA_TYPE @@ -1364,11 +1451,6 @@ mdt_free_inodes() { } setup_quota(){ - if [ $(lustre_version_code $SINGLEMDS) -lt $(version_code 2.3.50) ]; then - setup_quota_old $1 - return - fi - local mntpt=$1 # save old quota type & set new quota type @@ -1417,23 +1499,37 @@ setup_quota(){ } zconf_mount() { - local client=$1 - local mnt=$2 - local OPTIONS=${3:-$MOUNTOPT} - - local device=$MGSNID:/$FSNAME - if [ -z "$mnt" -o -z "$FSNAME" ]; then - echo Bad zconf mount command: opt=$OPTIONS dev=$device mnt=$mnt - exit 1 - fi + local client=$1 + local mnt=$2 + local opts=${3:-$MOUNT_OPTS} + opts=${opts:+-o $opts} + local flags=${4:-$MOUNT_FLAGS} + + local device=$MGSNID:/$FSNAME$FILESET + if [ -z "$mnt" -o -z "$FSNAME" ]; then + echo "Bad mount command: opt=$flags $opts dev=$device " \ + "mnt=$mnt" + exit 1 + fi - echo "Starting client: $client: $OPTIONS $device $mnt" - do_node $client mkdir -p $mnt - do_node $client mount -t lustre $OPTIONS $device $mnt || return 1 + echo "Starting client: $client: $flags $opts $device $mnt" + do_node $client mkdir -p $mnt + if [ -n "$FILESET" -a -z "$SKIP_FILESET" ];then + do_node $client $MOUNT_CMD $flags $opts $MGSNID:/$FSNAME \ + $mnt || return 1 + #disable FILESET if not supported + do_nodes $client lctl get_param -n \ + mdc.$FSNAME-MDT0000*.import | grep -q subtree || + device=$MGSNID:/$FSNAME + do_node $client mkdir -p $mnt/$FILESET + do_node $client "! grep -q $mnt' ' /proc/mounts || + umount $mnt" + fi + do_node $client $MOUNT_CMD $flags $opts $device $mnt || return 1 - set_default_debug_nodes $client + set_default_debug_nodes $client - return 0 + return 0 } zconf_umount() { @@ -1523,34 +1619,50 @@ sanity_mount_check () { # mount clients if not mouted zconf_mount_clients() { - local clients=$1 - local mnt=$2 - local OPTIONS=${3:-$MOUNTOPT} - - local device=$MGSNID:/$FSNAME - if [ -z "$mnt" -o -z "$FSNAME" ]; then - echo Bad zconf mount command: opt=$OPTIONS dev=$device mnt=$mnt - exit 1 - fi + local clients=$1 + local mnt=$2 + local opts=${3:-$MOUNT_OPTS} + opts=${opts:+-o $opts} + local flags=${4:-$MOUNT_FLAGS} + + local device=$MGSNID:/$FSNAME$FILESET + if [ -z "$mnt" -o -z "$FSNAME" ]; then + echo "Bad conf 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" + if [ -n "$FILESET" -a ! -n "$SKIP_FILESET" ]; then + do_nodes $clients "! grep -q $mnt' ' /proc/mounts || + umount $mnt" + do_nodes $clients $MOUNT_CMD $flags $opts $MGSNID:/$FSNAME \ + $mnt || return 1 + #disable FILESET if not supported + do_nodes $clients lctl get_param -n \ + mdc.$FSNAME-MDT0000*.import | grep -q subtree || + device=$MGSNID:/$FSNAME + do_nodes $clients mkdir -p $mnt/$FILESET + do_nodes $clients "! grep -q $mnt' ' /proc/mounts || + umount $mnt" + fi - do_nodes $clients " + 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]} - echo "Started clients $clients: " - do_nodes $clients "mount | grep $mnt' '" + echo "Started clients $clients: " + do_nodes $clients "mount | grep $mnt' '" - set_default_debug_nodes $clients + set_default_debug_nodes $clients - return 0 + return 0 } zconf_umount_clients() { @@ -1630,7 +1742,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 () { @@ -1923,18 +2035,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 @@ -1988,65 +2104,78 @@ wait_update () { } wait_update_facet() { + local verbose= + [ "$1" = "--verbose" ] && verbose="$1" && shift + local facet=$1 shift - wait_update $(facet_active_host $facet) "$@" + wait_update $verbose $(facet_active_host $facet) "$@" } sync_all_data() { do_nodes $(comma_list $(mdts_nodes)) \ - "lctl set_param -n osd*.*MDT*.force_sync 1" + "lctl set_param -n osd*.*MDT*.force_sync=1" do_nodes $(comma_list $(osts_nodes)) \ - "lctl set_param -n osd*.*OS*.force_sync 1" 2>&1 | + "lctl set_param -n osd*.*OS*.force_sync=1" 2>&1 | grep -v 'Found no match' } wait_delete_completed_mds() { local MAX_WAIT=${1:-20} + # for ZFS, waiting more time for DMUs to be committed + local ZFS_WAIT=${2:-5} 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" + + # the occupied disk space will be released + # only after DMUs are committed + if [[ $(facet_fstype $SINGLEMDS) == zfs ]]; then + echo "sleep $ZFS_WAIT for ZFS OSD" + sleep $ZFS_WAIT + fi + return fi sleep 1 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() { @@ -2269,7 +2398,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 @@ -2282,6 +2411,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 @@ -2295,6 +2432,13 @@ affected_facets () { } facet_failover() { + local E2FSCK_ON_MDT0=false + if [ "$1" == "--fsck" ]; then + shift + [ $(facet_fstype $SINGLEMDS) == ldiskfs ] && + E2FSCK_ON_MDT0=true + fi + local facets=$1 local sleep_time=$2 local -a affecteds @@ -2328,6 +2472,9 @@ facet_failover() { shutdown_facet $facet done + $E2FSCK_ON_MDT0 && (run_e2fsck $(facet_active_host $SINGLEMDS) \ + $(mdsdevname 1) "-n" || error "Running e2fsck") + for ((index=0; index<$total; index++)); do facet=$(echo ${affecteds[index]} | tr -s " " | cut -d"," -f 1) echo reboot facets: ${affecteds[index]} @@ -2592,7 +2739,7 @@ hostlist_expand() { done myList="${myList%* }"; - # We can select an object at a offset in the list + # We can select an object at an offset in the list [ $# -eq 2 ] && { cnt=0 for item in $myList; do @@ -2670,13 +2817,7 @@ facet_active() { } facet_active_host() { - local facet=$1 - local active=`facet_active $facet` - if [ "$facet" == client ]; then - echo $HOSTNAME - else - echo `facet_host $active` - fi + facet_host $(facet_active $1) } # Get the passive failover partner host of facet. @@ -2786,7 +2927,7 @@ get_env_vars() { local facet for var in ${!MODOPTS_*}; do - value=${!var} + value=${!var//\"/\\\"} echo -n " ${var}=\"$value\"" done @@ -2803,9 +2944,21 @@ get_env_vars() { fi done + for var in VERBOSE; do + if [ -n "${!var}" ]; then + echo -n " $var=${!var}" + fi + done + if [ -n "$FSTYPE" ]; then echo -n " FSTYPE=$FSTYPE" fi + + for var in LNETLND NETTYPE; do + if [ -n "${!var}" ]; then + echo -n " $var=${!var}" + fi + done } do_nodes() { @@ -2850,12 +3003,19 @@ do_nodes() { return ${PIPESTATUS[0]} } +## +# Execute commands on a single service's host +# +# The \a facet (service) may be on a local or remote node, which is +# determined at the time the command is run. +# +# usage: do_facet $facet command [arg ...] do_facet() { - local facet=$1 - shift - local HOST=`facet_active_host $facet` - [ -z $HOST ] && echo No host defined for facet ${facet} && exit 1 - do_node $HOST "$@" + local facet=$1 + shift + local HOST=$(facet_active_host $facet) + [ -z $HOST ] && echo "No host defined for facet ${facet}" && exit 1 + do_node $HOST "$@" } # Function: do_facet_random_file $FACET $FILE $SIZE @@ -2940,7 +3100,7 @@ ostvdevname() { eval VDEVPTR="";; zfs ) #if $OSTDEVn isn't defined, default is $OSTDEVBASE{n} - # Device formated by zfs + # Device formatted by zfs DEVNAME=OSTDEV$num eval VDEVPTR=${!DEVNAME:=${OSTDEVBASE}${num}};; * ) @@ -2950,7 +3110,7 @@ ostvdevname() { echo -n $VDEVPTR } -# Logical device formated for lustre +# Logical device formatted for lustre mdsdevname() { local num=$1 local DEVNAME=MDSDEV$num @@ -2984,7 +3144,7 @@ mdsvdevname() { eval VDEVPTR="";; zfs ) # if $MDSDEVn isn't defined, default is $MDSDEVBASE{n} - # Device formated by ZFS + # Device formatted by ZFS local DEVNAME=MDSDEV$num eval VDEVPTR=${!DEVNAME:=${MDSDEVBASE}${num}};; * ) @@ -3072,7 +3232,7 @@ unmount_ldiskfs() { local dev=$(facet_device $facet) local mnt=$(facet_mntpt $facet) - do_facet $facet umount -d $mnt + do_facet $facet $UMOUNT $mnt } var_name() { @@ -3183,6 +3343,7 @@ cleanup_echo_devs () { cleanupall() { nfs_client_mode && return + cifs_client_mode && return stopall $* cleanup_echo_devs @@ -3209,17 +3370,13 @@ 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 local fs_mkfs_opts local var - if [ $type == MGS ] && combined_mgs_mds; then - return 1 - fi - if [ $type == MGS ] || ( [ $type == MDS ] && [ "$dev" == $(mgsdevname) ] && [ "$host" == "$(facet_host mgs)" ] ); then @@ -3249,9 +3406,17 @@ mkfs_opts() { opts+=${L_GETIDENTITY:+" --param=mdt.identity_upcall=$L_GETIDENTITY"} if [ $fstype == ldiskfs ]; then - fs_mkfs_opts+=${MDSJOURNALSIZE:+" -J size=$MDSJOURNALSIZE"} - if [ ! -z $EJOURNAL ]; then - fs_mkfs_opts+=${MDSJOURNALSIZE:+" device=$EJOURNAL"} + # Check for wide striping + if [ $OSTCOUNT -gt 160 ]; then + MDSJOURNALSIZE=${MDSJOURNALSIZE:-4096} + fs_mkfs_opts+="-O large_xattr" + fi + + var=${facet}_JRN + if [ -n "${!var}" ]; then + fs_mkfs_opts+=" -J device=${!var}" + else + fs_mkfs_opts+=${MDSJOURNALSIZE:+" -J size=$MDSJOURNALSIZE"} fi fs_mkfs_opts+=${MDSISIZE:+" -i $MDSISIZE"} fi @@ -3262,7 +3427,12 @@ mkfs_opts() { opts+=${OSSCAPA:+" --param=ost.capa=$OSSCAPA"} if [ $fstype == ldiskfs ]; then - fs_mkfs_opts+=${OSTJOURNALSIZE:+" -J size=$OSTJOURNALSIZE"} + var=${facet}_JRN + if [ -n "${!var}" ]; then + fs_mkfs_opts+=" -J device=${!var}" + else + fs_mkfs_opts+=${OSTJOURNALSIZE:+" -J size=$OSTJOURNALSIZE"} + fi fi fi @@ -3289,37 +3459,81 @@ mkfs_opts() { echo -n "$opts" } -formatall() { +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 +} + +format_mgs() { local quiet if ! $VERBOSE; then quiet=yes fi + echo "Format mgs: $(mgsdevname)" + reformat_external_journal mgs + add mgs $(mkfs_opts mgs $(mgsdevname)) --reformat \ + $(mgsdevname) $(mgsvdevname) ${quiet:+>/dev/null} || exit 10 +} + +format_mdt() { + local num=$1 + local quiet + + if ! $VERBOSE; then + quiet=yes + fi + echo "Format mds$num: $(mdsdevname $num)" + reformat_external_journal mds$num + add mds$num $(mkfs_opts mds$num $(mdsdevname ${num})) \ + --reformat $(mdsdevname $num) $(mdsvdevname $num) \ + ${quiet:+>/dev/null} || exit 10 +} + +format_ost() { + local num=$1 + + if ! $VERBOSE; then + quiet=yes + fi + echo "Format ost$num: $(ostdevname $num)" + reformat_external_journal ost$num + add ost$num $(mkfs_opts ost$num $(ostdevname ${num})) \ + --reformat $(ostdevname $num) $(ostvdevname ${num}) \ + ${quiet:+>/dev/null} || exit 10 +} +formatall() { stopall # We need ldiskfs here, may as well load them all load_modules [ "$CLIENTONLY" ] && return echo Formatting mgs, mds, osts if ! combined_mgs_mds ; then - echo "Format mgs: $(mgsdevname)" - add mgs $(mkfs_opts mgs $(mgsdevname)) --reformat \ - $(mgsdevname) $(mgsvdevname) ${quiet:+>/dev/null} || - exit 10 + format_mgs fi for num in $(seq $MDSCOUNT); do - echo "Format mds$num: $(mdsdevname $num)" - add mds$num $(mkfs_opts mds$num $(mdsdevname ${num})) \ - --reformat $(mdsdevname $num) $(mdsvdevname $num) \ - ${quiet:+>/dev/null} || exit 10 + format_mdt $num 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})) \ - --reformat $(ostdevname $num) $(ostvdevname ${num}) \ - ${quiet:+>/dev/null} || exit 10 + format_ost $num done } @@ -3397,6 +3611,7 @@ writeconf_all () { setupall() { nfs_client_mode && return + cifs_client_mode && return sanity_mount_check || error "environments are insane!" @@ -3662,6 +3877,11 @@ nfs_client_mode () { return 1 } +cifs_client_mode () { + [ x$CIFSCLIENT = xyes ] && + echo "CIFSCLIENT=$CIFSCLIENT mode: setup, cleanup, check config skipped" +} + check_config_client () { local mntpt=$1 @@ -3709,6 +3929,7 @@ check_config_clients () { local mntpt=$1 nfs_client_mode && return + cifs_client_mode && return do_rpc_nodes "$clients" check_config_client $mntpt @@ -3755,6 +3976,7 @@ is_empty_fs() { check_and_setup_lustre() { nfs_client_mode && return + cifs_client_mode && return local MOUNTED=$(mounted_lustre_filesystems) @@ -3831,6 +4053,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 @@ -3960,96 +4189,92 @@ check_shared_dir() { return 0 } -# Run e2fsck on MDT and OST(s) to generate databases used for lfsck. -generate_db() { - local i - local ostidx - local dev +run_lfsck() { + do_nodes $(comma_list $(mdts_nodes) $(osts_nodes)) \ + $LCTL set_param printk=+lfsck + do_facet $SINGLEMDS "$LCTL lfsck_start -M $FSNAME-MDT0000 -r -A -t all" + + for k in $(seq $MDSCOUNT); do + # wait up to 10+1 minutes for LFSCK to complete + wait_update_facet --verbose mds${k} "$LCTL get_param -n \ + mdd.$(facet_svc mds${k}).lfsck_layout | + awk '/^status/ { print \\\$2 }'" "completed" 600 || + error "MDS${k} layout isn't the expected 'completed'" + wait_update_facet --verbose mds${k} "$LCTL get_param -n \ + mdd.$(facet_svc mds${k}).lfsck_namespace | + awk '/^status/ { print \\\$2 }'" "completed" 60 || + error "MDS${k} namespace isn't the expected 'completed'" + done + local rep_mdt=$(do_nodes $(comma_list $(mdts_nodes)) \ + $LCTL get_param -n mdd.$FSNAME-*.lfsck_* | + awk '/repaired/ { print $2 }' | calc_sum) + local rep_ost=$(do_nodes $(comma_list $(osts_nodes)) \ + $LCTL get_param -n obdfilter.$FSNAME-*.lfsck_* | + awk '/repaired/ { print $2 }' | calc_sum) + local repaired=$((rep_mdt + rep_ost)) + [ $repaired -eq 0 ] || + error "lfsck repaired $rep_mdt MDT and $rep_ost OST errors" +} + +dump_file_contents() { + local nodes=$1 + local dir=$2 + local logname=$3 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" + 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 +} - export MDSDB=$SHARED_DIRECTORY/mdsdb - export OSTDB=$SHARED_DIRECTORY/ostdb +dump_command_output() { + local nodes=$1 + local cmd=$2 + local logname=$3 + local node - # 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" + if [ -z "$nodes" -o -z "$cmd" -o -z "$logname" ]; then + error_noexit false \ + "Invalid parameters for dump_command_output()" + return 1 + fi - i=0 - ostidx=0 - OSTDB_LIST="" - for node in $(osts_nodes); do - for dev in ${OSTDEVS[i]}; do - run_e2fsck $node $dev "-n --mdsdb $MDSDB --ostdb $OSTDB-$ostidx" - OSTDB_LIST="$OSTDB_LIST $OSTDB-$ostidx" - ostidx=$((ostidx + 1)) - done - i=$((i + 1)) - done + for node in ${nodes}; do + do_node $node "echo ====${cmd}=======================; + $cmd" >> ${logname}.${node}.log + done } -# Run lfsck on server node if lfsck can't be found on client (LU-2571) -run_lfsck_remote() { - local cmd="$LFSCK_BIN -c -l --mdsdb $MDSDB --ostdb $OSTDB_LIST $MOUNT" - local client=$1 - local mounted=true - local rc=0 +log_zfs_info() { + local logname=$1 - #Check if lustre is already mounted - do_rpc_nodes $client is_mounted $MOUNT || mounted=false - if ! $mounted; then - zconf_mount $client $MOUNT || - error "failed to mount Lustre on $client" - fi - #Run lfsck - echo $cmd - do_node $client $cmd || rc=$? - #Umount if necessary - if ! $mounted; then - zconf_umount $client $MOUNT || - error "failed to unmount Lustre on $client" + # 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 - [ $rc -le $FSCK_MAX_ERR ] || - error "$cmd returned $rc, should be <= $FSCK_MAX_ERR" - echo "lfsck finished with rc=$rc" - - return $rc -} - -run_lfsck() { - local facets="client $SINGLEMDS" - local found=false - local facet - local node - local rc=0 - - for facet in $facets; do - node=$(facet_active_host $facet) - if check_progs_installed $node $LFSCK_BIN; then - found=true - break - fi - done - ! $found && error "None of \"$facets\" supports lfsck" - - run_lfsck_remote $node || rc=$? - - rm -rvf $MDSDB* $OSTDB* || true - return $rc + 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 - generate_db - run_lfsck - fi + if [ "$LFSCK_ALWAYS" = "yes" -a "$TESTSUITE" != "sanity-lfsck" -a \ + "$TESTSUITE" != "sanity-scrub" ]; then + run_lfsck + fi if is_mounted $MOUNT; then [ -n "$DIR" ] && rm -rf $DIR/[Rdfs][0-9]* || @@ -4057,18 +4282,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 } ####### @@ -4266,24 +4491,24 @@ 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() { -# OBD_FAIL_UPDATE_OBJ_NET_REP +# OBD_FAIL_OUT_UPDATE_NET_REP local index=$1 shift 1 RC=0 @@ -4319,21 +4544,51 @@ drop_ldlm_cancel() { return $RC } -drop_bl_callback() { +drop_bl_callback_once() { + local 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 fail_val=0 + 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 fail_val=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 } @@ -4350,12 +4605,10 @@ set_nodes_failloc () { } 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' - $LCTL mark "cancel_lru_locks $1 stop" + #$LCTL mark "cancel_lru_locks $1 start" + $LCTL set_param -n ldlm.namespaces.*$1*.lru_size=clear + $LCTL get_param ldlm.namespaces.*$1*.lock_unused_count | grep -v '=0' + #$LCTL mark "cancel_lru_locks $1 stop" } default_lru_size() @@ -4375,6 +4628,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 @@ -4424,7 +4684,7 @@ stop_full_debug_logging() { } # prints bash call stack -log_trace_dump() { +print_stack_trace() { echo " Trace dump:" for (( i=1; i < ${#BASH_LINENO[*]} ; i++ )) ; do local s=${BASH_SOURCE[$i]} @@ -4450,7 +4710,7 @@ error_noexit() { log " ${TESTSUITE} ${TESTNAME}: @@@@@@ ${TYPE}: $@ " - log_trace_dump + print_stack_trace >&2 mkdir -p $LOGDIR # We need to dump the logs on all nodes @@ -4470,6 +4730,9 @@ error_noexit() { echo "$@" > $LOGDIR/err fi fi + + # cleanup the env for failed tests + reset_fail_loc } exit_status () { @@ -4575,69 +4838,69 @@ 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() { - echo "$*" - module_loaded lnet || load_modules + echo "$*" >&2 + load_module ../libcfs/libcfs/libcfs local MSG="$*" # Get rid of ' @@ -4691,7 +4954,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. } @@ -4711,6 +4975,18 @@ banner() { log "$msg== $(date +"%H:%M:%S (%s)")" } +check_dmesg_for_errors() { + local res + local errors="VFS: Busy inodes after unmount of\|\ +ldiskfs_check_descriptors: Checksum for group 0 failed\|\ +group descriptors corrupted" + + res=$(do_nodes $(comma_list $(nodes_list)) "dmesg" | grep "$errors") + [ -z "$res" ] && return 0 + echo "Kernel error detected: $res" + return 1 +} + # # Run a single test function and cleanup after it. # @@ -4726,12 +5002,17 @@ run_one() { local SAVE_UMASK=`umask` umask 0022 + if ! grep -q $DIR /proc/mounts; then + $SETUP + fi + 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" + check_dmesg_for_errors || error "Error in dmesg detected" if [ "$PARALLEL" != "yes" ]; then ps auxww | grep -v grep | grep -q multiop && error "multiop still running" @@ -4740,6 +5021,7 @@ run_one() { unset tdir unset tfile umask $SAVE_UMASK + $CLEANUP return 0 } @@ -4750,14 +5032,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 @@ -4768,7 +5052,7 @@ run_one_logged() { [ $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 @@ -4785,6 +5069,7 @@ run_one_logged() { fi if [ -f $LOGDIR/err ]; then + log_zfs_info "$zfs_debug_log" $FAIL_ON_ERROR && exit $RC fi @@ -4803,46 +5088,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 } ######################## @@ -4965,6 +5249,7 @@ require_dsh_ost() remote_mgs_nodsh() { + [ "$CLIENTONLY" ] && return 0 || true local MGS MGS=$(facet_host mgs) remote_node $MGS && [ "$PDSH" = "no_dsh" -o -z "$PDSH" -o -z "$ost_HOST" ] @@ -5184,14 +5469,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. @@ -5347,7 +5632,7 @@ do_and_time () { SECONDS=0 eval '$cmd' - + [ ${PIPESTATUS[0]} -eq 0 ] || rc=1 echo $SECONDS @@ -5355,8 +5640,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 () { @@ -5371,25 +5657,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 () { @@ -5427,50 +5713,15 @@ restore_lustre_params() { } check_catastrophe() { - local rnodes=${1:-$(comma_list $(remote_nodes_list))} - local C=$CATASTROPHE - [ -f $C ] && [ $(cat $C) -ne 0 ] && return 1 - - [ -z "$rnodes" ] && return 0 - - local data - data=$(do_nodes "$rnodes" "rc=\\\$([ -f $C ] && - echo \\\$(< $C) || echo 0); - if [ \\\$rc -ne 0 ]; then echo \\\$(hostname): \\\$rc; fi - exit \\\$rc") - local rc=$? - if [ -n "$data" ]; then - echo $data - return $rc - fi - return 0 -} - -# CMD: determine mds index where directory inode presents -get_mds_dir () { - local dir=$1 - local file=$dir/f0.get_mds_dir_tmpfile + local nodes=${1:-$(comma_list $(nodes_list))} - mkdir -p $dir - rm -f $file - sleep 1 - local iused=$(lfs df -i $dir | grep MDT | awk '{print $3}') - local -a oldused=($iused) - - 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_nodes $nodes "rc=0; +val=\\\$($LCTL get_param -n catastrophe 2>&1); +if [[ \\\$? -eq 0 && \\\$val -ne 0 ]]; then + echo \\\$(hostname -s): \\\$val; + rc=\\\$val; +fi; +exit \\\$rc" } mdsrate_cleanup () { @@ -5505,17 +5756,7 @@ convert_facet2label() { } get_clientosc_proc_path() { - echo "${1}-osc-*" -} - -get_lustre_version () { - local facet=${1:-"$SINGLEMDS"} - do_facet $facet $LCTL get_param -n version | awk '/^lustre:/ {print $2}' -} - -lustre_version_code() { - local facet=${1:-"$SINGLEMDS"} - version_code $(get_lustre_version $1) + echo "${1}-osc-*" } # If the 2.0 MDS was mounted on 1.8 device, then the OSC and LOV names @@ -5533,19 +5774,21 @@ mds_on_old_device() { } get_mdtosc_proc_path() { - local mds_facet=$1 - local ost_label=${2:-"*OST*"} - - [ "$mds_facet" = "mds" ] && mds_facet=$SINGLEMDS - local mdt_label=$(convert_facet2label $mds_facet) - local mdt_index=$(echo $mdt_label | sed -e 's/^.*-//') - - if [ $(lustre_version_code $mds_facet) -le $(version_code 1.8.0) ] || - mds_on_old_device $mds_facet; then - echo "${ost_label}-osc" - else - echo "${ost_label}-osc-${mdt_index}" - fi + local mds_facet=$1 + local ost_label=${2:-"*OST*"} + + [ "$mds_facet" = "mds" ] && mds_facet=$SINGLEMDS + local mdt_label=$(convert_facet2label $mds_facet) + local mdt_index=$(echo $mdt_label | sed -e 's/^.*-//') + + if [ $(lustre_version_code $mds_facet) -le $(version_code 1.8.0) ] || + mds_on_old_device $mds_facet; then + echo "${ost_label}-osc" + elif [[ $ost_label = *OST* ]]; then + echo "${ost_label}-osc-${mdt_index}" + else + echo "${ost_label}-osp-${mdt_index}" + fi } get_osc_import_name() { @@ -5566,6 +5809,7 @@ _wait_import_state () { local expected=$1 local CONN_PROC=$2 local maxtime=${3:-$(max_recovery_time)} + local error_on_failure=${4:-1} local CONN_STATE local i=0 @@ -5578,9 +5822,12 @@ _wait_import_state () { # reconnect timeout and test can't see real disconnect [ "${CONN_STATE}" == "CONNECTING" ] && return 0 fi - [ $i -ge $maxtime ] && \ - error "can't put import for $CONN_PROC into ${expected} state after $i sec, have ${CONN_STATE}" && \ + if [ $i -ge $maxtime ]; then + [ $error_on_failure -ne 0 ] && \ + error "can't put import for $CONN_PROC into ${expected}" \ + "state after $i sec, have ${CONN_STATE}" return 1 + fi sleep 1 # Add uniq for multi-mount case CONN_STATE=$($LCTL get_param -n $CONN_PROC 2>/dev/null | cut -f2 | uniq) @@ -5595,10 +5842,11 @@ wait_import_state() { local state=$1 local params=$2 local maxtime=${3:-$(max_recovery_time)} + local error_on_failure=${4:-1} local param for param in ${params//,/ }; do - _wait_import_state $state $param $maxtime || return + _wait_import_state $state $param $maxtime $error_on_failure || return done } @@ -5654,8 +5902,8 @@ _wait_osc_import_state() { 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 target=$(get_osc_import_name $facet $ost_facet) + local param="osc.${target}.ost_server_uuid" local params=$param local i=0 @@ -5679,6 +5927,16 @@ _wait_osc_import_state() { params=$($LCTL list_param $param 2>/dev/null || true) done fi + + if [[ $ost_facet = mds* ]]; then + # no OSP connection to itself + if [[ $facet = $ost_facet ]]; then + return 0 + fi + param="osp.${target}.mdt_server_uuid" + params=$param + fi + if ! do_rpc_nodes "$(facet_active_host $facet)" \ wait_import_state $expected "$params" $maxtime; then error "import is not in ${expected} state" @@ -5703,10 +5961,81 @@ wait_osc_import_state() { fi } +_wait_mgc_import_state() { + local facet=$1 + local expected=$2 + local error_on_failure=${3:-1} + local param="mgc.*.mgs_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))) + + 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 + 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 \ + $error_on_failure; then + if [ $error_on_failure -ne 0 ]; then + error "import is not in ${expected} state" + fi + return 1 + fi + + return 0 +} + +wait_mgc_import_state() { + local facet=$1 + local expected=$2 + local error_on_failure=${3:-1} + local num + + if [[ $facet = mds ]]; then + for num in $(seq $MDSCOUNT); do + _wait_mgc_import_state mds$num "$expected" \ + $error_on_failure || return + done + else + _wait_mgc_import_state "$facet" "$expected" + $error_on_failure || return + fi +} + +wait_dne_interconnect() { + local num + + if [ $MDSCOUNT -gt 1 ]; then + for num in $(seq $MDSCOUNT); do + wait_osc_import_state mds mds$num FULL + done + fi +} + get_clientmdc_proc_path() { echo "${1}-mdc-*" } +get_clientmgc_proc_path() { + echo "*" +} + do_rpc_nodes () { local list=$1 shift @@ -5721,28 +6050,34 @@ do_rpc_nodes () { } wait_clients_import_state () { - local list=$1 - local facet=$2 - local expected=$3 + local list=$1 + local facet=$2 + local expected=$3 - local facets=$facet + local facets=$facet - if [ "$FAILURE_MODE" = HARD ]; then - facets=$(facets_on_host $(facet_active_host $facet)) - fi + if [ "$FAILURE_MODE" = HARD ]; then + facets=$(facets_on_host $(facet_active_host $facet)) + fi - for facet in ${facets//,/ }; do - local label=$(convert_facet2label $facet) - local proc_path - case $facet in - ost* ) proc_path="osc.$(get_clientosc_proc_path $label).ost_server_uuid" ;; - mds* ) proc_path="mdc.$(get_clientmdc_proc_path $label).mds_server_uuid" ;; - *) error "unknown facet!" ;; - esac - local params=$(expand_list $params $proc_path) - done + for facet in ${facets//,/ }; do + local label=$(convert_facet2label $facet) + local proc_path + case $facet in + ost* ) proc_path="osc.$(get_clientosc_proc_path \ + $label).ost_server_uuid" ;; + mds* ) proc_path="mdc.$(get_clientmdc_proc_path \ + $label).mds_server_uuid" ;; + mgs* ) proc_path="mgc.$(get_clientmgc_proc_path \ + $label).mgs_server_uuid" ;; + *) error "unknown facet!" ;; + esac + + local params=$(expand_list $params $proc_path) + done - if ! do_rpc_nodes "$list" wait_import_state_mount $expected $params; then + if ! do_rpc_nodes "$list" wait_import_state_mount $expected $params; + then error "import is not in ${expected} state" return 1 fi @@ -5799,19 +6134,21 @@ create_pool() { } add_pool_to_list () { - local fsname=${1%%.*} - local poolname=${1##$fsname.} + local fsname=${1%%.*} + local poolname=${1##$fsname.} - local listvar=${fsname}_CREATED_POOLS - eval export ${listvar}=$(expand_list ${!listvar} $poolname) + local listvar=${fsname}_CREATED_POOLS + local temp=${listvar}=$(expand_list ${!listvar} $poolname) + eval export $temp } remove_pool_from_list () { - local fsname=${1%%.*} - local poolname=${1##$fsname.} + local fsname=${1%%.*} + local poolname=${1##$fsname.} - local listvar=${fsname}_CREATED_POOLS - eval export ${listvar}=$(exclude_items_from_list ${!listvar} $poolname) + local listvar=${fsname}_CREATED_POOLS + local temp=${listvar}=$(exclude_items_from_list ${!listvar} $poolname) + eval export $temp } destroy_pool_int() { @@ -5929,22 +6266,48 @@ do_ls () { return $rc } -# target_start_and_reset_recovery_timer() -# service_time = at_est2timeout(service_time); -# service_time += 2 * (CONNECTION_SWITCH_MAX + CONNECTION_SWITCH_INC + -# INITIAL_CONNECT_TIMEOUT); -# CONNECTION_SWITCH_MAX : min(25U, max(CONNECTION_SWITCH_MIN,obd_timeout)) -#define CONNECTION_SWITCH_INC 1 -#define INITIAL_CONNECT_TIMEOUT max(CONNECTION_SWITCH_MIN,obd_timeout/20) -#define CONNECTION_SWITCH_MIN 5U +# check_and_start_recovery_timer() +# service_time = at_est2timeout(service_time); +# service_time += 2 * INITIAL_CONNECT_TIMEOUT; +# service_time += 2 * (CONNECTION_SWITCH_MAX + CONNECTION_SWITCH_INC); -max_recovery_time () { - local init_connect_timeout=$(( TIMEOUT / 20 )) - [[ $init_connect_timeout -ge 5 ]] || init_connect_timeout=5 +#define INITIAL_CONNECT_TIMEOUT max(CONNECTION_SWITCH_MIN, obd_timeout/20) +#define CONNECTION_SWITCH_MAX min(50, max(CONNECTION_SWITCH_MIN, obd_timeout)) +#define CONNECTION_SWITCH_MIN 5 +#define CONNECTION_SWITCH_INC 5 +max_recovery_time() { + local init_connect_timeout=$((TIMEOUT / 20)) + ((init_connect_timeout >= 5)) || init_connect_timeout=5 + + local service_time=$(($(at_max_get client) * 9 / 4 + 5)) + service_time=$((service_time + 2 * (init_connect_timeout + 50 + 5))) + + echo -n $service_time +} + +recovery_time_min() { + local connection_switch_min=5 + local connection_switch_inc=5 + local connection_switch_max + local reconnect_delay_max + local initial_connect_timeout + local max + local timout_20 + + #connection_switch_max=min(50, max($connection_switch_min,$TIMEOUT) + (($connection_switch_min > $TIMEOUT)) && + max=$connection_switch_min || max=$TIMEOUT + (($max < 50)) && connection_switch_max=$max || connection_switch_max=50 - local service_time=$(( $(at_max_get client) + $(( 2 * $(( 25 + 1 + init_connect_timeout)) )) )) + #initial_connect_timeout = max(connection_switch_min, obd_timeout/20) + timeout_20=$((TIMEOUT/20)) + (($connection_switch_min > $timeout_20)) && + initial_connect_timeout=$connection_switch_min || + initial_connect_timeout=$timeout_20 - echo $service_time + reconnect_delay_max=$((connection_switch_max + connection_switch_inc + \ + initial_connect_timeout)) + echo $((2 * reconnect_delay_max)) } get_clients_mount_count () { @@ -6573,12 +6936,14 @@ generate_string() { reformat_external_journal() { local facet=$1 + local var - if [ ! -z ${EJOURNAL} ]; then + var=${facet}_JRN + if [ -n "${!var}" ]; then local rcmd="do_facet $facet" - echo "reformat external journal on $facet:${EJOURNAL}" - ${rcmd} mke2fs -O journal_dev ${EJOURNAL} || return 1 + echo "reformat external journal on $facet:${!var}" + ${rcmd} mke2fs -O journal_dev ${!var} || return 1 fi } @@ -6618,14 +6983,10 @@ mds_backup_restore() { echo "backup data" ${rcmd} tar zcf $metadata -C $mntpt/ . > /dev/null 2>&1 || return 3 # step 6: umount - ${rcmd} umount -d $mntpt || return 4 - # step 7: reformat external journal if needed - reformat_external_journal $facet || return 5 + ${rcmd} $UMOUNT $mntpt || return 4 # step 8: reformat dev echo "reformat new device" - add $facet $(mkfs_opts $facet ${devname}) --backfstype ldiskfs \ - --reformat ${devname} $(mdsvdevname $(facet_number $facet)) \ - > /dev/null || exit 6 + format_mdt $(facet_number $facet) # step 9: mount dev ${rcmd} mount -t ldiskfs $opts $devname $mntpt || return 7 # step 10: restore metadata @@ -6638,7 +6999,7 @@ mds_backup_restore() { echo "remove recovery logs" ${rcmd} rm -fv $mntpt/OBJECTS/* $mntpt/CATALOGS # step 13: umount dev - ${rcmd} umount -d $mntpt || return 10 + ${rcmd} $UMOUNT $mntpt || return 10 # step 14: cleanup tmp backup ${rcmd} rm -f $metaea $metadata # step 15: reset device label - it's not virgin on @@ -6678,7 +7039,7 @@ mds_remove_ois() { done fi # step 4: umount - ${rcmd} umount -d $mntpt || return 2 + ${rcmd} $UMOUNT $mntpt || return 2 # OI files will be recreated when mounted as lustre next time. } @@ -6692,49 +7053,46 @@ generate_logname() { # make directory on different MDTs test_mkdir() { - local option - local parent - local child local path - local rc=0 - - case $# in - 1) path=$1;; - 2) option=$1 - path=$2;; - *) error "Only creating single directory is supported";; - esac + local p_option + local stripe_count=2 + local stripe_index=-1 + local OPTIND=1 + + while getopts "c:i:p" opt; do + case $opt in + c) stripe_count=$OPTARG;; + i) stripe_index=$OPTARG;; + p) p_option="-p";; + \?) error "only support -i -c -p";; + esac + done - child=$(basename $path) - parent=$(dirname $path) + shift $((OPTIND - 1)) + [ $# -eq 1 ] || error "Only creating single directory is supported" + path="$*" - if [ "$option" == "-p" -a -d $parent/$child ]; then - return $rc - fi + if [ "$p_option" == "-p" ]; then + local parent=$(dirname $path) - if [ ! -d ${parent} ]; then - if [ "$option" == "-p" ]; then - mkdir -p ${parent} - else - return 1 - fi + [ -d $path ] && return 0 + [ ! -d ${parent} ] && mkdir -p ${parent} fi if [ $MDSCOUNT -le 1 ]; then - mkdir $option $parent/$child || rc=$? + mkdir $path else - local mdt_idx=$($LFS getstripe -M $parent) local test_num=$(echo $testnum | sed -e 's/[^0-9]*//g') + local mdt_index - if [ "$mdt_idx" -ne 0 ]; then - mkdir $option $parent/$child || rc=$? + if [ $stripe_index -eq -1 ]; then + mdt_index=$((test_num % MDSCOUNT)) else - mdt_idx=$((test_num % MDSCOUNT)) - echo "mkdir $mdt_idx for $parent/$child" - $LFS setdirstripe -i $mdt_idx $parent/$child || rc=$? + mdt_index=$stripe_index fi + echo "striped dir -i$mdt_index -c$stripe_count $path" + $LFS setdirstripe -i$mdt_index -c$stripe_count $path fi - return $rc } # find the smallest and not in use file descriptor @@ -6748,3 +7106,341 @@ free_fd() [ $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 + 1)) lctl get_param -n \ + osp.$proc_path.prealloc_last_id) + local next_id=$(do_facet mds$((mdt_idx + 1)) 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 "$FSNAME.${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" +} + +killall_process () { + local clients=${1:-$(hostname)} + local name=$2 + local signal=$3 + local rc=0 + + do_nodes $clients "killall $signal $name" +}