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;
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;
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:
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)
/setuid
/sleeptest
/small_write
+/smalliomany
/stat
/statmany
/statone
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
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
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
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
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"
}
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/})
--- /dev/null
+#!/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
--- /dev/null
+#!/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
export PATH=$PATH:/sbin
TMP=${TMP:-/tmp}
+OSC=${OSC:-"osc"}
CC=${CC:-cc}
CHECKSTAT=${CHECKSTAT:-"checkstat -v"}
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) }'
}
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`
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
# 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
}
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
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
[ $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"
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
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
}
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
}
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
check_and_setup_lustre
+OSC=${OSC:-"osc"}
+
assert_DIR
rm -rf $DIR1/[df][0-9]* $DIR1/lnk $DIR/[df].${TESTSUITE}*
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"
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
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
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))
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 ========================="
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=$!
# 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
"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)) \
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
$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" ] ||
--- /dev/null
+/*
+ * 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 <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <time.h>
+#include <errno.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <getopt.h>
+
+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;
+}