From: Mikhail Pershin Date: Thu, 21 Aug 2014 10:23:33 +0000 (+0400) Subject: LU-3285 test: add Data-on-MDT tests and fixes X-Git-Tag: 2.10.56~64^2~11 X-Git-Url: https://git.whamcloud.com/?p=fs%2Flustre-release.git;a=commitdiff_plain;h=a7625cd2f37ac569ccede4ebfc6fcfc1151fbe6c LU-3285 test: add Data-on-MDT tests and fixes - add test for basic DoM functionality in sanity.sh - add test to read/write many files with small chunks of data, it is used for performance comparision. - the sanity-dom.sh is added to test Data-on-MDT. It contains specific sanity tests and calls sanity.sh and sanityn.sh with limited set of test to cover the same cases as OSC. - fixes for DoM code for issues revealed by tests. Test-Parameters: mdssizegb=20 testlist=sanity-dom,dom-performance Signed-off-by: Mikhal Pershin Change-Id: I17fbbf8e913cc14043703969d01ac65e6828fcc6 Reviewed-on: https://review.whamcloud.com/28020 Tested-by: Jenkins Tested-by: Maloo Reviewed-by: Jinshan Xiong Reviewed-by: Andreas Dilger --- diff --git a/lustre/lov/lov_object.c b/lustre/lov/lov_object.c index 216221a..ac0493e 100644 --- a/lustre/lov/lov_object.c +++ b/lustre/lov/lov_object.c @@ -449,8 +449,16 @@ static int lov_attr_get_dom(const struct lu_env *env, struct lov_object *lov, return OST_LVB_GET_ERR(loi->loi_lvb.lvb_blocks); cl_lvb2attr(attr, &loi->loi_lvb); - attr->cat_kms = attr->cat_size > loi->loi_kms ? attr->cat_size : - loi->loi_kms; + + /* DoM component size can be bigger than stripe size after + * client's setattr RPC, so do not count anything beyound + * component end. Alternatively, check that limit on server + * and do not allow size overflow there. */ + if (attr->cat_size > lle->lle_extent.e_end) + attr->cat_size = lle->lle_extent.e_end; + + attr->cat_kms = attr->cat_size; + dom->lo_dom_r0.lo_attr_valid = 1; *lov_attr = attr; @@ -530,7 +538,6 @@ static int lov_init_dom(const struct lu_env *env, struct lov_device *dev, struct cl_device *mdcdev; struct lov_oinfo *loi = NULL; struct cl_object_conf *sconf = <i->lti_stripe_conf; - struct inode *inode = conf->coc_inode; int rc; __u32 idx = 0; @@ -563,15 +570,6 @@ static int lov_init_dom(const struct lu_env *env, struct lov_device *dev, RETURN(-ENOMEM); fid_to_ostid(lu_object_fid(lov2lu(lov)), &loi->loi_oi); - /* Initialize lvb structure */ - loi->loi_lvb.lvb_mtime = LTIME_S(inode->i_mtime); - loi->loi_lvb.lvb_atime = LTIME_S(inode->i_atime); - loi->loi_lvb.lvb_ctime = LTIME_S(inode->i_ctime); - loi->loi_lvb.lvb_blocks = inode->i_blocks; - loi->loi_lvb.lvb_size = i_size_read(inode); - if (loi->loi_lvb.lvb_size > lsme->lsme_stripe_size) - loi->loi_lvb.lvb_size = lsme->lsme_stripe_size; - loi_kms_set(loi, loi->loi_lvb.lvb_size); sconf->u.coc_oinfo = loi; again: @@ -879,6 +877,11 @@ static int lov_attr_get_composite(const struct lu_env *env, if (lov_attr == NULL) continue; + CDEBUG(D_INODE, "COMP ID #%i: s=%llu m=%llu a=%llu c=%llu " + "b=%llu\n", index - 1, lov_attr->cat_size, + lov_attr->cat_mtime, lov_attr->cat_atime, + lov_attr->cat_ctime, lov_attr->cat_blocks); + /* merge results */ attr->cat_blocks += lov_attr->cat_blocks; if (attr->cat_size < lov_attr->cat_size) diff --git a/lustre/tests/.gitignore b/lustre/tests/.gitignore index 2bce603..eb86343 100644 --- a/lustre/tests/.gitignore +++ b/lustre/tests/.gitignore @@ -69,6 +69,7 @@ /setuid /sleeptest /small_write +/smalliomany /stat /statmany /statone diff --git a/lustre/tests/Makefile.am b/lustre/tests/Makefile.am index 33598d2..68dabfb 100644 --- a/lustre/tests/Makefile.am +++ b/lustre/tests/Makefile.am @@ -39,6 +39,7 @@ noinst_SCRIPTS += posix.sh sanity-scrub.sh scrub-performance.sh ha.sh noinst_SCRIPTS += sanity-lfsck.sh lfsck-performance.sh noinst_SCRIPTS += resolveip noinst_SCRIPTS += sanity-hsm.sh sanity-lsnapshot.sh sanity-pfl.sh +noinst_SCRIPTS += sanity-dom.sh dom-performance.sh nobase_noinst_SCRIPTS = cfg/local.sh nobase_noinst_SCRIPTS += test-groups/regression test-groups/regression-mpi nobase_noinst_SCRIPTS += acl/make-tree acl/run cfg/ncli.sh @@ -68,7 +69,7 @@ noinst_PROGRAMS = openunlink truncate directio writeme mlink utime noinst_PROGRAMS += tchmod fsx test_brw sendfile noinst_PROGRAMS += createmany chownmany statmany multifstat createtest noinst_PROGRAMS += opendirunlink opendevunlink unlinkmany checkstat -noinst_PROGRAMS += statone runas openfile rmdirmany +noinst_PROGRAMS += statone runas openfile rmdirmany smalliomany noinst_PROGRAMS += small_write multiop ll_sparseness_verify noinst_PROGRAMS += ll_sparseness_write mrename ll_dirstripe_verify mkdirmany noinst_PROGRAMS += openfilleddirunlink rename_many memhog diff --git a/lustre/tests/conf-sanity.sh b/lustre/tests/conf-sanity.sh index 7fd8581..a678edc 100644 --- a/lustre/tests/conf-sanity.sh +++ b/lustre/tests/conf-sanity.sh @@ -1687,6 +1687,7 @@ t32_test() { local tarball=$1 local writeconf=$2 local dne_upgrade=${dne_upgrade:-"no"} + local dom_upgrade=${dom_upgrade:-"no"} local ff_convert=${ff_convert:-"no"} local shall_cleanup_mdt=false local shall_cleanup_mdt1=false @@ -2023,11 +2024,6 @@ t32_test() { shall_cleanup_lustre=true $r $LCTL set_param debug="$PTLDEBUG" - t32_verify_quota $node $fsname $tmp/mnt/lustre || { - error_noexit "verify quota failed" - return 1 - } - if $r test -f $tmp/list; then # # There is not a Test Framework API to copy files to or @@ -2079,6 +2075,43 @@ t32_test() { echo "list verification skipped" fi + if [ "$dom_upgrade" != "no" ]; then + echo "Check DoM file can be created" + $SETSTRIPE -E 1M -L mdt -E EOF $tmp/mnt/lustre/dom || { + error_noexit "Verify DoM creation" + return 1 + } + [ $($GETSTRIPE -L $tmp/mnt/lustre/dom) == 100 ] || { + error_noexit "Verify a DoM file" + return 1 + } + dd if=/dev/urandom of=$tmp/mnt/lustre/dom bs=4096 \ + count=1 conv=fsync || { + error_noexit "Cannot write to DoM file" + return 1 + } + [ $(stat -c%s $tmp/mnt/lustre/dom) == 4096 ] || { + error_noexit "DoM: bad size after write" + return 1 + } + rm $tmp/mnt/lustre/dom + + $r $LCTL get_param -n lod.*MDT0000*.dom_stripesize || { + error_noexit "Getting \"dom_stripesize\"" + return 1 + } + $r $LCTL conf_param \ + $fsname-MDT0000.lod.dom_stripesize=0 || { + error_noexit "Changing \"dom_stripesize\"" + return 1 + } + wait_update $(facet_host mds) "$LCTL get_param \ + -n lod.*MDT0000*.dom_stripesize" 0 || { + error_noexit "Verifying \"dom_stripesize\"" + return 1 + } + fi + if [ "$dne_upgrade" != "no" ]; then $LFS mkdir -i 1 -c2 $tmp/mnt/lustre/striped_dir || { error_noexit "set striped dir failed" @@ -2383,6 +2416,21 @@ test_32d() { } run_test 32d "convert ff test" +test_32e() { + local tarballs + local tarball + local rc=0 + + t32_check + for tarball in $tarballs; do + echo $tarball | grep "2_9" || continue + #load_modules + dom_upgrade=yes t32_test $tarball writeconf || let "rc += $?" + done + return $rc +} +run_test 32e "dom upgrade test" + test_33a() { # bug 12333, was test_33 local FSNAME2=test-123 local MDSDEV=$(mdsdevname ${SINGLEMDS//mds/}) diff --git a/lustre/tests/dom-performance.sh b/lustre/tests/dom-performance.sh new file mode 100644 index 0000000..a75e849 --- /dev/null +++ b/lustre/tests/dom-performance.sh @@ -0,0 +1,324 @@ +#!/bin/bash +# +# Run select tests by setting ONLY, or as arguments to the script. +# Skip specific tests by setting EXCEPT. +# + +set -e + +ONLY=${ONLY:-"$*"} +ALWAYS_EXCEPT="" +[ "$SLOW" = "no" ] && EXCEPT_SLOW="" +# UPDATE THE COMMENT ABOVE WITH BUG NUMBERS WHEN CHANGING ALWAYS_EXCEPT! + +LUSTRE=${LUSTRE:-$(cd $(dirname $0)/..; echo $PWD)} + +. $LUSTRE/tests/test-framework.sh +CLEANUP=${CLEANUP:-:} +SETUP=${SETUP:-:} +init_test_env $@ +. ${CONFIG:=$LUSTRE/tests/cfg/$NAME.sh} +init_logging + +FAIL_ON_ERROR=false + +check_and_setup_lustre + +# $RUNAS_ID may get set incorrectly somewhere else +if [[ $UID -eq 0 && $RUNAS_ID -eq 0 ]]; then + skip_env "\$RUNAS_ID set to 0, but \$UID is also 0!" && exit +fi +check_runas_id $RUNAS_ID $RUNAS_GID $RUNAS + +build_test_filter + +DOM="yes" +DOM_SIZE=${DOM_SIZE:-"1M"} +OSC="mdc" + +rm -rf $DIR/* + +NORM=$DIR/norm +DOM=$DIR/dom +STATS=${STATS:-"yes"} + +# 1 stripe for normal files +mkdir -p $NORM +lfs setstripe -c 1 $NORM + +if [ "x$DNE" == "xyes" ] ; then + lfs setdirstripe -i 0 -c 2 $DOM +else + mkdir -p $DOM +fi + +lfs setstripe -E ${DOM_SIZE} -L mdt -E EOF $DOM + +# total number of files +FNUM=16384 +# number of threads +NUM=4 + +clear_stats() { + local cli=$1 + + $LCTL set_param -n ${cli}.*.${cli}_stats=0 + $LCTL set_param -n ${cli}.*.rpc_stats=0 + $LCTL set_param -n ${cli}.*.stats=0 + $LCTL set_param -n llite.*.read_ahead_stats=0 + $LCTL set_param -n llite.*.unstable_stats=0 +} + +collect_stats() { + local cli=$1 + + sync;sync + + if [ "x$STATS" != "xyes" ] ; then + return 0 + fi + + $LCTL get_param ${cli}.*.${cli}_stats + $LCTL get_param ${cli}.*.rpc_stats + # for OSC get both OSC and MDC stats + if [ $cli == "osc" ] ; then + $LCTL get_param mdc.*.stats + fi + $LCTL get_param ${cli}.*.stats + $LCTL get_param ${cli}.*.unstable_stats + $LCTL get_param ${cli}.*.${cli}_cached_mb + $LCTL get_param llite.*.read_ahead_stats +} + +setup_test() { + local cli=$1 + + cancel_lru_locks $cli + ### drop all debug + $LCTL set_param -n debug=0 + clear_stats $cli +} + +run_cmd() { + local cmd=$1 + + setup_test $OSC + if ! grep -qw "$MOUNT" /proc/mounts ; then + echo "!!!!! Lustre is not mounted !!!!!, aborting" + return 0 + fi + + echo "##### $cmd #####" + echo "##### $(date +'%F %H:%M:%S'): START" + eval $cmd + echo "##### $(date +'%F %H:%M:%S'): GETSTATS" + collect_stats $OSC + echo "##### $(date +'%F %H:%M:%S'): STOP" + remount_client $DIR + +} + +run_MDtest() { + if ! which mdtest > /dev/null 2>&1 ; then + echo "Mdtest is not installed, skipping" + return 0 + fi + + local mdtest=$(which mdtest) + + local TDIR=${1:-$MOUNT} + local th_num=$((FNUM * 2 / NUM)) + + for bsize in 4096 ; do + run_cmd "mpirun -np $NUM $mdtest \ + -i 3 -I $th_num -F -z 1 -b 1 -L -u -w $bsize -d $TDIR" + done + rm -rf $TDIR/* + return 0 +} + +run_smalliomany() { + if [ ! -f createmany ] ; then + echo "Createmany is not installed, skipping" + return 0 + fi + + if [ ! -f smalliomany ] ; then + echo "Smalliomany is not installed, skipping" + return 0 + fi + + local TDIR=${1:-$DIR} + local count=$FNUM + + local MIN=$((count * 16)) + [ $MDSSIZE -le $MIN ] && count=$((MDSSIZE / 16)) + + run_cmd "./createmany -o $TDIR/file- $count | grep 'total'" + + if [ -f statmany ]; then + run_cmd "./statmany -s $TDIR/file- $count $((count * 5)) | \ + grep 'total'" + fi + + for opc in w a r ; do + run_cmd "./smalliomany -${opc} $TDIR/file- $count 300 | \ + grep 'total'" + done + + run_cmd "./unlinkmany $TDIR/file- $count | grep 'total'" + return 0 +} + +run_IOR() { + if ! which IOR > /dev/null 2>&1 ; then + echo "IOR is not installed, skipping" + return 0 + fi + + local IOR=$(which IOR) + local iter=$((FNUM / NUM)) + + if [ "x$DIO" == "xyes" ] ; then + direct="-B" + else + direct="" + fi + + local TDIR=${1:-$MOUNT} + + for bsize in 4 ; do + segments=$((128 / bsize)) + + run_cmd "mpirun -np $NUM $IOR \ + -a POSIX -b ${bsize}K -t ${bsize}K -o $TDIR/ -k \ + -s $segments -w -r -i $iter -F -E -z -m -Z $direct" + # check READ performance only (no cache) + run_cmd "mpirun -np $NUM $IOR \ + -a POSIX -b ${bsize}K -t ${bsize}K -o $TDIR/ -X 42\ + -s $segments -r -i $iter -F -E -z -m -Z $direct" + done + rm -rf $TDIR/* + return 0 +} + +run_dbench() { + if ! which dbench > /dev/null 2>&1 ; then + echo "Dbench is not installed, skipping" + return 0 + fi + + if [ "x$DNE" == "xyes" ] ; then + echo "dbench uses subdirs, skipping for DNE setup" + return 0 + fi + + local TDIR=${1:-$MOUNT} + + run_cmd "dbench -D $TDIR $NUM | egrep -v 'warmup|execute'" + rm -rf $TDIR/* + return 0 +} + +run_smallfile() { + if ! which unzip > /dev/null 2>&1 ; then + echo "No unzip is installed, skipping" + return 0; + fi + + if [ "x$DIO" == "xyes" ] ; then + echo "smallfile has no DIRECT IO mode, skipping" + return 0 + fi + + if [ "x$DNE" == "xyes" ] ; then + echo "smallfile uses subdirs, skipping for DNE setup" + return 0 + fi + + local host_set=$(hostname) + + ### since smallfile is not installed system wide, get it right now + [ -f master.zip ] || \ + wget https://github.com/bengland2/smallfile/archive/master.zip + unzip -uo master.zip + cd ./smallfile-master + + if ! ls ./smallfile_cli.py > /dev/null 2>&1 ; then + echo "No smallfile test found, skipping" + cd .. + return 0 + fi + + local TDIR=${1:-$MOUNT} + local thrds=$NUM + local fsize=64 # in Kbytes + local total=$FNUM # files in test + local fnum=$((total / NUM)) + + SYNC_DIR=${MOUNT}/sync + mkdir -p $SYNC_DIR + + SMF="./smallfile_cli.py --pause 10 --host-set $host_set \ + --response-times Y --threads $thrds --file-size $fsize \ + --files $fnum --top $TDIR --network-sync-dir $SYNC_DIR \ + --file-size-distribution exponential" + + run_cmd "$SMF --operation create" + + for oper in read append overwrite ; do + for bsize in 8 ; do + run_cmd "$SMF --record-size $bsize --operation $oper" + done + done + run_cmd "$SMF --operation delete" + + rm -rf $TDIR/* + cd .. + return 0 +} + +test_smallio() { + OSC="mdc" + run_smalliomany $DOM + OSC="osc" + run_smalliomany $NORM +} +run_test smallio "Performance comparision: smallio" + +test_mdtest() { + OSC="mdc" + run_MDtest $DOM + OSC="osc" + run_MDtest $NORM +} +run_test mdtest "Performance comparision: mdtest" + +test_IOR() { + OSC="mdc" + run_IOR $DOM + OSC="osc" + run_IOR $NORM +} +run_test IOR "Performance comparision: IOR" + +test_dbench() { + OSC="mdc" + run_dbench $DOM + OSC="osc" + run_dbench $NORM +} +run_test dbench "Performance comparision: dbench" + +test_smf() { + OSC="mdc" + run_smallfile $DOM + OSC="osc" + run_smallfile $NORM + +} +run_test smf "Performance comparision: smallfile" + +complete $SECONDS +check_and_cleanup_lustre +exit_status diff --git a/lustre/tests/sanity-dom.sh b/lustre/tests/sanity-dom.sh new file mode 100644 index 0000000..7c47479 --- /dev/null +++ b/lustre/tests/sanity-dom.sh @@ -0,0 +1,125 @@ +#!/bin/bash +# +# Run select tests by setting ONLY, or as arguments to the script. +# Skip specific tests by setting EXCEPT. +# + +set -e + +ONLY=${ONLY:-"$*"} +ALWAYS_EXCEPT="$SANITY_DOM_EXCEPT" +[ "$SLOW" = "no" ] && EXCEPT_SLOW="" +# UPDATE THE COMMENT ABOVE WITH BUG NUMBERS WHEN CHANGING ALWAYS_EXCEPT! + +LUSTRE=${LUSTRE:-$(cd $(dirname $0)/..; echo $PWD)} + +. $LUSTRE/tests/test-framework.sh +CLEANUP=${CLEANUP:-:} +SETUP=${SETUP:-:} +init_test_env $@ +. ${CONFIG:=$LUSTRE/tests/cfg/$NAME.sh} +init_logging + +MULTIOP=${MULTIOP:-multiop} +OPENFILE=${OPENFILE:-openfile} +MOUNT_2=${MOUNT_2:-"yes"} +FAIL_ON_ERROR=false + +check_and_setup_lustre + +# $RUNAS_ID may get set incorrectly somewhere else +if [[ $UID -eq 0 && $RUNAS_ID -eq 0 ]]; then + skip_env "\$RUNAS_ID set to 0, but \$UID is also 0!" && exit +fi +check_runas_id $RUNAS_ID $RUNAS_GID $RUNAS + +build_test_filter + +DOM="yes" +DOM_SIZE=${DOM_SIZE:-"$((1024*1024))"} +OSC="mdc" + +lfs setstripe -E $DOM_SIZE -L mdt -E EOF $DIR1 + +mkdir -p $MOUNT2 +mount_client $MOUNT2 + +lctl set_param debug=0xffffffff 2> /dev/null + +test_1() { + dd if=/dev/zero of=$DIR1/$tfile bs=7k count=1 || error "write 1" + $TRUNCATE $DIR2/$tfile 1000 || error "truncate" + dd if=/dev/zero of=$DIR1/$tfile bs=3k count=1 seek=1 || error "write 2" + $CHECKSTAT -t file -s 6144 $DIR2/$tfile || error "stat" + rm $DIR1/$tfile +} +run_test 1 "write a file on one mount, truncate on the other, write again" + +test_2() { + SZ1=234852 + dd if=/dev/zero of=$DIR/$tfile bs=1M count=1 seek=4 || return 1 + dd if=/dev/zero bs=$SZ1 count=1 >> $DIR/$tfile || return 2 + dd if=$DIR/$tfile of=$DIR/${tfile}_left bs=1M skip=5 || return 3 + $CHECKSTAT -t file -s $SZ1 $DIR/${tfile}_left || + error "Error reading at the end of the file $tfile" +} +run_test 2 "Write with a seek, append, read from a single mountpoint" + +test_3() { + # Write on one node to the DoM stripe and then truncate to over DoM size + dd if=/dev/zero of=$DIR1/$tfile bs=$((DOM_SIZE-100)) count=1 || + return 1 + truncate $DIR1/$tfile $((DOM_SIZE+700)) || return 2 + # read on the second node inside DoM stripe to take a lock data from + # the first client + dd if=$DIR2/$tfile of=/dev/null bs=4096 count=1 seek=1 || return 3 + $CHECKSTAT -t file -s $((DOM_SIZE+700)) $DIR2/$tfile || + error "Wrong size after first truncate $tfile on first node" + # now do local truncate over DoM size and check size is correct + truncate $DIR2/$tfile $((DOM_SIZE+500)) || return 4 + $CHECKSTAT -t file -s $((DOM_SIZE+500)) $DIR2/$tfile || + error "Wrong size after second truncate on the same node" + $CHECKSTAT -t file -s $((DOM_SIZE+500)) $DIR1/$tfile || + error "Wrong size after second truncate on other node" +} +run_test 3 "Truncate over DoM size on different nodes" + +# TODO: tests below are from sanityn but their adapted version should be +# put here: 31 32 34 71 75 + +test_sn16() { + local file1=$DIR1/$tfile + local file2=$DIR2/$tfile + + touch $file1 + fsx -c 50 -p 1 -N 1000 -l $(($DOM_SIZE*2)) -S 0 -d -d $file1 $file2 +} +run_test sn16 "$FSXNUM iterations of dual-mount fsx" + +test_sanity() +{ + local SAVE_ONLY=$ONLY + + [ ! -f sanity.sh ] && skip_env "No sanity.sh skipping" && return + # XXX: to fix 45 + ONLY="36 39 40 41 42 43 46 56r 101e 119a 131 150 155a 155b 155c \ + 155d 207 241 251" OSC="mdc" DOM="yes" sh sanity.sh + ONLY=$SAVE_ONLY +} +run_test sanity "Run sanity with Data-on-MDT files" + +test_sanityn() +{ + local SAVE_ONLY=$ONLY + + [ ! -f sanity.sh ] && skip_env "No sanity.sh skipping" && return + # XXX: to fix 60 + ONLY="1 2 4 5 6 7 8 9 10 11 12 14 17 19 20 23 27 39 51a 51c 51d" \ + OSC="mdc" DOM="yes" sh sanityn.sh + ONLY=$SAVE_ONLY +} +run_test sanityn "Run sanityn with Data-on-MDT files" + +complete $SECONDS +check_and_cleanup_lustre +exit_status diff --git a/lustre/tests/sanity.sh b/lustre/tests/sanity.sh index 628cf5b..f3ce898 100755 --- a/lustre/tests/sanity.sh +++ b/lustre/tests/sanity.sh @@ -40,6 +40,7 @@ SRCDIR=$(cd $(dirname $0); echo $PWD) export PATH=$PATH:/sbin TMP=${TMP:-/tmp} +OSC=${OSC:-"osc"} CC=${CC:-cc} CHECKSTAT=${CHECKSTAT:-"checkstat -v"} @@ -3587,7 +3588,7 @@ test_41() { run_test 41 "test small file write + fstat =====================" count_ost_writes() { - lctl get_param -n osc.*.stats | + lctl get_param -n ${OSC}.*.stats | awk -vwrites=0 '/ost_write/ { writes += $2 } \ END { printf("%0.0f", writes) }' } @@ -3647,7 +3648,7 @@ setup_test42() { test_42a() { [ $PARALLEL == "yes" ] && skip "skip parallel run" && return setup_test42 - cancel_lru_locks osc + cancel_lru_locks $OSC stop_writeback sync; sleep 1; sync # just to be safe BEFOREWRITES=`count_ost_writes` @@ -3663,7 +3664,7 @@ run_test 42a "ensure that we don't flush on close" test_42b() { [ $PARALLEL == "yes" ] && skip "skip parallel run" && return setup_test42 - cancel_lru_locks osc + cancel_lru_locks $OSC stop_writeback sync dd if=/dev/zero of=$DIR/f42b bs=1024 count=100 @@ -3699,21 +3700,21 @@ run_test 42b "test destroy of file with cached dirty data ======" # start the file with a full-file pw lock to match against # until the truncate. trunc_test() { - test=$1 - file=$DIR/$test - offset=$2 - cancel_lru_locks osc + test=$1 + file=$DIR/$test + offset=$2 + cancel_lru_locks $OSC stop_writeback # prime the file with 0,EOF PW to match touch $file $TRUNCATE $file 0 sync; sync # now the real test.. - dd if=/dev/zero of=$file bs=1024 count=100 - BEFOREWRITES=`count_ost_writes` - $TRUNCATE $file $offset - cancel_lru_locks osc - AFTERWRITES=`count_ost_writes` + dd if=/dev/zero of=$file bs=1024 count=100 + BEFOREWRITES=`count_ost_writes` + $TRUNCATE $file $offset + cancel_lru_locks $OSC + AFTERWRITES=`count_ost_writes` start_writeback } @@ -3912,7 +3913,7 @@ run_test 44a "test sparse pwrite ===============================" dirty_osc_total() { tot=0 - for d in `lctl get_param -n osc.*.cur_dirty_bytes`; do + for d in `lctl get_param -n ${OSC}.*.cur_dirty_bytes`; do tot=$(($tot + $d)) done echo $tot @@ -6784,7 +6785,7 @@ test_101e() { done echo "Cancel LRU locks on lustre client to flush the client cache" - cancel_lru_locks osc + cancel_lru_locks $OSC echo "Reset readahead stats" $LCTL set_param -n llite.*.read_ahead_stats 0 @@ -10078,31 +10079,31 @@ test_150() { [ $PARALLEL == "yes" ] && skip "skip parallel run" && return local TF="$TMP/$tfile" - dd if=/dev/urandom of=$TF bs=6096 count=1 || error "dd failed" - cp $TF $DIR/$tfile - cancel_lru_locks osc - cmp $TF $DIR/$tfile || error "$TMP/$tfile $DIR/$tfile differ" - remount_client $MOUNT - df -P $MOUNT - cmp $TF $DIR/$tfile || error "$TF $DIR/$tfile differ (remount)" + dd if=/dev/urandom of=$TF bs=6096 count=1 || error "dd failed" + cp $TF $DIR/$tfile + cancel_lru_locks $OSC + cmp $TF $DIR/$tfile || error "$TMP/$tfile $DIR/$tfile differ" + remount_client $MOUNT + df -P $MOUNT + cmp $TF $DIR/$tfile || error "$TF $DIR/$tfile differ (remount)" - $TRUNCATE $TF 6000 - $TRUNCATE $DIR/$tfile 6000 - cancel_lru_locks osc - cmp $TF $DIR/$tfile || error "$TF $DIR/$tfile differ (truncate1)" + $TRUNCATE $TF 6000 + $TRUNCATE $DIR/$tfile 6000 + cancel_lru_locks $OSC + cmp $TF $DIR/$tfile || error "$TF $DIR/$tfile differ (truncate1)" - echo "12345" >>$TF - echo "12345" >>$DIR/$tfile - cancel_lru_locks osc - cmp $TF $DIR/$tfile || error "$TF $DIR/$tfile differ (append1)" + echo "12345" >>$TF + echo "12345" >>$DIR/$tfile + cancel_lru_locks $OSC + cmp $TF $DIR/$tfile || error "$TF $DIR/$tfile differ (append1)" - echo "12345" >>$TF - echo "12345" >>$DIR/$tfile - cancel_lru_locks osc - cmp $TF $DIR/$tfile || error "$TF $DIR/$tfile differ (append2)" + echo "12345" >>$TF + echo "12345" >>$DIR/$tfile + cancel_lru_locks $OSC + cmp $TF $DIR/$tfile || error "$TF $DIR/$tfile differ (append2)" - rm -f $TF - true + rm -f $TF + true } run_test 150 "truncate/append tests" @@ -10650,7 +10651,7 @@ test_155_small_load() { dd if=/dev/urandom of=$temp bs=6096 count=1 || \ error "dd of=$temp bs=6096 count=1 failed" cp $temp $file - cancel_lru_locks osc + cancel_lru_locks $OSC cmp $temp $file || error "$temp $file differ" $TRUNCATE $temp 6000 @@ -14026,7 +14027,7 @@ run_test 240 "race between ldlm enqueue and the connection RPC (no ASSERT)" test_241_bio() { for LOOP in $(seq $1); do dd if=$DIR/$tfile of=/dev/null bs=40960 count=1 2>/dev/null - cancel_lru_locks osc || true + cancel_lru_locks $OSC || true done } @@ -14040,7 +14041,7 @@ test_241_dio() { test_241a() { # was test_241 dd if=/dev/zero of=$DIR/$tfile count=1 bs=40960 ls -la $DIR/$tfile - cancel_lru_locks osc + cancel_lru_locks $OSC test_241_bio 1000 & PID=$! test_241_dio 1000 @@ -14996,6 +14997,283 @@ test_260() { } run_test 260 "Check mdc_close fail" +### Data-on-MDT sanity tests ### +test_270a() { + # create DoM file + local dom=$DIR/$tdir/dom_file + local tmp=$DIR/$tdir/tmp_file + + mkdir -p $DIR/$tdir + + # basic checks for DoM component creation + $SETSTRIPE -E 1024K -E 1024K -L mdt $dom 2>/dev/null && + error "Can set MDT layout to non-first entry" + + $SETSTRIPE -E 1024K -L mdt -E 1024K -L mdt $dom 2>/dev/null && + error "Can define multiple entries as MDT layout" + + $SETSTRIPE -E 1M -L mdt $dom || + error "Can't create DoM layout" + + [ $($GETSTRIPE -L $dom) == 100 ] || error "bad pattern" + [ $($GETSTRIPE -c $dom) == 0 ] || error "bad stripe count" + [ $($GETSTRIPE -S $dom) == 1048576 ] || error "bad stripe size" + + local mdtidx=$($GETSTRIPE -M $dom) + local mdtname=MDT$(printf %04x $mdtidx) + local facet=mds$((mdtidx + 1)) + local space_check=1 + + # Skip free space checks with ZFS + if [ "$(facet_fstype $facet)" == "zfs" ]; then + space_check=0 + fi + + # write + sync + local mdtfree1=$(do_facet $facet \ + lctl get_param -n osd*.*$mdtname.kbytesfree) + dd if=/dev/urandom of=$tmp bs=1024 count=100 + # check also direct IO along write + dd if=$tmp of=$dom bs=102400 count=1 oflag=direct + sync + cmp $tmp $dom || error "file data is different" + [ $(stat -c%s $dom) == 102400 ] || error "bad size after write" + if [ $space_check == 1 ]; then + local mdtfree2=$(do_facet $facet \ + lctl get_param -n osd*.*$mdtname.kbytesfree) + [ $(($mdtfree1 - $mdtfree2)) -ge 102 ] || + error "MDT free space is wrong after write" + fi + + # truncate + $TRUNCATE $dom 10000 + [ $(stat -c%s $dom) == 10000 ] || error "bad size after truncate" + if [ $space_check == 1 ]; then + mdtfree1=$(do_facet $facet \ + lctl get_param -n osd*.*$mdtname.kbytesfree) + [ $(($mdtfree1 - $mdtfree2)) -ge 92 ] || + error "MDT free space is wrong after truncate" + fi + + # append + cat $tmp >> $dom + sync + [ $(stat -c%s $dom) == 112400 ] || error "bad size after append" + if [ $space_check == 1 ]; then + mdtfree2=$(do_facet $facet \ + lctl get_param -n osd*.*$mdtname.kbytesfree) + [ $(($mdtfree1 - $mdtfree2)) -ge 102 ] || + error "MDT free space is wrong after append" + fi + + # delete + rm $dom + if [ $space_check == 1 ]; then + mdtfree1=$(do_facet $facet \ + lctl get_param -n osd*.*$mdtname.kbytesfree) + [ $(($mdtfree1 - $mdtfree2)) -ge 112 ] || + error "MDT free space is wrong after removal" + fi + + # combined striping + $SETSTRIPE -E 1024K -L mdt -E EOF $dom || + error "Can't create DoM + OST striping" + + dd if=/dev/urandom of=$tmp bs=1024 count=2000 + # check also direct IO along write + dd if=$tmp of=$dom bs=102400 count=20 oflag=direct + sync + cmp $tmp $dom || error "file data is different" + [ $(stat -c%s $dom) == 2048000 ] || error "bad size after write" + rm $dom + rm $tmp + + return 0 +} +run_test 270a "DoM: basic functionality tests" + +test_270b() { + local dom=$DIR/$tdir/dom_file + local max_size=1048576 + + mkdir -p $DIR/$tdir + $SETSTRIPE -E $max_size -L mdt $dom + + # truncate over the limit + $TRUNCATE $dom $(($max_size + 1)) && + error "successful truncate over the maximum size" + # write over the limit + dd if=/dev/zero of=$dom bs=$max_size seek=1 count=1 && + error "successful write over the maximum size" + # append over the limit + dd if=/dev/zero of=$dom bs=$(($max_size - 3)) count=1 + echo "12345" >> $dom && error "successful append over the maximum size" + rm $dom + + return 0 +} +run_test 270b "DoM: maximum size overflow checks for DoM-only file" + +test_270c() { + mkdir -p $DIR/$tdir + $SETSTRIPE -E 1024K -L mdt $DIR/$tdir + + # check files inherit DoM EA + touch $DIR/$tdir/first + [ $($GETSTRIPE -L $DIR/$tdir/first) == 100 ] || + error "bad pattern" + [ $($GETSTRIPE -c $DIR/$tdir/first) == 0 ] || + error "bad stripe count" + [ $($GETSTRIPE -S $DIR/$tdir/first) == 1048576 ] || + error "bad stripe size" + + # check directory inherits DoM EA and uses it as default + mkdir $DIR/$tdir/subdir + touch $DIR/$tdir/subdir/second + [ $($GETSTRIPE -L $DIR/$tdir/subdir/second) == 100 ] || + error "bad pattern in sub-directory" + [ $($GETSTRIPE -c $DIR/$tdir/subdir/second) == 0 ] || + error "bad stripe count in sub-directory" + [ $($GETSTRIPE -S $DIR/$tdir/subdir/second) == 1048576 ] || + error "bad stripe size in sub-directory" + return 0 +} +run_test 270c "DoM: DoM EA inheritance tests" + +test_270d() { + mkdir -p $DIR/$tdir + $SETSTRIPE -E 1024K -L mdt $DIR/$tdir + + # inherit default DoM striping + mkdir $DIR/$tdir/subdir + touch $DIR/$tdir/subdir/f1 + + # change default directory striping + $SETSTRIPE -c 1 $DIR/$tdir/subdir + touch $DIR/$tdir/subdir/f2 + [ $($GETSTRIPE -c $DIR/$tdir/subdir/f2) == 1 ] || + error "wrong default striping in file 2" + [ $($GETSTRIPE -L $DIR/$tdir/subdir/f2) == 1 ] || + error "bad pattern in file 2" + return 0 +} +run_test 270d "DoM: change striping from DoM to RAID0" + +test_270e() { + mkdir -p $DIR/$tdir/dom + mkdir -p $DIR/$tdir/norm + DOMFILES=20 + NORMFILES=10 + $SETSTRIPE -E 1M -L mdt $DIR/$tdir/dom + $SETSTRIPE -i 0 -S 2M $DIR/$tdir/norm + + createmany -o $DIR/$tdir/dom/dom- $DOMFILES + createmany -o $DIR/$tdir/norm/norm- $NORMFILES + + # find DoM files by layout + NUM=$($LFIND -L mdt -type f $DIR/$tdir 2>/dev/null | wc -l) + [ $NUM -eq $DOMFILES ] || + error "lfs find -L: found $NUM, expected $DOMFILES" + echo "Test 1: lfs find 20 DOM files by layout: OK" + + # there should be 1 dir with default DOM striping + NUM=$($LFIND -L mdt -type d $DIR/$tdir 2>/dev/null | wc -l) + [ $NUM -eq 1 ] || + error "lfs find -L: found $NUM, expected 1 dir" + echo "Test 2: lfs find 1 DOM dir by layout: OK" + + # find DoM files by stripe size + NUM=$($LFIND -S -1200K -type f $DIR/$tdir 2>/dev/null | wc -l) + [ $NUM -eq $DOMFILES ] || + error "lfs find -S: found $NUM, expected $DOMFILES" + echo "Test 4: lfs find 20 DOM files by stripe size: OK" + + # find files by stripe offset except DoM files + NUM=$($LFIND -i 0 -type f $DIR/$tdir 2>/dev/null | wc -l) + [ $NUM -eq $NORMFILES ] || + error "lfs find -i: found $NUM, expected $NORMFILES" + echo "Test 5: lfs find no DOM files by stripe index: OK" + return 0 +} +run_test 270e "DoM: lfs find with DoM files test" + +test_270f() { + local mdtname=${FSNAME}-MDT0000-mdtlov + local dom=$DIR/$tdir/dom_file + local dom_limit_saved=$(do_facet mds1 $LCTL get_param -n \ + lod.$mdtname.dom_stripesize) + local dom_limit=131072 + + do_facet mds1 $LCTL set_param -n lod.$mdtname.dom_stripesize=$dom_limit + local dom_current=$(do_facet mds1 $LCTL get_param -n \ + lod.$mdtname.dom_stripesize) + [ ${dom_limit} -eq ${dom_current} ] || + error "Cannot change per-MDT DoM stripe limit to $dom_limit" + + $LFS mkdir -i 0 -c 1 $DIR/$tdir + $SETSTRIPE -d $DIR/$tdir + $SETSTRIPE -E $dom_limit -L mdt $DIR/$tdir || + error "Can't set directory default striping" + + # exceed maximum stripe size + $SETSTRIPE -E $(($dom_limit * 2)) -L mdt $dom && + error "Able to create DoM component size more than LOD limit" + + do_facet mds1 $LCTL set_param -n lod.$mdtname.dom_stripesize=0 + dom_current=$(do_facet mds1 $LCTL get_param -n \ + lod.$mdtname.dom_stripesize) + [ 0 -eq ${dom_current} ] || + error "Can't set zero DoM stripe limit" + + # too low values to be aligned with smallest stripe size 64K + do_facet mds1 $LCTL set_param -n lod.$mdtname.dom_stripesize=30000 + dom_current=$(do_facet mds1 $LCTL get_param -n \ + lod.$mdtname.dom_stripesize) + [ 30000 -eq ${dom_current} ] && + error "Can set too small DoM stripe limit" + + do_facet mds1 $LCTL set_param -n lod.$mdtname.dom_stripesize=2147483648 + dom_current=$(do_facet mds1 $LCTL get_param -n \ + lod.$mdtname.dom_stripesize) + echo $dom_current + [ 2147483648 -eq ${dom_current} ] && + error "Can set too large DoM stripe limit" + + do_facet mds1 $LCTL set_param -n \ + lod.$mdtname.dom_stripesize=$((dom_limit * 2)) + $SETSTRIPE -E $((dom_limit * 2)) -L mdt $dom || + error "Can't create DoM component size after limit change" + do_facet mds1 $LCTL set_param -n \ + lod.$mdtname.dom_stripesize=$((dom_limit / 2)) + $SETSTRIPE -E $dom_limit -L mdt ${dom}_big && + error "Can create big DoM component after limit decrease" + touch ${dom}_def || + error "Can't create file with old default layout" + + do_facet mds1 $LCTL set_param -n lod.*.dom_stripesize=$dom_limit_saved + return 0 +} +run_test 270f "DoM: maximum DoM stripe size checks" + +test_271a() { + local dom=$DIR/$tdir/dom + + mkdir -p $DIR/$tdir + + $SETSTRIPE -E 1024K -L mdt $dom + + lctl set_param -n mdc.*.stats=clear + dd if=/dev/zero of=$dom bs=4096 count=1 || return 1 + cat $dom > /dev/null + local reads=$(lctl get_param -n mdc.*.stats | \ + awk '/ost_read/ {print $2}') + [ -z $reads ] || error "Unexpected $reads READ RPCs" + ls $dom + rm -f $dom +} +run_test 271a "DoM: data is cached for read after write" + cleanup_test_300() { trap 0 umask $SAVE_UMASK diff --git a/lustre/tests/sanityn.sh b/lustre/tests/sanityn.sh index c20f7f7..e7ce1d7 100755 --- a/lustre/tests/sanityn.sh +++ b/lustre/tests/sanityn.sh @@ -48,6 +48,8 @@ TRACE=${TRACE:-""} check_and_setup_lustre +OSC=${OSC:-"osc"} + assert_DIR rm -rf $DIR1/[df][0-9]* $DIR1/lnk $DIR/[df].${TESTSUITE}* @@ -432,6 +434,8 @@ run_test 18 "mmap sanity check =================================" test_19() { # bug3811 local node=$(facet_active_host ost1) + [ "x$DOM" = "xyes" ] && node=$(facet_active_host $SINGLEMDS) + # check whether obdfilter is cache capable at all if ! get_osd_param $node '' read_cache_enable >/dev/null; then echo "not cache-capable obdfilter" @@ -446,7 +450,7 @@ test_19() { # bug3811 cp $TMP/$tfile $DIR1/$tfile for i in `seq 1 20`; do [ $((i % 5)) -eq 0 ] && log "$testname loop $i" - cancel_lru_locks osc > /dev/null + cancel_lru_locks $OSC > /dev/null cksum $DIR1/$tfile | cut -d" " -f 1,2 > $TMP/sum1 & \ cksum $DIR2/$tfile | cut -d" " -f 1,2 > $TMP/sum2 wait @@ -462,12 +466,12 @@ run_test 19 "test concurrent uncached read races ===============" test_20() { test_mkdir $DIR1/d20 - cancel_lru_locks osc + cancel_lru_locks $OSC CNT=$((`lctl get_param -n llite.*.dump_page_cache | wc -l`)) $MULTIOP $DIR1/f20 Ow8190c $MULTIOP $DIR2/f20 Oz8194w8190c $MULTIOP $DIR1/f20 Oz0r8190c - cancel_lru_locks osc + cancel_lru_locks $OSC CNTD=$((`lctl get_param -n llite.*.dump_page_cache | wc -l` - $CNT)) [ $CNTD -gt 0 ] && \ error $CNTD" page left in cache after lock cancel" || true @@ -498,7 +502,7 @@ test_23() { # Bug 5972 echo "atime should be updated while another read" > $DIR1/$tfile # clear the lock(mode: LCK_PW) gotten from creating operation - cancel_lru_locks osc + cancel_lru_locks $OSC time1=$(date +%s) echo "now is $time1" sleep $((at_diff + 1)) @@ -530,9 +534,9 @@ test_24a() { OSC=`lctl dl | awk '/-osc-|OSC.*MNT/ {print $4}' | head -n 1` # OSC=`lctl dl | awk '/-osc-/ {print $4}' | head -n 1` - lctl --device %$OSC deactivate + lctl --device %osc deactivate lfs df -i || error "lfs df -i with deactivated OSC failed" - lctl --device %$OSC activate + lctl --device %osc activate lfs df || error "lfs df with reactivated OSC failed" } run_test 24a "lfs df [-ih] [path] test =========================" @@ -622,7 +626,7 @@ test_26b() { run_test 26b "sync mtime between ost and mds" test_27() { - cancel_lru_locks osc + cancel_lru_locks $OSC lctl clear dd if=/dev/zero of=$DIR2/$tfile bs=$((4096+4))k conv=notrunc count=4 seek=3 & DD2_PID=$! @@ -741,38 +745,39 @@ run_test 31b "voluntary OST cancel / blocking ast race==============" # enable/disable lockless truncate feature, depending on the arg 0/1 enable_lockless_truncate() { - lctl set_param -n osc.*.lockless_truncate $1 + lctl set_param -n $OSC.*.lockless_truncate $1 } test_32a() { # bug 11270 local p="$TMP/$TESTSUITE-$TESTNAME.parameters" - save_lustre_params client "osc.*.lockless_truncate" > $p - cancel_lru_locks osc + + save_lustre_params client "$OSC.*.lockless_truncate" > $p + cancel_lru_locks $OSC enable_lockless_truncate 1 rm -f $DIR1/$tfile lfs setstripe -c -1 $DIR1/$tfile dd if=/dev/zero of=$DIR1/$tfile count=$OSTCOUNT bs=$STRIPE_BYTES > \ /dev/null 2>&1 - clear_stats osc.*.osc_stats + clear_stats $OSC.*.${OSC}_stats log "checking cached lockless truncate" $TRUNCATE $DIR1/$tfile 8000000 $CHECKSTAT -s 8000000 $DIR2/$tfile || error "wrong file size" - [ $(calc_stats osc.*.osc_stats lockless_truncate) -ne 0 ] || + [ $(calc_stats $OSC.*.${OSC}_stats lockless_truncate) -ne 0 ] || error "cached truncate isn't lockless" log "checking not cached lockless truncate" $TRUNCATE $DIR2/$tfile 5000000 $CHECKSTAT -s 5000000 $DIR1/$tfile || error "wrong file size" - [ $(calc_stats osc.*.osc_stats lockless_truncate) -ne 0 ] || + [ $(calc_stats $OSC.*.${OSC}_stats lockless_truncate) -ne 0 ] || error "not cached truncate isn't lockless" log "disabled lockless truncate" enable_lockless_truncate 0 - clear_stats osc.*.osc_stats + clear_stats $OSC.*.${OSC}_stats $TRUNCATE $DIR2/$tfile 3000000 $CHECKSTAT -s 3000000 $DIR1/$tfile || error "wrong file size" - [ $(calc_stats osc.*.osc_stats lockless_truncate) -eq 0 ] || + [ $(calc_stats $OSC.*.${OSC}_stats lockless_truncate) -eq 0 ] || error "lockless truncate disabling failed" rm $DIR1/$tfile # restore lockless_truncate default values @@ -795,21 +800,21 @@ test_32b() { # bug 11270 "ldlm.namespaces.filter-*.contended_locks" >> $p save_lustre_params $facets \ "ldlm.namespaces.filter-*.contention_seconds" >> $p - clear_stats osc.*.osc_stats + clear_stats $OSC.*.${OSC}_stats # agressive lockless i/o settings do_nodes $(comma_list $(osts_nodes)) \ "lctl set_param -n ldlm.namespaces.*.max_nolock_bytes=2000000 \ ldlm.namespaces.filter-*.contended_locks=0 \ ldlm.namespaces.filter-*.contention_seconds=60" - lctl set_param -n osc.*.contention_seconds=60 + lctl set_param -n $OSC.*.contention_seconds=60 for i in {1..5}; do dd if=/dev/zero of=$DIR1/$tfile bs=4k count=1 conv=notrunc > \ /dev/null 2>&1 dd if=/dev/zero of=$DIR2/$tfile bs=4k count=1 conv=notrunc > \ /dev/null 2>&1 done - [ $(calc_stats osc.*.osc_stats lockless_write_bytes) -ne 0 ] || + [ $(calc_stats $OSC.*.${OSC}_stats lockless_write_bytes) -ne 0 ] || error "lockless i/o was not triggered" # disable lockless i/o (it is disabled by default) do_nodes $(comma_list $(osts_nodes)) \ @@ -818,15 +823,15 @@ test_32b() { # bug 11270 ldlm.namespaces.filter-*.contention_seconds=0" # set contention_seconds to 0 at client too, otherwise Lustre still # remembers lock contention - lctl set_param -n osc.*.contention_seconds=0 - clear_stats osc.*.osc_stats + lctl set_param -n $OSC.*.contention_seconds=0 + clear_stats $OSC.*.${OSC}_stats for i in {1..1}; do dd if=/dev/zero of=$DIR1/$tfile bs=4k count=1 conv=notrunc > \ /dev/null 2>&1 dd if=/dev/zero of=$DIR2/$tfile bs=4k count=1 conv=notrunc > \ /dev/null 2>&1 done - [ $(calc_stats osc.*.osc_stats lockless_write_bytes) -eq 0 ] || + [ $(calc_stats $OSC.*.${OSC}_stats lockless_write_bytes) -eq 0 ] || error "lockless i/o works when disabled" rm -f $DIR1/$tfile restore_lustre_params <$p @@ -1380,7 +1385,7 @@ test_39d() { # LU-7310 $LCTL set_param fail_loc=0 - cancel_lru_locks osc + cancel_lru_locks $OSC local mtime2=$(stat -c %Y $DIR2/$tfile) [ "$mtime2" -ge "$d1" ] && [ "$mtime2" -le "$d2" ] || diff --git a/lustre/tests/smalliomany.c b/lustre/tests/smalliomany.c new file mode 100644 index 0000000..b2c666d --- /dev/null +++ b/lustre/tests/smalliomany.c @@ -0,0 +1,156 @@ +/* + * GPL HEADER START + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 only, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License version 2 for more details (a copy is included + * in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; If not, see + * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * GPL HEADER END + */ +/* + * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved. + * Use is subject to license terms. + */ +/* + * This file is part of Lustre, http://www.lustre.org/ + * Lustre is a trademark of Sun Microsystems, Inc. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static void usage(char *prog) +{ + printf("usage: %s {-w|-a|-r} filenamefmt count seconds\n" + "-w : write mode\n" + "-a : append\n" + "-r : read mode\n", prog); + exit(EXIT_FAILURE); +} + +int main(int argc, char **argv) +{ + int do_read = 0, do_append = 0; + char *base, *endp; + long int start, last; + long end = ~0UL >> 1, count = ~0UL >> 1; + int c, i, fd, rc = 0, len, mode = 0; + long nbytes = 0; + char buf[4096]; + + while ((c = getopt(argc, argv, "war")) != -1) { + switch (c) { + case 'w': + mode = O_RDWR; + break; + case 'a': + do_append = 1; + mode = O_RDWR | O_APPEND; + break; + case 'r': + do_read = 1; + mode = O_RDONLY; + break; + case '?': + printf("Unknown option '%c'\n", optopt); + usage(argv[0]); + } + } + + if (optind + 3 != argc) { + fprintf(stderr, + "missing filenamebase, total_files, or seconds\n"); + usage(argv[0]); + } + + base = argv[optind]; + if (strlen(base) > 4080) { + fprintf(stderr, "filenamebase too long\n"); + exit(1); + } + + count = strtoul(argv[optind + 1], NULL, 0); + + end = strtoul(argv[optind + 2], &endp, 0); + if (end <= 0 && *endp != '\0') { + fprintf(stderr, "%s: error: bad number of seconds '%s'\n", + argv[0], argv[optind + 2]); + exit(2); + } + + srand(42); + + start = last = time(0); + end += start; + + for (i = 0; i < count && time(0) < end; i++) { + char filename[4096]; + + snprintf(filename, sizeof(filename), "%s%d", base, i); + + fd = open(filename, mode, 0666); + if (fd < 0) { + fprintf(stderr, "fail to open %s\n", filename); + rc = errno; + break; + } + + len = random() % 4096; + + if (do_read == 0) { + c = write(fd, buf, len); + if (c != len) { + fprintf(stderr, "fail to write %s, len %d," + " written %d\n", filename, len, c); + rc = errno; + break; + } + } else { + c = read(fd, buf, len); + } + nbytes += c; + + if (close(fd) < 0) { + fprintf(stderr, "can't close %s\n", filename); + rc = errno; + break; + } + + if (i && (i % 10000) == 0) { + printf(" - %ld bytes (time %ld total %ld last %ld)" + "\n", nbytes, time(0), time(0) - start, + time(0) - last); + last = time(0); + } + } + printf("total: %s %ld bytes in %ld seconds: %.2f bytes/second\n", + do_read ? "read" : do_append ? "append" : "write", nbytes, + time(0) - start, ((double)nbytes / (time(0) - start))); + + return rc; +}