echo "fsstress.$_n : $_param"
echo "-----------------------------------------------"
# -v >$tmp.out
- if ! $here/src/fsstress $_param $FSSTRESS_AVOID -n $_count -d $out >/dev/null 2>&1
+ if ! $here/ltp/fsstress $_param $FSSTRESS_AVOID -n $_count -d $out >/dev/null 2>&1
then
echo " fsstress (count=$_count) returned $? - see $seq.full"
# Test out a level 0 dump/restore to a tape of a subdir
# i.e. it is testing out drive_scsitape.c
#
-# Use src/fsstress to create a directory structure with a mix of files
+# Use fsstress to create a directory structure with a mix of files
#
#-----------------------------------------------------------------------
# Copyright (c) 2000-2001 Silicon Graphics, Inc. All Rights Reserved.
QA output created by 022
Put scsi tape driver into variable block size mode
-Creating directory system to dump using src/fsstress.
+Creating directory system to dump using fsstress.
-----------------------------------------------
fsstress : -f link=10 -f creat=10 -f mkdir=10 -f truncate=5 -f symlink=10
|| _fail "!!! failed to loop mount xfs"
_log "stress"
-src/fsstress -d $SCRATCH_MNT/test -n 1000 $FSSTRESS_AVOID >> $seq.full 2>&1 \
+ltp/fsstress -d $SCRATCH_MNT/test -n 1000 $FSSTRESS_AVOID >> $seq.full 2>&1 \
|| _fail "!!! stress failed"
_log "clean"
|| _fail "!!! failed to loop mount xfs"
_log "stress ext2 on xfs via loop"
-src/fsstress -d $SCRATCH_MNT/test2 -n 1000 $FSSTRESS_AVOID >> $seq.full 2>&1 \
+ltp/fsstress -d $SCRATCH_MNT/test2 -n 1000 $FSSTRESS_AVOID >> $seq.full 2>&1 \
|| _fail "!!! stress ext2 failed"
_log "clean"
#
_wipe_fs
-mkdir -p $dump_dir ||\
- _error "cannot mkdir \"$dump_dir\""
+mkdir -p $dump_dir || _fail "cannot mkdir \"$dump_dir\""
cd $dump_dir
echo "Do the incremental dumps"
_require_scratch
# set up fs for 1K inodes
-export MKFS_OPTIONS="-i size=1024"
-_scratch_mkfs_xfs >>$here/$seq.full || _error "mkfs failed"
-_scratch_mount >>$here/$seq.full || _error "mount failed"
+_scratch_mkfs_xfs -i size=1024 >>$here/$seq.full || _fail "mkfs failed"
+_scratch_mount >>$here/$seq.full || _fail "mount failed"
cd $SCRATCH_MNT
# xfs_growfs -n $SCRATCH_MNT
# -n 10 makes this take about 10 seconds,
# This allows the loop to end shortly after $tmp/running
# is deleted
- $here/src/fsstress -d "$STRESS_DIR" -n 10 > /dev/null 2>&1
+ $here/ltp/fsstress -d "$STRESS_DIR" -n 10 > /dev/null 2>&1
sync
done
# real QA test starts here
-$here/src/fsstress \
+$here/ltp/fsstress \
-d $TEST_DIR/fsstress \
-f allocsp=0 \
-f freesp=0 \
#
-# Copyright (c) 2000-2001 Silicon Graphics, Inc. All Rights Reserved.
+# Copyright (c) 2000-2003 Silicon Graphics, Inc. All Rights Reserved.
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of version 2 of the GNU General Public License as
TESTS = $(shell sed -n -e '/^[0-9][0-9][0-9]*/s/ .*//p' group)
CONFIGURE = configure include/builddefs
-LSRCFILES = configure configure.in
-LDIRT = *.bad *.new *.core *.full *.raw core a.out *.bak \
- check.log check.time config.* conftest*
+LSRCFILES = configure configure.in aclocal.m4 README VERSION
+LDIRT = config.log .dep config.status config.cache confdefs.h conftest* \
+ check.log check.time
-SUBDIRS = include src
+SUBDIRS = include lib ltp src m4
default: $(CONFIGURE) new remake check $(TESTS)
ifeq ($(HAVE_BUILDDEFS), no)
clean: # if configure hasn't run, nothing to clean
endif
-$(CONFIGURE): configure.in include/builddefs.in
- rm -f config.cache
+$(CONFIGURE):
autoconf
./configure
-install install-dev: default
- $(SUBDIRS_MAKERULE)
+aclocal.m4::
+ aclocal --acdir=$(TOPDIR)/m4 --output=$@
realclean distclean: clean
rm -f $(LDIRT) $(CONFIGURE)
- rm -rf autom4te.cache
+ rm -rf autom4te.cache Logs
export CHECK_OPTIONS=${CHECK_OPTIONS:="-g auto"}
export BENCH_PASSES=${BENCH_PASSES:=5}
-export DEBUG=${DEBUG:=-DEXPERIMENTAL_LARGE_SECTORS}
+#export DEBUG=${DEBUG:=...} # arbitrary CFLAGS really.
export MALLOCLIB=${MALLOCLIB:=/usr/lib/libefence.a}
export LOCAL_CONFIGURE_OPTIONS=${LOCAL_CONFIGURE_OPTIONS:=--enable-readline=yes}
flutz)
MODULAR=0
EMAIL="nathans@larry"
- TEST_DEV=/dev/sda5
+ TEST_DEV=/dev/sda5
+ TEST_LOGDEV=/dev/sda9
TEST_DIR=/xfsqa1
SCRATCH_DEV=/dev/sda6
SCRATCH_LOGDEV=/dev/sda7
_set_variable
}
-_error()
-{
- echo "Error: $*" | tee -a $here/$seq.full
- echo "(see $here/$seq.full for details)"
- status=1
- exit
-}
-
_wipe_fs()
{
_require_scratch
- _scratch_mkfs_xfs >>$here/$seq.full || _error "mkfs failed"
- _scratch_mount >>$here/$seq.full || _error "mount failed"
+ _scratch_mkfs_xfs >>$here/$seq.full || _fail "mkfs failed"
+ _scratch_mount >>$here/$seq.full || _fail "mount failed"
}
#
_stable_fs()
{
_saveddir=`pwd`; cd /
- umount $SCRATCH_MNT >>$here/$seq.full || _error "unmount failed"
- _scratch_mount >>$here/$seq.full || _error "mount failed"
+ umount $SCRATCH_MNT >>$here/$seq.full || _fail "unmount failed"
+ _scratch_mount >>$here/$seq.full || _fail "mount failed"
cd $_saveddir
}
#
-# Run src/fsstress to create a mixture of
+# Run fsstress to create a mixture of
# files,dirs,links,symlinks
#
# Pinched from test 013.
#
_create_dumpdir_stress()
{
- echo "Creating directory system to dump using src/fsstress."
+ echo "Creating directory system to dump using fsstress."
_wipe_fs
echo "-----------------------------------------------"
echo "fsstress : $_param"
echo "-----------------------------------------------"
- if ! $here/src/fsstress $_param -s 1 $FSSTRESS_AVOID -n $_count -d $dump_dir >$tmp.out 2>&1
+ if ! $here/ltp/fsstress $_param -s 1 $FSSTRESS_AVOID -n $_count -d $dump_dir >$tmp.out 2>&1
then
echo " fsstress (count=$_count) returned $? - see $here/$seq.full"
{
echo "Creating directory system to dump using src/fill."
- mkdir -p $dump_dir ||\
- _error "cannot mkdir \"$dump_dir\""
+ mkdir -p $dump_dir || _fail "cannot mkdir \"$dump_dir\""
cd $dump_dir
$verbose && echo -n "Setup "
_create_dumpdir_largefile()
{
_wipe_fs
- mkdir -p $dump_dir ||\
- _error "cannot mkdir \"$dump_dir\""
+ mkdir -p $dump_dir || _fail "cannot mkdir \"$dump_dir\""
_largesize=4294967297
_largefile=$dump_dir/largefile
echo "dd a largefile at offset $_largesize"
{
echo "Creating directory system of symlinks to dump."
- mkdir -p $dump_dir ||\
- _error "cannot mkdir \"$dump_dir\""
+ mkdir -p $dump_dir || _fail "cannot mkdir \"$dump_dir\""
cd $dump_dir
$verbose && echo -n "Setup "
_wipe_fs
echo "Creating directory system of hardlinks to incrementally dump."
- mkdir -p $dump_dir ||\
- _error "cannot mkdir \"$dump_dir\""
+ mkdir -p $dump_dir || _fail "cannot mkdir \"$dump_dir\""
cd $dump_dir
_create_hardset $_numsets
case $1
in
-f)
- [ -z "$2" ] && _error "missing argument for -f"
+ [ -z "$2" ] && _fail "missing argument for -f"
dumptape=$2
shift
;;
-L)
- [ -z "$2" ] && _error "missing argument for -L"
+ [ -z "$2" ] && _fail "missing argument for -L"
session_label=$2
shift
;;
do_quota_check=false
;;
-l)
- [ -z "$2" ] && _error "missing argument for -l"
+ [ -z "$2" ] && _fail "missing argument for -l"
dump_args="$dump_args -l$2"
shift
;;
*)
- _error "invalid argument to common.dump function: $1"
+ _fail "invalid argument to common.dump function: $1"
;;
esac
shift
_prepare_restore_dir()
{
rm -rf $restore_dir
- mkdir $restore_dir ||\
- _error "failed to mkdir $restore_dir"
+ mkdir $restore_dir || _fail "failed to mkdir $restore_dir"
}
-dnl unpacking check - this file must exist
-AC_INIT(src/fsstress.c)
-pkg_name="xfstests"
-AC_SUBST(pkg_name)
+AC_INIT(src/xfsctl.c)
+AC_PACKAGE_GLOBALS(xfstests)
+AC_PACKAGE_UTILITIES(xfstests)
-#
-# Note: the following environment variables may be set to override the
-# defaults (to change paths and/or executables, build parameters, etc):
-#
-# DEBUG OPTIMIZER MAKE CC LD TAR ZIP RPM AWK SED ECHO
-# MALLOCLIB DISTRIBUTION PACKAGE_BUILDER PREFIX ROOT_PREFIX
-#
+AC_PACKAGE_NEED_UUID_H
+AC_PACKAGE_NEED_UUIDCOMPARE
-DEBUG=${DEBUG:-'-DDEBUG'} # -DNDEBUG
-OPTIMIZER=${OPTIMIZER:-'-g'} # (-O1 enforced default)
-MALLOCLIB=${MALLOCLIB:-''} # /usr/lib/libefence.a
+AC_PACKAGE_NEED_XFS_LIBXFS_H
+AC_PACKAGE_NEED_XFSCTL_MACRO
+AC_PACKAGE_NEED_LIBXFSINIT_LIBXFS
+AC_PACKAGE_NEED_XFS_HANDLE_H
+AC_PACKAGE_NEED_ATTRLIST_LIBHANDLE
-dnl Debug build?
-debug_build="$DEBUG"
-AC_SUBST(debug_build)
+AC_PACKAGE_NEED_ATTR_XATTR_H
+AC_PACKAGE_NEED_GETXATTR_LIBATTR
+AC_PACKAGE_NEED_SYS_ACL_H
+AC_PACKAGE_NEED_ACL_LIBACL_H
+AC_PACKAGE_NEED_ACLINIT_LIBACL
-dnl Optimization options?
-opt_build="$OPTIMIZER"
-AC_SUBST(opt_build)
+AC_PACKAGE_WANT_LIBGDBM
-dnl Alternate malloc library?
-malloc_lib="$MALLOCLIB"
-AC_SUBST(malloc_lib)
-
-dnl Set version
-. ./VERSION
-
-pkg_version=${PKG_MAJOR}.${PKG_MINOR}.${PKG_REVISION}
-pkg_release=$PKG_BUILD
-AC_SUBST(pkg_version)
-AC_SUBST(pkg_release)
-
-pkg_distribution="SGI ProPack"
-test -z "$DISTRIBUTION" || pkg_distribution="$DISTRIBUTION"
-AC_SUBST(pkg_distribution)
-
-pkg_builder=`id -u -n`@`hostname`
-test -z "$PACKAGE_BUILDER" || pkg_builder="$PACKAGE_BUILDER"
-AC_SUBST(pkg_builder)
-
-dnl check if user wants their own C compiler
-test -z "$CC" && AC_PROG_CC
-cc=$CC
-AC_SUBST(cc)
-
-dnl check if users wants their own make
-test -z "$MAKE" && AC_PATH_PROG(MAKE, make, /usr/bin/make)
-make=$MAKE
-AC_SUBST(make)
-
-dnl check if users wants their own linker
-test -z "$LD" && AC_PATH_PROG(LD, ld, /usr/bin/ld)
-ld=$LD
-AC_SUBST(ld)
-
-dnl check if the tar program is available
-test -z "$TAR" && AC_PATH_PROG(TAR, tar)
-tar=$TAR
-AC_SUBST(tar)
-
-dnl check if the gzip program is available
-test -z "$ZIP" && AC_PATH_PROG(ZIP, gzip, /bin/gzip)
-zip=$ZIP
-AC_SUBST(zip)
-
-dnl check if the rpm program is available
-test -z "$RPM" && AC_PATH_PROG(RPM, rpm, /bin/rpm)
-rpm=$RPM
-AC_SUBST(rpm)
-
-dnl .. and what version is rpm
-rpm_version=0
-test -x $RPM && \
- rpm_version=`$RPM --version | awk '{print $NF}' | awk -F. '{print $1}'`
-AC_SUBST(rpm_version)
-
-dnl check if the makedepend program is available
-test -z "$MAKEDEPEND" && AC_PATH_PROG(MAKEDEPEND, makedepend, /bin/true)
-makedepend=$MAKEDEPEND
-AC_SUBST(makedepend)
-
-dnl check if symbolic links are supported
-AC_PROG_LN_S
-
-dnl check if user wants their own awk, sed and echo
-test -z "$AWK" && AC_PATH_PROG(AWK, awk, /bin/awk)
-awk=$AWK
-AC_SUBST(awk)
-test -z "$SED" && AC_PATH_PROG(SED, sed, /bin/sed)
-sed=$SED
-AC_SUBST(sed)
-test -z "$ECHO" && AC_PATH_PROG(ECHO, echo, /bin/echo)
-echo=$ECHO
-AC_SUBST(echo)
-
-CPPFLAGS="-I/usr/include/xfs"
-AC_SUBST(CPPFLAGS)
-
-dnl Checks for UUID header and library.
-AC_CHECK_HEADER(uuid/uuid.h,, [
- echo
- echo 'FATAL ERROR: could not find a valid UUID header.'
- echo 'Install either the e2fsprogs-devel (rpm) or the uuid-dev (deb) package.'
- exit 1
-])
-AC_CHECK_LIB(uuid, uuid_generate,, [
- echo
- echo 'FATAL ERROR: could not find a valid UUID library.'
- echo 'Install either the e2fsprogs-devel (rpm) or the uuid-dev (deb) package.'
- exit 1
-])
-libuuid="/usr/lib/libuuid.a"
-AC_SUBST(libuuid)
-
-dnl Checks for base XFS headers and libraries.
-AC_CHECK_HEADER(xfs/libxfs.h,, [
- echo
- echo 'FATAL ERROR: could not find a valid XFS library header.'
- echo 'Install either the xfsprogs-devel (rpm) or the xfslibs-dev (deb) package.'
- echo 'Alternatively, run "make install-dev" from the xfsprogs source.'
- exit 1
-])
-AC_CHECK_LIB(xfs, libxfs_init,, [
- echo
- echo 'FATAL ERROR: could not find a valid XFS base library.'
- echo 'Install either the xfsprogs-devel (rpm) or the xfslibs-dev (deb) package.'
- echo 'Alternatively, run "make install-dev" from the xfsprogs source.'
- exit 1
-])
-AC_CHECK_HEADER(xfs/handle.h,, [
- echo
- echo 'FATAL ERROR: could not find a valid XFS handle header.'
- echo 'Install either the xfsprogs-devel (rpm) or the xfslibs-dev (deb) package.'
- echo 'Alternatively, run "make install-dev" from the xfsprogs source.'
- exit 1
-])
-AC_CHECK_LIB(handle, path_to_handle,, [
- echo
- echo 'FATAL ERROR: could not find a valid XFS handle library.'
- echo 'Install either the xfsprogs-devel (rpm) or the xfslibs-dev (deb) package.'
- echo 'Alternatively, run "make install-dev" from the xfsprogs source.'
- exit 1
-])
-libxfs="-lxfs"
-libhdl="-lhandle"
-AC_SUBST(libxfs)
-AC_SUBST(libhdl)
-
-dnl Checks for Extended Attributes header and library.
-AC_CHECK_HEADER(attr/xattr.h,, [
- echo
- echo 'FATAL ERROR: could not find a valid Extended Attributes header.'
- echo 'Install either the attr-devel (rpm) or the attr-dev (deb) package.'
- echo 'Alternatively, run "make install-dev" from the attr source.'
- exit 1
-])
-AC_CHECK_LIB(attr, getxattr,, [
- echo
- echo 'FATAL ERROR: could not find a valid Extended Attributes library.'
- echo 'Install either the libattr (rpm) or the libattr1 (deb) package.'
- echo 'Alternatively, run "make install-lib" from the attr source.'
- exit 1
-])
-libattr="-lattr"
-AC_SUBST(libattr)
-
-dnl Checks for Access Control List headers and library.
-AC_CHECK_HEADER(sys/acl.h,, [
- echo
- echo 'FATAL ERROR: could not find a valid Access Control List headers.'
- echo 'Install either the acl-devel (rpm) or the acl (deb) package.'
- echo 'Alternatively, run "make install-dev" from the acl source.'
- exit 1
-])
-AC_CHECK_HEADER(acl/libacl.h,, [
- echo
- echo 'FATAL ERROR: could not find a valid Access Control List headers.'
- echo 'Install either the acl-devel (rpm) or the acl (deb) package.'
- echo 'Alternatively, run "make install-dev" from the acl source.'
- exit 1
-])
-AC_CHECK_LIB(acl, acl_init,, [
- echo
- echo 'FATAL ERROR: could not find a valid Access Control List library.'
- echo 'Install either the libacl (rpm) or the libacl1 (deb) package.'
- echo 'Alternatively, run "make install-lib" from the acl source.'
- exit 1
-])
-libacl="-lacl"
-AC_SUBST(libacl)
-
-dnl Checks for GNU database manager header and library.
-libgdbm=""
-have_db=true
-AC_CHECK_HEADER(gdbm/ndbm.h,, [ have_db=false ])
-if test $have_db = "true" -a -f /usr/lib/libgdbm.a; then
- libgdbm="/usr/lib/libgdbm.a"
-fi
-AC_SUBST(libgdbm)
-AC_SUBST(have_db)
-
-dnl alternate root and usr prefixes
-test -z "$ROOT_PREFIX" && ROOT_PREFIX=""
-root_prefix="$ROOT_PREFIX"
-test -z "$PREFIX" && PREFIX="/usr"
-prefix="$PREFIX"
-
-dnl man pages (source)
-dnl also check if man page source is gzipped
-dnl (usually on Debian, but not Redhat pre-7.0)
-pkg_man_dir=${prefix}/share/man
-have_zipped_manpages=false
-for d in ${prefix}/share/man ${prefix}/man ; do
- if test -f $d/man1/man.1.gz
- then
- pkg_man_dir=$d
- have_zipped_manpages=true
- break
- fi
-done
-AC_SUBST(pkg_man_dir)
-AC_SUBST(have_zipped_manpages)
-
-dnl binaries
-pkg_bin_dir=${prefix}/sbin
-AC_SUBST(pkg_bin_dir)
-
-dnl static libraries
-pkg_lib_dir=${prefix}/lib
-AC_SUBST(pkg_lib_dir)
-
-dnl runtime shared system libraries
-pkg_slib_dir=${root_prefix}/lib
-AC_SUBST(pkg_slib_dir)
-
-dnl system binaries
-pkg_sbin_dir=${root_prefix}/sbin
-AC_SUBST(pkg_sbin_dir)
-
-dnl include files
-pkg_inc_dir=${prefix}/include
-AC_SUBST(pkg_inc_dir)
-
-dnl doc directory
-pkg_doc_dir=${prefix}/share/doc/${pkg_name}
-AC_SUBST(pkg_doc_dir)
-
-
-dnl
-dnl output files
-dnl
-
-AC_OUTPUT( \
-dnl Build definitions for use in Makefiles
- include/builddefs \
-)
+AC_OUTPUT(include/builddefs)
070 attr auto
071 rw
072 rw
-073 copy
+#073 copy
#
-# Copyright (c) 2000-2001 Silicon Graphics, Inc. All Rights Reserved.
+# Copyright (c) 2000-2003 Silicon Graphics, Inc. All Rights Reserved.
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of version 2 of the GNU General Public License as
TOPDIR = ..
include $(TOPDIR)/include/builddefs
+HFILES = dataascii.h databin.h pattern.h \
+ random_range.h string_to_tokens.h tlibio.h write_log.h
LSRCFILES = builddefs.in buildrules
default install install-dev:
#
-# Copyright (c) 2000-2001 Silicon Graphics, Inc. All Rights Reserved.
+# Copyright (c) 2003 Silicon Graphics, Inc. All Rights Reserved.
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of version 2 of the GNU General Public License as
LIBGDBM = @libgdbm@
LIBUUID = @libuuid@
LIBHANDLE = @libhdl@
-HAVE_DB = @have_db@
-CPPFLAGS = -I/usr/include/xfs -I/usr/include/attr
-
-BUILDRULES = $(TOPDIR)/include/buildrules
-
-# General package information
-PKG_NAME = @pkg_name@
-PKG_RELEASE = @pkg_release@
-PKG_VERSION = @pkg_version@
-PKG_DISTRIBUTION = @pkg_distribution@
-PKG_BUILDER = @pkg_builder@
-PKG_BIN_DIR = @pkg_bin_dir@
-PKG_LIB_DIR = @pkg_lib_dir@
-PKG_SBIN_DIR = @pkg_sbin_dir@
-PKG_SLIB_DIR = @pkg_slib_dir@
-PKG_INC_DIR = @pkg_inc_dir@
-PKG_MAN_DIR = @pkg_man_dir@
-PKG_DOC_DIR = @pkg_doc_dir@
-
-# LCFLAGS, LLDFLAGS, LLDLIBS, LSRCFILES and LDIRT may be specified in
-# user Makefiles. Note: LSRCFILES is anything other than Makefile, $(CFILES)
-# $(CXXFILES), or $(HFILES) and is used to construct the manifest list
-# during the "dist" phase (packaging).
-
-CFLAGS += -O1 $(OPTIMIZER) $(DEBUG) -funsigned-char -Wall $(LCFLAGS) \
- -I$(TOPDIR)/include '-DVERSION="$(PKG_VERSION)"' -D_GNU_SOURCE \
- -D_FILE_OFFSET_BITS=64
-
-LDFLAGS = $(LLDFLAGS)
-LDLIBS = $(LLDLIBS) $(MALLOCLIB)
-
-MAKEOPTS = --no-print-directory
-SRCFILES = Makefile $(HFILES) $(CFILES) $(LSRCFILES) $(LFILES) $(YFILES)
-DIRT = $(LDIRT) dep dep.bak $(OBJECTS) $(CMDTARGET) $(LIBTARGET) \
- $(STATICLIBTARGET) *.[1-9].gz
-
-OBJECTS = $(ASFILES:.s=.o) \
- $(CFILES:.c=.o) \
- $(LFILES:.l=.o) \
- $(YFILES:%.y=%.tab.o)
-
-MAKE = @make@
-CC = @cc@
-LD = @ld@
-AWK = @awk@
-SED = @sed@
-INSTALL = $(TOPDIR)/install-sh -o root -g root
-ECHO = @echo@
-LN_S = @LN_S@
-
-CCF = $(CC) $(CFLAGS)
-MAKEF = $(MAKE) $(MAKEOPTS)
-CXXF = $(CXX) $(CXXFLAGS)
-LDF = $(LD) $(LDFLAGS)
-MAKEDEPEND = @makedepend@
-
-ZIP = @zip@
-TAR = @tar@
-RPM = @rpm@
-RPM_VERSION = @rpm_version@
-
-HAVE_ZIPPED_MANPAGES = @have_zipped_manpages@
-
-SHELL = /bin/sh
-IMAGES_DIR = $(TOPDIR)/all-images
-DIST_DIR = $(TOPDIR)/dist
-
-SUBDIRS_MAKERULE = \
- @for d in $(SUBDIRS) ""; do \
- if test -d "$$d" -a ! -z "$$d"; then \
- $(ECHO) === $$d ===; \
- $(MAKEF) -C $$d $@ || exit $$?; \
- fi; \
- done
-
-MAN_MAKERULE = \
- @for f in *.[12345678] ""; do \
- if test ! -z "$$f"; then \
- $(ZIP) --best -c < $$f > $$f.gz; \
- fi; \
- done
+LIBTEST = $(TOPDIR)/lib/libtest.la
+
+PKG_NAME = @pkg_name@
+PKG_USER = @pkg_user@
+PKG_GROUP = @pkg_group@
+PKG_RELEASE = @pkg_release@
+PKG_VERSION = @pkg_version@
+PKG_PLATFORM = @pkg_platform@
+PKG_DISTRIBUTION= @pkg_distribution@
+
+CC = @cc@
+AWK = @awk@
+SED = @sed@
+TAR = @tar@
+ZIP = @zip@
+MAKE = @make@
+ECHO = @echo@
+SORT = @sort@
+LN_S = @LN_S@
+LIBTOOL = @LIBTOOL@
+MAKEDEPEND = @makedepend@
+
+MSGFMT = @msgfmt@
+MSGMERGE = @msgmerge@
+
+RPM = @rpm@
+RPMBUILD = @rpmbuild@
+RPM_VERSION = @rpm_version@
+
+ENABLE_SHARED = @enable_shared@
+ENABLE_DBM = @enable_dbm@
+
+ifeq ($(PKG_PLATFORM),linux)
+PCFLAGS = -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64
+endif
+ifeq ($(PKG_PLATFORM),darwin)
+PCFLAGS = -traditional-cpp
+endif
-INSTALL_MAN = \
- @for d in $(MAN_PAGES); do \
- first=true; \
- for m in `$(AWK) '/^\.SH NAME/ {ok=1; next} ok {print; exit}' $$d \
- | sed -e 's/,/ /g' -e 's/\\-.*//' -e 's/\\\f[0-9]//g' -e 's/ / /g;q'`; \
- do \
- [ -z "$$m" -o "$$m" = "\\" ] && continue; \
- t=$(MAN_DEST)/$$m.$(MAN_SECTION); \
- if $$first; then \
- if $(HAVE_ZIPPED_MANPAGES); then \
- $(ZIP) --best -c $$d > $$d.gz; _sfx=.gz; \
- fi; \
- u=$$m.$(MAN_SECTION)$$_sfx; \
- echo $(INSTALL) -m 644 $${d}$$_sfx $${t}$$_sfx; \
- $(INSTALL) -m 644 $${d}$$_sfx $${t}$$_sfx; \
- else \
- echo $(INSTALL) -S $$u $${t}$$_sfx; \
- $(INSTALL) -S $$u $${t}$$_sfx; \
- fi; \
- first=false; \
- done; \
- done
+CFLAGS += -O1 $(OPTIMIZER) $(DEBUG) -funsigned-char -Wall -I$(TOPDIR)/include \
+ -DVERSION=\"$(PKG_VERSION)\"
-DIST_MAKERULE = \
- $(MAKEF) -C build dist
+# Global, Platform, Local CFLAGS
+CFLAGS += $(GCFLAGS) $(PCFLAGS) $(LCFLAGS)
-SOURCE_MAKERULE = \
- @test -z "$$DIR" && DIR="."; \
- for f in $(SRCFILES) ""; do \
- if test ! -z "$$f"; then $(ECHO) $$DIR/$$f; fi;\
- done; \
- for d in `echo $(SUBDIRS)` ; do \
- if test -d "$$d" -a ! -z "$$d"; then \
- $(MAKEF) DIR=$$DIR/$$d -C $$d $@ || exit $$?; \
- fi; \
- done
+include $(TOPDIR)/include/buildmacros
endif
--- /dev/null
+#
+# Copyright (c) 2002-2003 Silicon Graphics, Inc. All Rights Reserved.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of version 2 of the GNU General Public License as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it would be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+#
+# Further, this software is distributed without any warranty that it is
+# free of the rightful claim of any third person regarding infringement
+# or the like. Any license provided herein, whether implied or
+# otherwise, applies only to this software file. Patent licenses, if
+# any, provided herein do not apply to combinations of this program with
+# other software, or any other product whatsoever.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write the Free Software Foundation, Inc., 59
+# Temple Place - Suite 330, Boston MA 02111-1307, USA.
+#
+# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+# Mountain View, CA 94043, or:
+#
+# http://www.sgi.com
+#
+# For further information regarding this notice, see:
+#
+# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
+#
+
+BUILDRULES = $(TOPDIR)/include/buildrules
+
+# LCFLAGS, LLDFLAGS, LLDLIBS, LSRCFILES and LDIRT may be specified in
+# user Makefiles. Note: LSRCFILES is anything other than Makefile, $(CFILES)
+# $(CXXFILES), or $(HFILES) and is used to construct the manifest list
+# during the "dist" phase (packaging).
+
+LDFLAGS = $(LLDFLAGS)
+LDLIBS = $(LLDLIBS) $(PLDLIBS) $(MALLOCLIB)
+
+MAKEOPTS = --no-print-directory
+SRCFILES = Makefile $(HFILES) $(CFILES) $(LSRCFILES) $(LFILES) $(YFILES)
+
+DEPDIRT = dep dep.bak
+MANDIRT = *.[1-9].gz
+PODIRT = *.tmpo *.mo
+CDIRT = $(OBJECTS) $(LTOBJECTS) $(LTCOMMAND) $(LTLIBRARY)
+DIRT = $(LDIRT) $(DEPDIRT) $(MANDIRT) $(PODIRT) $(CDIRT)
+
+OBJECTS = $(ASFILES:.s=.o) \
+ $(CFILES:.c=.o) \
+ $(LFILES:.l=.o) \
+ $(YFILES:%.y=%.tab.o)
+
+INSTALL = $(TOPDIR)/install-sh -o $(PKG_USER) -g $(PKG_GROUP)
+
+SHELL = /bin/sh
+IMAGES_DIR = $(TOPDIR)/all-images
+DIST_DIR = $(TOPDIR)/dist
+
+CCF = $(CC) $(CFLAGS) $(CPPFLAGS)
+MAKEF = $(MAKE) $(MAKEOPTS)
+CXXF = $(CXX) $(CXXFLAGS)
+
+# For libtool.
+LIBNAME = $(basename $(LTLIBRARY))
+LTOBJECTS = $(OBJECTS:.o=.lo)
+LTVERSION = $(LT_CURRENT):$(LT_REVISION):$(LT_AGE)
+
+LTLINK = $(LIBTOOL) --mode=link $(CC)
+LTEXEC = $(LIBTOOL) --mode=execute
+LTINSTALL = $(LIBTOOL) --mode=install $(INSTALL)
+LTCOMPILE = $(LIBTOOL) --mode=compile $(CCF) -D_REENTRANT -fno-strict-aliasing
+
+ifeq ($(ENABLE_SHARED),yes)
+LTLDFLAGS += -rpath $(PKG_LIB_DIR)
+LTLDFLAGS += -version-info $(LTVERSION)
+endif
+
+ifeq ($(ENABLE_SHARED),yes)
+INSTALL_LTLIB = \
+ cd $(TOPDIR)/$(LIBNAME)/.libs; \
+ ../$(INSTALL) -m 755 -d $(PKG_LIB_DIR); \
+ ../$(INSTALL) -m 644 -T so_dot_version $(LIBNAME).lai $(PKG_LIB_DIR); \
+ test "$(PKG_DISTRIBUTION)" = debian || \
+ ../$(INSTALL) -T so_dot_current $(LIBNAME).lai $(PKG_LIB_DIR)
+endif
+
+# Libtool thinks the static and shared libs should be in the same dir, so
+# make the static lib appear in the place we chose as rpath (using the two
+# symlinks below).
+# Other things want the shared libs to appear in /usr/lib, else they'll
+# link with the static libs there. So, another symlink to get the .so into
+# /usr/lib.
+ifeq ($(ENABLE_SHARED),yes)
+INSTALL_LTLIB_DEV = \
+ cd $(TOPDIR)/$(LIBNAME)/.libs; \
+ ../$(INSTALL) -m 755 -d $(PKG_DEVLIB_DIR); \
+ ../$(INSTALL) -m 644 -T old_lib $(LIBNAME).lai $(PKG_DEVLIB_DIR); \
+ ../$(INSTALL) -m 644 $(LIBNAME).lai $(PKG_DEVLIB_DIR)/$(LIBNAME).la ; \
+ ../$(INSTALL) -m 755 -d $(PKG_LIB_DIR); \
+ ../$(INSTALL) -T so_base $(LIBNAME).lai $(PKG_LIB_DIR); \
+ ../$(INSTALL) -S $(PKG_DEVLIB_DIR)/$(LIBNAME).a $(PKG_LIB_DIR)/$(LIBNAME).a; \
+ ../$(INSTALL) -S $(PKG_DEVLIB_DIR)/$(LIBNAME).la $(PKG_LIB_DIR)/$(LIBNAME).la; \
+ ../$(INSTALL) -S $(PKG_LIB_DIR)/$(LIBNAME).so $(PKG_DEVLIB_DIR)/$(LIBNAME).so
+else
+INSTALL_LTLIB_DEV = $(INSTALL_LTLIB_STATIC)
+endif
+
+INSTALL_LTLIB_STATIC = \
+ cd $(TOPDIR)/$(LIBNAME)/.libs; \
+ ../$(INSTALL) -m 755 -d $(PKG_DEVLIB_DIR); \
+ ../$(INSTALL) -m 644 -T old_lib $(LIBNAME).lai $(PKG_DEVLIB_DIR)
+
+INSTALL_MAN = \
+ @for d in $(MAN_PAGES); do \
+ first=true; \
+ for m in `$(AWK) \
+ '/^\.S[h|H] NAME/ {ok=1; next} ok {print; exit}' $$d \
+ | $(SED) \
+ -e 's/^\.Nm //' -e 's/,/ /g' -e 's/\\-.*//' \
+ -e 's/\\\f[0-9]//g' -e 's/ / /g;q'`; \
+ do \
+ [ -z "$$m" -o "$$m" = "\\" ] && continue; \
+ t=$(MAN_DEST)/$$m.$(MAN_SECTION); \
+ if $$first; then \
+ if $(HAVE_ZIPPED_MANPAGES); then \
+ $(ZIP) -9 -c $$d > $$d.gz; _sfx=.gz; \
+ fi; \
+ u=$$m.$(MAN_SECTION)$$_sfx; \
+ echo $(INSTALL) -m 644 $${d}$$_sfx $${t}$$_sfx;\
+ $(INSTALL) -m 644 $${d}$$_sfx $${t}$$_sfx; \
+ else \
+ echo $(INSTALL) -S $$u $${t}$$_sfx; \
+ $(INSTALL) -S $$u $${t}$$_sfx; \
+ fi; \
+ first=false; \
+ done; \
+ done
+
+ifeq ($(ENABLE_GETTEXT),yes)
+INSTALL_LINGUAS = \
+ @for l in $(LINGUAS) ""; do \
+ if test -f "$$l.mo" ; then \
+ ldir=$(PKG_LOCALE_DIR)/$$l/LC_MESSAGES; \
+ $(INSTALL) -m 755 -d $$ldir; \
+ $(INSTALL) -m 644 $$l.mo $$ldir/$(PKG_NAME).mo; \
+ fi; \
+ done
+endif
+
+SUBDIRS_MAKERULE = \
+ @for d in $(SUBDIRS) ""; do \
+ if test -d "$$d" -a ! -z "$$d"; then \
+ $(ECHO) === $$d ===; \
+ $(MAKEF) -C $$d $@ || exit $$?; \
+ fi; \
+ done
+
+MAN_MAKERULE = \
+ @for f in *.[12345678] ""; do \
+ if test ! -z "$$f"; then \
+ $(ZIP) --best -c < $$f > $$f.gz; \
+ fi; \
+ done
+
+DIST_MAKERULE = \
+ $(MAKEF) -C build dist
+
+SOURCE_MAKERULE = \
+ @test -z "$$DIR" && DIR="."; \
+ for f in $(SRCFILES) ""; do \
+ if test ! -z "$$f"; then $(ECHO) $$DIR/$$f; fi;\
+ done; \
+ for d in `echo $(SUBDIRS)` ; do \
+ if test -d "$$d" -a ! -z "$$d"; then \
+ $(MAKEF) DIR=$$DIR/$$d -C $$d $@ || exit $$?; \
+ fi; \
+ done
#
-# Copyright (c) 1999, 2001 Silicon Graphics, Inc. All Rights Reserved.
-#
+# Copyright (c) 1999, 2001-2003 Silicon Graphics, Inc. All Rights Reserved.
+#
# This program is free software; you can redistribute it and/or modify it
# under the terms of version 2 of the GNU General Public License as published
# by the Free Software Fondation.
-#
+#
# This program is distributed in the hope that it would be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. Further, any license provided herein,
# distributed without any warranty that the program is delivered free of the
# rightful claim of any third person by way of infringement or the like. See
# the GNU General Public License for more details.
-#
+#
# You should have received a copy of the GNU General Public License along with
# this program; if not, write the Free Software Foundation, Inc., 59 Temple
# Place - Suite 330, Boston MA 02111-1307, USA.
include $(TOPDIR)/include/builddefs
-#
-# Standard targets
-#
-ifdef CMDTARGET
-$(CMDTARGET) : $(SUBDIRS) $(OBJECTS)
- $(CCF) -o $(CMDTARGET) $(LDFLAGS) $(OBJECTS) $(LDLIBS)
-$(CMDTARGET).static : $(SUBDIRS) $(OBJECTS)
- $(CCF) -static -o $(CMDTARGET).static $(LDFLAGS) $(OBJECTS) $(LDLIBS)
-endif
-
-ifdef LIBTARGET
-$(LIBTARGET) : $(SUBDIRS) $(OBJECTS)
- $(CC) $(LDFLAGS) -fPIC -shared -Wl,-soname,$(LIBTARGET) -o $(LIBTARGET) $(OBJECTS) $(LDLIBS)
-endif
-
-ifdef STATICLIBTARGET
-$(STATICLIBTARGET) : $(SUBDIRS) $(OBJECTS)
- $(AR) crf $(STATICLIBTARGET) $?
-endif
-
clean clobber : $(SUBDIRS)
rm -f $(DIRT)
+ @rm -fr .libs
$(SUBDIRS_MAKERULE)
# Never blow away subdirs
$(SUBDIRS_MAKERULE)
endif
+#
+# Standard targets
+#
+
+ifdef LTCOMMAND
+$(LTCOMMAND) : $(SUBDIRS) $(OBJECTS) $(LTDEPENDENCIES)
+ $(LTLINK) -o $@ $(LDFLAGS) $(OBJECTS) $(LDLIBS)
+endif
+
+ifdef LTLIBRARY
+$(LTLIBRARY) : $(SUBDIRS) $(LTOBJECTS)
+ $(LTLINK) $(LTLDFLAGS) -o $(LTLIBRARY) $(LTOBJECTS) $(LTLIBS)
+
+%.lo: %.c
+ $(LTCOMPILE) -c $<
+endif
+
+ifdef LINGUAS
+%.pot: $(XGETTEXTFILES)
+ xgettext --omit-header --language=C --keyword=_ -o $@ $(XGETTEXTFILES)
+
+%.po: $(PKG_NAME).pot
+ $(MSGMERGE) -o $@.tmpo $@ $<
+ @if ! diff $@.tmpo $@ >/dev/null; then \
+ echo "$@ is out of date, see $@.tmpo"; \
+ fi
+
+%.mo: %.po
+ $(MSGFMT) -o $@ $<
+endif
+
source :
$(SOURCE_MAKERULE)
-endif
+endif # _BUILDRULES_INCLUDED_
$(_FORCE):
depend : $(CFILES) $(HFILES)
$(SUBDIRS_MAKERULE)
- touch dep
- $(MAKEDEPEND) -fdep -- $(CFLAGS) -- $(CFILES)
+ touch .dep
+ $(MAKEDEPEND) -f - -- $(CFLAGS) -- $(CFILES) | \
+ $(SED) -e 's,`pwd`,$(TOPDIR),g' \
+ -e 's, */[^ ]*,,g' \
+ -e '/^[^ ]*: *$$/d' \
+ -e '/^#.*/d' -e '/^ *$$/d' \
+ > .dep
+ test -s .dep || rm -f .dep
# Include dep, but only if it exists
-ifeq ($(shell test -f dep && echo dep), dep)
-include dep
+ifeq ($(shell test -f .dep && echo .dep), .dep)
+include .dep
endif
--- /dev/null
+/*
+ * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like. Any license provided herein, whether implied or
+ * otherwise, applies only to this software file. Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+ * Mountain View, CA 94043, or:
+ *
+ * http://www.sgi.com
+ *
+ * For further information regarding this notice, see:
+ *
+ * http://oss.sgi.com/projects/GenInfo/NoticeExplan/
+ */
+#ifndef _DATAASCII_H_
+#define _DATAASCII_H_
+
+/***********************************************************************
+ * int dataasciigen(listofchars, buffer, size, offset)
+ *
+ * This function fills buffer with ascii characters.
+ * The ascii characters are obtained from listofchars or the CHARS array
+ * if listofchars is NULL.
+ * Each char is selected by an index. The index is the remainder
+ * of count divided by the array size.
+ * This method allows more than one process to write to a location
+ * in a file without corrupting it for another process' point of view.
+ *
+ * The return value will be the number of character written in buffer
+ * (size).
+ *
+ ***********************************************************************/
+int dataasciigen(char *, char *, int, int);
+
+/***********************************************************************
+ * int dataasciichk(listofchars, buffer, size, count, errmsg)
+ *
+ * This function checks the contents of a buffer produced by
+ * dataasciigen.
+ *
+ * return values:
+ * >= 0 : error at character count
+ * < 0 : no error
+ ***********************************************************************/
+
+int dataasciichk(char *, char *, int, int, char**);
+
+#endif
--- /dev/null
+#ifndef _DATABIN_H_
+#define _DATABIN_H_
+
+/*******************************************************************************
+* NAME
+* databingen - fill a buffer with a data pattern
+*
+* SYNOPSIS
+* (void) databingen(mode, buffer, bsize, offset)
+* int mode;
+* char *buffer;
+* int bsize;
+* int offset;
+*
+* DESCRIPTION
+* datagen fills the buffer pointed to by 'buffer' with 'bsize' bytes
+* of data of the form indicated by 'mode'.
+* All modes (expect r -random) are file offset based.
+* This allows more than process to do writing to the file without
+* corrupting it if the same modes were used.
+* They data modes to choose from, these are:
+*
+* 'a' - writes an alternating bit pattern (i.e. 0x5555555...)
+*
+* 'c' - writes a checkerboard pattern (i.e. 0xff00ff00ff00...)
+*
+* 'C' - writes counting pattern (i.e. 0 - 07, 0 - 07, ...);
+*
+* 'o' - writes all bits set (i.e. 0xffffffffffffff...)
+*
+* 'z' - writes all bits cleared (i.e. 0x000000000...);
+*
+* 'r' - writes random integers
+*
+* RETURN VALUE
+* None
+*
+*******************************************************************************/
+
+void databingen( int mode, unsigned char *buffer, int bsize, int offset );
+
+void databinchedk( int mode, unsigned char *buffer, int bsize, int offset, char **errmsg);
+
+#endif
--- /dev/null
+/*
+ * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like. Any license provided herein, whether implied or
+ * otherwise, applies only to this software file. Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+ * Mountain View, CA 94043, or:
+ *
+ * http://www.sgi.com
+ *
+ * For further information regarding this notice, see:
+ *
+ * http://oss.sgi.com/projects/GenInfo/NoticeExplan/
+ */
+#ifndef _FILE_LOCK_H_
+#define _FILE_LOCK_H_
+
+extern char Fl_syscall_str[128];
+
+int file_lock( int , int, char ** );
+int record_lock( int , int , int , int , char ** );
+
+#endif /* _FILE_LOCK_H_ */
--- /dev/null
+/*
+ * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like. Any license provided herein, whether implied or
+ * otherwise, applies only to this software file. Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+ * Mountain View, CA 94043, or:
+ *
+ * http://www.sgi.com
+ *
+ * For further information regarding this notice, see:
+ *
+ * http://oss.sgi.com/projects/GenInfo/NoticeExplan/
+ */
+#ifndef _FORKER_H_
+#define _FORKER_H_
+
+#define FORKER_MAX_PIDS 4098
+
+extern int Forker_pids[FORKER_MAX_PIDS]; /* holds pids of forked processes */
+extern int Forker_npids; /* number of entries in Forker_pids */
+
+/*
+ * This function will fork and the parent will exit zero and
+ * the child will return. This will orphan the returning process
+ * putting it in the background.
+ */
+int background( char * );
+
+/*
+ * Forker will fork ncopies-1 copies of self.
+ *
+ * arg 1: Number of copies of the process to be running after return.
+ * This value minus one is the number of forks performed.
+ * arg 2: mode: 0 - all children are first generation descendents.
+ * 1 - each subsequent child is a descendent of another
+ * descendent, resulting in only one direct descendent of the
+ * parent and each other child is a child of another child in
+ * relation to the parent.
+ * arg 3: prefix: string to preceed any error messages. A value of NULL
+ * results in no error messages on failure.
+ * returns: returns to parent the number of children forked.
+ */
+int forker( int , int , char * );
+
+#endif /* _FORKER_H_ */
--- /dev/null
+/*
+ * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like. Any license provided herein, whether implied or
+ * otherwise, applies only to this software file. Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+ * Mountain View, CA 94043, or:
+ *
+ * http://www.sgi.com
+ *
+ * For further information regarding this notice, see:
+ *
+ * http://oss.sgi.com/projects/GenInfo/NoticeExplan/
+ */
+#ifndef _OPEN_FLAGS_H_
+#define _OPEN_FLAGS_H_
+
+/***********************************************************************
+ * This function attempts to convert open flag bits into human readable
+ * symbols (i.e. O_TRUNC). If there are more than one symbol,
+ * the <sep> string will be placed as a separator between symbols.
+ * Commonly used separators would be a comma "," or pipe "|".
+ * If <mode> is one and not all <openflags> bits can be converted to
+ * symbols, the "UNKNOWN" symbol will be added to return string.
+ *
+ * Return Value
+ * openflags2symbols will return the indentified symbols.
+ * If no symbols are recognized the return value will be a empty
+ * string or the "UNKNOWN" symbol.
+ *
+ * Limitations
+ * Currently (05/96) all known symbols are coded into openflags2symbols.
+ * If new open flags are added this code will have to updated
+ * to know about them or they will not be recognized.
+ *
+ * The Open_symbols must be large enough to hold all possible symbols
+ * for a given system.
+ *
+ ***********************************************************************/
+char *openflags2symbols( int, char *, int );
+
+/***********************************************************************
+ * This function will take a string of comma separated open flags symbols
+ * and translate them into an open flag bitmask.
+ * If any symbol is not valid, -1 is returned. On this error condition
+ * the badname pointer is updated if not NULL. badname will point
+ * to the beginning location of where the invalid symbol was found.
+ * string will be returned unchanged.
+ *
+ * A signal received while parsing string could cause the string to
+ * contain a NULL character in the middle of it.
+ *
+ ***********************************************************************/
+int parse_open_flags( char *, char ** );
+
+#endif
--- /dev/null
+/*
+ * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like. Any license provided herein, whether implied or
+ * otherwise, applies only to this software file. Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+ * Mountain View, CA 94043, or:
+ *
+ * http://www.sgi.com
+ *
+ * For further information regarding this notice, see:
+ *
+ * http://oss.sgi.com/projects/GenInfo/NoticeExplan/
+ */
+#ifndef _PATTERN_H_
+#define _PATTERN_H_
+
+/*
+ * pattern_check(buf, buflen, pat, patlen, patshift)
+ *
+ * Check a buffer of length buflen against repeated occurrances of
+ * a pattern whose length is patlen. Patshift can be used to rotate
+ * the pattern by patshift bytes to the left.
+ *
+ * Patshift may be greater than patlen, the pattern will be rotated by
+ * (patshift % patshift) bytes.
+ *
+ * pattern_check returns -1 if the buffer does not contain repeated
+ * occurrances of the indicated pattern (shifted by patshift).
+ *
+ * The algorithm used to check the buffer relies on the fact that buf is
+ * supposed to be repeated copies of pattern. The basic algorithm is
+ * to validate the first patlen bytes of buf against the pat argument
+ * passed in - then validate the next patlen bytes against the 1st patlen
+ * bytes - the next (2*patlen) bytes against the 1st (2*pathen) bytes, and
+ * so on. This algorithm only works when the assumption of a buffer full
+ * of repeated copies of a pattern holds, and gives MUCH better results
+ * then walking the buffer byte by byte.
+ *
+ * Performance wise, It appears to be about 5% slower than doing a straight
+ * memcmp of 2 buffers, but the big win is that it does not require a
+ * 2nd comparison buffer, only the pattern.
+ */
+int pattern_check( char * , int , char * , int , int );
+
+/*
+ * pattern_fill(buf, buflen, pat, patlen, patshift)
+ *
+ * Fill a buffer of length buflen with repeated occurrances of
+ * a pattern whose length is patlen. Patshift can be used to rotate
+ * the pattern by patshift bytes to the left.
+ *
+ * Patshift may be greater than patlen, the pattern will be rotated by
+ * (patshift % patlen) bytes.
+ *
+ * If buflen is not a multiple of patlen, a partial pattern will be written
+ * in the last part of the buffer. This implies that a buffer which is
+ * shorter than the pattern length will receive only a partial pattern ...
+ *
+ * pattern_fill always returns 0 - no validation of arguments is done.
+ *
+ * The algorithm used to fill the buffer relies on the fact that buf is
+ * supposed to be repeated copies of pattern. The basic algorithm is
+ * to fill the first patlen bytes of buf with the pat argument
+ * passed in - then copy the next patlen bytes with the 1st patlen
+ * bytes - the next (2*patlen) bytes with the 1st (2*pathen) bytes, and
+ * so on. This algorithm only works when the assumption of a buffer full
+ * of repeated copies of a pattern holds, and gives MUCH better results
+ * then filling the buffer 1 byte at a time.
+ */
+int pattern_fill( char * , int , char * , int , int );
+
+#endif
--- /dev/null
+/*
+ * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like. Any license provided herein, whether implied or
+ * otherwise, applies only to this software file. Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+ * Mountain View, CA 94043, or:
+ *
+ * http://www.sgi.com
+ *
+ * For further information regarding this notice, see:
+ *
+ * http://oss.sgi.com/projects/GenInfo/NoticeExplan/
+ */
+#ifndef _STR_TO_BYTES_
+#define _STR_TO_BYTES_
+
+int str_to_bytes ( char * );
+long str_to_lbytes ( char * );
+long long str_to_llbytes( char * );
+
+#endif
--- /dev/null
+/*
+ * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like. Any license provided herein, whether implied or
+ * otherwise, applies only to this software file. Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+ * Mountain View, CA 94043, or:
+ *
+ * http://www.sgi.com
+ *
+ * For further information regarding this notice, see:
+ *
+ * http://oss.sgi.com/projects/GenInfo/NoticeExplan/
+ */
+
+/* $Id: test.h,v 1.1 2003/07/07 06:36:46 nathans Exp $ */
+
+#ifndef __TEST_H__
+#define __TEST_H__
+
+#include <stdio.h>
+#include <signal.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+
+#define TPASS 0 /* Test passed flag */
+#define TFAIL 1 /* Test failed flag */
+#define TBROK 2 /* Test broken flag */
+#define TWARN 4 /* Test warning flag */
+#define TRETR 8 /* Test retire flag */
+#define TINFO 16 /* Test information flag */
+#define TCONF 32 /* Test not appropriate for configuration flag */
+
+/*
+ * To determine if you are on a Umk or Unicos system,
+ * use sysconf(_SC_CRAY_SYSTEM). But since _SC_CRAY_SYSTEM
+ * is not defined until 90, it will be define here if not already
+ * defined.
+ * if ( sysconf(_SC_CRAY_SYSTEM) == 1 )
+ * on UMK
+ * else # returned 0 or -1
+ * on Unicos
+ * This is only being done on CRAY systems.
+ */
+#ifdef CRAY
+#ifndef _SC_CRAY_SYSTEM
+#define _SC_CRAY_SYSTEM 140
+#endif /* ! _SC_CRAY_SYSTEM */
+#endif /* CRAY */
+
+/*
+ * Ensure that NUMSIGS is defined.
+ * It should be defined in signal.h or sys/signal.h on
+ * UNICOS/mk and IRIX systems. On UNICOS systems,
+ * it is not defined, thus it is being set to UNICOS's NSIG.
+ * Note: IRIX's NSIG (signals are 1-(NSIG-1))
+ * is not same meaning as UNICOS/UMK's NSIG (signals 1-NSIG)
+ */
+#ifndef NUMSIGS
+#define NUMSIGS NSIG
+#endif
+
+
+/* defines for unexpected signal setup routine (set_usig.c) */
+#define FORK 1 /* SIGCLD is to be ignored */
+#define NOFORK 0 /* SIGCLD is to be caught */
+#define DEF_HANDLER 0 /* tells set_usig() to use default signal handler */
+
+/*
+ * The following defines are used to control tst_res and t_result reporting.
+ */
+
+#define TOUTPUT "TOUTPUT" /* The name of the environment variable */
+ /* that can be set to one of the following */
+ /* strings to control tst_res output */
+ /* If not set, TOUT_VERBOSE_S is assumed */
+
+#define TOUT_VERBOSE_S "VERBOSE" /* All test cases reported */
+#define TOUT_CONDENSE_S "CONDENSE" /* ranges are used where identical messages*/
+ /* occur for sequential test cases */
+#define TOUT_NOPASS_S "NOPASS" /* No pass test cases are reported */
+#define TOUT_DISCARD_S "DISCARD" /* No output is reported */
+
+#define TST_NOBUF "TST_NOBUF" /* The name of the environment variable */
+ /* that can be set to control whether or not */
+ /* tst_res will buffer output into 4096 byte */
+ /* blocks of output */
+ /* If not set, buffer is done. If set, no */
+ /* internal buffering will be done in tst_res */
+ /* t_result does not have internal buffering */
+
+/*
+ * The following defines are used to control tst_tmpdir, tst_wildcard and t_mkchdir
+ */
+
+#define TDIRECTORY "TDIRECTORY" /* The name of the environment variable */
+ /* that if is set, the value (directory) */
+ /* is used by all tests as their working */
+ /* directory. tst_rmdir and t_rmdir will */
+ /* not attempt to clean up. */
+ /* This environment variable should only */
+ /* be set when doing system testing since */
+ /* tests will collide and break and fail */
+ /* because of setting it. */
+
+#define TEMPDIR "/tmp" /* This is the default temporary directory. */
+ /* The environment variable TMPDIR is */
+ /* used prior to this valid by tempnam(3). */
+ /* To control the base location of the */
+ /* temporary directory, set the TMPDIR */
+ /* environment variable to desired path */
+
+/*
+ * The following contains support for error message passing.
+ * See test_error.c for details.
+ */
+#define TST_ERR_MESG_SIZE 1023 /* max size of error message */
+#define TST_ERR_FILE_SIZE 511 /* max size of module name used by compiler */
+#define TST_ERR_FUNC_SIZE 127 /* max size of func name */
+
+typedef struct {
+ int te_line; /* line where last error was reported. Use */
+ /* "__LINE__" and let compiler do the rest */
+ int te_level; /* If set, will prevent current stored */
+ /* error to not be overwritten */
+ char te_func[TST_ERR_FUNC_SIZE+1]; /* name of function of last error */
+ /* Name of function or NULL */
+ char te_file[TST_ERR_FILE_SIZE+1]; /* module of last error. Use */
+ /* "__FILE__" and let compiler do the rest */
+ char te_mesg[TST_ERR_MESG_SIZE+1]; /* string of last error */
+
+} _TST_ERROR;
+
+extern _TST_ERROR Tst_error; /* defined in test_error.c */
+#if __STDC__
+extern void tst_set_error(char *file, int line, char *func, char *fmt, ...);
+#else
+extern void tst_set_error();
+#endif
+extern void tst_clear_error();
+
+
+/*
+ * The following define contains the name of an environmental variable
+ * that can be used to specify the number of iterations.
+ * It is supported in parse_opts.c and USC_setup.c.
+ */
+#define USC_ITERATION_ENV "USC_ITERATIONS"
+
+/*
+ * The following define contains the name of an environmental variable
+ * that can be used to specify to iteration until desired time
+ * in floating point seconds has gone by.
+ * Supported in USC_setup.c.
+ */
+#define USC_LOOP_WALLTIME "USC_LOOP_WALLTIME"
+
+/*
+ * The following define contains the name of an environmental variable
+ * that can be used to specify that no functional checks are wanted.
+ * It is supported in parse_opts.c and USC_setup.c.
+ */
+#define USC_NO_FUNC_CHECK "USC_NO_FUNC_CHECK"
+
+/*
+ * The following define contains the name of an environmental variable
+ * that can be used to specify the delay between each loop iteration.
+ * The value is in seconds (fractional numbers are allowed).
+ * It is supported in parse_opts.c.
+ */
+#define USC_LOOP_DELAY "USC_LOOP_DELAY"
+
+/*
+ * The following prototypes are needed to remove compile errors
+ * on IRIX systems when compiled with -n32 and -64.
+ */
+extern void tst_res(int ttype, char *fname, char *arg_fmt, ...);
+extern void tst_resm(int ttype, char *arg_fmt, ...);
+extern void tst_brk(int ttype, char *fname, void (*func)(),
+ char *arg_fmt, ...);
+extern void tst_brkloop(int ttype, char *fname, void (*func)(),
+ char *arg_fmt, ...);
+extern void tst_brkm(int ttype, void (*func)(), char *arg_fmt, ...);
+extern void tst_brkloopm(int ttype, void (*func)(), char *arg_fmt, ...);
+
+extern int tst_environ();
+extern void tst_exit();
+extern void tst_flush();
+
+/* prototypes for the t_res.c functions */
+extern void t_result(char *tcid, int tnum, int ttype, char *tmesg);
+extern void tt_exit();
+extern int t_environ();
+extern void t_breakum(char *tcid, int total, int typ, char *msg, void (*fnc)());
+
+extern void tst_sig(int fork_flag, void (*handler)(), void (*cleanup)());
+extern void tst_tmpdir();
+extern void tst_rmdir();
+
+extern char * get_high_address(void);
+
+extern void get_kver(int*, int*, int*);
+extern int tst_kvercmp(int, int, int);
+
+#endif /* end of __TEST_H__ */
--- /dev/null
+/*
+ * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like. Any license provided herein, whether implied or
+ * otherwise, applies only to this software file. Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+ * Mountain View, CA 94043, or:
+ *
+ * http://www.sgi.com
+ *
+ * For further information regarding this notice, see:
+ *
+ * http://oss.sgi.com/projects/GenInfo/NoticeExplan/
+ */
+
+#define LIO_IO_SYNC 00001 /* read/write */
+#define LIO_IO_ASYNC 00002 /* reada/writea/aio_write/aio_read */
+#define LIO_IO_SLISTIO 00004 /* single stride sync listio */
+#define LIO_IO_ALISTIO 00010 /* single stride async listio */
+#define LIO_IO_SYNCV 00020 /* single-buffer readv/writev */
+#define LIO_IO_SYNCP 00040 /* pread/pwrite */
+
+#ifdef sgi
+#define LIO_IO_ATYPES 00077 /* all io types */
+#define LIO_IO_TYPES 00061 /* all io types, non-async */
+#endif /* sgi */
+#ifdef linux
+#define LIO_IO_TYPES 00021 /* all io types */
+#endif /* linux */
+#ifdef CRAY
+#define LIO_IO_TYPES 00017 /* all io types */
+#endif /* CRAY */
+
+#define LIO_WAIT_NONE 00010000 /* return asap -- use with care */
+#define LIO_WAIT_ACTIVE 00020000 /* spin looking at iosw fields, or EINPROGRESS */
+#define LIO_WAIT_RECALL 00040000 /* call recall(2)/aio_suspend(3) */
+#define LIO_WAIT_SIGPAUSE 00100000 /* call pause */
+#define LIO_WAIT_SIGACTIVE 00200000 /* spin waiting for signal */
+#ifdef sgi
+#define LIO_WAIT_CBSUSPEND 00400000 /* aio_suspend waiting for callback */
+#define LIO_WAIT_SIGSUSPEND 01000000 /* aio_suspend waiting for signal */
+#define LIO_WAIT_ATYPES 01760000 /* all async wait types, except nowait */
+#define LIO_WAIT_TYPES 00020000 /* all sync wait types (sorta) */
+#endif /* sgi */
+#ifdef linux
+#define LIO_WAIT_TYPES 00300000 /* all wait types, except nowait */
+#endif /* linux */
+#ifdef CRAY
+#define LIO_WAIT_TYPES 00360000 /* all wait types, except nowait */
+#endif /* CRAY */
+
+/* meta wait io */
+/* 00 000 0000 */
+
+#ifdef sgi
+/* all callback wait types */
+#define LIO_WAIT_CBTYPES (LIO_WAIT_CBSUSPEND)
+/* all signal wait types */
+#define LIO_WAIT_SIGTYPES (LIO_WAIT_SIGPAUSE|LIO_WAIT_SIGACTIVE|LIO_WAIT_SIGSUSPEND)
+/* all aio_{read,write} or lio_listio */
+#define LIO_IO_ASYNC_TYPES (LIO_IO_ASYNC|LIO_IO_SLISTIO|LIO_IO_ALISTIO)
+#endif /* sgi */
+#ifdef linux
+/* all signal wait types */
+#define LIO_WAIT_SIGTYPES (LIO_WAIT_SIGPAUSE)
+#endif /* linux */
+#ifdef CRAY
+/* all signal wait types */
+#define LIO_WAIT_SIGTYPES (LIO_WAIT_SIGPAUSE|LIO_WAIT_SIGACTIVE)
+#endif /* CRAY */
+
+/*
+ * This bit provides a way to randomly pick an io type and wait method.
+ * lio_read_buffer() and lio_write_buffer() functions will call
+ * lio_random_methods() with the given method.
+ */
+#define LIO_RANDOM 010000000
+
+/*
+ * This bit provides a way for the programmer to use async i/o with
+ * signals and to use their own signal handler. By default,
+ * the signal will only be given to the system call if the wait
+ * method is LIO_WAIT_SIGPAUSE or LIO_WAIT_SIGACTIVE.
+ * Whenever these wait methods are used, libio signal handler
+ * will be used.
+ */
+#define LIO_USE_SIGNAL 020000000
+
+/*
+ * prototypes/structures for functions in the libio.c module. See comments
+ * in that module, or man page entries for information on the individual
+ * functions.
+ */
+
+int stride_bounds(int offset, int stride, int nstrides,
+ int bytes_per_stride, int *min_byte, int *max_byte);
+
+int lio_set_debug(int level);
+int lio_parse_io_arg1(char *string);
+void lio_help1(char *prefex);
+int lio_parse_io_arg2(char *string, char **badtoken);
+void lio_help2(char *prefex);
+int lio_write_buffer(int fd, int method, char *buffer, int size,
+ int sig, char **errmsg, long wrd);
+
+int lio_read_buffer(int fd, int method, char *buffer, int size,
+ int sig, char **errmsg, long wrd);
+int lio_random_methods(long mask);
+
+#if CRAY
+#include <sys/iosw.h>
+int lio_wait4asyncio(int method, int fd, struct iosw **statptr);
+int lio_check_asyncio(char *io_type, int size, struct iosw *status);
+#endif /* CRAY */
+#ifdef sgi
+#include <aio.h>
+int lio_wait4asyncio(int method, int fd, aiocb_t *aiocbp);
+int lio_check_asyncio(char *io_type, int size, aiocb_t *aiocbp, int method);
+#endif /* sgi */
+
+/*
+ * Define the structure that contains the infomation that is used
+ * by the parsing and help functions.
+ */
+struct lio_info_type {
+ char *token;
+ int bits;
+ char *desc;
+};
+
+
--- /dev/null
+/*
+ * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like. Any license provided herein, whether implied or
+ * otherwise, applies only to this software file. Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+ * Mountain View, CA 94043, or:
+ *
+ * http://www.sgi.com
+ *
+ * For further information regarding this notice, see:
+ *
+ * http://oss.sgi.com/projects/GenInfo/NoticeExplan/
+ */
+
+/* $Id: usctest.h,v 1.1 2003/07/07 06:36:46 nathans Exp $ */
+
+/**********************************************************
+ *
+ * IRIX/Linux Feature Test and Evaluation - Silicon Graphics, Inc.
+ *
+ * FUNCTION NAME : usctest.h
+ *
+ * FUNCTION TITLE : System Call Test Macros
+ *
+ * SYNOPSIS:
+ * See DESCRIPTION below.
+ *
+ * AUTHOR : William Roske
+ *
+ * INITIAL RELEASE : UNICOS 7.0
+ *
+ * DESCRIPTION
+ * TEST(SCALL) - calls a system call
+ * TEST_VOID(SCALL) - same as TEST() but for syscalls with no return value.
+ * TEST_CLEANUP - print the log of errno return counts if STD_ERRNO_LOG
+ * is set.
+ * TEST_PAUSEF(HAND) - Pause for SIGUSR1 if the pause flag is set.
+ * Use "hand" as the interrupt handling function
+ * TEST_PAUSE - Pause for SIGUSR1 if the pause flag is set.
+ * Use internal function to do nothing on signal and go on.
+ * TEST_LOOPING(COUNTER) - Conditional to check if test should
+ * loop. Evaluates to TRUE (1) or FALSE (0).
+ * TEST_ERROR_LOG(eno) - log that this errno was received,
+ * if STD_ERRNO_LOG is set.
+ * TEST_EXP_ENOS(array) - set the bits in TEST_VALID_ENO array at
+ * positions specified in integer "array"
+ *
+ * RETURN VALUE
+ * TEST(SCALL) - Global Variables set:
+ * int TEST_RETURN=return code from SCALL
+ * int TEST_ERRNO=value of errno at return from SCALL
+ * TEST_VOID(SCALL) - Global Variables set:
+ * int TEST_ERRNO=value of errno at return from SCALL
+ * TEST_CLEANUP - None.
+ * TEST_PAUSEF(HAND) - None.
+ * TEST_PAUSE - None.
+ * TEST_LOOPING(COUNTER) - True if COUNTER < STD_LOOP_COUNT or
+ * STD_INFINITE is set.
+ * TEST_ERROR_LOG(eno) - None
+ * TEST_EXP_ENOS(array) - None
+ *
+ * KNOWN BUGS
+ * If you use the TEST_PAUSE or TEST_LOOPING macros, you must
+ * link in parse_opts.o, which contains the code for those functions.
+ *
+ *#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#**/
+
+#ifndef __USCTEST_H__
+#define __USCTEST_H__ 1
+
+#ifndef _SC_CLK_TCK
+#include <unistd.h>
+#endif
+
+#include <sys/param.h>
+
+/*
+ * Ensure that PATH_MAX is defined
+ */
+#ifndef PATH_MAX
+#ifdef MAXPATHLEN
+#define PATH_MAX MAXPATHLEN
+#else
+#define PATH_MAX 1024
+#endif
+#endif
+
+#ifndef CRAY
+#ifndef BSIZE
+#define BSIZE BBSIZE
+#endif
+#endif
+
+/***********************************************************************
+ * Define option_t structure type.
+ * Entries in this struct are used by the parse_opts routine
+ * to indicate valid options and return option arguments
+ ***********************************************************************/
+typedef struct {
+ char *option; /* Valid option string (one option only) like "a:" */
+ int *flag; /* pointer to location to set true if option given */
+ char **arg; /* pointer to location to place argument, if needed */
+} option_t;
+
+/***********************************************************************
+ * The following globals are defined in parse_opts.c but must be
+ * externed here because they are used in the macros defined below.
+ ***********************************************************************/
+extern int STD_FUNCTIONAL_TEST, /* turned off by -f to not do functional test */
+ STD_TIMING_ON, /* turned on by -t to print timing stats */
+ STD_PAUSE, /* turned on by -p to pause before loop */
+ STD_INFINITE, /* turned on by -i0 to loop forever */
+ STD_LOOP_COUNT, /* changed by -in to set loop count to n */
+ STD_ERRNO_LOG, /* turned on by -e to log errnos returned */
+ STD_ERRNO_LIST[], /* counts of errnos returned. indexed by errno */
+ STD_COPIES,
+ STD_argind;
+
+extern float STD_LOOP_DURATION, /* wall clock time to iterate */
+ STD_LOOP_DELAY; /* delay time after each iteration */
+
+#define USC_MAX_ERRNO 2000
+
+/**********************************************************************
+ * Prototype for parse_opts routine
+ **********************************************************************/
+extern char *parse_opts(int ac, char **av, option_t *user_optarr, void (*uhf)());
+
+
+/*
+ * define a structure
+ */
+struct usc_errno_t {
+ int flag;
+};
+
+/***********************************************************************
+ ****
+ ****
+ ****
+ **********************************************************************/
+#ifdef _USC_LIB_
+
+extern int TEST_RETURN;
+extern int TEST_ERRNO;
+
+#else
+/***********************************************************************
+ * Global array of bit masks to indicate errnos that are expected.
+ * Bits set by TEST_EXP_ENOS() macro and used by TEST_CLEANUP() macro.
+ ***********************************************************************/
+struct usc_errno_t TEST_VALID_ENO[USC_MAX_ERRNO];
+
+/***********************************************************************
+ * Globals for returning the return code and errno from the system call
+ * test macros.
+ ***********************************************************************/
+int TEST_RETURN;
+int TEST_ERRNO;
+
+/***********************************************************************
+ * temporary variables for determining max and min times in TEST macro
+ ***********************************************************************/
+long btime, etime, tmptime;
+
+#endif /* _USC_LIB_ */
+
+/***********************************************************************
+ * structure for timing accumulator and counters
+ ***********************************************************************/
+struct tblock {
+ long tb_max;
+ long tb_min;
+ long tb_total;
+ long tb_count;
+};
+
+/***********************************************************************
+ * The following globals are externed here so that they are accessable
+ * in the macros that follow.
+ ***********************************************************************/
+extern struct tblock tblock;
+extern void STD_go();
+extern int (*_TMP_FUNC)(void);
+extern void STD_opts_help();
+
+
+/***********************************************************************
+ * TEST: calls a system call
+ *
+ * parameters:
+ * SCALL = system call and parameters to execute
+ *
+ ***********************************************************************/
+#define TEST(SCALL) errno=0; TEST_RETURN = (unsigned) SCALL; TEST_ERRNO=errno;
+
+/***********************************************************************
+ * TEST_VOID: calls a system call
+ *
+ * parameters:
+ * SCALL = system call and parameters to execute
+ *
+ * Note: This is IDENTICAL to the TEST() macro except that it is intended
+ * for use with syscalls returning no values (void syscall()). The
+ * Typecasting nothing (void) into an unsigned integer causes compilation
+ * errors.
+ *
+ ***********************************************************************/
+#define TEST_VOID(SCALL) errno=0; SCALL; TEST_ERRNO=errno;
+
+/***********************************************************************
+ * TEST_CLEANUP: print system call timing stats and errno log entries
+ * to stdout if STD_TIMING_ON and STD_ERRNO_LOG are set, respectively.
+ * Do NOT print ANY information if no system calls logged.
+ *
+ * parameters:
+ * none
+ *
+ ***********************************************************************/
+#define TEST_CLEANUP \
+if ( STD_ERRNO_LOG ) { \
+ for (tmptime=0; tmptime<USC_MAX_ERRNO; tmptime++) { \
+ if ( STD_ERRNO_LIST[tmptime] ) { \
+ if ( TEST_VALID_ENO[tmptime].flag ) \
+ tst_resm(TINFO, "ERRNO %d:\tReceived %d Times", \
+ tmptime, STD_ERRNO_LIST[tmptime]); \
+ else \
+ tst_resm(TINFO, \
+ "ERRNO %d:\tReceived %d Times ** UNEXPECTED **", \
+ tmptime, STD_ERRNO_LIST[tmptime]); \
+ } \
+ } \
+}
+
+/***********************************************************************
+ * TEST_PAUSEF: Pause for SIGUSR1 if the pause flag is set.
+ * Set the user specified function as the interrupt
+ * handler instead of "STD_go"
+ *
+ * parameters:
+ * none
+ *
+ ***********************************************************************/
+#define TEST_PAUSEF(HANDLER) \
+if ( STD_PAUSE ) { \
+ _TMP_FUNC = (int (*)())signal(SIGUSR1, HANDLER); \
+ pause(); \
+ signal(SIGUSR1, (void (*)())_TMP_FUNC); \
+}
+
+/***********************************************************************
+ * TEST_PAUSE: Pause for SIGUSR1 if the pause flag is set.
+ * Just continue when signal comes in.
+ *
+ * parameters:
+ * none
+ *
+ ***********************************************************************/
+#define TEST_PAUSE usc_global_setup_hook();
+int usc_global_setup_hook();
+
+/***********************************************************************
+ * TEST_LOOPING now call the usc_test_looping function.
+ * The function will return 1 if the test should continue
+ * iterating.
+ *
+ ***********************************************************************/
+#define TEST_LOOPING usc_test_looping
+int usc_test_looping(int counter);
+
+/***********************************************************************
+ * TEST_ERROR_LOG(eno): log this errno if STD_ERRNO_LOG flag set
+ *
+ * parameters:
+ * int eno: the errno location in STD_ERRNO_LIST to log.
+ *
+ ***********************************************************************/
+#define TEST_ERROR_LOG(eno) \
+ if ( STD_ERRNO_LOG ) \
+ if ( eno < USC_MAX_ERRNO ) \
+ STD_ERRNO_LIST[eno]++; \
+
+
+/***********************************************************************
+ * TEST_EXP_ENOS(array): set the bits associated with the nput errnos
+ * in the TEST_VALID_ENO array.
+ *
+ * parameters:
+ * int array[]: a zero terminated array of errnos expected.
+ *
+ ***********************************************************************/
+#define TEST_EXP_ENOS(array) \
+ tmptime=0; \
+ while (array[tmptime] != 0) { \
+ if (array[tmptime] < USC_MAX_ERRNO) \
+ TEST_VALID_ENO[array[tmptime]].flag=1; \
+ tmptime++; \
+ }
+
+
+#endif /* end of __USCTEST_H__ */
--- /dev/null
+#
+# Copyright (c) 2003 Silicon Graphics, Inc. All Rights Reserved.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of version 2 of the GNU General Public License as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it would be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+#
+# Further, this software is distributed without any warranty that it is
+# free of the rightful claim of any third person regarding infringement
+# or the like. Any license provided herein, whether implied or
+# otherwise, applies only to this software file. Patent licenses, if
+# any, provided herein do not apply to combinations of this program with
+# other software, or any other product whatsoever.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write the Free Software Foundation, Inc., 59
+# Temple Place - Suite 330, Boston MA 02111-1307, USA.
+#
+# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+# Mountain View, CA 94043, or:
+#
+# http://www.sgi.com
+#
+# For further information regarding this notice, see:
+#
+# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
+#
+
+TOPDIR = ..
+include $(TOPDIR)/include/builddefs
+
+LTLIBRARY = libtest.la
+LT_CURRENT = 0
+LT_REVISION = 0
+LT_AGE = 0
+
+#
+# Everything (except for random.c) copied directly from LTP.
+# Refer to http://ltp.sourceforge.net/ for complete source.
+#
+CFILES = dataascii.c databin.c datapid.c file_lock.c forker.c \
+ pattern.c open_flags.c random_range.c string_to_tokens.c \
+ str_to_bytes.c tlibio.c write_log.c \
+ random.c
+
+default: $(LTLIBRARY)
+
+include $(BUILDRULES)
+
+install install-dev: default
--- /dev/null
+/*
+ * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like. Any license provided herein, whether implied or
+ * otherwise, applies only to this software file. Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+ * Mountain View, CA 94043, or:
+ *
+ * http://www.sgi.com
+ *
+ * For further information regarding this notice, see:
+ *
+ * http://oss.sgi.com/projects/GenInfo/NoticeExplan/
+ */
+#include <stdio.h>
+#include <string.h>
+#include "dataascii.h"
+
+#define CHARS "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghjiklmnopqrstuvwxyz\n"
+#define CHARS_SIZE sizeof(CHARS)
+
+#ifdef UNIT_TEST
+#include <stdlib.h> /* malloc */
+#endif
+
+static char Errmsg[80];
+
+int
+dataasciigen(listofchars, buffer, bsize, offset)
+char *listofchars; /* a null terminated list of characters */
+char *buffer;
+int bsize;
+int offset;
+{
+ int cnt;
+ int total;
+ int ind; /* index into CHARS array */
+ char *chr;
+ int chars_size;
+ char *charlist;
+
+ chr=buffer;
+ total=offset+bsize;
+
+ if ( listofchars == NULL ) {
+ charlist=CHARS;
+ chars_size=CHARS_SIZE;
+ }
+ else {
+ charlist=listofchars;
+ chars_size=strlen(listofchars);
+ }
+
+ for(cnt=offset; cnt<total; cnt++) {
+ ind=cnt%chars_size;
+ *chr++=charlist[ind];
+ }
+
+ return bsize;
+
+} /* end of dataasciigen */
+
+int
+dataasciichk(listofchars, buffer, bsize, offset, errmsg)
+char *listofchars; /* a null terminated list of characters */
+char *buffer;
+int bsize;
+int offset;
+char **errmsg;
+{
+ int cnt;
+ int total;
+ int ind; /* index into CHARS array */
+ char *chr;
+ int chars_size;
+ char *charlist;
+
+ chr=buffer;
+ total=offset+bsize;
+
+ if ( listofchars == NULL ) {
+ charlist=CHARS;
+ chars_size=CHARS_SIZE;
+ }
+ else {
+ charlist=listofchars;
+ chars_size=strlen(listofchars);
+ }
+
+ if ( errmsg != NULL ) {
+ *errmsg = Errmsg;
+ }
+
+ for(cnt=offset; cnt<total; chr++, cnt++) {
+ ind=cnt%chars_size;
+ if ( *chr != charlist[ind] ) {
+ sprintf(Errmsg,
+ "data mismatch at offset %d, exp:%#o, act:%#o", cnt,
+ charlist[ind], *chr);
+ return cnt;
+ }
+ }
+
+ sprintf(Errmsg, "all %d bytes match desired pattern", bsize);
+ return -1; /* buffer is ok */
+
+} /* end of dataasciichk */
+
+
+#if UNIT_TEST
+
+/***********************************************************************
+ * main for doing unit testing
+ ***********************************************************************/
+int
+main(ac, ag)
+int ac;
+char **ag;
+{
+
+int size=1023;
+char *buffer;
+int ret;
+char *errmsg;
+
+ if ((buffer=(char *)malloc(size)) == NULL ) {
+ perror("malloc");
+ exit(2);
+ }
+
+ dataasciigen(NULL, buffer, size, 0);
+ printf("dataasciigen(NULL, buffer, %d, 0)\n", size);
+
+ ret=dataasciichk(NULL, buffer, size, 0, &errmsg);
+ printf("dataasciichk(NULL, buffer, %d, 0, &errmsg) returned %d %s\n",
+ size, ret, errmsg);
+
+ if ( ret == -1 )
+ printf("\tPASS return value is -1 as expected\n");
+ else
+ printf("\tFAIL return value is %d, expected -1\n", ret);
+
+ ret=dataasciichk(NULL, &buffer[1], size-1, 1, &errmsg);
+ printf("dataasciichk(NULL, &buffer[1], %d, 1, &errmsg) returned %d %s\n",
+ size-1, ret, errmsg);
+
+ if ( ret == -1 )
+ printf("\tPASS return value is -1 as expected\n");
+ else
+ printf("\tFAIL return value is %d, expected -1\n", ret);
+
+ buffer[25]= 0x0;
+ printf("changing char 25\n");
+
+ ret=dataasciichk(NULL, &buffer[1], size-1, 1, &errmsg);
+ printf("dataasciichk(NULL, &buffer[1], %d, 1, &errmsg) returned %d %s\n",
+ size-1, ret, errmsg);
+
+ if ( ret == 25 )
+ printf("\tPASS return value is 25 as expected\n");
+ else
+ printf("\tFAIL return value is %d, expected 25\n", ret);
+
+ dataasciigen("this is a test of the my string" , buffer, size, 0);
+ printf("dataasciigen(\"this is a test of the my string\", buffer, %d, 0)\n", size);
+
+ ret=dataasciichk("this is a test of the my string", buffer, size, 0, &errmsg);
+ printf("dataasciichk(\"this is a test of the my string\", buffer, %d, 0, &errmsg) returned %d %s\n",
+ size, ret, errmsg);
+
+ if ( ret == -1 )
+ printf("\tPASS return value is -1 as expected\n");
+ else
+ printf("\tFAIL return value is %d, expected -1\n", ret);
+
+ ret=dataasciichk("this is a test of the my string", &buffer[1], size-1, 1, &errmsg);
+ printf("dataasciichk(\"this is a test of the my string\", &buffer[1], %d, 1, &errmsg) returned %d %s\n",
+ size-1, ret, errmsg);
+
+ if ( ret == -1 )
+ printf("\tPASS return value is -1 as expected\n");
+ else
+ printf("\tFAIL return value is %d, expected -1\n", ret);
+
+ buffer[25]= 0x0;
+ printf("changing char 25\n");
+
+ ret=dataasciichk("this is a test of the my string", &buffer[1], size-1, 1, &errmsg);
+ printf("dataasciichk(\"this is a test of the my string\", &buffer[1], %d, 1, &errmsg) returned %d %s\n",
+ size-1, ret, errmsg);
+
+ if ( ret == 25 )
+ printf("\tPASS return value is 25 as expected\n");
+ else
+ printf("\tFAIL return value is %d, expected 25\n", ret);
+
+ exit(0);
+}
+
+#endif
+
--- /dev/null
+/*
+ * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like. Any license provided herein, whether implied or
+ * otherwise, applies only to this software file. Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+ * Mountain View, CA 94043, or:
+ *
+ * http://www.sgi.com
+ *
+ * For further information regarding this notice, see:
+ *
+ * http://oss.sgi.com/projects/GenInfo/NoticeExplan/
+ */
+#include <stdio.h>
+#include <sys/param.h>
+#include <string.h> /* memset */
+#include <stdlib.h> /* rand */
+#include "databin.h"
+
+#if UNIT_TEST
+#include <malloc.h>
+#endif
+
+static char Errmsg[80];
+
+void
+databingen (mode, buffer, bsize, offset)
+int mode; /* either a, c, r, o, z or C */
+unsigned char *buffer; /* buffer pointer */
+int bsize; /* size of buffer */
+int offset; /* offset into the file where buffer starts */
+{
+int ind;
+
+ switch (mode)
+ {
+ default:
+ case 'a': /* alternating bit pattern */
+ memset(buffer,0x55,bsize);
+ break;
+
+ case 'c': /* checkerboard pattern */
+ memset(buffer,0xf0,bsize);
+ break;
+
+ case 'C': /* */
+ for (ind=0;ind< bsize;ind++) {
+ buffer[ind] = ((offset+ind)%8 & 0177);
+ }
+ break;
+
+ case 'o':
+ memset(buffer,0xff,bsize);
+ break;
+
+ case 'z':
+ memset(buffer,0x0,bsize);
+ break;
+
+ case 'r': /* random */
+ for (ind=0;ind< bsize;ind++) {
+ buffer[ind] = (rand () & 0177) | 0100;
+ }
+ }
+}
+
+/***********************************************************************
+ *
+ * return values:
+ * >= 0 : error at byte offset into the file, offset+buffer[0-(bsize-1)]
+ * < 0 : no error
+ ***********************************************************************/
+int
+databinchk(mode, buffer, bsize, offset, errmsg)
+int mode; /* either a, c, r, z, o, or C */
+unsigned char *buffer; /* buffer pointer */
+int bsize; /* size of buffer */
+int offset; /* offset into the file where buffer starts */
+char **errmsg;
+{
+ int cnt;
+ unsigned char *chr;
+ int total;
+ long expbits;
+ long actbits;
+
+ chr=buffer;
+ total=bsize;
+
+ if ( errmsg != NULL ) {
+ *errmsg = Errmsg;
+ }
+
+ switch (mode)
+ {
+ default:
+ case 'a': /* alternating bit pattern */
+ expbits=0x55;
+ break;
+
+ case 'c': /* checkerboard pattern */
+ expbits=0xf0;
+ break;
+
+ case 'C': /* counting pattern */
+ for (cnt=0;cnt< bsize;cnt++) {
+ expbits = ((offset+cnt)%8 & 0177);
+
+ if ( buffer[cnt] != expbits ) {
+ sprintf(Errmsg,
+ "data mismatch at offset %d, exp:%#lo, act:%#o",
+ offset+cnt, expbits, buffer[cnt]);
+ return offset+cnt;
+ }
+ }
+ sprintf(Errmsg, "all %d bytes match desired pattern", bsize);
+ return -1;
+
+ case 'o':
+ expbits=0xff;
+ break;
+
+ case 'z':
+ expbits=0;
+ break;
+
+ case 'r':
+ return -1; /* no check can be done for random */
+ }
+
+ for (cnt=0; cnt<bsize; chr++, cnt++) {
+ actbits = (long)*chr;
+
+ if ( actbits != expbits ) {
+ sprintf(Errmsg, "data mismatch at offset %d, exp:%#lo, act:%#lo",
+ offset+cnt, expbits, actbits);
+ return offset+cnt;
+ }
+ }
+
+ sprintf(Errmsg, "all %d bytes match desired pattern", bsize);
+ return -1; /* all ok */
+}
+
+#if UNIT_TEST
+
+/***********************************************************************
+ * main for doing unit testing
+ ***********************************************************************/
+int
+main(ac, ag)
+int ac;
+char **ag;
+{
+
+ int size=1023;
+ int offset;
+ int number;
+ unsigned char *buffer;
+ int ret;
+ char *errmsg;
+
+ if ((buffer=(unsigned char *)malloc(size)) == NULL ) {
+ perror("malloc");
+ exit(2);
+ }
+
+
+printf("***** for a ****************************\n");
+ databingen('a', buffer, size, 0);
+ printf("databingen('a', buffer, %d, 0)\n", size);
+
+ ret=databinchk('a', buffer, size, 0, &errmsg);
+ printf("databinchk('a', buffer, %d, 0, &errmsg) returned %d: %s\n",
+ size, ret, errmsg);
+ if ( ret == -1 )
+ printf("\tPASS return value of -1 as expected\n");
+ else
+ printf("\tFAIL return value %d, expected -1\n", ret);
+
+ offset=232400;
+ ret=databinchk('a', &buffer[1], size-1, offset, &errmsg);
+ printf("databinchk('a', &buffer[1], %d, %d, &errmsg) returned %d: %s\n",
+ size, offset, ret, errmsg);
+ if ( ret == -1 )
+ printf("\tPASS return value of -1 as expected\n");
+ else
+ printf("\tFAIL return value %d, expected -1\n", ret);
+
+ buffer[15]= 0x0;
+ printf("changing char 15 (offset (%d+15) = %d) to 0x0\n", offset, offset+15);
+ number=offset+15;
+
+ ret=databinchk('a', &buffer[1], size-1, offset+1, &errmsg);
+ printf("databinchk('a', &buffer[1], %d, %d, &errmsg) returned %d: %s\n",
+ size-1, offset+1, ret, errmsg);
+ if ( ret == number )
+ printf("\tPASS return value of %d as expected\n", number);
+ else
+ printf("\tFAIL return value %d, expected %d\n", ret, number);
+
+
+
+printf("***** for c ****************************\n");
+ databingen('c', buffer, size, 0);
+ printf("databingen('c', buffer, %d, 0)\n", size);
+
+ ret=databinchk('c', buffer, size, 0, &errmsg);
+ printf("databinchk('c', buffer, %d, 0, &errmsg) returned %d: %s\n",
+ size, ret, errmsg);
+ if ( ret == -1 )
+ printf("\tPASS return value of -1 as expected\n");
+ else
+ printf("\tFAIL return value %d, expected -1\n", ret);
+
+ offset=232400;
+ ret=databinchk('c', &buffer[1], size-1, offset, &errmsg);
+ printf("databinchk('c', &buffer[1], %d, %d, &errmsg) returned %d: %s\n",
+ size, offset, ret, errmsg);
+ if ( ret == -1 )
+ printf("\tPASS return value of -1 as expected\n");
+ else
+ printf("\tFAIL return value %d, expected -1\n", ret);
+
+ buffer[15]= 0x0;
+ printf("changing char 15 (offset (%d+15) = %d) to 0x0\n", offset, offset+15);
+ number=offset+15;
+
+ ret=databinchk('c', &buffer[1], size-1, offset+1, &errmsg);
+ printf("databinchk('c', &buffer[1], %d, %d, &errmsg) returned %d: %s\n",
+ size-1, offset+1, ret, errmsg);
+ if ( ret == number )
+ printf("\tPASS return value of %d as expected\n", number);
+ else
+ printf("\tFAIL return value %d, expected %d\n", ret, number);
+
+printf("***** for C ****************************\n");
+
+ databingen('C', buffer, size, 0);
+ printf("databingen('C', buffer, %d, 0)\n", size);
+
+ ret=databinchk('C', buffer, size, 0, &errmsg);
+ printf("databinchk('C', buffer, %d, 0, &errmsg) returned %d: %s\n",
+ size, ret, errmsg);
+ if ( ret == -1 )
+ printf("\tPASS return value of -1 as expected\n");
+ else
+ printf("\tFAIL return value %d, expected -1\n", ret);
+
+ offset=18;
+ ret=databinchk('C', &buffer[18], size-18, 18, &errmsg);
+ printf("databinchk('C', &buffer[18], %d, 18, &errmsg) returned %d: %s\n",
+ size-18, ret, errmsg);
+ if ( ret == -1 )
+ printf("\tPASS return value of -1 as expected\n");
+ else
+ printf("\tFAIL return value %d, expected -1\n", ret);
+
+ buffer[20]= 0x0;
+ buffer[21]= 0x0;
+ printf("changing char 20 and 21 to 0x0 (offset %d and %d)\n", 20,
+ 21);
+
+ ret=databinchk('C', &buffer[18], size-18, 18, &errmsg);
+ printf("databinchk('C', &buffer[18], %d, 18, &errmsg) returned %d: %s\n",
+ size-18, ret, errmsg);
+
+ if ( ret == 20 || ret == 21 )
+ printf("\tPASS return value of %d or %d as expected\n",
+ 20, 21);
+ else
+ printf("\tFAIL return value %d, expected %d or %d\n", ret,
+ 20, 21 );
+
+ exit(0);
+
+}
+
+#endif
+
--- /dev/null
+/*
+ * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like. Any license provided herein, whether implied or
+ * otherwise, applies only to this software file. Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+ * Mountain View, CA 94043, or:
+ *
+ * http://www.sgi.com
+ *
+ * For further information regarding this notice, see:
+ *
+ * http://oss.sgi.com/projects/GenInfo/NoticeExplan/
+ */
+/************
+
+64 bits in a Cray word
+
+ 12345678901234567890123456789012
+1234567890123456789012345678901234567890123456789012345678901234
+________________________________________________________________
+< pid >< word-offset in file (same #) >< pid >
+
+1234567890123456789012345678901234567890123456789012345678901234
+________________________________________________________________
+< pid >< offset in file of this word >< pid >
+
+
+8 bits to a bytes == character
+ NBPW 8
+************/
+
+#include <stdio.h>
+#include <sys/param.h>
+#ifdef UNIT_TEST
+#include <unistd.h>
+#include <stdlib.h>
+#endif
+
+static char Errmsg[80];
+
+#define LOWER16BITS(X) (X & 0177777)
+#define LOWER32BITS(X) (X & 0xffffffff)
+
+/***
+#define HIGHBITS(WRD, bits) ( (-1 << (64-bits)) & WRD)
+#define LOWBITS(WRD, bits) ( (-1 >> (64-bits)) & WRD)
+****/
+
+#define NBPBYTE 8 /* number bits per byte */
+
+#ifndef DEBUG
+#define DEBUG 0
+#endif
+
+/***********************************************************************
+ *
+ *
+ * 1 2 3 4 5 6 7 8 9 10 11 12 13 14 14 15 bytes
+ * 1234567890123456789012345678901234567890123456789012345678901234 bits
+ * ________________________________________________________________ 1 word
+ * < pid >< offset in file of this word >< pid >
+ *
+ * the words are put together where offset zero is the start.
+ * thus, offset 16 is the start of the second full word
+ * Thus, offset 8 is in middle of word 1
+ ***********************************************************************/
+int
+datapidgen(pid, buffer, bsize, offset)
+int pid;
+char *buffer;
+int bsize;
+int offset;
+{
+#if CRAY
+
+ int cnt;
+ int tmp;
+ char *chr;
+ long *wptr;
+ long word;
+ int woff; /* file offset for the word */
+ int boff; /* buffer offset or index */
+ int num_full_words;
+
+ num_full_words = bsize/NBPW;
+ boff = 0;
+
+ if ( cnt=(offset % NBPW) ) { /* partial word */
+
+ woff = offset - cnt;
+#if DEBUG
+printf("partial at beginning, cnt = %d, woff = %d\n", cnt, woff);
+#endif
+
+ word = ((LOWER16BITS(pid) << 48) | (LOWER32BITS(woff) << 16) | LOWER16BITS(pid));
+
+ chr = (char *)&word;
+
+ for (tmp=0; tmp<cnt; tmp++) { /* skip unused bytes */
+ chr++;
+ }
+
+ for (; boff<(NBPW-cnt) && boff<bsize; boff++, chr++) {
+ buffer[boff] = *chr;
+ }
+ }
+
+ /*
+ * full words
+ */
+
+ num_full_words = (bsize-boff)/NBPW;
+
+ woff = offset+boff;
+
+ for (cnt=0; cnt<num_full_words; woff += NBPW, cnt++ ) {
+
+ word = ((LOWER16BITS(pid) << 48) | (LOWER32BITS(woff) << 16) | LOWER16BITS(pid));
+
+ chr = (char *)&word;
+ for(tmp=0; tmp<NBPW; tmp++, chr++) {
+ buffer[boff++] = *chr;
+ }
+/****** Only if wptr is a word ellined
+ wptr = (long *)&buffer[boff];
+ *wptr = word;
+ boff += NBPW;
+*****/
+
+ }
+
+ /*
+ * partial word at end of buffer
+ */
+
+ if ( cnt=((bsize-boff) % NBPW) ) {
+#if DEBUG
+printf("partial at end\n");
+#endif
+ word = ((LOWER16BITS(pid) << 48) | (LOWER32BITS(woff) << 16) | LOWER16BITS(pid));
+
+ chr = (char *)&word;
+
+ for (tmp=0; tmp<cnt && boff<bsize; tmp++, chr++) {
+ buffer[boff++] = *chr;
+ }
+ }
+
+ return bsize;
+
+#else
+ return -1; /* not support on non-64 bits word machines */
+
+#endif
+
+}
+
+/***********************************************************************
+ *
+ *
+ ***********************************************************************/
+int
+datapidchk(pid, buffer, bsize, offset, errmsg)
+int pid;
+char *buffer;
+int bsize;
+int offset;
+char **errmsg;
+{
+#if CRAY
+
+ int cnt;
+ int tmp;
+ char *chr;
+ long *wptr;
+ long word;
+ int woff; /* file offset for the word */
+ int boff; /* buffer offset or index */
+ int num_full_words;
+
+
+ if ( errmsg != NULL ) {
+ *errmsg = Errmsg;
+ }
+
+
+ num_full_words = bsize/NBPW;
+ boff = 0;
+
+ if ( cnt=(offset % NBPW) ) { /* partial word */
+ woff = offset - cnt;
+ word = ((LOWER16BITS(pid) << 48) | (LOWER32BITS(woff) << 16) | LOWER16BITS(pid));
+
+ chr = (char *)&word;
+
+ for (tmp=0; tmp<cnt; tmp++) { /* skip unused bytes */
+ chr++;
+ }
+
+ for (; boff<(NBPW-cnt) && boff<bsize; boff++, chr++) {
+ if (buffer[boff] != *chr) {
+ sprintf(Errmsg, "Data mismatch at offset %d, exp:%#o, act:%#o",
+ offset+boff, *chr, buffer[boff]);
+ return offset+boff;
+ }
+ }
+ }
+
+ /*
+ * full words
+ */
+
+ num_full_words = (bsize-boff)/NBPW;
+
+ woff = offset+boff;
+
+ for (cnt=0; cnt<num_full_words; woff += NBPW, cnt++ ) {
+ word = ((LOWER16BITS(pid) << 48) | (LOWER32BITS(woff) << 16) | LOWER16BITS(pid));
+
+ chr = (char *)&word;
+ for(tmp=0; tmp<NBPW; tmp++, boff++, chr++) {
+ if ( buffer[boff] != *chr ) {
+ sprintf(Errmsg, "Data mismatch at offset %d, exp:%#o, act:%#o",
+ woff, *chr, buffer[boff]);
+ return woff;
+ }
+ }
+
+/****** only if a word elined
+ wptr = (long *)&buffer[boff];
+ if ( *wptr != word ) {
+ sprintf(Errmsg, "Data mismatch at offset %d, exp:%#o, act:%#o",
+ woff, word, *wptr);
+ return woff;
+ }
+ boff += NBPW;
+******/
+ }
+
+ /*
+ * partial word at end of buffer
+ */
+
+ if ( cnt=((bsize-boff) % NBPW) ) {
+#if DEBUG
+printf("partial at end\n");
+#endif
+ word = ((LOWER16BITS(pid) << 48) | (LOWER32BITS(woff) << 16) | LOWER16BITS(pid));
+
+ chr = (char *)&word;
+
+
+ for (tmp=0; tmp<cnt && boff<bsize; boff++, tmp++, chr++) {
+ if ( buffer[boff] != *chr ) {
+ sprintf(Errmsg, "Data mismatch at offset %d, exp:%#o, act:%#o",
+ offset+boff, *chr, buffer[boff]);
+ return offset+boff;
+ }
+ }
+ }
+
+ sprintf(Errmsg, "all %d bytes match desired pattern", bsize);
+ return -1; /* buffer is ok */
+
+#else
+
+ if ( errmsg != NULL ) {
+ *errmsg = Errmsg;
+ }
+ sprintf(Errmsg, "Not supported on this OS.");
+ return 0;
+
+#endif
+
+
+} /* end of datapidchk */
+
+#if UNIT_TEST
+
+/***********************************************************************
+ * main for doing unit testing
+ ***********************************************************************/
+int
+main(ac, ag)
+int ac;
+char **ag;
+{
+
+int size=1234;
+char *buffer;
+int ret;
+char *errmsg;
+
+ if ((buffer=(char *)malloc(size)) == NULL ) {
+ perror("malloc");
+ exit(2);
+ }
+
+
+ datapidgen(-1, buffer, size, 3);
+
+/***
+fwrite(buffer, size, 1, stdout);
+fwrite("\n", 1, 1, stdout);
+****/
+
+ printf("datapidgen(-1, buffer, size, 3)\n");
+
+ ret=datapidchk(-1, buffer, size, 3, &errmsg);
+ printf("datapidchk(-1, buffer, %d, 3, &errmsg) returned %d %s\n",
+ size, ret, errmsg);
+ ret=datapidchk(-1, &buffer[1], size-1, 4, &errmsg);
+ printf("datapidchk(-1, &buffer[1], %d, 4, &errmsg) returned %d %s\n",
+ size-1, ret, errmsg);
+
+ buffer[25]= 0x0;
+ buffer[26]= 0x0;
+ buffer[27]= 0x0;
+ buffer[28]= 0x0;
+ printf("changing char 25-28\n");
+
+ ret=datapidchk(-1, &buffer[1], size-1, 4, &errmsg);
+ printf("datapidchk(-1, &buffer[1], %d, 4, &errmsg) returned %d %s\n",
+ size-1, ret, errmsg);
+
+printf("------------------------------------------\n");
+
+ datapidgen(getpid(), buffer, size, 5);
+
+/*******
+fwrite(buffer, size, 1, stdout);
+fwrite("\n", 1, 1, stdout);
+******/
+
+ printf("\ndatapidgen(getpid(), buffer, size, 5)\n");
+
+ ret=datapidchk(getpid(), buffer, size, 5, &errmsg);
+ printf("datapidchk(getpid(), buffer, %d, 5, &errmsg) returned %d %s\n",
+ size, ret, errmsg);
+
+ ret=datapidchk(getpid(), &buffer[1], size-1, 6, &errmsg);
+ printf("datapidchk(getpid(), &buffer[1], %d, 6, &errmsg) returned %d %s\n",
+ size-1, ret, errmsg);
+
+ buffer[25]= 0x0;
+ printf("changing char 25\n");
+
+ ret=datapidchk(getpid(), &buffer[1], size-1, 6, &errmsg);
+ printf("datapidchk(getpid(), &buffer[1], %d, 6, &errmsg) returned %d %s\n",
+ size-1, ret, errmsg);
+
+ exit(0);
+}
+
+#endif
+
--- /dev/null
+/*
+ * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like. Any license provided herein, whether implied or
+ * otherwise, applies only to this software file. Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+ * Mountain View, CA 94043, or:
+ *
+ * http://www.sgi.com
+ *
+ * For further information regarding this notice, see:
+ *
+ * http://oss.sgi.com/projects/GenInfo/NoticeExplan/
+ */
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/file.h>
+#include <sys/param.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <errno.h>
+#include <sys/sysmacros.h>
+#include <string.h> /* memset, strerror */
+#include "file_lock.h"
+
+
+#ifndef EFSEXCLWR
+#define EFSEXCLWR 503
+#endif
+
+/*
+ * String containing the last system call.
+ *
+ */
+char Fl_syscall_str[128];
+
+static char errmsg[256];
+
+/***********************************************************************
+ *
+ * Test interface to the fcntl system call.
+ * It will loop if the LOCK_NB flags is NOT set.
+ ***********************************************************************/
+int
+file_lock(fd, flags, errormsg)
+int fd;
+int flags;
+char **errormsg;
+{
+ register int cmd, ret;
+ struct flock flocks;
+
+ memset(&flocks, 0, sizeof(struct flock));
+
+ if (flags&LOCK_NB)
+ cmd = F_SETLK;
+ else
+ cmd = F_SETLKW;
+
+ flocks.l_whence = 0;
+ flocks.l_start = 0;
+ flocks.l_len = 0;
+
+ if (flags&LOCK_UN)
+ flocks.l_type = F_UNLCK;
+ else if (flags&LOCK_EX)
+ flocks.l_type = F_WRLCK;
+ else if (flags&LOCK_SH)
+ flocks.l_type = F_RDLCK;
+ else {
+ errno = EINVAL;
+ if ( errormsg != NULL ) {
+ sprintf(errmsg,
+ "Programmer error, called file_lock with in valid flags\n");
+ *errormsg = errmsg;
+ }
+ return -1;
+ }
+
+ sprintf(Fl_syscall_str,
+ "fcntl(%d, %d, &flocks): type:%d whence:%d, start:%lld len:%lld\n",
+ fd, cmd, flocks.l_type, flocks.l_whence,
+ (long long)flocks.l_start, (long long)flocks.l_len);
+
+ while (1) {
+ ret = fcntl(fd, cmd, &flocks);
+
+ if ( ret < 0 ) {
+ if ( cmd == F_SETLK )
+ switch (errno) {
+ /* these errors are okay */
+ case EACCES: /* Permission denied */
+ case EINTR: /* interrupted system call */
+#ifdef EFILESH
+ case EFILESH: /* file shared */
+#endif
+ case EFSEXCLWR: /* File is write protected */
+ continue; /* retry getting lock */
+ }
+ if ( errormsg != NULL ) {
+ sprintf(errmsg, "fcntl(%d, %d, &flocks): errno:%d %s\n",
+ fd, cmd, errno, strerror(errno));
+ *errormsg = errmsg;
+ }
+ return -1;
+ }
+ break;
+ }
+
+ return ret;
+
+} /* end of file_lock */
+
+/***********************************************************************
+ *
+ * Test interface to the fcntl system call.
+ * It will loop if the LOCK_NB flags is NOT set.
+ ***********************************************************************/
+int
+record_lock(fd, flags, start, len, errormsg)
+int fd;
+int flags;
+int start;
+int len;
+char **errormsg;
+{
+ register int cmd, ret;
+ struct flock flocks;
+
+ memset(&flocks, 0, sizeof(struct flock));
+
+ if (flags&LOCK_NB)
+ cmd = F_SETLK;
+ else
+ cmd = F_SETLKW;
+
+ flocks.l_whence = 0;
+ flocks.l_start = start;
+ flocks.l_len = len;
+
+ if (flags&LOCK_UN)
+ flocks.l_type = F_UNLCK;
+ else if (flags&LOCK_EX)
+ flocks.l_type = F_WRLCK;
+ else if (flags&LOCK_SH)
+ flocks.l_type = F_RDLCK;
+ else {
+ errno = EINVAL;
+ if ( errormsg != NULL ) {
+ sprintf(errmsg,
+ "Programmer error, called record_lock with in valid flags\n");
+ *errormsg = errmsg;
+ }
+ return -1;
+ }
+
+ sprintf(Fl_syscall_str,
+ "fcntl(%d, %d, &flocks): type:%d whence:%d, start:%lld len:%lld\n",
+ fd, cmd, flocks.l_type, flocks.l_whence,
+ (long long)flocks.l_start, (long long)flocks.l_len);
+
+ while (1) {
+ ret = fcntl(fd, cmd, &flocks);
+
+ if ( ret < 0 ) {
+ if ( cmd == F_SETLK )
+ switch (errno) {
+ /* these errors are okay */
+ case EACCES: /* Permission denied */
+ case EINTR: /* interrupted system call */
+#ifdef EFILESH
+ case EFILESH: /* file shared */
+#endif
+ case EFSEXCLWR: /* File is write protected */
+ continue; /* retry getting lock */
+ }
+ if ( errormsg != NULL ) {
+ sprintf(errmsg, "fcntl(%d, %d, &flocks): errno:%d %s\n",
+ fd, cmd, errno, strerror(errno));
+ *errormsg = errmsg;
+ }
+ return -1;
+ }
+ break;
+ }
+
+ return ret;
+
+} /* end of record_lock */
+
+
--- /dev/null
+/*
+ * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like. Any license provided herein, whether implied or
+ * otherwise, applies only to this software file. Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+ * Mountain View, CA 94043, or:
+ *
+ * http://www.sgi.com
+ *
+ * For further information regarding this notice, see:
+ *
+ * http://oss.sgi.com/projects/GenInfo/NoticeExplan/
+ */
+/**************************************************************
+ *
+ * OS Testing - Silicon Graphics, Inc.
+ *
+ * FUNCTION NAME : forker
+ * background
+ *
+ * FUNCTION TITLE : fork desired number of copies of the current process
+ * fork a process and return control to caller
+ *
+ * SYNOPSIS:
+ * int forker(ncopies, mode, prefix)
+ * int ncopies;
+ * int mode;
+ * char *prefix;
+ *
+ * int background(prefix);
+ * char *prefix;
+ *
+ * extern int Forker_pids[];
+ * extern int Forker_npids;
+ *
+ * AUTHOR : Richard Logan
+ *
+ * CO-PILOT(s) : Dean Roehrich
+ *
+ * INITIAL RELEASE : UNICOS 8.0
+ *
+ * DESIGN DESCRIPTION
+ * The background function will do a fork of the current process.
+ * The parent process will then exit, thus orphaning the
+ * child process. Doing this will not nice the child process
+ * like executing a cmd in the background using "&" from the shell.
+ * If the fork fails and prefix is not NULL, a error message is printed
+ * to stderr and the process will exit with a value of errno.
+ *
+ * The forker function will fork <ncopies> minus one copies
+ * of the current process. There are two modes in how the forks
+ * will be done. Mode 0 (default) will have all new processes
+ * be childern of the parent process. Using Mode 1,
+ * the parent process will have one child and that child will
+ * fork the next process, if necessary, and on and on.
+ * The forker function will return the number of successful
+ * forks. This value will be different for the parent and each child.
+ * Using mode 0, the parent will get the total number of successful
+ * forks. Using mode 1, the newest child will get the total number
+ * of forks. The parent will get a return value of 1.
+ *
+ * The forker function also updates the global variables
+ * Forker_pids[] and Forker_npids. The Forker_pids array will
+ * be updated to contain the pid of each new process. The
+ * Forker_npids variable contains the number of entries
+ * in Forker_pids. Note, not all processes will have
+ * access to all pids via Forker_pids. If using mode 0, only the
+ * parent process and the last process will have all information.
+ * If using mode 1, only the last child process will have all information.
+ *
+ * If the prefix parameter is not NULL and the fork system call fails,
+ * a error message will be printed to stderr. The error message
+ * the be preceeded with prefix string. If prefix is NULL,
+ * no error message is printed.
+ *
+ * SPECIAL REQUIREMENTS
+ * None.
+ *
+ * UPDATE HISTORY
+ * This should contain the description, author, and date of any
+ * "interesting" modifications (i.e. info should helpful in
+ * maintaining/enhancing this module).
+ * username description
+ * ----------------------------------------------------------------
+ * rrl This functions will first written during
+ * the SFS testing days, 1993.
+ *
+ * BUGS/LIMITATIONS
+ * The child pids are stored in the fixed array, Forker_pids.
+ * The array only has space for 4098 pids. Only the first
+ * 4098 pids will be stored in the array.
+ *
+ **************************************************************/
+
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h> /* fork, getpid, sleep */
+#include <string.h>
+#include <stdlib.h> /* exit */
+#include "forker.h"
+
+int Forker_pids[FORKER_MAX_PIDS]; /* holds pids of forked processes */
+int Forker_npids=0; /* number of entries in Forker_pids */
+
+/***********************************************************************
+ *
+ * This function will fork and the parent will exit zero and
+ * the child will return. This will orphan the returning process
+ * putting it in the background.
+ *
+ * Return Value
+ * 0 : if fork did not fail
+ * !0 : if fork failed, the return value will be the errno.
+ ***********************************************************************/
+int
+background(prefix)
+char *prefix;
+{
+ switch (fork()) {
+ case -1:
+ if ( prefix != NULL )
+ fprintf(stderr, "%s: In %s background(), fork() failed, errno:%d %s\n",
+ prefix, __FILE__, errno, strerror(errno));
+ exit(errno);
+
+ case 0: /* child process */
+ break;
+
+ default:
+ exit(0);
+ }
+
+ return 0;
+
+} /* end of background */
+
+/***********************************************************************
+ * Forker will fork ncopies-1 copies of self.
+ *
+ ***********************************************************************/
+int
+forker(ncopies, mode, prefix)
+int ncopies;
+int mode; /* 0 - all childern of parent, 1 - only 1 direct child */
+char *prefix; /* if ! NULL, an message will be printed to stderr */
+ /* if fork fails. The prefix (program name) will */
+ /* preceed the message */
+{
+ int cnt;
+ int pid;
+ static int ind = 0;
+
+ Forker_pids[ind]=0;
+
+ for ( cnt=1; cnt < ncopies; cnt++ ) {
+
+ switch ( mode ) {
+ case 1 : /* only 1 direct child */
+ if ( (pid = fork()) == -1 ) {
+ if ( prefix != NULL )
+ fprintf(stderr, "%s: %s,forker(): fork() failed, errno:%d %s\n",
+ prefix, __FILE__, errno, strerror(errno));
+ return 0;
+ }
+ Forker_npids++;
+
+ switch (pid ) {
+ case 0: /* child - continues the forking */
+
+ if ( Forker_npids < FORKER_MAX_PIDS )
+ Forker_pids[Forker_npids-1]=getpid();
+ break;
+
+ default: /* parent - stop the forking */
+ if ( Forker_npids < FORKER_MAX_PIDS )
+ Forker_pids[Forker_npids-1]=pid;
+ return cnt-1;
+ }
+
+ break;
+
+ default : /* all new processes are childern of parent */
+ if ( (pid = fork()) == -1 ) {
+ if ( prefix != NULL )
+ fprintf(stderr, "%s: %s,forker(): fork() failed, errno:%d %s\n",
+ prefix, __FILE__, errno, strerror(errno));
+ return cnt-1;
+ }
+ Forker_npids++;
+
+ switch (pid ) {
+ case 0: /* child - stops the forking */
+ if ( Forker_npids < FORKER_MAX_PIDS )
+ Forker_pids[Forker_npids-1]=getpid();
+ return cnt;
+
+ default: /* parent - continues the forking */
+ if ( Forker_npids < FORKER_MAX_PIDS )
+ Forker_pids[Forker_npids-1]=pid;
+ break;
+ }
+ break;
+ }
+ }
+
+ if ( Forker_npids < FORKER_MAX_PIDS )
+ Forker_pids[Forker_npids]=0;
+ return cnt-1;
+
+} /* end of forker */
+
+
+#if UNIT_TEST
+
+/*
+ * The following is a unit test main for the background and forker
+ * functions.
+ */
+
+int
+main(argc, argv)
+int argc;
+char **argv;
+{
+ int ncopies=1;
+ int mode=0;
+ int ret;
+ int ind;
+
+ if ( argc == 1 ) {
+ printf("Usage: %s ncopies [mode]\n", argv[0]);
+ exit(1);
+ }
+
+ if ( sscanf(argv[1], "%i", &ncopies) != 1 ) {
+ printf("%s: ncopies argument must be integer\n", argv[0]);
+ exit(1);
+ }
+
+ if ( argc == 3 )
+ if ( sscanf(argv[2], "%i", &mode) != 1 ) {
+ printf("%s: mode argument must be integer\n", argv[0]);
+ exit(1);
+ }
+
+ printf("Starting Pid = %d\n", getpid());
+ ret=background(argv[0]);
+ printf("After background() ret:%d, pid = %d\n", ret, getpid());
+
+ ret=forker(ncopies, mode, argv[0]);
+
+ printf("forker(%d, %d, %s) ret:%d, pid = %d, sleeping 30 seconds.\n",
+ ncopies, mode, argv[0], ret, getpid());
+
+ printf("%d My version of Forker_pids[], Forker_npids = %d\n",
+ getpid(), Forker_npids);
+
+ for (ind=0; ind<Forker_npids; ind++){
+ printf("%d ind:%-2d pid:%d\n", getpid(), ind, Forker_pids[ind]);
+ }
+
+ sleep(30);
+ exit(0);
+}
+
+#endif /* UNIT_TEST */
--- /dev/null
+/*
+ * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like. Any license provided herein, whether implied or
+ * otherwise, applies only to this software file. Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+ * Mountain View, CA 94043, or:
+ *
+ * http://www.sgi.com
+ *
+ * For further information regarding this notice, see:
+ *
+ * http://oss.sgi.com/projects/GenInfo/NoticeExplan/
+ */
+/**************************************************************
+ *
+ * OS Testing - Silicon Graphics, Inc.
+ *
+ * FUNCTION NAME : parse_open_flags
+ * openflags2symbols
+ *
+ * FUNCTION TITLE : converts open flag symbols into bitmask
+ * converts open flag bitmask into symbols
+ *
+ * SYNOPSIS:
+ * int parse_open_flags(symbols, badname)
+ * char *symbols;
+ * char **badname;
+ *
+ * char *openflags2symbols(openflags, sep, mode)
+ * int openflags;
+ * char *sep;
+ * int mode;
+ *
+ * AUTHOR : Richard Logan
+ *
+ * CO-PILOT(s) : Dean Roehrich
+ *
+ * INITIAL RELEASE : UNICOS 8.0
+ *
+ * DESIGN DESCRIPTION
+ * The parse_open_flags function can be used to convert
+ * a list of comma separated open(2) flag symbols (i.e. O_TRUNC)
+ * into the bitmask that can be used by open(2).
+ * If a symbol is unknown and <badname> is not NULL, <badname>
+ * will updated to point that symbol in <string>.
+ * Parse_open_flags will return -1 on this error.
+ * Otherwise parse_open_flags will return the open flag bitmask.
+ * If parse_open_flags returns, <string> will left unchanged.
+ *
+ * The openflags2symbols function attempts to convert open flag
+ * bits into human readable symbols (i.e. O_TRUNC). If there
+ * are more than one symbol, the <sep> string will be placed as
+ * a separator between symbols. Commonly used separators would
+ * be a comma "," or pipe "|". If <mode> is one and not all
+ * <openflags> bits can be converted to symbols, the "UNKNOWN"
+ * symbol will be added to return string.
+ * Openflags2symbols will return the indentified symbols.
+ * If no symbols are recognized the return value will be a empty
+ * string or the "UNKNOWN" symbol.
+ *
+ * SPECIAL REQUIREMENTS
+ * None.
+ *
+ * UPDATE HISTORY
+ * This should contain the description, author, and date of any
+ * "interesting" modifications (i.e. info should helpful in
+ * maintaining/enhancing this module).
+ * username description
+ * ----------------------------------------------------------------
+ * rrl This code was first created during the beginning
+ * of the SFS testing days. I think that was in 1993.
+ * This code was updated in 05/96.
+ * (05/96) openflags2symbols was written.
+ *
+ * BUGS/LIMITATIONS
+ * Currently (05/96) all known symbols are coded into openflags2symbols.
+ * If new open flags are added this code will have to updated
+ * to know about them or they will not be recognized.
+ *
+ **************************************************************/
+
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/param.h>
+#include <string.h> /* strcat */
+#include "open_flags.h"
+
+#define UNKNOWN_SYMBOL "UNKNOWN"
+
+static char Open_symbols[512]; /* space for openflags2symbols return value */
+
+struct open_flag_t {
+ char *symbol;
+ int flag;
+};
+
+static struct open_flag_t Open_flags[] = {
+ { "O_RDONLY", O_RDONLY },
+ { "O_WRONLY", O_WRONLY },
+ { "O_RDWR", O_RDWR },
+ { "O_SYNC", O_SYNC },
+ { "O_CREAT", O_CREAT },
+ { "O_TRUNC", O_TRUNC },
+ { "O_EXCL", O_EXCL },
+ { "O_APPEND", O_APPEND },
+ { "O_NONBLOCK", O_NONBLOCK },
+#if O_NOCTTY
+ { "O_NOCTTY", O_NOCTTY },
+#endif
+#if O_DSYNC
+ { "O_DSYNC", O_DSYNC },
+#endif
+#if O_RSYNC
+ { "O_RSYNC", O_RSYNC },
+#endif
+#if O_ASYNC
+ { "O_ASYNC", O_ASYNC },
+#endif
+#if O_PTYIGN
+ { "O_PTYIGN", O_PTYIGN },
+#endif
+#if O_NDELAY
+ { "O_NDELAY", O_NDELAY },
+#endif
+#if O_RAW
+ { "O_RAW", O_RAW },
+#endif
+#ifdef O_SSD
+ { "O_SSD", O_SSD },
+#endif
+#if O_BIG
+ { "O_BIG", O_BIG },
+#endif
+#if O_PLACE
+ { "O_PLACE", O_PLACE },
+#endif
+#if O_RESTART
+ { "O_RESTART", O_RESTART },
+#endif
+#if O_SFSXOP
+ { "O_SFSXOP", O_SFSXOP },
+#endif
+#if O_SFS_DEFER_TM
+ { "O_SFS_DEFER_TM", O_SFS_DEFER_TM },
+#endif
+#if O_WELLFORMED
+ { "O_WELLFORMED", O_WELLFORMED },
+#endif
+#if O_LDRAW
+ { "O_LDRAW", O_LDRAW },
+#endif
+#if O_T3D
+ { "O_T3D", O_T3D },
+#endif /* O_T3D */
+#if O_PARALLEL
+ { "O_PARALLEL", O_PARALLEL },
+ { "O_FSA", O_PARALLEL|O_WELLFORMED|O_RAW }, /* short cut */
+#endif /* O_PARALLEL */
+#ifdef O_LARGEFILE
+ { "O_LARGEFILE", O_LARGEFILE },
+#endif
+#ifdef O_DIRECT
+ { "O_DIRECT", O_DIRECT },
+#endif
+#ifdef O_PRIV
+ { "O_PRIV", O_PRIV },
+#endif
+
+};
+
+int
+parse_open_flags(char *string, char **badname)
+{
+ int bits = 0;
+ char *name;
+ char *cc;
+ char savecc;
+ int found;
+ int ind;
+
+ name=string;
+ cc=name;
+
+ while ( 1 ) {
+
+ for(; ((*cc != ',') && (*cc != '\0')); cc++);
+ savecc = *cc;
+ *cc = '\0';
+
+ found = 0;
+
+ for(ind=0; ind < sizeof(Open_flags)/sizeof(struct open_flag_t); ind++) {
+ if ( strcmp(name, Open_flags[ind].symbol) == 0 ) {
+ bits |= Open_flags[ind].flag;
+ found=1;
+ break;
+ }
+ }
+
+ *cc = savecc; /* restore string */
+
+ if ( found == 0 ) { /* invalid name */
+ if ( badname != NULL )
+ *badname = name;
+ return -1;
+ }
+
+ if ( savecc == '\0' )
+ break;
+
+ name = ++cc;
+
+ } /* end while */
+
+ return bits;
+
+} /* end of parse_open_flags */
+
+
+char *
+openflags2symbols(int openflags, char *sep, int mode)
+{
+ int ind;
+ int size;
+ int bits = openflags;
+ int havesome=0;
+
+ Open_symbols[0]='\0';
+
+ size=sizeof(Open_flags)/sizeof(struct open_flag_t);
+
+ /*
+ * Deal with special case of O_RDONLY. If O_WRONLY nor O_RDWR
+ * bits are not set, assume O_RDONLY.
+ */
+
+ if ( (bits & (O_WRONLY | O_RDWR)) == 0 ) {
+ strcat(Open_symbols, "O_RDONLY");
+ havesome=1;
+ }
+
+ /*
+ * Loop through all but O_RDONLY elments of Open_flags
+ */
+ for(ind=1; ind < size; ind++) {
+
+ if ( (bits & Open_flags[ind].flag) == Open_flags[ind].flag ) {
+ if ( havesome )
+ strcat(Open_symbols, sep);
+
+ strcat(Open_symbols, Open_flags[ind].symbol);
+ havesome++;
+
+ /* remove flag bits from bits */
+ bits = bits & (~Open_flags[ind].flag);
+ }
+ }
+
+ /*
+ * If not all bits were identified and mode was equal to 1,
+ * added UNKNOWN_SYMBOL to return string
+ */
+ if ( bits && mode == 1 ) { /* not all bits were identified */
+ if ( havesome )
+ strcat(Open_symbols, sep);
+ strcat(Open_symbols, UNKNOWN_SYMBOL);
+ }
+
+ return Open_symbols;
+
+} /* end of openflags2symbols */
+
+
+#ifdef UNIT_TEST
+
+/*
+ * The following code provides a UNIT test main for
+ * parse_open_flags and openflags2symbols functions.
+ */
+
+int
+main(argc, argv)
+int argc;
+char **argv;
+{
+ int bits;
+ int ret;
+ char *err;
+
+ if (argc == 1 ) {
+ printf("Usage: %s openflagsbits\n\t%s symbols\n", argv[0], argv[0]);
+ exit(1);
+ }
+
+ if ( sscanf(argv[1], "%i", &bits) == 1 ) {
+ printf("openflags2symbols(%#o, \",\", 1) returned %s\n",
+ bits, openflags2symbols(bits, ",", 1));
+
+ } else {
+ ret=parse_open_flags(argv[1], &err);
+ if ( ret == -1 )
+ printf("parse_open_flags(%s, &err) returned -1, err = %s\n",
+ argv[0], err);
+ else
+ printf("parse_open_flags(%s, &err) returned %#o\n", argv[0], ret);
+ }
+
+ exit(0);
+}
+
+#endif /* end of UNIT_TEST */
--- /dev/null
+/*
+ * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like. Any license provided herein, whether implied or
+ * otherwise, applies only to this software file. Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+ * Mountain View, CA 94043, or:
+ *
+ * http://www.sgi.com
+ *
+ * For further information regarding this notice, see:
+ *
+ * http://oss.sgi.com/projects/GenInfo/NoticeExplan/
+ */
+#include <string.h>
+#include "pattern.h"
+
+/*
+ * The routines in this module are used to fill/check a data buffer
+ * with/against a known pattern.
+ */
+
+int
+pattern_check(buf, buflen, pat, patlen, patshift)
+char *buf;
+int buflen;
+char *pat;
+int patlen;
+int patshift;
+{
+ int nb, ncmp, nleft;
+ char *cp;
+
+ if (patlen)
+ patshift = patshift % patlen;
+
+ cp = buf;
+ nleft = buflen;
+
+ /*
+ * The following 2 blocks of code are to compare the first patlen
+ * bytes of buf. We need 2 checks if patshift is > 0 since we
+ * must check the last (patlen - patshift) bytes, and then the
+ * first (patshift) bytes.
+ */
+
+ nb = patlen - patshift;
+ if (nleft < nb) {
+ return (memcmp(cp, pat + patshift, nleft) ? -1 : 0);
+ } else {
+ if (memcmp(cp, pat + patshift, nb))
+ return -1;
+
+ nleft -= nb;
+ cp += nb;
+ }
+
+ if (patshift > 0) {
+ nb = patshift;
+ if (nleft < nb) {
+ return (memcmp(cp, pat, nleft) ? -1 : 0);
+ } else {
+ if (memcmp(cp, pat, nb))
+ return -1;
+
+ nleft -= nb;
+ cp += nb;
+ }
+ }
+
+ /*
+ * Now, verify the rest of the buffer using the algorithm described
+ * in the function header.
+ */
+
+ ncmp = cp - buf;
+ while (ncmp < buflen) {
+ nb = (ncmp < nleft) ? ncmp : nleft;
+ if (memcmp(buf, cp, nb))
+ return -1;
+
+ cp += nb;
+ ncmp += nb;
+ nleft -= nb;
+ }
+
+ return 0;
+}
+
+int
+pattern_fill(buf, buflen, pat, patlen, patshift)
+char *buf;
+int buflen;
+char *pat;
+int patlen;
+int patshift;
+{
+ int trans, ncopied, nleft;
+ char *cp;
+
+ if (patlen)
+ patshift = patshift % patlen;
+
+ cp = buf;
+ nleft = buflen;
+
+ /*
+ * The following 2 blocks of code are to fill the first patlen
+ * bytes of buf. We need 2 sections if patshift is > 0 since we
+ * must first copy the last (patlen - patshift) bytes into buf[0]...,
+ * and then the first (patshift) bytes of pattern following them.
+ */
+
+ trans = patlen - patshift;
+ if (nleft < trans) {
+ memcpy(cp, pat + patshift, nleft);
+ return 0;
+ } else {
+ memcpy(cp, pat + patshift, trans);
+ nleft -= trans;
+ cp += trans;
+ }
+
+ if (patshift > 0) {
+ trans = patshift;
+ if (nleft < trans) {
+ memcpy(cp, pat, nleft);
+ return 0;
+ } else {
+ memcpy(cp, pat, trans);
+ nleft -= trans;
+ cp += trans;
+ }
+ }
+
+ /*
+ * Now, fill the rest of the buffer using the algorithm described
+ * in the function header comment.
+ */
+
+ ncopied = cp - buf;
+ while (ncopied < buflen) {
+ trans = (ncopied < nleft) ? ncopied : nleft;
+ memcpy(cp, buf, trans);
+ cp += trans;
+ ncopied += trans;
+ nleft -= trans;
+ }
+
+ return(0);
+}
--- /dev/null
+/**************************************************************************
+ *
+ * random.c -- pseudo random number generator
+ * Copyright (C) 1994 Chris Wallace (csw@bruce.cs.monash.edu.au)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ **************************************************************************/
+
+#include <sys/types.h>
+
+/*
+ * modified by dxm@sgi.com so that this file acts as a drop in replacement
+ * for srandom and random.
+ */
+
+/*
+ * A random number generator called as a function by
+ * random (iseed) or irandm (iseed)
+ * The parameter should be a pointer to a 2-element int32_t vector.
+ * The first function returns a double uniform in 0 .. 1.
+ * The second returns a int32_t integer uniform in 0 .. 2**31-1
+ * Both update iseed[] in exactly the same way.
+ * iseed[] must be a 2-element integer vector.
+ * The initial value of the second element may be anything.
+ *
+ * The period of the random sequence is 2**32 * (2**32-1)
+ * The table mt[0:127] is defined by mt[i] = 69069 ** (128-i)
+ */
+
+#define MASK ((int32_t) 593970775)
+/* or in hex, 23674657 */
+
+#define SCALE ((double) 1.0 / (1024.0 * 1024.0 * 1024.0 * 2.0))
+/* i.e. 2 to power -31 */
+
+static int32_t mt [128] = {
+ 902906369,
+ 2030498053,
+ -473499623,
+ 1640834941,
+ 723406961,
+ 1993558325,
+ -257162999,
+ -1627724755,
+ 913952737,
+ 278845029,
+ 1327502073,
+ -1261253155,
+ 981676113,
+ -1785280363,
+ 1700077033,
+ 366908557,
+ -1514479167,
+ -682799163,
+ 141955545,
+ -830150595,
+ 317871153,
+ 1542036469,
+ -946413879,
+ -1950779155,
+ 985397153,
+ 626515237,
+ 530871481,
+ 783087261,
+ -1512358895,
+ 1031357269,
+ -2007710807,
+ -1652747955,
+ -1867214463,
+ 928251525,
+ 1243003801,
+ -2132510467,
+ 1874683889,
+ -717013323,
+ 218254473,
+ -1628774995,
+ -2064896159,
+ 69678053,
+ 281568889,
+ -2104168611,
+ -165128239,
+ 1536495125,
+ -39650967,
+ 546594317,
+ -725987007,
+ 1392966981,
+ 1044706649,
+ 687331773,
+ -2051306575,
+ 1544302965,
+ -758494647,
+ -1243934099,
+ -75073759,
+ 293132965,
+ -1935153095,
+ 118929437,
+ 807830417,
+ -1416222507,
+ -1550074071,
+ -84903219,
+ 1355292929,
+ -380482555,
+ -1818444007,
+ -204797315,
+ 170442609,
+ -1636797387,
+ 868931593,
+ -623503571,
+ 1711722209,
+ 381210981,
+ -161547783,
+ -272740131,
+ -1450066095,
+ 2116588437,
+ 1100682473,
+ 358442893,
+ -1529216831,
+ 2116152005,
+ -776333095,
+ 1265240893,
+ -482278607,
+ 1067190005,
+ 333444553,
+ 86502381,
+ 753481377,
+ 39000101,
+ 1779014585,
+ 219658653,
+ -920253679,
+ 2029538901,
+ 1207761577,
+ -1515772851,
+ -236195711,
+ 442620293,
+ 423166617,
+ -1763648515,
+ -398436623,
+ -1749358155,
+ -538598519,
+ -652439379,
+ 430550625,
+ -1481396507,
+ 2093206905,
+ -1934691747,
+ -962631983,
+ 1454463253,
+ -1877118871,
+ -291917555,
+ -1711673279,
+ 201201733,
+ -474645415,
+ -96764739,
+ -1587365199,
+ 1945705589,
+ 1303896393,
+ 1744831853,
+ 381957665,
+ 2135332261,
+ -55996615,
+ -1190135011,
+ 1790562961,
+ -1493191723,
+ 475559465,
+ 69069
+ };
+
+double
+_random (int32_t is [2])
+{
+ int32_t it, leh, nit;
+
+ it = is [0];
+ leh = is [1];
+ if (it <= 0)
+ it = (it + it) ^ MASK;
+ else
+ it = it + it;
+ nit = it - 1;
+/* to ensure all-ones pattern omitted */
+ leh = leh * mt[nit & 127] + nit;
+ is [0] = it; is [1] = leh;
+ if (leh < 0) leh = ~leh;
+ return (SCALE * ((int32_t) (leh | 1)));
+}
+
+
+
+int32_t
+_irandm (int32_t is [2])
+{
+ int32_t it, leh, nit;
+
+ it = is [0];
+ leh = is [1];
+ if (it <= 0)
+ it = (it + it) ^ MASK;
+ else
+ it = it + it;
+ nit = it - 1;
+/* to ensure all-ones pattern omitted */
+ leh = leh * mt[nit & 127] + nit;
+ is [0] = it; is [1] = leh;
+ if (leh < 0) leh = ~leh;
+ return (leh);
+}
+
+/*
+ * make this a drop in replacement for random and srandom
+ *
+ * XXX not thread safe I guess.
+ */
+
+static int32_t saved_seed[2];
+
+long random(void)
+{
+ return _irandm(saved_seed);
+}
+
+void srandom(unsigned seed)
+{
+ saved_seed[0]=seed;
+ saved_seed[1]=0;
+ _irandm(saved_seed);
+}
+
--- /dev/null
+/*
+ * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like. Any license provided herein, whether implied or
+ * otherwise, applies only to this software file. Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+ * Mountain View, CA 94043, or:
+ *
+ * http://www.sgi.com
+ *
+ * For further information regarding this notice, see:
+ *
+ * http://oss.sgi.com/projects/GenInfo/NoticeExplan/
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <malloc.h>
+#include "random_range.h"
+
+/*
+ * Internal format of the range array set up by parse_range()
+ */
+
+struct range {
+ int min;
+ int max;
+ int mult;
+};
+
+/*
+ * parse_ranges() is a function to parse a comma-separated list of range
+ * tokens each having the following form:
+ *
+ * num
+ * or
+ * min:max[:mult]
+ *
+ * any of the values may be blank (ie. min::mult, :max, etc.) and default
+ * values for missing arguments may be supplied by the caller.
+ *
+ * The special first form is short hand for 'num:num'.
+ *
+ * After parsing the string, the ranges are put into an array of integers,
+ * which is malloc'd by the routine. The min, max, and mult entries of each
+ * range can be extracted from the array using the range_min(), range_max(),
+ * and range_mult() functions.
+ *
+ * It is the responsibility of the caller to free the space allocated by
+ * parse_ranges() - a single call to free() will free the space.
+ *
+ * str The string to parse - assumed to be a comma-separated
+ * list of tokens having the above format.
+ * defmin default value to plug in for min, if it is missing
+ * defmax default value to plug in for max, if it is missing
+ * defmult default value to plug in for mult, if missing
+ * parse_func A user-supplied function pointer, which parse_ranges()
+ * can call to parse the min, max, and mult strings. This
+ * allows for customized number formats. The function
+ * MUST have the following prototype:
+ * parse_func(char *str, int *val)
+ * The function should return -1 if str cannot be parsed
+ * into an integer, or >= 0 if it was successfully
+ * parsed. The resulting integer will be stored in
+ * *val. If parse_func is NULL, parse_ranges will parse
+ * the tokens in a manner consistent with the the sscanf
+ * %i format.
+ * range_ptr A user-supplied char **, which will be set to point
+ * at malloc'd space which holds the parsed range
+ * values. If range_ptr is NULL, parse_ranges() just
+ * parses the string. The data returned in range_ptr
+ * should not be processed directly - use the functions
+ * range_min(), range_max(), and range_mult() to access
+ * data for a given range.
+ * errptr user-supplied char ** which can be set to point to a
+ * static error string. If errptr is NULL, it is ignored.
+ *
+ * parse_range() returns -1 on error, or the number of ranges parsed.
+ */
+
+static int str_to_int();
+static long long divider(long long, long long, long long, long long);
+
+int
+parse_ranges(str, defmin, defmax, defmult, parse_func, rangeptr, errptr)
+char *str;
+int defmin;
+int defmax;
+int defmult;
+int (*parse_func)();
+char **rangeptr;
+char **errptr;
+{
+ int ncommas;
+ char *tmpstr, *cp, *tok, *n1str, *n2str, *multstr;
+ struct range *rp, *ranges;
+ static char errmsg[256];
+
+ if (errptr != NULL) {
+ *errptr = errmsg;
+ }
+
+ for (ncommas = 0, cp = str; *cp != '\0'; cp++) {
+ if (*cp == ',') {
+ ncommas++;
+ }
+ }
+
+ if (parse_func == NULL) {
+ parse_func = str_to_int;
+ }
+
+ tmpstr = strdup(str);
+ ranges = (struct range *)malloc((ncommas+1) * sizeof(struct range));
+ rp = ranges;
+
+ tok = strtok(tmpstr, ",");
+ while (tok != NULL) {
+ n1str = tok;
+ n2str = NULL;
+ multstr = NULL;
+
+ rp->min = defmin;
+ rp->max = defmax;
+ rp->mult = defmult;
+
+ if ((cp = strchr(n1str, ':')) != NULL) {
+ *cp = '\0';
+ n2str = cp+1;
+
+ if ((cp = strchr(n2str, ':')) != NULL) {
+ *cp = '\0';
+ multstr = cp+1;
+ }
+ }
+
+ /*
+ * Parse the 'min' field - if it is zero length (:n2[:mult]
+ * format), retain the default value, otherwise, pass the
+ * string to the parse function.
+ */
+
+ if ((int)strlen(n1str) > 0) {
+ if ((*parse_func)(n1str, &rp->min) < 0) {
+ sprintf(errmsg, "error parsing string %s into an integer", n1str);
+ free(tmpstr);
+ free(ranges);
+ return -1;
+ }
+ }
+
+ /*
+ * Process the 'max' field - if one was not present (n1 format)
+ * set max equal to min. If the field was present, but
+ * zero length (n1: format), retain the default. Otherwise
+ * pass the string to the parse function.
+ */
+
+ if (n2str == NULL) {
+ rp->max = rp->min;
+ } else if ((int)strlen(n2str) > 0) {
+ if ((*parse_func)(n2str, &rp->max) < 0) {
+ sprintf(errmsg, "error parsing string %s into an integer", n2str);
+ free(tmpstr);
+ free(ranges);
+ return -1;
+ }
+ }
+
+ /*
+ * Process the 'mult' field - if one was not present
+ * (n1:n2 format), or the field was zero length (n1:n2: format)
+ * then set the mult field to defmult - otherwise pass then
+ * mult field to the parse function.
+ */
+
+ if (multstr != NULL && (int)strlen(multstr) > 0) {
+ if ((*parse_func)(multstr, &rp->mult) < 0) {
+ sprintf(errmsg, "error parsing string %s into an integer", multstr);
+ free(tmpstr);
+ free(ranges);
+ return -1;
+ }
+ }
+
+ rp++;
+ tok = strtok(NULL, ",");
+ }
+
+ free(tmpstr);
+
+ if (rangeptr != NULL) {
+ *rangeptr = (char *)ranges;
+ } else {
+ free(ranges); /* just running in parse mode */
+ }
+
+ return (rp - ranges);
+}
+
+/*
+ * The default integer-parsing function
+ */
+
+static int
+str_to_int(str, ip)
+char *str;
+int *ip;
+{
+ char c;
+
+ if (sscanf(str, "%i%c", ip, &c) != 1) {
+ return -1;
+ } else {
+ return 0;
+ }
+}
+
+/*
+ * Three simple functions to return the min, max, and mult values for a given
+ * range. It is assumed that rbuf is a range buffer set up by parse_ranges(),
+ * and that r is a valid range within that buffer.
+ */
+
+int
+range_min(rbuf, r)
+char *rbuf;
+int r;
+{
+ return ((struct range *)rbuf)[r].min;
+}
+
+int
+range_max(rbuf, r)
+char *rbuf;
+int r;
+{
+ return ((struct range *)rbuf)[r].max;
+}
+
+int
+range_mult(rbuf, r)
+char *rbuf;
+int r;
+{
+ return ((struct range *)rbuf)[r].mult;
+}
+
+/*****************************************************************************
+ * random_range(int start, int end, int mult, char **errp)
+ *
+ * Returns a psuedo-random number which is >= 'start', <= 'end', and a multiple
+ * of 'mult'. Start and end may be any valid integer, but mult must be an
+ * integer > 0. errp is a char ** which will be set to point to a static
+ * error message buffer if it is not NULL, and an error occurs.
+ *
+ * The errp is the only way to check if the routine fails - currently the only
+ * failure conditions are:
+ *
+ * mult < 1
+ * no numbers in the start-end range that are a multiple of 'mult'
+ *
+ * If random_range_fails, and errp is a valid pointer, it will point to an
+ * internal error buffer. If errp is a vaild pointer, and random_range
+ * is successful, errp will be set to NULL.
+ *
+ * Note - if mult is 1 (the most common case), there are error conditions
+ * possible, and errp need not be used.
+ *
+ * Note: Uses lrand48(), assuming that set_random_seed() uses srand48() when
+ * setting the seed.
+ *****************************************************************************/
+
+long
+random_range(min, max, mult, errp)
+int min;
+int max;
+int mult;
+char **errp;
+{
+ int r, nmults, orig_min, orig_max, orig_mult, tmp;
+ extern long lrand48();
+ static char errbuf[128];
+
+ /*
+ * Sanity check
+ */
+
+ if (mult < 1) {
+ if (errp != NULL) {
+ sprintf(errbuf, "mult arg must be greater than 0");
+ *errp = errbuf;
+ }
+ return -1;
+ }
+
+ /*
+ * Save original parameter values for use in error message
+ */
+
+ orig_min = min;
+ orig_max = max;
+ orig_mult = mult;
+
+ /*
+ * switch min/max if max < min
+ */
+
+ if (max < min) {
+ tmp = max;
+ max = min;
+ min = tmp;
+ }
+
+ /*
+ * select the random number
+ */
+
+ if ((r = min % mult)) /* bump to the next higher 'mult' multiple */
+ min += mult - r;
+
+ if ((r = max % mult)) /* reduce to the next lower 'mult' multiple */
+ max -= r;
+
+ if (min > max) { /* no 'mult' multiples between min & max */
+ if (errp != NULL) {
+ sprintf(errbuf, "no numbers in the range %d:%d that are a multiple of %d", orig_min, orig_max, orig_mult);
+ *errp = errbuf;
+ }
+ return -1;
+ }
+
+ if (errp != NULL) {
+ *errp = NULL;
+ }
+
+ nmults = ((max - min) / mult) + 1;
+#if CRAY
+ /*
+ * If max is less than 2gb, then the value can fit in 32 bits
+ * and the standard lrand48() routine can be used.
+ */
+ if ( max <= (long)2147483647 ) {
+ return (long) (min + (((long)lrand48() % nmults) * mult));
+ } else {
+ /*
+ * max is greater than 2gb - meeds more than 32 bits.
+ * Since lrand48 only will get a number up to 32bits.
+ */
+ long randnum;
+ randnum=divider(min, max, 0, -1);
+ return (long) (min + ((randnum % nmults) * mult));
+ }
+
+#else
+ return (min + ((lrand48() % nmults) * mult));
+#endif
+
+}
+
+/*
+ * Just like random_range, but all values are longs.
+ */
+long
+random_rangel(min, max, mult, errp)
+long min;
+long max;
+long mult;
+char **errp;
+{
+ long r, nmults, orig_min, orig_max, orig_mult, tmp;
+ extern long lrand48();
+ static char errbuf[128];
+
+ /*
+ * Sanity check
+ */
+
+ if (mult < 1) {
+ if (errp != NULL) {
+ sprintf(errbuf, "mult arg must be greater than 0");
+ *errp = errbuf;
+ }
+ return -1;
+ }
+
+ /*
+ * Save original parameter values for use in error message
+ */
+
+ orig_min = min;
+ orig_max = max;
+ orig_mult = mult;
+
+ /*
+ * switch min/max if max < min
+ */
+
+ if (max < min) {
+ tmp = max;
+ max = min;
+ min = tmp;
+ }
+
+ /*
+ * select the random number
+ */
+
+ if ((r = min % mult)) /* bump to the next higher 'mult' multiple */
+ min += mult - r;
+
+ if ((r = max % mult)) /* reduce to the next lower 'mult' multiple */
+ max -= r;
+
+ if (min > max) { /* no 'mult' multiples between min & max */
+ if (errp != NULL) {
+ sprintf(errbuf,
+ "no numbers in the range %ld:%ld that are a multiple of %ld",
+ orig_min, orig_max, orig_mult);
+ *errp = errbuf;
+ }
+ return -1;
+ }
+
+ if (errp != NULL) {
+ *errp = NULL;
+ }
+
+ nmults = ((max - min) / mult) + 1;
+#if CRAY || (_MIPS_SZLONG == 64)
+ /*
+ * If max is less than 2gb, then the value can fit in 32 bits
+ * and the standard lrand48() routine can be used.
+ */
+ if ( max <= (long)2147483647 ) {
+ return (long) (min + (((long)lrand48() % nmults) * mult));
+ } else {
+ /*
+ * max is greater than 2gb - meeds more than 32 bits.
+ * Since lrand48 only will get a number up to 32bits.
+ */
+ long randnum;
+ randnum=divider(min, max, 0, -1);
+ return (long) (min + ((randnum % nmults) * mult));
+ }
+
+#else
+ return (min + ((lrand48() % nmults) * mult));
+#endif
+}
+
+/*
+ * Attempts to be just like random_range, but everything is long long (64 bit)
+ */
+long long
+random_rangell(min, max, mult, errp)
+long long min;
+long long max;
+long long mult;
+char **errp;
+{
+ long long r, nmults, orig_min, orig_max, orig_mult, tmp;
+ long long randnum;
+ extern long lrand48();
+ static char errbuf[128];
+
+ /*
+ * Sanity check
+ */
+
+ if (mult < 1) {
+ if (errp != NULL) {
+ sprintf(errbuf, "mult arg must be greater than 0");
+ *errp = errbuf;
+ }
+ return -1;
+ }
+
+ /*
+ * Save original parameter values for use in error message
+ */
+
+ orig_min = min;
+ orig_max = max;
+ orig_mult = mult;
+
+ /*
+ * switch min/max if max < min
+ */
+
+ if (max < min) {
+ tmp = max;
+ max = min;
+ min = tmp;
+ }
+
+ /*
+ * select the random number
+ */
+
+ if ((r = min % mult)) /* bump to the next higher 'mult' multiple */
+ min += mult - r;
+
+ if ((r = max % mult)) /* reduce to the next lower 'mult' multiple */
+ max -= r;
+
+ if (min > max) { /* no 'mult' multiples between min & max */
+ if (errp != NULL) {
+ sprintf(errbuf,
+ "no numbers in the range %lld:%lld that are a multiple of %lld",
+ orig_min, orig_max, orig_mult);
+ *errp = errbuf;
+ }
+ return -1;
+ }
+
+ if (errp != NULL) {
+ *errp = NULL;
+ }
+
+ nmults = ((max - min) / mult) + 1;
+ /*
+ * If max is less than 2gb, then the value can fit in 32 bits
+ * and the standard lrand48() routine can be used.
+ */
+ if ( max <= (long)2147483647 ) {
+ return (long long) (min + (((long long)lrand48() % nmults) * mult));
+ } else {
+ /*
+ * max is greater than 2gb - meeds more than 32 bits.
+ * Since lrand48 only will get a number up to 32bits.
+ */
+ randnum=divider(min, max, 0, -1);
+ return (long long) (min + ((randnum % nmults) * mult));
+ }
+
+}
+
+/*
+ * This functional will recusively call itself to return a random
+ * number min and max. It was designed to work the 64bit numbers
+ * even when compiled as 32 bit process.
+ * algorithm: to use the official lrand48() routine - limited to 32 bits.
+ * find the difference between min and max (max-min).
+ * if the difference is 2g or less, use the random number gotton from lrand48().
+ * Determine the midway point between min and max.
+ * if the midway point is less than 2g from min or max,
+ * randomly add the random number gotton from lrand48() to
+ * either min or the midpoint.
+ * Otherwise, call outself with min and max being min and midway value or
+ * midway value and max. This will reduce the range in half.
+ */
+static long long
+divider(long long min, long long max, long long cnt, long long rand)
+{
+ long long med, half, diff;
+
+ /*
+ * prevent run away code. We are dividing by two each count.
+ * if we get to a count of more than 32, we should have gotten
+ * to 2gb.
+ */
+ if ( cnt > 32 )
+ return -1;
+
+ /*
+ * Only get a random number the first time.
+ */
+ if ( cnt == 0 || rand < -1 ) {
+ rand = (long long)lrand48(); /* 32 bit random number */
+ }
+
+ diff = max - min;
+
+ if ( diff <= 2147483647 )
+ return min + rand;
+
+ half = diff/(long long)2; /* half the distance between min and max */
+ med = min + half; /* med way point between min and max */
+
+#if DEBUG
+printf("divider: min=%lld, max=%lld, cnt=%lld, rand=%lld\n", min, max, cnt, rand);
+printf(" diff = %lld, half = %lld, med = %lld\n", diff, half, med);
+#endif
+
+ if ( half <= 2147483647 ) {
+ /*
+ * If half is smaller than 2gb, we can use the random number
+ * to pick the number within the min to med or med to max
+ * if the cnt bit of rand is zero or one, respectively.
+ */
+ if ( rand & (1<<cnt) )
+ return med + rand;
+ else
+ return min + rand;
+ } else {
+ /*
+ * recursively call ourself to reduce the value to the bottom half
+ * or top half (bit cnt is set).
+ */
+ if ( rand & (1<<cnt) ) {
+ return divider(med, max, cnt+1, rand);
+ } else {
+ return divider(min, med, cnt+1, rand);
+ }
+
+ }
+
+}
+
+
+/*****************************************************************************
+ * random_range_seed(s)
+ *
+ * Sets the random seed to s. Uses srand48(), assuming that lrand48() will
+ * be used in random_range().
+ *****************************************************************************/
+
+void
+random_range_seed(s)
+long s;
+{
+ extern void srand48();
+
+ srand48(s);
+}
+
+/****************************************************************************
+ * random_bit(mask)
+ *
+ * This function randomly returns a single bit from the bits
+ * set in mask. If mask is zero, zero is returned.
+ *
+ ****************************************************************************/
+long
+random_bit(long mask)
+{
+ int nbits = 0; /* number of set bits in mask */
+ long bit; /* used to count bits and num of set bits choosen */
+ int nshift; /* used to count bit shifts */
+
+ if ( mask == 0 )
+ return 0;
+
+ /*
+ * get the number of bits set in mask
+ */
+#ifndef CRAY
+
+ bit=1L;
+ for ( nshift=0; nshift<sizeof(long)*8; nshift++) {
+ if ( mask & bit )
+ nbits++;
+ bit=bit<<1;
+ }
+
+#else
+ nbits=_popcnt(mask);
+#endif /* if CRAY */
+
+ /*
+ * randomly choose a bit.
+ */
+ bit=random_range(1, nbits, 1, NULL);
+
+ /*
+ * shift bits until you determine which bit was randomly choosen.
+ * nshift will hold the number of shifts to make.
+ */
+
+ nshift=0;
+ while (bit) {
+ /* check if the current one's bit is set */
+ if ( mask & 1L ) {
+ bit--;
+ }
+ mask = mask >> 1;
+ nshift++;
+ }
+
+ return 01L << (nshift-1);
+
+}
+
+
+#if RANDOM_BIT_UNITTEST
+/*
+ * The following is a unit test main function for random_bit().
+ */
+main(argc, argv)
+int argc;
+char **argv;
+{
+ int ind;
+ int cnt, iter;
+ long mask, ret;
+
+ printf("test for first and last bit set\n");
+ mask=1L;
+ ret=random_bit(mask);
+ printf("random_bit(%#o) returned %#o\n", mask, ret);
+
+ mask=1L<<(sizeof(long)*8-1);
+ ret=random_bit(mask);
+ printf("random_bit(%#o) returned %#o\n", mask, ret);
+
+ if ( argc >= 3 ) {
+ iter=atoi(argv[1]);
+ for (ind=2; ind<argc; ind++) {
+ printf("Calling random_bit %d times for mask %#o\n", iter, mask);
+ sscanf(argv[ind], "%i", &mask);
+ for (cnt=0; cnt<iter; cnt++) {
+ ret=random_bit(mask);
+ printf("random_bit(%#o) returned %#o\n", mask, ret);
+ }
+ }
+ }
+ exit(0);
+}
+
+#endif /* end if RANDOM_BIT_UNITTEST */
+
+
+#if UNIT_TEST
+/*
+ * The following is a unit test main function for random_range*().
+ */
+
+#define PARTNUM 10 /* used to determine even distribution of random numbers */
+#define MEG 1024*1024*1024
+#define GIG 1073741824
+int
+main(argc, argv)
+int argc;
+char **argv;
+{
+ int ind;
+ int cnt, iter=10;
+ int imin=0, imult=1, itmin, itmax=0;
+#if CRAY
+ int imax=6*GIG; /* higher than 32 bits */
+#else
+ int imax=1048576;
+#endif
+
+ long lret, lmin=0, lmult=1, ltmin, ltmax=0;
+#if CRAY || (_MIPS_SZLONG == 64)
+ long lmax=6*(long)GIG; /* higher than 32 bits */
+#else
+ long lmax=1048576;
+#endif
+ long long llret, llmin=0, llmult=1, lltmin, lltmax=0;
+ long long llmax=(long long)80*(long long)GIG;
+
+ long part;
+ long long lpart;
+ long cntarr[PARTNUM];
+ long valbound[PARTNUM];
+ long long lvalbound[PARTNUM];
+
+ for (ind=0; ind<PARTNUM; ind++ )
+ cntarr[ind]=0;
+
+ if ( argc < 2 ) {
+ printf("Usage: %s func [iterations] \n", argv[0]);
+ printf("func can be random_range, random_rangel, random_rangell\n");
+ exit(1);
+ }
+
+ if ( argc >= 3 ) {
+ if ( sscanf(argv[2], "%i", &iter) != 1 ) {
+ printf("Usage: %s [func iterations] \n", argv[0]);
+ printf("argv[2] is not a number\n");
+ exit(1);
+ }
+ }
+
+
+ /*
+ * random_rangel ()
+ */
+ if ( strcmp(argv[1], "random_rangel") == 0 ) {
+ ltmin=lmax;
+ part = lmax/PARTNUM;
+ for(ind=0; ind<PARTNUM; ind++) {
+ valbound[ind]=part*ind;
+ }
+
+ for(cnt=0; cnt<iter; cnt++) {
+ lret=random_rangel(lmin, lmax, lmult, NULL);
+ if ( iter < 100 )
+ printf("%ld\n", lret);
+ if ( lret < ltmin )
+ ltmin = lret;
+ if ( lret > ltmax )
+ ltmax = lret;
+ for(ind=0; ind<PARTNUM-1; ind++) {
+ if ( valbound[ind] < lret && lret <= valbound[ind+1] ) {
+ cntarr[ind]++;
+ break;
+ }
+ }
+ if ( lret > valbound[PARTNUM-1] ) {
+ cntarr[PARTNUM-1]++;
+ }
+ }
+ for(ind=0; ind<PARTNUM-1; ind++) {
+ printf("%2d %-13ld to %-13ld %5ld %4.4f\n", ind+1,
+ valbound[ind], valbound[ind+1], cntarr[ind],
+ (float)(cntarr[ind]/(float)iter));
+ }
+ printf("%2d %-13ld to %-13ld %5ld %4.4f\n", PARTNUM,
+ valbound[PARTNUM-1], lmax, cntarr[PARTNUM-1],
+ (float)(cntarr[PARTNUM-1]/(float)iter));
+ printf(" min=%ld, max=%ld\n", ltmin, ltmax);
+
+ } else if ( strcmp(argv[1], "random_rangell") == 0 ) {
+ /*
+ * random_rangell() unit test
+ */
+ lltmin=llmax;
+ lpart = llmax/PARTNUM;
+ for(ind=0; ind<PARTNUM; ind++) {
+ lvalbound[ind]=(long long)(lpart*ind);
+ }
+
+ for(cnt=0; cnt<iter; cnt++) {
+ llret=random_rangell(llmin, llmax, llmult, NULL);
+ if ( iter < 100 )
+ printf("random_rangell returned %lld\n", llret);
+ if ( llret < lltmin )
+ lltmin = llret;
+ if ( llret > lltmax )
+ lltmax = llret;
+
+ for(ind=0; ind<PARTNUM-1; ind++) {
+ if ( lvalbound[ind] < llret && llret <= lvalbound[ind+1] ) {
+ cntarr[ind]++;
+ break;
+ }
+ }
+ if ( llret > lvalbound[PARTNUM-1] ) {
+ cntarr[PARTNUM-1]++;
+ }
+ }
+ for(ind=0; ind<PARTNUM-1; ind++) {
+ printf("%2d %-13lld to %-13lld %5ld %4.4f\n", ind+1,
+ lvalbound[ind], lvalbound[ind+1], cntarr[ind],
+ (float)(cntarr[ind]/(float)iter));
+ }
+ printf("%2d %-13lld to %-13lld %5ld %4.4f\n", PARTNUM,
+ lvalbound[PARTNUM-1], llmax, cntarr[PARTNUM-1],
+ (float)(cntarr[PARTNUM-1]/(float)iter));
+ printf(" min=%lld, max=%lld\n", lltmin, lltmax);
+
+ } else {
+ /*
+ * random_range() unit test
+ */
+ itmin=imax;
+ part = imax/PARTNUM;
+ for(ind=0; ind<PARTNUM; ind++) {
+ valbound[ind]=part*ind;
+ }
+
+ for(cnt=0; cnt<iter; cnt++) {
+ lret=random_range(imin, imax, imult, NULL);
+ if ( iter < 100 )
+ printf("%ld\n", lret);
+ if ( lret < itmin )
+ itmin = lret;
+ if ( lret > itmax )
+ itmax = lret;
+
+ for(ind=0; ind<PARTNUM-1; ind++) {
+ if ( valbound[ind] < lret && lret <= valbound[ind+1] ) {
+ cntarr[ind]++;
+ break;
+ }
+ }
+ if ( lret > valbound[PARTNUM-1] ) {
+ cntarr[PARTNUM-1]++;
+ }
+ }
+ for(ind=0; ind<PARTNUM-1; ind++) {
+ printf("%2d %-13ld to %-13ld %5ld %4.4f\n", ind+1,
+ valbound[ind], valbound[ind+1], cntarr[ind],
+ (float)(cntarr[ind]/(float)iter));
+ }
+ printf("%2d %-13ld to %-13ld %5ld %4.4f\n", PARTNUM,
+ valbound[PARTNUM-1], (long)imax, cntarr[PARTNUM-1],
+ (float)(cntarr[PARTNUM-1]/(float)iter));
+ printf(" min=%d, max=%d\n", itmin, itmax);
+
+ }
+
+ exit(0);
+}
+
+#endif
--- /dev/null
+/*
+ * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like. Any license provided herein, whether implied or
+ * otherwise, applies only to this software file. Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+ * Mountain View, CA 94043, or:
+ *
+ * http://www.sgi.com
+ *
+ * For further information regarding this notice, see:
+ *
+ * http://oss.sgi.com/projects/GenInfo/NoticeExplan/
+ */
+#include <stdio.h>
+#include <sys/param.h>
+#include "str_to_bytes.h"
+
+/****************************************************************************
+ * str_to_bytes(s)
+ *
+ * Computes the number of bytes described by string s. s is assumed to be
+ * a base 10 positive (ie. >= 0) number followed by an optional single
+ * character multiplier. The following multipliers are supported:
+ *
+ * char mult
+ * -----------------
+ * b BSIZE or BBSIZE
+ * k 1024 bytes
+ * K 1024 * sizeof(long)
+ * m 2^20 (1048576)
+ * M 2^20 (1048576 * sizeof(long)
+ * g 2^30 (1073741824)
+ * G 2^30 (1073741824) * sizeof(long)
+ *
+ * for instance, "1k" and "1024" would both cause str_to_bytes to return 1024.
+ *
+ * Returns -1 if mult is an invalid character, or if the integer portion of
+ * s is not a positive integer.
+ *
+ ****************************************************************************/
+
+#if CRAY
+#define B_MULT BSIZE /* block size */
+#elif sgi
+#define B_MULT BBSIZE /* block size */
+#elif linux
+#define B_MULT DEV_BSIZE /* block size */
+#endif
+
+
+#define K_MULT 1024 /* Kilo or 2^10 */
+#define M_MULT 1048576 /* Mega or 2^20 */
+#define G_MULT 1073741824 /* Giga or 2^30 */
+#define T_MULT 1099511627776 /* tera or 2^40 */
+
+int
+str_to_bytes(s)
+char *s;
+{
+ char mult, junk;
+ int nconv;
+ float num;
+
+ nconv = sscanf(s, "%f%c%c", &num, &mult, &junk);
+ if (nconv == 0 || nconv == 3 )
+ return -1;
+
+ if (nconv == 1)
+ return num;
+
+ switch (mult) {
+ case 'b':
+ return (int)(num * (float)B_MULT);
+ case 'k':
+ return (int)(num * (float)K_MULT);
+ case 'K':
+ return (int)((num * (float)K_MULT) * sizeof(long));
+ case 'm':
+ return (int)(num * (float)M_MULT);
+ case 'M':
+ return (int)((num * (float)M_MULT) * sizeof(long));
+ case 'g':
+ return (int)(num * (float)G_MULT);
+ case 'G':
+ return (int)((num * (float)G_MULT) * sizeof(long));
+ default:
+ return -1;
+ }
+}
+
+long
+str_to_lbytes(s)
+char *s;
+{
+ char mult, junk;
+ long nconv;
+ float num;
+
+ nconv = sscanf(s, "%f%c%c", &num, &mult, &junk);
+ if (nconv == 0 || nconv == 3 )
+ return -1;
+
+ if (nconv == 1)
+ return (long)num;
+
+ switch (mult) {
+ case 'b':
+ return (long)(num * (float)B_MULT);
+ case 'k':
+ return (long)(num * (float)K_MULT);
+ case 'K':
+ return (long)((num * (float)K_MULT) * sizeof(long));
+ case 'm':
+ return (long)(num * (float)M_MULT);
+ case 'M':
+ return (long)((num * (float)M_MULT) * sizeof(long));
+ case 'g':
+ return (long)(num * (float)G_MULT);
+ case 'G':
+ return (long)((num * (float)G_MULT) * sizeof(long));
+ default:
+ return -1;
+ }
+}
+
+/*
+ * Force 64 bits number when compiled as 32 IRIX binary.
+ * This allows for a number bigger than 2G.
+ */
+
+long long
+str_to_llbytes(s)
+char *s;
+{
+ char mult, junk;
+ long nconv;
+ double num;
+
+ nconv = sscanf(s, "%lf%c%c", &num, &mult, &junk);
+ if (nconv == 0 || nconv == 3 )
+ return -1;
+
+ if (nconv == 1)
+ return (long long)num;
+
+ switch (mult) {
+ case 'b':
+ return (long long)(num * (float)B_MULT);
+ case 'k':
+ return (long long)(num * (float)K_MULT);
+ case 'K':
+ return (long long)((num * (float)K_MULT) * sizeof(long long));
+ case 'm':
+ return (long long)(num * (float)M_MULT);
+ case 'M':
+ return (long long)((num * (float)M_MULT) * sizeof(long long));
+ case 'g':
+ return (long long)(num * (float)G_MULT);
+ case 'G':
+ return (long long)((num * (float)G_MULT) * sizeof(long long));
+ default:
+ return -1;
+ }
+}
+
+#ifdef UNIT_TEST
+
+main(int argc, char **argv)
+{
+ int ind;
+
+ if (argc == 1 ) {
+ fprintf(stderr, "missing str_to_bytes() parameteres\n");
+ exit(1);
+ }
+
+ for (ind=1; ind<argc; ind++) {
+
+ printf("str_to_bytes(%s) returned %d\n",
+ argv[ind], str_to_bytes(argv[ind]));
+
+ printf("str_to_lbytes(%s) returned %ld\n",
+ argv[ind], str_to_lbytes(argv[ind]));
+
+ printf("str_to_llbytes(%s) returned %lld\n",
+ argv[ind], str_to_llbytes(argv[ind]));
+ }
+}
+
+#endif
--- /dev/null
+/*
+ * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like. Any license provided herein, whether implied or
+ * otherwise, applies only to this software file. Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+ * Mountain View, CA 94043, or:
+ *
+ * http://www.sgi.com
+ *
+ * For further information regarding this notice, see:
+ *
+ * http://oss.sgi.com/projects/GenInfo/NoticeExplan/
+ */
+/**********************************************************
+ *
+ * OS Testing - Silicon Graphics, Inc.
+ *
+ * FUNCTION NAME : string_to_tokens
+ *
+ * FUNCTION TITLE : Break a string into its tokens
+ *
+ * SYNOPSIS:
+ *
+ * int string_to_tokens(arg_string, arg_array, array_size, separator)
+ * char *arg_string;
+ * char *arg_array[];
+ * int array_size;
+ * char *separator;
+ *
+ * AUTHOR : Richard Logan
+ *
+ * DATE : 10/94
+ *
+ * INITIAL RELEASE : UNICOS 7.0
+ *
+ * DESCRIPTION
+ * This function parses the string 'arg_string', placing pointers to
+ * the 'separator' separated tokens into the elements of 'arg_array'.
+ * The array is terminated with a null pointer.
+ * 'arg_array' must contains at least 'array_size' elements.
+ * Only the first 'array_size' minus one tokens will be placed into
+ * 'arg_array'. If there are more than 'array_size'-1 tokens, the rest are
+ * ignored by this routine.
+ *
+ * RETURN VALUE
+ * This function returns the number of 'separator' separated tokens that
+ * were found in 'arg_string'.
+ * If 'arg_array' or 'separator' is NULL or 'array_size' is less than 2, -1 is returned.
+ *
+ * WARNING
+ * This function uses strtok() to parse 'arg_string', and thus
+ * physically alters 'arg_string' by placing null characters where the
+ * separators originally were.
+ *
+ *
+ *#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#**/
+#include <stdio.h>
+#include <string.h> /* for string functions */
+#include "string_to_tokens.h"
+
+int
+string_to_tokens(char *arg_string, char *arg_array[], int array_size, char *separator)
+{
+ int num_toks = 0; /* number of tokens found */
+ char *strtok();
+
+ if ( arg_array == NULL || array_size <= 1 || separator == NULL )
+ return -1;
+
+ /*
+ * Use strtok() to parse 'arg_string', placing pointers to the
+ * individual tokens into the elements of 'arg_array'.
+ */
+ if ( (arg_array[num_toks] = strtok(arg_string, separator)) == NULL ) {
+ return 0;
+ }
+
+ for (num_toks=1;num_toks<array_size; num_toks++) {
+ if ( (arg_array[num_toks] = strtok(NULL, separator)) == NULL )
+ break;
+ }
+
+ if ( num_toks == array_size )
+ arg_array[num_toks] = NULL;
+
+ /*
+ * Return the number of tokens that were found in 'arg_string'.
+ */
+ return(num_toks);
+
+} /* end of string_to_tokens */
--- /dev/null
+/*
+ * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like. Any license provided herein, whether implied or
+ * otherwise, applies only to this software file. Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+ * Mountain View, CA 94043, or:
+ *
+ * http://www.sgi.com
+ *
+ * For further information regarding this notice, see:
+ *
+ * http://oss.sgi.com/projects/GenInfo/NoticeExplan/
+ */
+/*
+ *
+ * Lib i/o
+ *
+ * This file contains several functions to doing reads and writes.
+ * It was written so that a single function could be called in a test
+ * program and only a io type field value would have to change to
+ * do different types of io. There is even a couple of functions that
+ * will allow you to parse a string to determine the iotype.
+ *
+ * This file contains functions for writing/reading to/from open files
+ * Prototypes:
+ *
+ * Functions declared in this module - see individual function code for
+ * usage comments:
+ *
+ * int stride_bounds(int offset, int stride, int nstrides,
+ * int bytes_per_stride, int *min, int *max);
+
+ * int lio_write_buffer(int fd, int method, char *buffer, int size,
+ * char **errmsg, long wrd);
+ * int lio_read_buffer(int fd, int method, char *buffer, int size,
+ * char **errmsg, long wrd);
+ *
+ * #ifdef CRAY
+ * int lio_wait4asyncio(int method, int fd, struct iosw **statptr)
+ * int lio_check_asyncio(char *io_type, int size, struct iosw *status)
+ * #endif
+ * #ifdef sgi
+ * int lio_wait4asyncio(int method, int fd, aiocb_t *aiocbp)
+ * int lio_check_asyncio(char *io_type, int size, aiocb_t *aiocbp, int method)
+ * #endif
+ *
+ * int lio_parse_io_arg1(char *string)
+ * void lio_help1(char *prefix);
+ *
+ * int lio_parse_io_arg2(char *string, char **badtoken)
+ * void lio_help2(char *prefix);
+ *
+ * int lio_set_debug(int level);
+ *
+ * char Lio_SysCall[];
+ * struct lio_info_type Lio_info1[];
+ * struct lio_info_type Lio_info2[];
+ *
+ * Author : Richard Logan
+ *
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/param.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/file.h>
+#include <signal.h>
+#ifdef CRAY
+#include <sys/secparm.h>
+#include <sys/iosw.h>
+#include <sys/listio.h>
+#else
+/* for linux or sgi */
+#include <sys/uio.h> /* readv(2)/writev(2) */
+#include <string.h> /* bzero */
+#endif
+#ifdef sgi
+#include <aio.h>
+#endif
+#include <stdlib.h> /* atoi, abs */
+
+#include "tlibio.h" /* defines LIO* marcos */
+
+#ifndef PATH_MAX
+#define PATH_MAX MAXPATHLEN
+#endif
+
+#if 0 /* disabled until it's needed -- roehrich 6/11/97 */
+#define BUG1_workaround 1 /* Work around a condition where aio_return gives
+ * a value of zero but there is no errno followup
+ * and the read/write operation actually did its
+ * job. spr/pv 705244
+ */
+#endif
+
+
+#ifndef linux
+static void lio_async_signal_handler();
+#endif
+#ifdef sgi
+static void lio_async_callback_handler();
+#endif
+
+/*
+ * Define the structure as used in lio_parse_arg1 and lio_help1
+ */
+struct lio_info_type Lio_info1[] = {
+ { "s", LIO_IO_SYNC, "sync i/o" },
+ { "p", LIO_IO_ASYNC|LIO_WAIT_SIGACTIVE, "async i/o using a loop to wait for a signal" },
+ { "b", LIO_IO_ASYNC|LIO_WAIT_SIGPAUSE, "async i/o using pause" },
+ { "a", LIO_IO_ASYNC|LIO_WAIT_RECALL, "async i/o using recall/aio_suspend" },
+#ifdef sgi
+ { "r",
+ LIO_RANDOM|LIO_IO_TYPES|LIO_WAIT_TYPES, "random sync i/o types and wait methods" },
+ { "R",
+ LIO_RANDOM|LIO_IO_ATYPES|LIO_WAIT_ATYPES, "random i/o types and wait methods" },
+#else
+ { "r",
+ LIO_RANDOM|LIO_IO_TYPES|LIO_WAIT_TYPES, "random i/o types and wait methods" },
+ { "R",
+ LIO_RANDOM|LIO_IO_TYPES|LIO_WAIT_TYPES, "random i/o types and wait methods" },
+#endif
+ { "l", LIO_IO_SLISTIO|LIO_WAIT_RECALL, "single stride sync listio" },
+ { "L", LIO_IO_ALISTIO|LIO_WAIT_RECALL, "single stride async listio using recall" },
+ { "X", LIO_IO_ALISTIO|LIO_WAIT_SIGPAUSE, "single stride async listio using pause" },
+ { "v", LIO_IO_SYNCV, "single buffer sync readv/writev" },
+ { "P", LIO_IO_SYNCP, "sync pread/pwrite" },
+};
+
+/*
+ * Define the structure used by lio_parse_arg2 and lio_help2
+ */
+struct lio_info_type Lio_info2[] = {
+ { "sync", LIO_IO_SYNC, "sync i/o (read/write)"},
+ { "async", LIO_IO_ASYNC, "async i/o (reada/writea/aio_read/aio_write)" },
+ { "slistio", LIO_IO_SLISTIO, "single stride sync listio" },
+ { "alistio", LIO_IO_ALISTIO, "single stride async listio" },
+ { "syncv", LIO_IO_SYNCV, "single buffer sync readv/writev"},
+ { "syncp", LIO_IO_SYNCP, "pread/pwrite"},
+ { "active", LIO_WAIT_ACTIVE, "spin on status/control values" },
+ { "recall", LIO_WAIT_RECALL, "use recall(2)/aio_suspend(3) to wait for i/o to complete" },
+ { "sigactive", LIO_WAIT_SIGACTIVE, "spin waiting for signal" },
+ { "sigpause", LIO_WAIT_SIGPAUSE, "call pause(2) to wait for signal" },
+/* nowait is a touchy thing, it's an accident that this implementation worked at all. 6/27/97 roehrich */
+/* { "nowait", LIO_WAIT_NONE, "do not wait for async io to complete" },*/
+ { "random", LIO_RANDOM, "set random bit" },
+ { "randomall",
+ LIO_RANDOM|LIO_IO_TYPES|LIO_WAIT_TYPES,
+ "all random i/o types and wait methods (except nowait)" },
+};
+
+char Lio_SysCall[PATH_MAX]; /* string containing last i/o system call */
+
+static volatile int Received_signal = 0; /* number of signals received */
+static volatile int Rec_signal;
+#ifdef sgi
+static volatile int Received_callback = 0; /* number of callbacks received */
+static volatile int Rec_callback;
+#endif
+static char Errormsg[500];
+static int Debug_level = 0;
+
+
+
+/***********************************************************************
+ * stride_bounds()
+ *
+ * Determine the bounds of a strided request, normalized to offset. Returns
+ * the number of bytes needed to satisfy the request, and optionally sets
+ * *min and *max to the mininum and maximum bytes referenced, normalized
+ * around offset.
+ *
+ * Returns -1 on error - the only possible error conditions are illegal values
+ * for nstrides and/or bytes_per_stride - both parameters must be >= 0.
+ *
+ * (maule, 11/16/95)
+ ***********************************************************************/
+
+int
+stride_bounds(offset, stride, nstrides, bytes_per_stride, min, max)
+int offset;
+int stride;
+int nstrides;
+int bytes_per_stride;
+int *min;
+int *max;
+{
+ int nbytes, min_byte, max_byte;
+
+ /*
+ * sanity checks ...
+ */
+
+ if (nstrides < 0 || bytes_per_stride < 0) {
+ return -1;
+ }
+
+ if (stride == 0) {
+ stride = bytes_per_stride;
+ }
+
+ /*
+ * Determine the # of bytes needed to satisfy the request. This
+ * value, along with the offset argument, determines the min and max
+ * bytes referenced.
+ */
+
+
+ nbytes = abs(stride) * (nstrides-1) + bytes_per_stride;
+
+ if (stride < 0) {
+ max_byte = offset + bytes_per_stride - 1;
+ min_byte = max_byte - nbytes + 1;
+ } else {
+ min_byte = offset;
+ max_byte = min_byte + nbytes - 1;
+ }
+
+ if (min != NULL) {
+ *min = min_byte;
+ }
+
+ if (max != NULL) {
+ *max = max_byte;
+ }
+
+ return nbytes;
+}
+
+/***********************************************************************
+ * This function will allow someone to set the debug level.
+ ***********************************************************************/
+int
+lio_set_debug(level)
+{
+ int old;
+
+ old = Debug_level;
+ Debug_level = level;
+ return old;
+}
+
+/***********************************************************************
+ * This function will parse a string and return desired io-method.
+ * Only the first character of the string is used.
+ *
+ * This function does not provide for meaningful option arguments,
+ * but it supports current growfiles/btlk interface.
+ *
+ * (rrl 04/96)
+ ***********************************************************************/
+int
+lio_parse_io_arg1(char *string)
+{
+ int ind;
+ int found=0;
+ int mask=0;
+
+ /*
+ * Determine if token is a valid string.
+ */
+ for(ind=0; ind<sizeof(Lio_info1)/sizeof(struct lio_info_type); ind++) {
+ if ( strcmp(string, Lio_info1[ind].token) == 0 ) {
+ mask |= Lio_info1[ind].bits;
+ found = 1;
+ break;
+ }
+ }
+
+ if ( found == 0 ) {
+ return -1;
+ }
+
+ return mask;
+
+}
+
+/***********************************************************************
+ * This function will print a help message describing the characters
+ * that can be parsed by lio_parse_io_arg1().
+ * They will be printed one per line.
+ * (rrl 04/96)
+ ***********************************************************************/
+void
+lio_help1(char *prefix)
+{
+ int ind;
+
+ for(ind=0; ind<sizeof(Lio_info1)/sizeof(struct lio_info_type); ind++) {
+ printf("%s %s : %s\n", prefix,
+ Lio_info1[ind].token, Lio_info1[ind].desc);
+ }
+
+ return;
+}
+
+/***********************************************************************
+ * This function will parse a string and return the desired io-method.
+ * This function will take a comma separated list of io type and wait
+ * method tokens as defined in Lio_info2[]. If a token does not match
+ * any of the tokens in Lio_info2[], it will be coverted to a number.
+ * If it was a number, those bits are also set.
+ *
+ * (rrl 04/96)
+ ***********************************************************************/
+int
+lio_parse_io_arg2(char *string, char **badtoken)
+{
+ char *token = string;
+ char *cc = token;
+ char savecc;
+ int found;
+ int mask=0;
+
+ int tmp;
+ int ind;
+ char chr;
+
+ if ( token == NULL )
+ return -1;
+
+ for (;;) {
+ for (; ((*cc != ',') && (*cc != '\0')); cc++);
+ savecc = *cc;
+ *cc = '\0';
+
+ found = 0;
+
+ /*
+ * Determine if token is a valid string or number and if
+ * so, add the bits to the mask.
+ */
+ for(ind=0; ind<sizeof(Lio_info2)/sizeof(struct lio_info_type); ind++) {
+ if ( strcmp(token, Lio_info2[ind].token) == 0 ) {
+ mask |= Lio_info2[ind].bits;
+ found = 1;
+ break;
+ }
+ }
+
+ /*
+ * If token does not match one of the defined tokens, determine
+ * if it is a number, if so, add the bits.
+ */
+ if ( !found ) {
+ if (sscanf(token, "%i%c", &tmp, &chr) == 1 ) {
+ mask |= tmp;
+ found=1;
+ }
+ }
+
+ *cc = savecc;
+
+ if (!found) { /* token is not valid */
+ if ( badtoken != NULL)
+ *badtoken = token;
+ return(-1);
+ }
+
+ if (savecc == '\0')
+ break;
+
+ token = ++cc;
+ }
+
+ return mask;
+}
+
+/***********************************************************************
+ * This function will print a help message describing the tokens
+ * that can be parsed by lio_parse_io_arg2().
+ * It will print them one per line.
+ *
+ * (rrl 04/96)
+ ***********************************************************************/
+void
+lio_help2(char *prefix)
+{
+ int ind;
+
+ for(ind=0; ind<sizeof(Lio_info2)/sizeof(struct lio_info_type); ind++) {
+ printf("%s %s : %s\n", prefix,
+ Lio_info2[ind].token, Lio_info2[ind].desc);
+ }
+ return;
+}
+
+#ifndef linux
+/***********************************************************************
+ * This is an internal signal handler.
+ * If the handler is called, it will increment the Received_signal
+ * global variable.
+ ***********************************************************************/
+static void
+lio_async_signal_handler(int sig)
+{
+ if ( Debug_level )
+ printf("DEBUG %s/%d: received signal %d, a signal caught %d times\n",
+ __FILE__, __LINE__, sig, Received_signal+1);
+
+ Received_signal++;
+
+ return;
+}
+#endif
+
+#ifdef sgi
+/***********************************************************************
+ * This is an internal callback handler.
+ * If the handler is called, it will increment the Received_callback
+ * global variable.
+ ***********************************************************************/
+static void
+lio_async_callback_handler(sigval_t sigval)
+{
+ if ( Debug_level )
+ printf("DEBUG %s/%d: received callback, nbytes=%ld, a callback called %d times\n",
+ __FILE__, __LINE__, sigval.sival_int, Received_callback+1);
+
+ Received_callback++;
+
+ return;
+}
+#endif /* sgi */
+
+/***********************************************************************
+ * lio_random_methods
+ * This function will randomly choose an io type and wait method
+ * from set of io types and wait methods. Since this information
+ * is stored in a bitmask, it randomly chooses an io type from
+ * the io type bits specified and does the same for wait methods.
+ *
+ * Return Value
+ * This function will return a value with all non choosen io type
+ * and wait method bits cleared. The LIO_RANDOM bit is also
+ * cleared. All other bits are left unchanged.
+ *
+ * (rrl 04/96)
+ ***********************************************************************/
+int
+lio_random_methods(long curr_mask)
+{
+ int mask=0;
+ long random_bit();
+
+ /* remove random select, io type, and wait method bits from curr_mask */
+ mask = curr_mask & (~(LIO_IO_TYPES | LIO_WAIT_TYPES | LIO_RANDOM));
+
+ /* randomly select io type from specified io types */
+ mask = mask | random_bit(curr_mask & LIO_IO_TYPES);
+
+ /* randomly select wait methods from specified wait methods */
+ mask = mask | random_bit(curr_mask & LIO_WAIT_TYPES);
+
+ return mask;
+}
+
+/***********************************************************************
+ * Generic write function
+ * This function can be used to do a write using write(2), writea(2),
+ * aio_write(3), writev(2), pwrite(2),
+ * or single stride listio(2)/lio_listio(3).
+ * By setting the desired bits in the method
+ * bitmask, the caller can control the type of write and the wait method
+ * that will be used. If no io type bits are set, write will be used.
+ *
+ * If async io was attempted and no wait method bits are set then the
+ * wait method is: recall(2) for writea(2) and listio(2); aio_suspend(3) for
+ * aio_write(3) and lio_listio(3).
+ *
+ * If multiple wait methods are specified,
+ * only one wait method will be used. The order is predetermined.
+ *
+ * If the call specifies a signal and one of the two signal wait methods,
+ * a signal handler for the signal is set. This will reset an already
+ * set handler for this signal.
+ *
+ * If the LIO_RANDOM method bit is set, this function will randomly
+ * choose a io type and wait method from bits in the method argument.
+ *
+ * If an error is encountered, an error message will be generated
+ * in a internal static buffer. If errmsg is not NULL, it will
+ * be updated to point to the static buffer, allowing the caller
+ * to print the error message.
+ *
+ * Return Value
+ * If a system call fails, -errno is returned.
+ * If LIO_WAIT_NONE bit is set, the return value is the return value
+ * of the system call.
+ * If the io did not fail, the amount of data written is returned.
+ * If the size the system call say was written is different
+ * then what was asked to be written, errmsg is updated for
+ * this error condition. The return value is still the amount
+ * the system call says was written.
+ *
+ * (rrl 04/96)
+ ***********************************************************************/
+int
+lio_write_buffer(fd, method, buffer, size, sig, errmsg, wrd)
+int fd; /* open file descriptor */
+int method; /* contains io type and wait method bitmask */
+char *buffer; /* pointer to buffer */
+int size; /* the size of the io */
+int sig; /* signal to use if async io */
+char **errmsg; /* char pointer that will be updated to point to err message */
+long wrd; /* to allow future features, use zero for now */
+{
+ int ret = 0; /* syscall return or used to get random method */
+ char *io_type; /* Holds string of type of io */
+#ifndef linux
+ int omethod = method;
+ int listio_cmd; /* Holds the listio/lio_listio cmd */
+#endif
+#ifdef CRAY
+ struct listreq request; /* Used when a listio is wanted */
+ struct iosw status, *statptr[1];
+#else
+ /* for linux or sgi */
+ struct iovec iov; /* iovec for writev(2) */
+#endif
+#ifdef sgi
+ aiocb_t aiocbp; /* POSIX aio control block */
+ aiocb_t *aiolist[1]; /* list of aio control blocks for lio_listio */
+ off64_t poffset; /* pwrite(2) offset */
+#endif
+
+ /*
+ * If LIO_RANDOM bit specified, get new method randomly.
+ */
+ if ( method & LIO_RANDOM ) {
+ if( Debug_level > 3 )
+ printf("DEBUG %s/%d: method mask to choose from: %#o\n", __FILE__, __LINE__, method );
+ method = lio_random_methods(method);
+ if ( Debug_level > 2 )
+ printf("DEBUG %s/%d: random chosen method %#o\n", __FILE__, __LINE__, method);
+ }
+
+ if ( errmsg != NULL )
+ *errmsg = Errormsg;
+
+ Rec_signal=Received_signal; /* get the current number of signals received */
+#ifdef sgi
+ Rec_callback=Received_callback; /* get the current number of callbacks received */
+#endif
+
+#ifdef CRAY
+ bzero(&status, sizeof(struct iosw));
+ bzero(&request, sizeof(struct listreq));
+ statptr[0] = &status;
+#else
+ /* for linux or sgi */
+ bzero(&iov, sizeof(struct iovec));
+ iov.iov_base = buffer;
+ iov.iov_len = size;
+#endif
+#ifdef sgi
+ bzero(&aiocbp, sizeof(aiocb_t));
+ aiocbp.aio_fildes = fd;
+ aiocbp.aio_nbytes = size;
+ aiocbp.aio_buf = buffer;
+/* aiocbp.aio_offset = lseek( fd, 0, SEEK_CUR ); -- set below */
+ aiocbp.aio_sigevent.sigev_notify = SIGEV_NONE;
+ aiocbp.aio_sigevent.sigev_signo = 0;
+ aiocbp.aio_sigevent.sigev_func = NULL;
+ aiocbp.aio_sigevent.sigev_value.sival_int = 0;
+ aiolist[0] = &aiocbp;
+
+ if( (ret = lseek( fd, 0, SEEK_CUR )) == -1 ){
+ ret = 0;
+ /* If there is an error and it is not ESPIPE then kick out the error.
+ * If the fd is a fifo then we have to make sure that
+ * lio_random_methods() didn't select pwrite/pread; if it did then
+ * switch to write/read.
+ */
+ if( errno == ESPIPE ){
+ if( method & LIO_IO_SYNCP ){
+ if( omethod & LIO_RANDOM ){
+ method &= ~LIO_IO_SYNCP;
+ method |= LIO_IO_SYNC;
+ if( Debug_level > 2 )
+ printf("DEBUG %s/%d: random chosen method switched to %#o for fifo\n", __FILE__, __LINE__, method );
+ }
+ else if( Debug_level ){
+ printf("DEBUG %s/%d: pwrite will fail when it writes to a fifo\n",
+ __FILE__, __LINE__ );
+ }
+ }
+ /* else: let it ride */
+ }
+ else{
+ sprintf(Errormsg, "%s/%d lseek(fd=%d,0,SEEK_CUR) failed, errno=%d %s",
+ __FILE__, __LINE__, fd, errno, strerror(errno));
+ return -errno;
+ }
+ }
+ poffset = (off64_t)ret;
+ aiocbp.aio_offset = ret;
+
+#endif
+
+ /*
+ * If the LIO_USE_SIGNAL bit is not set, only use the signal
+ * if the LIO_WAIT_SIGPAUSE or the LIO_WAIT_SIGACTIVE bits are bit.
+ * Otherwise there is not necessary a signal handler to trap
+ * the signal.
+ */
+ if ( sig && !(method & LIO_USE_SIGNAL) &&
+ ! (method & LIO_WAIT_SIGTYPES) ){
+
+ sig=0; /* ignore signal parameter */
+ }
+
+#ifdef sgi
+ if ( sig && (method & LIO_WAIT_CBTYPES) )
+ sig=0; /* ignore signal parameter */
+#endif
+
+ /*
+ * only setup signal hander if sig was specified and
+ * a sig wait method was specified.
+ * Doing this will change the handler for this signal. The
+ * old signal handler will not be restored.
+ *** restoring the signal handler could be added ***
+ */
+
+ if ( sig && (method & LIO_WAIT_SIGTYPES) ){
+#ifdef CRAY
+ sigctl(SCTL_REG, sig, lio_async_signal_handler);
+#endif
+#ifdef sgi
+ aiocbp.aio_sigevent.sigev_notify = SIGEV_SIGNAL;
+ aiocbp.aio_sigevent.sigev_signo = sig;
+ sigset(sig, lio_async_signal_handler);
+#endif /* sgi */
+ }
+#ifdef sgi
+ else if( method & LIO_WAIT_CBTYPES ){
+ /* sival_int just has to be something that I can use
+ * to identify the callback, and "size" happens to be handy...
+ */
+ aiocbp.aio_sigevent.sigev_notify = SIGEV_CALLBACK;
+ aiocbp.aio_sigevent.sigev_func = lio_async_callback_handler;
+ aiocbp.aio_sigevent.sigev_value.sival_int = size;
+ }
+#endif
+
+ /*
+ * Determine the system call that will be called and produce
+ * the string of the system call and place it in Lio_SysCall.
+ * Also update the io_type char pointer to give brief description
+ * of system call. Execute the system call and check for
+ * system call failure. If sync i/o, return the number of
+ * bytes written/read.
+ */
+
+ if ( (method & LIO_IO_SYNC) || (method & LIO_IO_TYPES) == 0 ){
+ /*
+ * write(2) is used if LIO_IO_SYNC bit is set or not none
+ * of the LIO_IO_TYPES bits are set (default).
+ */
+
+ sprintf(Lio_SysCall,
+ "write(%d, buf, %d)", fd, size);
+ io_type="write";
+
+ if ( Debug_level ) {
+ printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__, Lio_SysCall);
+ }
+
+ if ((ret = write(fd, buffer, size)) == -1) {
+ sprintf(Errormsg, "%s/%d write(%d, buf, %d) ret:-1, errno=%d %s",
+ __FILE__, __LINE__,
+ fd, size, errno, strerror(errno));
+ return -errno;
+ }
+
+ if ( ret != size ) {
+ sprintf(Errormsg,
+ "%s/%d write(%d, buf, %d) returned=%d",
+ __FILE__, __LINE__,
+ fd, size, ret);
+ }
+ else if ( Debug_level > 1 )
+ printf("DEBUG %s/%d: write completed without error (ret %d)\n",
+ __FILE__, __LINE__, ret);
+
+ return ret;
+
+ }
+
+ else if ( method & LIO_IO_ASYNC ) {
+#ifdef CRAY
+ sprintf(Lio_SysCall,
+ "writea(%d, buf, %d, &status, %d)", fd, size, sig);
+ io_type="writea";
+
+ if ( Debug_level ) {
+ printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__, Lio_SysCall);
+ }
+
+ sigoff();
+ if ((ret = writea(fd, buffer, size, &status, sig)) == -1) {
+ sprintf(Errormsg,
+ "%s/%d writea(%d, buf, %d, &stat, %d) ret:-1, errno=%d %s",
+ __FILE__, __LINE__,
+ fd, size, sig, errno, strerror(errno));
+ sigon();
+ return -errno;
+ }
+#endif
+#ifdef sgi
+ sprintf(Lio_SysCall,
+ "aio_write(fildes=%d, buf, nbytes=%d, signo=%d)", fd, size, sig);
+ io_type="aio_write";
+
+ if ( Debug_level ) {
+ printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__, Lio_SysCall);
+ }
+
+ if( sig )
+ sighold( sig );
+ if ((ret = aio_write(&aiocbp)) == -1) {
+ sprintf(Errormsg,
+ "%s/%d aio_write(fildes=%d, buf, nbytes=%d, signo=%d) ret:-1, errno=%d %s",
+ __FILE__, __LINE__,
+ fd, size, sig, errno, strerror(errno));
+ if( sig )
+ sigrelse( sig );
+ return -errno;
+ }
+#endif
+ } /* LIO_IO_ASYNC */
+
+ else if ( method & LIO_IO_SLISTIO ) {
+#ifdef CRAY
+ request.li_opcode = LO_WRITE;
+ request.li_fildes = fd;
+ request.li_buf = buffer;
+ request.li_nbyte = size;
+ request.li_status = &status;
+ request.li_signo = sig;
+ request.li_nstride = 0;
+ request.li_filstride = 0;
+ request.li_memstride = 0;
+
+ listio_cmd=LC_WAIT;
+ io_type="listio(2) sync write";
+
+ sprintf(Lio_SysCall,
+ "listio(LC_WAIT, &req, 1) LO_WRITE, fd:%d, nbyte:%d",
+ fd, size);
+
+ if ( Debug_level ) {
+ printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__, Lio_SysCall);
+ }
+
+ sigoff();
+ if ( listio(listio_cmd, &request, 1) == -1 ) {
+ sprintf(Errormsg, "%s/%d %s failed, fd:%d, nbyte:%d errno=%d %s",
+ __FILE__, __LINE__,
+ Lio_SysCall, fd, size, errno, strerror(errno));
+ sigon();
+ return -errno;
+ }
+
+ if ( Debug_level > 1 )
+ printf("DEBUG %s/%d: %s did not return -1\n",
+ __FILE__, __LINE__, Lio_SysCall);
+
+ ret=lio_check_asyncio(io_type, size, &status);
+ return ret;
+
+#endif
+#ifdef sgi
+
+ aiocbp.aio_lio_opcode = LIO_WRITE;
+ listio_cmd=LIO_WAIT;
+ io_type="lio_listio(3) sync write";
+
+ sprintf(Lio_SysCall,
+ "lio_listio(LIO_WAIT, aiolist, 1, NULL) LIO_WRITE, fd:%d, nbyte:%d, sig:%d",
+ fd, size, sig );
+
+ if ( Debug_level ) {
+ printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__, Lio_SysCall);
+ }
+
+ if( sig )
+ sighold( sig );
+ if ( lio_listio(listio_cmd, aiolist, 1, NULL) == -1 ) {
+ sprintf(Errormsg, "%s/%d %s failed, fd:%d, nbyte:%d errno=%d %s",
+ __FILE__, __LINE__,
+ Lio_SysCall, fd, size, errno, strerror(errno));
+ if( sig )
+ sigrelse( sig );
+ return -errno;
+ }
+
+ if ( Debug_level > 1 )
+ printf("DEBUG %s/%d: %s did not return -1\n",
+ __FILE__, __LINE__, Lio_SysCall);
+
+ ret=lio_check_asyncio(io_type, size, &aiocbp, method);
+ return ret;
+#endif
+ } /* LIO_IO_SLISTIO */
+
+ else if ( method & LIO_IO_ALISTIO ) {
+#ifdef CRAY
+ request.li_opcode = LO_WRITE;
+ request.li_fildes = fd;
+ request.li_buf = buffer;
+ request.li_nbyte = size;
+ request.li_status = &status;
+ request.li_signo = sig;
+ request.li_nstride = 0;
+ request.li_filstride = 0;
+ request.li_memstride = 0;
+
+ listio_cmd=LC_START;
+ io_type="listio(2) async write";
+
+ sprintf(Lio_SysCall,
+ "listio(LC_START, &req, 1) LO_WRITE, fd:%d, nbyte:%d",
+ fd, size);
+
+ if ( Debug_level ) {
+ printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__, Lio_SysCall);
+ }
+
+ sigoff();
+ if ( listio(listio_cmd, &request, 1) == -1 ) {
+ sprintf(Errormsg, "%s/%d %s failed, fd:%d, nbyte:%d errno=%d %s",
+ __FILE__, __LINE__,
+ Lio_SysCall, fd, size, errno, strerror(errno));
+ sigon();
+ return -errno;
+ }
+#endif
+#ifdef sgi
+ aiocbp.aio_lio_opcode = LIO_WRITE;
+ listio_cmd=LIO_NOWAIT;
+ io_type="lio_listio(3) async write";
+
+ sprintf(Lio_SysCall,
+ "lio_listio(LIO_NOWAIT, aiolist, 1, NULL) LIO_WRITE, fd:%d, nbyte:%d",
+ fd, size);
+
+ if ( Debug_level ) {
+ printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__, Lio_SysCall);
+ }
+
+ if( sig )
+ sighold( sig );
+ if ( lio_listio(listio_cmd, aiolist, 1, NULL) == -1 ) {
+ sprintf(Errormsg, "%s/%d %s failed, fd:%d, nbyte:%d errno=%d %s",
+ __FILE__, __LINE__,
+ Lio_SysCall, fd, size, errno, strerror(errno));
+ if( sig )
+ sigrelse( sig );
+ return -errno;
+ }
+#endif
+ }/* LIO_IO_ALISTIO */
+
+#ifndef CRAY
+ else if ( method & LIO_IO_SYNCV ) {
+ io_type="writev(2)";
+
+ sprintf(Lio_SysCall,
+ "writev(%d, &iov, 1) nbyte:%d", fd, size);
+
+ if ( Debug_level ) {
+ printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__, Lio_SysCall);
+ }
+ if ((ret = writev(fd, &iov, 1)) == -1) {
+ sprintf(Errormsg, "%s/%d writev(%d, iov, 1) nbyte:%d ret:-1, errno=%d %s",
+ __FILE__, __LINE__,
+ fd, size, errno, strerror(errno));
+ return -errno;
+ }
+
+ if ( ret != size ) {
+ sprintf(Errormsg,
+ "%s/%d writev(%d, iov, 1) nbyte:%d returned=%d",
+ __FILE__, __LINE__,
+ fd, size, ret);
+ }
+ else if ( Debug_level > 1 )
+ printf("DEBUG %s/%d: writev completed without error (ret %d)\n",
+ __FILE__, __LINE__, ret);
+
+ return ret;
+ } /* LIO_IO_SYNCV */
+#endif
+
+#ifdef sgi
+ else if ( method & LIO_IO_SYNCP ) {
+ io_type="pwrite(2)";
+
+ sprintf(Lio_SysCall,
+ "pwrite(%d, buf, %d, %lld)", fd, size, poffset);
+
+ if ( Debug_level ) {
+ printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__, Lio_SysCall);
+ }
+ if ((ret = pwrite(fd, buffer, size, poffset)) == -1) {
+ sprintf(Errormsg, "%s/%d pwrite(%d, buf, %d, %lld) ret:-1, errno=%d %s",
+ __FILE__, __LINE__,
+ fd, size, poffset, errno, strerror(errno));
+ return -errno;
+ }
+
+ if ( ret != size ) {
+ sprintf(Errormsg,
+ "%s/%d pwrite(%d, buf, %d, %lld) returned=%d",
+ __FILE__, __LINE__,
+ fd, size, poffset, ret);
+ }
+ else if ( Debug_level > 1 )
+ printf("DEBUG %s/%d: pwrite completed without error (ret %d)\n",
+ __FILE__, __LINE__, ret);
+
+ return ret;
+ } /* LIO_IO_SYNCP */
+#endif
+
+ else {
+ printf("DEBUG %s/%d: No I/O method chosen\n", __FILE__, __LINE__ );
+ return -1;
+ }
+
+ /*
+ * wait for async io to complete.
+ */
+#ifdef CRAY
+ ret=lio_wait4asyncio(method, fd, statptr);
+#endif
+#ifdef sgi
+ ret=lio_wait4asyncio(method, fd, &aiocbp);
+#endif
+
+ /*
+ * If there was an error waiting for async i/o to complete,
+ * return the error value (errno) to the caller.
+ * Note: Errormsg should already have been updated.
+ */
+ if ( ret < 0 ) {
+ return ret;
+ }
+
+ /*
+ * If i/o was not waited for (may not have been completed at this time),
+ * return the size that was requested.
+ */
+ if ( ret == 1 )
+ return size;
+
+ /*
+ * check that async io was successful.
+ * Note: if the there was an system call failure, -errno
+ * was returned and Errormsg should already have been updated.
+ * If amount i/o was different than size, Errormsg should already
+ * have been updated but the actual i/o size if returned.
+ */
+
+#ifdef CRAY
+ ret=lio_check_asyncio(io_type, size, &status);
+#endif
+#ifdef sgi
+ ret=lio_check_asyncio(io_type, size, &aiocbp, method);
+#endif
+
+ return ret;
+} /* end of lio_write_buffer */
+
+/***********************************************************************
+ * Generic read function
+ * This function can be used to do a read using read(2), reada(2),
+ * aio_read(3), readv(2), pread(2),
+ * or single stride listio(2)/lio_listio(3).
+ * By setting the desired bits in the method
+ * bitmask, the caller can control the type of read and the wait method
+ * that will be used. If no io type bits are set, read will be used.
+ *
+ * If async io was attempted and no wait method bits are set then the
+ * wait method is: recall(2) for reada(2) and listio(2); aio_suspend(3) for
+ * aio_read(3) and lio_listio(3).
+ *
+ * If multiple wait methods are specified,
+ * only one wait method will be used. The order is predetermined.
+ *
+ * If the call specifies a signal and one of the two signal wait methods,
+ * a signal handler for the signal is set. This will reset an already
+ * set handler for this signal.
+ *
+ * If the LIO_RANDOM method bit is set, this function will randomly
+ * choose a io type and wait method from bits in the method argument.
+ *
+ * If an error is encountered, an error message will be generated
+ * in a internal static buffer. If errmsg is not NULL, it will
+ * be updated to point to the static buffer, allowing the caller
+ * to print the error message.
+ *
+ * Return Value
+ * If a system call fails, -errno is returned.
+ * If LIO_WAIT_NONE bit is set, the return value is the return value
+ * of the system call.
+ * If the io did not fail, the amount of data written is returned.
+ * If the size the system call say was written is different
+ * then what was asked to be written, errmsg is updated for
+ * this error condition. The return value is still the amount
+ * the system call says was written.
+ *
+ * (rrl 04/96)
+ ***********************************************************************/
+int
+lio_read_buffer(fd, method, buffer, size, sig, errmsg, wrd)
+int fd; /* open file descriptor */
+int method; /* contains io type and wait method bitmask */
+char *buffer; /* pointer to buffer */
+int size; /* the size of the io */
+int sig; /* signal to use if async io */
+char **errmsg; /* char pointer that will be updated to point to err message */
+long wrd; /* to allow future features, use zero for now */
+{
+ int ret = 0; /* syscall return or used to get random method */
+ char *io_type; /* Holds string of type of io */
+#ifndef linux
+ int listio_cmd; /* Holds the listio/lio_listio cmd */
+ int omethod = method;
+#endif
+#ifdef CRAY
+ struct listreq request; /* Used when a listio is wanted */
+ struct iosw status, *statptr[1];
+#else
+ /* for linux or sgi */
+ struct iovec iov; /* iovec for readv(2) */
+#endif
+#ifdef sgi
+ aiocb_t aiocbp; /* POSIX aio control block */
+ aiocb_t *aiolist[1]; /* list of aio control blocks for lio_listio */
+ off64_t poffset; /* pread(2) offset */
+#endif
+
+ /*
+ * If LIO_RANDOM bit specified, get new method randomly.
+ */
+ if ( method & LIO_RANDOM ) {
+ if( Debug_level > 3 )
+ printf("DEBUG %s/%d: method mask to choose from: %#o\n", __FILE__, __LINE__, method );
+ method = lio_random_methods(method);
+ if ( Debug_level > 2 )
+ printf("DEBUG %s/%d: random chosen method %#o\n", __FILE__, __LINE__, method);
+ }
+
+ if ( errmsg != NULL )
+ *errmsg = Errormsg;
+
+ Rec_signal=Received_signal; /* get the current number of signals received */
+#ifdef sgi
+ Rec_callback=Received_callback; /* get the current number of callbacks received */
+#endif
+
+#ifdef CRAY
+ bzero(&status, sizeof(struct iosw));
+ bzero(&request, sizeof(struct listreq));
+ statptr[0] = &status;
+#else
+ /* for linux or sgi */
+ bzero(&iov, sizeof(struct iovec));
+ iov.iov_base = buffer;
+ iov.iov_len = size;
+#endif
+#ifdef sgi
+ bzero(&aiocbp, sizeof(aiocb_t));
+ aiocbp.aio_fildes = fd;
+ aiocbp.aio_nbytes = size;
+ aiocbp.aio_buf = buffer;
+/* aiocbp.aio_offset = lseek( fd, 0, SEEK_CUR ); -- set below */
+ aiocbp.aio_sigevent.sigev_notify = SIGEV_NONE;
+ aiocbp.aio_sigevent.sigev_signo = 0;
+ aiocbp.aio_sigevent.sigev_func = NULL;
+ aiocbp.aio_sigevent.sigev_value.sival_int = 0;
+ aiolist[0] = &aiocbp;
+
+ if( (ret = lseek( fd, 0, SEEK_CUR )) == -1 ){
+ ret = 0;
+ /* If there is an error and it is not ESPIPE then kick out the error.
+ * If the fd is a fifo then we have to make sure that
+ * lio_random_methods() didn't select pwrite/pread; if it did then
+ * switch to write/read.
+ */
+ if( errno == ESPIPE ){
+ if( method & LIO_IO_SYNCP ){
+ if( omethod & LIO_RANDOM ){
+ method &= ~LIO_IO_SYNCP;
+ method |= LIO_IO_SYNC;
+ if( Debug_level > 2 )
+ printf("DEBUG %s/%d: random chosen method switched to %#o for fifo\n", __FILE__, __LINE__, method );
+ }
+ else if( Debug_level ){
+ printf("DEBUG %s/%d: pread will fail when it reads from a fifo\n",
+ __FILE__, __LINE__ );
+ }
+ }
+ /* else: let it ride */
+ }
+ else{
+ sprintf(Errormsg, "%s/%d lseek(fd=%d,0,SEEK_CUR) failed, errno=%d %s",
+ __FILE__, __LINE__, fd, errno, strerror(errno));
+ return -errno;
+ }
+ }
+ poffset = (off64_t)ret;
+ aiocbp.aio_offset = ret;
+
+#endif
+
+ /*
+ * If the LIO_USE_SIGNAL bit is not set, only use the signal
+ * if the LIO_WAIT_SIGPAUSE or the LIO_WAIT_SIGACTIVE bits are set.
+ * Otherwise there is not necessarily a signal handler to trap
+ * the signal.
+ */
+ if ( sig && !(method & LIO_USE_SIGNAL) &&
+ ! (method & LIO_WAIT_SIGTYPES) ){
+
+ sig=0; /* ignore signal parameter */
+ }
+
+#ifdef sgi
+ if ( sig && (method & LIO_WAIT_CBTYPES) )
+ sig=0; /* ignore signal parameter */
+#endif
+
+ /*
+ * only setup signal hander if sig was specified and
+ * a sig wait method was specified.
+ * Doing this will change the handler for this signal. The
+ * old signal handler will not be restored.
+ *** restoring the signal handler could be added ***
+ */
+
+ if ( sig && (method & LIO_WAIT_SIGTYPES) ){
+#ifdef CRAY
+ sigctl(SCTL_REG, sig, lio_async_signal_handler);
+#endif
+#ifdef sgi
+ aiocbp.aio_sigevent.sigev_notify = SIGEV_SIGNAL;
+ aiocbp.aio_sigevent.sigev_signo = sig;
+ sigset(sig, lio_async_signal_handler);
+#endif /* CRAY */
+ }
+#ifdef sgi
+ else if( method & LIO_WAIT_CBTYPES ){
+ aiocbp.aio_sigevent.sigev_notify = SIGEV_CALLBACK;
+ aiocbp.aio_sigevent.sigev_func = lio_async_callback_handler;
+ /* sival_int just has to be something that I can use
+ * to identify the callback, and "size" happens to be handy...
+ */
+ aiocbp.aio_sigevent.sigev_value.sival_int = size;
+ }
+#endif
+
+ /*
+ * Determine the system call that will be called and produce
+ * the string of the system call and place it in Lio_SysCall.
+ * Also update the io_type char pointer to give brief description
+ * of system call. Execute the system call and check for
+ * system call failure. If sync i/o, return the number of
+ * bytes written/read.
+ */
+
+ if ( (method & LIO_IO_SYNC) || (method & LIO_IO_TYPES) == 0 ){
+ /*
+ * read(2) is used if LIO_IO_SYNC bit is set or not none
+ * of the LIO_IO_TYPES bits are set (default).
+ */
+
+ sprintf(Lio_SysCall,
+ "read(%d, buf, %d)", fd, size);
+ io_type="read";
+
+ if ( Debug_level ) {
+ printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__, Lio_SysCall);
+ }
+
+ if ((ret = read(fd, buffer, size)) == -1) {
+ sprintf(Errormsg, "%s/%d read(%d, buf, %d) ret:-1, errno=%d %s",
+ __FILE__, __LINE__,
+ fd, size, errno, strerror(errno));
+ return -errno;
+ }
+
+ if ( ret != size ) {
+ sprintf(Errormsg,
+ "%s/%d read(%d, buf, %d) returned=%d",
+ __FILE__, __LINE__,
+ fd, size, ret);
+ }
+ else if ( Debug_level > 1 )
+ printf("DEBUG %s/%d: read completed without error (ret %d)\n",
+ __FILE__, __LINE__, ret);
+
+ return ret;
+
+ }
+
+ else if ( method & LIO_IO_ASYNC ) {
+#ifdef CRAY
+ sprintf(Lio_SysCall,
+ "reada(%d, buf, %d, &status, %d)", fd, size, sig);
+ io_type="reada";
+
+ if ( Debug_level ) {
+ printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__, Lio_SysCall);
+ }
+
+ sigoff();
+ if ((ret = reada(fd, buffer, size, &status, sig)) == -1) {
+ sprintf(Errormsg,
+ "%s/%d reada(%d, buf, %d, &stat, %d) ret:-1, errno=%d %s",
+ __FILE__, __LINE__,
+ fd, size, sig, errno, strerror(errno));
+ sigon();
+ return -errno;
+ }
+#endif
+#ifdef sgi
+ sprintf(Lio_SysCall,
+ "aio_read(fildes=%d, buf, nbytes=%d, signo=%d)", fd, size, sig);
+ io_type="aio_read";
+
+ if ( Debug_level ) {
+ printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__, Lio_SysCall);
+ }
+
+ if( sig )
+ sighold( sig );
+ if ((ret = aio_read(&aiocbp)) == -1) {
+ sprintf(Errormsg,
+ "%s/%d aio_read(fildes=%d, buf, nbytes=%d, signo=%d) ret:-1, errno=%d %s",
+ __FILE__, __LINE__,
+ fd, size, sig, errno, strerror(errno));
+ if( sig )
+ sigrelse( sig );
+ return -errno;
+ }
+#endif
+ } /* LIO_IO_ASYNC */
+
+ else if ( method & LIO_IO_SLISTIO ) {
+#ifdef CRAY
+ request.li_opcode = LO_READ;
+ request.li_fildes = fd;
+ request.li_buf = buffer;
+ request.li_nbyte = size;
+ request.li_status = &status;
+ request.li_signo = sig;
+ request.li_nstride = 0;
+ request.li_filstride = 0;
+ request.li_memstride = 0;
+
+ listio_cmd=LC_WAIT;
+ io_type="listio(2) sync read";
+
+ sprintf(Lio_SysCall,
+ "listio(LC_WAIT, &req, 1) LO_READ, fd:%d, nbyte:%d",
+ fd, size);
+
+ if ( Debug_level ) {
+ printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__, Lio_SysCall);
+ }
+
+ sigoff();
+ if ( listio(listio_cmd, &request, 1) == -1 ) {
+ sprintf(Errormsg, "%s/%d %s failed, fd:%d, nbyte:%d errno=%d %s",
+ __FILE__, __LINE__,
+ Lio_SysCall, fd, size, errno, strerror(errno));
+ sigon();
+ return -errno;
+ }
+
+ if ( Debug_level > 1 )
+ printf("DEBUG %s/%d: %s did not return -1\n",
+ __FILE__, __LINE__, Lio_SysCall);
+
+ ret=lio_check_asyncio(io_type, size, &status);
+ return ret;
+#endif
+#ifdef sgi
+ aiocbp.aio_lio_opcode = LIO_READ;
+ listio_cmd=LIO_WAIT;
+ io_type="lio_listio(3) sync read";
+
+ sprintf(Lio_SysCall,
+ "lio_listio(LIO_WAIT, aiolist, 1, NULL) LIO_READ, fd:%d, nbyte:%d",
+ fd, size);
+
+ if ( Debug_level ) {
+ printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__, Lio_SysCall);
+ }
+
+ if( sig )
+ sighold( sig );
+ if ( lio_listio(listio_cmd, aiolist, 1, NULL) == -1 ) {
+ sprintf(Errormsg, "%s/%d %s failed, fd:%d, nbyte:%d errno=%d %s",
+ __FILE__, __LINE__,
+ Lio_SysCall, fd, size, errno, strerror(errno));
+ if( sig )
+ sigrelse( sig );
+ return -errno;
+ }
+
+ if ( Debug_level > 1 )
+ printf("DEBUG %s/%d: %s did not return -1\n",
+ __FILE__, __LINE__, Lio_SysCall);
+
+ ret=lio_check_asyncio(io_type, size, &aiocbp, method);
+ return ret;
+#endif
+ }/* LIO_IO_SLISTIO */
+
+ else if ( method & LIO_IO_ALISTIO ) {
+#ifdef CRAY
+ request.li_opcode = LO_READ;
+ request.li_fildes = fd;
+ request.li_buf = buffer;
+ request.li_nbyte = size;
+ request.li_status = &status;
+ request.li_signo = sig;
+ request.li_nstride = 0;
+ request.li_filstride = 0;
+ request.li_memstride = 0;
+
+ listio_cmd=LC_START;
+ io_type="listio(2) async read";
+
+ sprintf(Lio_SysCall,
+ "listio(LC_START, &req, 1) LO_READ, fd:%d, nbyte:%d",
+ fd, size);
+
+ if ( Debug_level ) {
+ printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__, Lio_SysCall);
+ }
+
+ sigoff();
+ if ( listio(listio_cmd, &request, 1) == -1 ) {
+ sprintf(Errormsg, "%s/%d %s failed, fd:%d, nbyte:%d errno=%d %s",
+ __FILE__, __LINE__,
+ Lio_SysCall, fd, size, errno, strerror(errno));
+ sigon();
+ return -errno;
+ }
+#endif
+#ifdef sgi
+ aiocbp.aio_lio_opcode = LIO_READ;
+ listio_cmd=LIO_NOWAIT;
+ io_type="lio_listio(3) async read";
+
+ sprintf(Lio_SysCall,
+ "lio_listio(LIO_NOWAIT, aiolist, 1, NULL) LIO_READ, fd:%d, nbyte:%d",
+ fd, size);
+
+ if ( Debug_level ) {
+ printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__, Lio_SysCall);
+ }
+
+ if( sig )
+ sighold( sig );
+ if ( lio_listio(listio_cmd, aiolist, 1, NULL) == -1 ) {
+ sprintf(Errormsg, "%s/%d %s failed, fd:%d, nbyte:%d errno=%d %s",
+ __FILE__, __LINE__,
+ Lio_SysCall, fd, size, errno, strerror(errno));
+ if( sig )
+ sigrelse( sig );
+ return -errno;
+ }
+#endif
+ } /* LIO_IO_ALISTIO */
+
+#ifndef CRAY
+ else if ( method & LIO_IO_SYNCV ) {
+ io_type="readv(2)";
+
+ sprintf(Lio_SysCall,
+ "readv(%d, &iov, 1) nbyte:%d", fd, size);
+
+ if ( Debug_level ) {
+ printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__, Lio_SysCall);
+ }
+ if ((ret = readv(fd, &iov, 1)) == -1) {
+ sprintf(Errormsg, "%s/%d readv(%d, iov, 1) nbyte:%d ret:-1, errno=%d %s",
+ __FILE__, __LINE__,
+ fd, size, errno, strerror(errno));
+ return -errno;
+ }
+
+ if ( ret != size ) {
+ sprintf(Errormsg,
+ "%s/%d readv(%d, iov, 1) nbyte:%d returned=%d",
+ __FILE__, __LINE__,
+ fd, size, ret);
+ }
+ else if ( Debug_level > 1 )
+ printf("DEBUG %s/%d: readv completed without error (ret %d)\n",
+ __FILE__, __LINE__, ret);
+
+ return ret;
+ } /* LIO_IO_SYNCV */
+#endif
+
+#ifdef sgi
+ else if ( method & LIO_IO_SYNCP ) {
+ io_type="pread(2)";
+
+ sprintf(Lio_SysCall,
+ "pread(%d, buf, %d, %lld)", fd, size, poffset);
+
+ if ( Debug_level ) {
+ printf("DEBUG %s/%d: %s\n", __FILE__, __LINE__, Lio_SysCall);
+ }
+ if ((ret = pread(fd, buffer, size, poffset)) == -1) {
+ sprintf(Errormsg, "%s/%d pread(%d, buf, %d, %lld) ret:-1, errno=%d %s",
+ __FILE__, __LINE__,
+ fd, size, poffset, errno, strerror(errno));
+ return -errno;
+ }
+
+ if ( ret != size ) {
+ sprintf(Errormsg,
+ "%s/%d pread(%d, buf, %d, %lld) returned=%d",
+ __FILE__, __LINE__,
+ fd, size, poffset, ret);
+ }
+ else if ( Debug_level > 1 )
+ printf("DEBUG %s/%d: pread completed without error (ret %d)\n",
+ __FILE__, __LINE__, ret);
+
+ return ret;
+ } /* LIO_IO_SYNCP */
+#endif
+
+ else {
+ printf("DEBUG %s/%d: No I/O method chosen\n", __FILE__, __LINE__ );
+ return -1;
+ }
+
+ /*
+ * wait for async io to complete.
+ * Note: Sync io should have returned prior to getting here.
+ */
+#ifdef CRAY
+ ret=lio_wait4asyncio(method, fd, statptr);
+#endif
+#ifdef sgi
+ ret=lio_wait4asyncio(method, fd, &aiocbp);
+#endif
+
+ /*
+ * If there was an error waiting for async i/o to complete,
+ * return the error value (errno) to the caller.
+ * Note: Errormsg should already have been updated.
+ */
+ if ( ret < 0 ) {
+ return ret;
+ }
+
+ /*
+ * If i/o was not waited for (may not have been completed at this time),
+ * return the size that was requested.
+ */
+ if ( ret == 1 )
+ return size;
+
+ /*
+ * check that async io was successful.
+ * Note: if the there was an system call failure, -errno
+ * was returned and Errormsg should already have been updated.
+ * If amount i/o was different than size, Errormsg should already
+ * have been updated but the actual i/o size if returned.
+ */
+
+#ifdef CRAY
+ ret=lio_check_asyncio(io_type, size, &status);
+#endif
+#ifdef sgi
+ ret=lio_check_asyncio(io_type, size, &aiocbp, method);
+#endif
+
+ return ret;
+} /* end of lio_read_buffer */
+
+
+#ifndef linux
+/***********************************************************************
+ * This function will check that async io was successful.
+ * It can also be used to check sync listio since it uses the
+ * same method.
+ *
+ * Return Values
+ * If status.sw_error is set, -status.sw_error is returned.
+ * Otherwise sw_count's field value is returned.
+ *
+ * (rrl 04/96)
+ ***********************************************************************/
+int
+#ifdef CRAY
+lio_check_asyncio(char *io_type, int size, struct iosw *status)
+#else
+lio_check_asyncio(char *io_type, int size, aiocb_t *aiocbp, int method)
+#endif
+{
+ int ret;
+
+#ifdef CRAY
+ if ( status->sw_error ) {
+ sprintf(Errormsg,
+ "%s/%d %s, sw_error set = %d %s, sw_count = %d",
+ __FILE__, __LINE__, io_type,
+ status->sw_error, strerror(status->sw_error), status->sw_count);
+ return -status->sw_error;
+ }
+ else if ( status->sw_count != size ) {
+ sprintf(Errormsg,
+ "%s/%d %s, sw_count not as expected(%d), but actual:%d",
+ __FILE__, __LINE__, io_type,
+ size, status->sw_count);
+ }
+ else if ( Debug_level > 1 ) {
+ printf("DEBUG %s/%d: %s completed without error (sw_error == 0, sw_count == %d)\n",
+ __FILE__, __LINE__, io_type, status->sw_count);
+ }
+
+ return status->sw_count;
+
+#else
+
+ int cnt = 1;
+
+ /* The I/O may have been synchronous with signal completion. It doesn't
+ * make sense, but the combination could be generated. Release the
+ * completion signal here otherwise it'll hang around and bite us
+ * later.
+ */
+ if( aiocbp->aio_sigevent.sigev_notify == SIGEV_SIGNAL )
+ sigrelse( aiocbp->aio_sigevent.sigev_signo );
+
+ ret = aio_error( aiocbp );
+
+ while( ret == EINPROGRESS ){
+ ret = aio_error( aiocbp );
+ ++cnt;
+ }
+ if( cnt > 1 ){
+ sprintf(Errormsg,
+ "%s/%d %s, aio_error had to loop on EINPROGRESS, cnt=%d; random method %#o; sigev_notify=%s",
+ __FILE__, __LINE__, io_type, cnt, method,
+ (aiocbp->aio_sigevent.sigev_notify == SIGEV_SIGNAL ? "signal" :
+ aiocbp->aio_sigevent.sigev_notify == SIGEV_NONE ? "none" :
+ aiocbp->aio_sigevent.sigev_notify == SIGEV_CALLBACK ? "callback" :
+ "unknown") );
+ return -ret;
+ }
+
+ if( ret != 0 ){
+ sprintf(Errormsg,
+ "%s/%d %s, aio_error = %d %s; random method %#o",
+ __FILE__, __LINE__, io_type,
+ ret, strerror(ret),
+ method );
+ return -ret;
+ }
+ ret = aio_return( aiocbp );
+ if( ret != size ){
+ sprintf(Errormsg,
+ "%s/%d %s, aio_return not as expected(%d), but actual:%d",
+ __FILE__, __LINE__, io_type,
+ size, ret);
+
+#ifdef BUG1_workaround
+ if( ret == 0 ){
+ ret = size;
+ if( Debug_level > 1 ){
+ printf("WARN %s/%d: %s completed with bug1_workaround (aio_error == 0, aio_return now == %d)\n",
+ __FILE__, __LINE__, io_type, ret);
+ }
+ }
+#endif /* BUG1_workaround */
+
+ }
+ else if( Debug_level > 1 ){
+ printf("DEBUG %s/%d: %s completed without error (aio_error == 0, aio_return == %d)\n",
+ __FILE__, __LINE__, io_type, ret);
+ }
+
+ return ret;
+
+#endif
+
+} /* end of lio_check_asyncio */
+
+
+/***********************************************************************
+ *
+ * This function will wait for async io to complete.
+ * If multiple wait methods are specified, the order is predetermined
+ * to LIO_WAIT_RECALL,
+ * LIO_WAIT_ACTIVE, LIO_WAIT_SIGPAUSE, LIO_WAIT_SIGACTIVE,
+ * then LIO_WAIT_NONE.
+ *
+ * If no wait method was specified the default wait method is: recall(2)
+ * or aio_suspend(3), as appropriate.
+ *
+ * Return Values
+ * <0: errno of failed recall
+ * 0 : async io was completed
+ * 1 : async was not waited for, io may not have completed.
+ *
+ * (rrl 04/96)
+ ***********************************************************************/
+int
+#ifdef CRAY
+lio_wait4asyncio(int method, int fd, struct iosw **statptr)
+#else
+lio_wait4asyncio(int method, int fd, aiocb_t *aiocbp)
+#endif
+{
+ int cnt;
+#ifdef sgi
+ int ret;
+ const aiocb_t *aioary[1];
+#endif
+
+ if ( (method & LIO_WAIT_RECALL)
+#ifdef sgi
+ || (method & LIO_WAIT_CBSUSPEND)
+ || (method & LIO_WAIT_SIGSUSPEND)
+#endif
+ || ((method & LIO_WAIT_TYPES) == 0) ){
+ /*
+ * If method has LIO_WAIT_RECALL bit set or method does
+ * not have any wait method bits set (default), use recall/aio_suspend.
+ */
+#ifdef CRAY
+ if ( Debug_level > 2 )
+ printf("DEBUG %s/%d: wait method : recall\n", __FILE__, __LINE__);
+ sigon();
+ if ( recall(fd, 1, statptr) ) {
+ sprintf(Errormsg, "%s/%d recall(%d, 1, stat) failed, errno:%d %s",
+ __FILE__, __LINE__,
+ fd, errno, strerror(errno));
+ return -errno;
+ }
+#else
+ if ( Debug_level > 2 )
+ printf("DEBUG %s/%d: wait method : aio_suspend, sigev_notify=%s\n", __FILE__, __LINE__,
+ (aiocbp->aio_sigevent.sigev_notify == SIGEV_SIGNAL ? "signal" :
+ aiocbp->aio_sigevent.sigev_notify == SIGEV_NONE ? "none" :
+ aiocbp->aio_sigevent.sigev_notify == SIGEV_CALLBACK ? "callback" :
+ "unknown") );
+
+ aioary[0] = aiocbp;
+ ret = aio_suspend( aioary, 1, NULL );
+ if( (ret == -1) && (errno == EINTR) ){
+ if( aiocbp->aio_sigevent.sigev_notify == SIGEV_SIGNAL ){
+ if( Debug_level > 2 ){
+ printf("DEBUG %s/%d: aio_suspend received EINTR, sigev_notify=SIGEV_SIGNAL -- ok\n",
+ __FILE__, __LINE__ );
+ }
+ }
+ else {
+ sprintf(Errormsg, "%s/%d aio_suspend received EINTR, sigev_notify=%s, not ok\n",
+ __FILE__, __LINE__,
+ (aiocbp->aio_sigevent.sigev_notify == SIGEV_SIGNAL ? "signal" :
+ aiocbp->aio_sigevent.sigev_notify == SIGEV_NONE ? "none" :
+ aiocbp->aio_sigevent.sigev_notify == SIGEV_CALLBACK ? "callback" :
+ "unknown") );
+ return -errno;
+ }
+ }
+ else if ( ret ) {
+ sprintf(Errormsg, "%s/%d aio_suspend(fildes=%d, aioary, 1, NULL) failed, errno:%d %s",
+ __FILE__, __LINE__,
+ fd, errno, strerror(errno));
+ return -errno;
+ }
+#endif
+
+ } else if ( method & LIO_WAIT_ACTIVE ) {
+ if ( Debug_level > 2 )
+ printf("DEBUG %s/%d: wait method : active\n", __FILE__, __LINE__);
+#ifdef CRAY
+ sigon();
+ /*
+ * loop until sw_flag, sw_count or sw_error field elements
+ * change to non-zero.
+ */
+ cnt=0;
+ while ( (*statptr)->sw_flag == 0 &&
+ (*statptr)->sw_count == 0 &&
+ (*statptr)->sw_error == 0 ) {
+ cnt++;
+ }
+#else
+ /* loop while aio_error() returns EINPROGRESS */
+ cnt=0;
+ while(1){
+ ret = aio_error( aiocbp );
+ if( (ret == 0) || (ret != EINPROGRESS) ){
+ break;
+ }
+ ++cnt;
+ }
+
+#endif
+ if ( Debug_level > 5 && cnt && (cnt % 50) == 0 )
+ printf("DEBUG %s/%d: wait active cnt = %d\n",
+ __FILE__, __LINE__, cnt);
+
+ } else if ( method & LIO_WAIT_SIGPAUSE ) {
+ if ( Debug_level > 2 )
+ printf("DEBUG %s/%d: wait method : sigpause\n", __FILE__, __LINE__);
+#ifdef sgi
+ /* note: don't do the sigon() for CRAY in this case. why? -- roehrich 6/11/97 */
+ if( aiocbp->aio_sigevent.sigev_notify == SIGEV_SIGNAL )
+ sigrelse( aiocbp->aio_sigevent.sigev_signo );
+ else {
+ printf("DEBUG %s/%d: sigev_notify != SIGEV_SIGNAL\n", __FILE__, __LINE__ );
+ return -1;
+ }
+#endif
+ pause();
+
+ } else if ( method & LIO_WAIT_SIGACTIVE ) {
+ if ( Debug_level > 2 )
+ printf("DEBUG %s/%d: wait method : sigactive\n", __FILE__, __LINE__);
+#ifdef CRAY
+ sigon();
+#else
+ if( aiocbp->aio_sigevent.sigev_notify == SIGEV_SIGNAL )
+ sigrelse( aiocbp->aio_sigevent.sigev_signo );
+ else {
+ printf("DEBUG %s/%d: sigev_notify != SIGEV_SIGNAL\n", __FILE__, __LINE__ );
+ return -1;
+ }
+#endif
+ /* loop waiting for signal */
+ while ( Received_signal == Rec_signal ){
+#ifdef CRAY
+ sigon();
+#else
+ sigrelse( aiocbp->aio_sigevent.sigev_signo );
+#endif
+ }
+
+ } else if ( method & LIO_WAIT_NONE ) {
+ if ( Debug_level > 2 )
+ printf("DEBUG %s/%d: wait method : none\n", __FILE__, __LINE__);
+ /* It's broken because the aiocb/iosw is an automatic variable in
+ * lio_{read,write}_buffer, so when the function returns and the
+ * I/O completes there will be nowhere to write the I/O status.
+ * It doesn't cause a problem on unicos--probably because of some
+ * compiler quirk, or an accident. It causes POSIX async I/O
+ * to core dump some threads. spr/pv 705909. 6/27/97 roehrich
+ */
+ sprintf(Errormsg, "%s/%d LIO_WAIT_NONE was selected (this is broken)\n",
+ __FILE__, __LINE__ );
+#ifdef CRAY
+ sigon();
+#endif
+/* return 1;*/
+ return -1;
+ }
+ else {
+ if( Debug_level > 2 )
+ printf("DEBUG %s/%d: no wait method was chosen\n", __FILE__, __LINE__ );
+ return -1;
+ }
+
+ return 0;
+
+} /* end of lio_wait4asyncio */
+
+#endif /* ifndef linux */
+
+#if UNIT_TEST
+/***********************************************************************
+ * The following code is provided as unit test.
+ * Just define add "-DUNIT_TEST=1" to the cc line.
+ *
+ * (rrl 04/96)
+ ***********************************************************************/
+struct unit_info_t {
+ int method;
+ int sig;
+ char *str;
+} Unit_info[] = {
+ { LIO_IO_SYNC, 0, "sync io" },
+ { LIO_IO_SYNCV, 0, "sync readv/writev" },
+ { LIO_IO_SYNCP, 0, "sync pread/pwrite" },
+ { LIO_IO_ASYNC, 0, "async io, def wait" },
+ { LIO_IO_SLISTIO, 0, "sync listio" },
+ { LIO_IO_ALISTIO, 0, "async listio, def wait" },
+ { LIO_IO_ASYNC|LIO_WAIT_ACTIVE, 0, "async active" },
+ { LIO_IO_ASYNC|LIO_WAIT_RECALL, 0, "async recall/suspend" },
+ { LIO_IO_ASYNC|LIO_WAIT_SIGPAUSE, SIGUSR1, "async sigpause" },
+ { LIO_IO_ASYNC|LIO_WAIT_SIGACTIVE, SIGUSR1, "async sigactive" },
+ { LIO_IO_ALISTIO|LIO_WAIT_ACTIVE, 0, "async listio active" },
+ { LIO_IO_ALISTIO|LIO_WAIT_RECALL, 0, "async listio recall" },
+ { LIO_IO_ALISTIO|LIO_WAIT_SIGACTIVE, SIGUSR1, "async listio sigactive" },
+ { LIO_IO_ALISTIO|LIO_WAIT_SIGPAUSE, SIGUSR1, "async listio sigpause" },
+ { LIO_IO_ASYNC, SIGUSR2, "async io, def wait, sigusr2" },
+ { LIO_IO_ALISTIO, SIGUSR2, "async listio, def wait, sigusr2" },
+};
+
+int
+main(argc, argv)
+int argc;
+char **argv;
+{
+ extern char *optarg;
+ extern int optind;
+
+ int fd;
+ char *err;
+ char buffer[4096];
+ int size=4096;
+ int ret;
+ int ind;
+ int iter=3;
+ int method;
+ int exit_status = 0;
+ int c;
+ int i;
+ char *symbols = NULL;
+ int die_on_err = 0;
+
+ while( (c = getopt(argc,argv,"s:di:")) != -1 ){
+ switch(c){
+ case 's': symbols = optarg; break;
+ case 'd': ++die_on_err; break;
+ case 'i': iter = atoi(optarg); break;
+ }
+ }
+
+ if ((fd=open("unit_test_file", O_CREAT|O_RDWR|O_TRUNC, 0777)) == -1 ) {
+ perror("open(unit_test_file, O_CREAT|O_RDWR|O_TRUNC, 0777) failed");
+ exit(1);
+ }
+
+ Debug_level=9;
+
+ if ( symbols != NULL ) {
+ if ( (method=lio_parse_io_arg2(symbols, &err)) == -1 ){
+ printf("lio_parse_io_arg2(%s, &err) failed, bad token starting at %s\n",
+ symbols, err);
+ if( die_on_err )
+ exit(1);
+ }
+ else
+ printf("lio_parse_io_arg2(%s, &err) returned %#o\n", symbols, method);
+
+ exit_status = 0;
+ for(ind=0; ind < iter; ind++ ) {
+ memset( buffer, 'A', 4096 );
+ if( lseek(fd, 0, 0) == -1 ){
+ printf("lseek(fd,0,0), %d, failed, errno %d\n",
+ __LINE__, errno );
+ ++exit_status;
+ }
+ if ((ret=lio_write_buffer(fd, method, buffer,
+ size, SIGUSR1, &err, 0)) != size ) {
+ printf("lio_write_buffer returned -1, err = %s\n", err);
+ } else
+ printf("lio_write_buffer returned %d\n", ret);
+
+ memset( buffer, 'B', 4096 );
+ if( lseek(fd, 0, 0) == -1 ){
+ printf("lseek(fd,0,0), %d, failed, errno %d\n",
+ __LINE__, errno );
+ ++exit_status;
+ }
+ if ((ret=lio_read_buffer(fd, method, buffer,
+ size, SIGUSR2, &err, 0)) != size ) {
+ printf("lio_read_buffer returned -1, err = %s\n", err);
+ } else
+ printf("lio_read_buffer returned %d\n", ret);
+
+ for( i = 0; i < 4096; ++i ){
+ if( buffer[i] != 'A' ){
+ printf(" buffer[%d] = %d\n", i, buffer[i] );
+ ++exit_status;
+ break;
+ }
+ }
+
+ if( exit_status )
+ exit(exit_status);
+
+ }
+
+ unlink("unit_test_file");
+ exit(0);
+ }
+
+ for(ind=0; ind < sizeof(Unit_info)/sizeof(struct unit_info_t); ind++ ) {
+
+ printf("\n********* write %s ***************\n", Unit_info[ind].str);
+ if( lseek(fd, 0, 0) == -1 ){
+ printf("lseek(fd,0,0), %d, failed, errno %d\n",
+ __LINE__, errno );
+ ++exit_status;
+ }
+
+ memset( buffer, 'A', 4096 );
+ if ((ret=lio_write_buffer(fd, Unit_info[ind].method, buffer,
+ size, Unit_info[ind].sig, &err, 0)) != size ) {
+ printf(">>>>> lio_write_buffer(fd,0%x,buffer,%d,%d,err,0) returned -1,\n err = %s\n",
+ Unit_info[ind].method, size, Unit_info[ind].sig, err);
+ ++exit_status;
+ if( die_on_err )
+ exit(exit_status);
+ } else{
+ printf("lio_write_buffer returned %d\n", ret);
+ }
+
+ printf("\n********* read %s ***************\n", Unit_info[ind].str);
+ if( lseek(fd, 0, 0) == -1 ){
+ printf("lseek(fd,0,0), %d, failed, errno %d\n",
+ __LINE__, errno );
+ ++exit_status;
+ }
+ memset( buffer, 'B', 4096 );
+ if ((ret=lio_read_buffer(fd, Unit_info[ind].method, buffer,
+ size, Unit_info[ind].sig, &err, 0)) != size ) {
+ printf(">>>>> lio_read_buffer(fd,0%x,buffer,%d,%d,err,0) returned -1,\n err = %s\n",
+ Unit_info[ind].method, size, Unit_info[ind].sig, err);
+ ++exit_status;
+ if( die_on_err )
+ exit(exit_status);
+ } else {
+ printf("lio_read_buffer returned %d\n", ret);
+ }
+
+ for( i = 0; i < 4096; ++i ){
+ if( buffer[i] != 'A' ){
+ printf(" buffer[%d] = %d\n", i, buffer[i] );
+ ++exit_status;
+ if( die_on_err )
+ exit(exit_status);
+ break;
+ }
+ }
+
+ fflush(stdout);
+ fflush(stderr);
+ sleep(1);
+
+ }
+
+ unlink("unit_test_file");
+
+ exit(exit_status);
+}
+#endif
--- /dev/null
+/*
+ * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like. Any license provided herein, whether implied or
+ * otherwise, applies only to this software file. Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+ * Mountain View, CA 94043, or:
+ *
+ * http://www.sgi.com
+ *
+ * For further information regarding this notice, see:
+ *
+ * http://oss.sgi.com/projects/GenInfo/NoticeExplan/
+ */
+/*
+ * This module contains code for logging writes to files, and for
+ * perusing the resultant logfile. The main intent of all this is
+ * to provide a 'write history' of a file which can be examined to
+ * judge the state of a file (ie. whether it is corrupted or not) based
+ * on the write activity.
+ *
+ * The main abstractions available to the user are the wlog_file, and
+ * the wlog_rec. A wlog_file is a handle encapsulating a write logfile.
+ * It is initialized with the wlog_open() function. This handle is
+ * then passed to the various wlog_xxx() functions to provide transparent
+ * access to the write logfile.
+ *
+ * The wlog_rec datatype is a structure which contains all the information
+ * about a file write. Examples include the file name, offset, length,
+ * pattern, etc. In addition there is a bit which is cleared/set based
+ * on whether or not the write has been confirmed as complete. This
+ * allows the write logfile to contain information on writes which have
+ * been initiated, but not yet completed (as in async io).
+ *
+ * There is also a function to scan a write logfile in reverse order.
+ *
+ * NOTE: For target file analysis based on a write logfile, the
+ * assumption is made that the file being written to is
+ * locked from simultaneous access, so that the order of
+ * write completion is predictable. This is an issue when
+ * more than 1 process is trying to write data to the same
+ * target file simultaneously.
+ *
+ * The history file created is a collection of variable length records
+ * described by scruct wlog_rec_disk in write_log.h. See that module for
+ * the layout of the data on disk.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include "write_log.h"
+
+#ifndef BSIZE
+#ifdef linux
+#define BSIZE DEV_BSIZE
+#else
+#define BSIZE BBSIZE
+#endif
+#endif
+
+#ifndef PATH_MAX
+#define PATH_MAX 255
+/*#define PATH_MAX pathconf("/", _PC_PATH_MAX)*/
+#endif
+
+char Wlog_Error_String[256];
+
+#if __STDC__
+static int wlog_rec_pack(struct wlog_rec *wrec, char *buf, int flag);
+static int wlog_rec_unpack(struct wlog_rec *wrec, char *buf);
+#else
+static int wlog_rec_pack();
+static int wlog_rec_unpack();
+#endif
+
+/*
+ * Initialize a write logfile. wfile is a wlog_file structure that has
+ * the w_file field filled in. The rest of the information in the
+ * structure is initialized by the routine.
+ *
+ * The trunc flag is used to indicate whether or not the logfile should
+ * be truncated if it currently exists. If it is non-zero, the file will
+ * be truncated, otherwise it will be appended to.
+ *
+ * The mode argument is the [absolute] mode which the file will be
+ * given if it does not exist. This mode is not affected by your process
+ * umask.
+ */
+
+int
+wlog_open(wfile, trunc, mode)
+struct wlog_file *wfile;
+int trunc;
+int mode;
+{
+ int omask, oflags;
+
+ if (trunc)
+ trunc = O_TRUNC;
+
+ omask = umask(0);
+
+ /*
+ * Open 1 file descriptor as O_APPEND
+ */
+
+ oflags = O_WRONLY | O_APPEND | O_CREAT | trunc;
+ wfile->w_afd =
+ open(wfile->w_file, oflags, mode);
+ umask(omask);
+
+ if (wfile->w_afd == -1) {
+ sprintf(Wlog_Error_String,
+ "Could not open write_log - open(%s, %#o, %#o) failed: %s\n",
+ wfile->w_file, oflags, mode, strerror(errno));
+ return -1;
+ }
+
+ /*
+ * Open the next fd as a random access descriptor
+ */
+
+ oflags = O_RDWR;
+ if ((wfile->w_rfd = open(wfile->w_file, oflags)) == -1) {
+ sprintf(Wlog_Error_String,
+ "Could not open write log - open(%s, %#o) failed: %s\n",
+ wfile->w_file, oflags, strerror(errno));
+ close(wfile->w_afd);
+ wfile->w_afd = -1;
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * Release all resources associated with a wlog_file structure allocated
+ * with the wlog_open() call.
+ */
+
+int
+wlog_close(wfile)
+struct wlog_file *wfile;
+{
+ close(wfile->w_afd);
+ close(wfile->w_rfd);
+ return 0;
+}
+
+/*
+ * Write a wlog_rec structure to a write logfile. Offset is used to
+ * control where the record will be written. If offset is < 0, the
+ * record will be appended to the end of the logfile. Otherwise, the
+ * record which exists at the indicated offset will be overlayed. This
+ * is so that we can record writes which are outstanding (with the w_done
+ * bit in wrec cleared), but not completed, and then later update the
+ * logfile when the write request completes (as with async io). When
+ * offset is >= 0, only the fixed length portion of the record is
+ * rewritten. See text in write_log.h for details on the format of an
+ * on-disk record.
+ *
+ * The return value of the function is the byte offset in the logfile
+ * where the record begins.
+ *
+ * Note: It is the callers responsibility to make sure that the offset
+ * parameter 'points' to a valid record location when a record is to be
+ * overlayed. This is guarenteed by saving the return value of a previous
+ * call to wlog_record_write() which wrote the record to be overlayed.
+ *
+ * Note2: The on-disk version of the wlog_rec is MUCH different than
+ * the user version. Don't expect to od the logfile and see data formatted
+ * as it is in the wlog_rec structure. Considerable data packing takes
+ * place before the record is written.
+ */
+
+int
+wlog_record_write(wfile, wrec, offset)
+struct wlog_file *wfile;
+struct wlog_rec *wrec;
+long offset;
+{
+ int reclen;
+ char wbuf[WLOG_REC_MAX_SIZE + 2];
+
+ /*
+ * If offset is -1, we append the record at the end of file
+ *
+ * Otherwise, we overlay wrec at the file offset indicated and assume
+ * that the caller passed us the correct offset. We do not record the
+ * fname in this case.
+ */
+
+ reclen = wlog_rec_pack(wrec, wbuf, (offset < 0));
+
+ if (offset < 0) {
+ /*
+ * Since we're writing a complete new record, we must also tack
+ * its length onto the end so that wlog_scan_backward() will work.
+ * Length is asumed to fit into 2 bytes.
+ */
+
+ wbuf[reclen] = reclen / 256;
+ wbuf[reclen+1] = reclen % 256;
+ reclen += 2;
+
+ write(wfile->w_afd, wbuf, reclen);
+ offset = lseek(wfile->w_afd, 0, SEEK_CUR) - reclen;
+ } else {
+ lseek(wfile->w_rfd, offset, SEEK_SET);
+ write(wfile->w_rfd, wbuf, reclen);
+ }
+
+ return offset;
+}
+
+/*
+ * Function to scan a logfile in reverse order. Wfile is a valid
+ * wlog_file structure initialized by wlog_open(). nrecs is the number
+ * of records to scan (all records are scanned if nrecs is 0). func is
+ * a user-supplied function to call for each record found. The function
+ * will be passed a single parameter - a wlog_rec structure .
+ */
+
+int
+wlog_scan_backward(wfile, nrecs, func, data)
+struct wlog_file *wfile;
+int nrecs;
+int (*func)();
+long data;
+{
+ int fd, leftover, nbytes, offset, recnum, reclen, rval;
+ char buf[BSIZE*32], *bufend, *cp, *bufstart;
+ char albuf[WLOG_REC_MAX_SIZE];
+ struct wlog_rec wrec;
+
+ fd = wfile->w_rfd;
+
+ /*
+ * Move to EOF. offset will always hold the current file offset
+ */
+
+ lseek(fd, 0, SEEK_END);
+ offset = lseek(fd, 0, SEEK_CUR);
+
+ bufend = buf + sizeof(buf);
+ bufstart = buf;
+
+ recnum = 0;
+ leftover = 0;
+ while ((!nrecs || recnum < nrecs) && offset > 0) {
+ /*
+ * Check for beginning of file - if there aren't enough bytes
+ * remaining to fill buf, adjust bufstart.
+ */
+
+ if (offset + leftover < sizeof(buf)) {
+ bufstart = bufend - (offset + leftover);
+ offset = 0;
+ } else {
+ offset -= sizeof(buf) - leftover;
+ }
+
+ /*
+ * Move to the proper file offset, and read into buf
+ */
+
+ lseek(fd, offset, SEEK_SET);
+ nbytes = read(fd, bufstart, bufend - bufstart - leftover);
+
+ if (nbytes == -1) {
+ sprintf(Wlog_Error_String,
+ "Could not read history file at offset %d - read(%d, %p, %d) failed: %s\n",
+ offset, fd, bufstart,
+ (int)(bufend - bufstart - leftover), strerror(errno));
+ return -1;
+ }
+
+ cp = bufend;
+ leftover = 0;
+
+ while (cp >= bufstart) {
+
+ /*
+ * If cp-bufstart is not large enough to hold a piece
+ * of record length information, copy remainder to end
+ * of buf and continue reading the file.
+ */
+
+ if (cp - bufstart < 2) {
+ leftover = cp - bufstart;
+ memcpy(bufend - leftover, bufstart, leftover);
+ break;
+ }
+
+ /*
+ * Extract the record length. We must do it this way
+ * instead of casting cp to an int because cp might
+ * not be word aligned.
+ */
+
+ reclen = (*(cp-2) * 256) + *(cp -1);
+
+ /*
+ * If cp-bufstart isn't large enough to hold a
+ * complete record, plus the length information, copy
+ * the leftover bytes to the end of buf and continue
+ * reading.
+ */
+
+ if (cp - bufstart < reclen + 2) {
+ leftover = cp - bufstart;
+ memcpy(bufend - leftover, bufstart, leftover);
+ break;
+ }
+
+ /*
+ * Adjust cp to point at the start of the record.
+ * Copy the record into wbuf so that it is word
+ * aligned and pass the record to the user supplied
+ * function.
+ */
+
+ cp -= reclen + 2;
+ memcpy(albuf, cp, reclen);
+
+ wlog_rec_unpack(&wrec, albuf);
+
+ /*
+ * Call the user supplied function -
+ * stop if instructed to.
+ */
+
+ if ((rval = (*func)(&wrec, data)) == WLOG_STOP_SCAN) {
+ break;
+ }
+
+ recnum++;
+
+ if (nrecs && recnum >= nrecs)
+ break;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * The following 2 routines are used to pack and unpack the user
+ * visible wlog_rec structure to/from a character buffer which is
+ * stored or read from the write logfile. Any changes to either of
+ * these routines must be reflected in the other.
+ */
+
+static int
+wlog_rec_pack(wrec, buf, flag)
+struct wlog_rec *wrec;
+char *buf;
+int flag;
+{
+ char *file, *host, *pattern;
+ struct wlog_rec_disk *wrecd;
+
+ wrecd = (struct wlog_rec_disk *)buf;
+
+ wrecd->w_pid = (uint)wrec->w_pid;
+ wrecd->w_offset = (uint)wrec->w_offset;
+ wrecd->w_nbytes = (uint)wrec->w_nbytes;
+ wrecd->w_oflags = (uint)wrec->w_oflags;
+ wrecd->w_done = (uint)wrec->w_done;
+ wrecd->w_async = (uint)wrec->w_async;
+
+ wrecd->w_pathlen = (wrec->w_pathlen > 0) ? (uint)wrec->w_pathlen : 0;
+ wrecd->w_hostlen = (wrec->w_hostlen > 0) ? (uint)wrec->w_hostlen : 0;
+ wrecd->w_patternlen = (wrec->w_patternlen > 0) ? (uint)wrec->w_patternlen : 0;
+
+ /*
+ * If flag is true, we should also pack the variable length parts
+ * of the wlog_rec. By default, we only pack the fixed length
+ * parts.
+ */
+
+ if (flag) {
+ file = buf + sizeof(struct wlog_rec_disk);
+ host = file + wrecd->w_pathlen;
+ pattern = host + wrecd->w_hostlen;
+
+ if (wrecd->w_pathlen > 0)
+ memcpy(file, wrec->w_path, wrecd->w_pathlen);
+
+ if (wrecd->w_hostlen > 0)
+ memcpy(host, wrec->w_host, wrecd->w_hostlen);
+
+ if (wrecd->w_patternlen > 0)
+ memcpy(pattern, wrec->w_pattern, wrecd->w_patternlen);
+
+ return (sizeof(struct wlog_rec_disk) +
+ wrecd->w_pathlen + wrecd->w_hostlen + wrecd->w_patternlen);
+ } else {
+ return sizeof(struct wlog_rec_disk);
+ }
+}
+
+static int
+wlog_rec_unpack(wrec, buf)
+struct wlog_rec *wrec;
+char *buf;
+{
+ char *file, *host, *pattern;
+ struct wlog_rec_disk *wrecd;
+
+ bzero((char *)wrec, sizeof(struct wlog_rec));
+ wrecd = (struct wlog_rec_disk *)buf;
+
+ wrec->w_pid = wrecd->w_pid;
+ wrec->w_offset = wrecd->w_offset;
+ wrec->w_nbytes = wrecd->w_nbytes;
+ wrec->w_oflags = wrecd->w_oflags;
+ wrec->w_hostlen = wrecd->w_hostlen;
+ wrec->w_pathlen = wrecd->w_pathlen;
+ wrec->w_patternlen = wrecd->w_patternlen;
+ wrec->w_done = wrecd->w_done;
+ wrec->w_async = wrecd->w_async;
+
+ if (wrec->w_pathlen > 0) {
+ file = buf + sizeof(struct wlog_rec_disk);
+ memcpy(wrec->w_path, file, wrec->w_pathlen);
+ }
+
+ if (wrec->w_hostlen > 0) {
+ host = buf + sizeof(struct wlog_rec_disk) + wrec->w_pathlen;
+ memcpy(wrec->w_host, host, wrec->w_hostlen);
+ }
+
+ if (wrec->w_patternlen > 0) {
+ pattern = buf + sizeof(struct wlog_rec_disk) +
+ wrec->w_pathlen + wrec->w_hostlen;
+ memcpy(wrec->w_pattern, pattern, wrec->w_patternlen);
+ }
+
+ return 0;
+}
--- /dev/null
+#
+# Copyright (c) 2003 Silicon Graphics, Inc. All Rights Reserved.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of version 2 of the GNU General Public License as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it would be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+#
+# Further, this software is distributed without any warranty that it is
+# free of the rightful claim of any third person regarding infringement
+# or the like. Any license provided herein, whether implied or
+# otherwise, applies only to this software file. Patent licenses, if
+# any, provided herein do not apply to combinations of this program with
+# other software, or any other product whatsoever.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write the Free Software Foundation, Inc., 59
+# Temple Place - Suite 330, Boston MA 02111-1307, USA.
+#
+# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+# Mountain View, CA 94043, or:
+#
+# http://www.sgi.com
+#
+# For further information regarding this notice, see:
+#
+# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
+#
+
+TOPDIR = ..
+include $(TOPDIR)/include/builddefs
+
+TARGETS = doio fsstress fsx growfiles iogen
+CFILES = $(TARGETS:=.c)
+HFILES = doio.h
+LDIRT = $(TARGETS)
+LCFLAGS =
+
+default: $(TARGETS)
+
+include $(BUILDRULES)
+LINKTEST = $(LTLINK) $@.c -o $@ $(CFLAGS) $(LDFLAGS)
+
+doio: doio.c $(LIBTEST)
+ $(LINKTEST) $(LIBTEST) $(LDLIBS)
+
+fsstress: fsstress.c $(LIBATTR) $(LIBTEST)
+ $(LINKTEST) $(LIBATTR) $(LIBTEST) $(LDLIBS)
+
+fsx: fsx.c
+ $(LINKTEST) $(LDLIBS)
+
+growfiles: growfiles.c $(LIBTEST)
+ $(LINKTEST) $(LIBTEST) $(LDLIBS)
+
+iogen: iogen.c $(LIBTEST)
+ $(LINKTEST) $(LIBTEST) $(LDLIBS)
--- /dev/null
+/*
+ * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like. Any license provided herein, whether implied or
+ * otherwise, applies only to this software file. Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+ * Mountain View, CA 94043, or:
+ *
+ * http://www.sgi.com
+ *
+ * For further information regarding this notice, see:
+ *
+ * http://oss.sgi.com/projects/GenInfo/NoticeExplan/
+ */
+/*
+ * doio - a general purpose io initiator with system call and
+ * write logging. See doio.h for the structure which defines
+ * what doio requests should look like.
+ *
+ * programming
+ * notes:
+ * -----------
+ * messages should generally be printed using doio_fprintf().
+ *
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <string.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <time.h>
+#include <stdarg.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/sysmacros.h>
+#ifdef CRAY
+#include <sys/iosw.h>
+#endif
+#ifdef sgi
+#include <aio.h> /* for aio_read,write */
+#include <inttypes.h> /* for uint64_t type */
+#include <siginfo.h> /* signal handlers & SA_SIGINFO */
+#endif
+#ifndef CRAY
+#include <sys/uio.h> /* for struct iovec (readv)*/
+#include <sys/mman.h> /* for mmap(2) */
+#include <sys/ipc.h> /* for i/o buffer in shared memory */
+#include <sys/shm.h> /* for i/o buffer in shared memory */
+#endif
+#include <sys/wait.h>
+#ifdef CRAY
+#include <sys/listio.h>
+#include <sys/panic.h>
+#endif
+#include <sys/time.h> /* for delays */
+
+#ifndef NO_XFS
+#include <xfs/libxfs.h>
+struct io_req;
+int do_xfsctl(struct io_req *);
+#endif
+
+#include "doio.h"
+#include "pattern.h"
+#include "write_log.h"
+#include "random_range.h"
+#include "string_to_tokens.h"
+
+#ifndef O_SSD
+#define O_SSD 0 /* so code compiles on a CRAY2 */
+#endif
+
+#define UINT64_T unsigned long long
+
+#ifndef O_PARALLEL
+#define O_PARALLEL 0 /* so O_PARALLEL may be used in expressions */
+#endif
+
+#define PPID_CHECK_INTERVAL 5 /* check ppid every <-- iterations */
+#define MAX_AIO 256 /* maximum number of async I/O ops */
+#ifdef _CRAYMPP
+#define MPP_BUMP 16 /* page un-alignment for MPP */
+#else
+#define MPP_BUMP 0
+#endif
+
+
+#define SYSERR strerror(errno)
+
+/*
+ * getopt() string of supported cmdline arguments.
+ */
+
+#define OPTS "aC:d:ehm:n:kr:w:vU:V:M:N:"
+
+#define DEF_RELEASE_INTERVAL 0
+
+/*
+ * Flags set in parse_cmdline() to indicate which options were selected
+ * on the cmdline.
+ */
+
+int a_opt = 0; /* abort on data compare errors */
+int e_opt = 0; /* exec() after fork()'ing */
+int C_opt = 0; /* Data Check Type */
+int d_opt = 0; /* delay between operations */
+int k_opt = 0; /* lock file regions during writes */
+int m_opt = 0; /* generate periodic messages */
+int n_opt = 0; /* nprocs */
+int r_opt = 0; /* resource release interval */
+int w_opt = 0; /* file write log file */
+int v_opt = 0; /* verify writes if set */
+int U_opt = 0; /* upanic() on varios conditions */
+int V_opt = 0; /* over-ride default validation fd type */
+int M_opt = 0; /* data buffer allocation types */
+char TagName[40]; /* name of this doio (see Monster) */
+
+
+/*
+ * Misc globals initialized in parse_cmdline()
+ */
+
+char *Prog = NULL; /* set up in parse_cmdline() */
+int Upanic_Conditions; /* set by args to -U */
+int Release_Interval; /* arg to -r */
+int Nprocs; /* arg to -n */
+char *Write_Log; /* arg to -w */
+char *Infile; /* input file (defaults to stdin) */
+int *Children; /* pids of child procs */
+int Nchildren = 0;
+int Nsiblings = 0; /* tfork'ed siblings */
+int Execd = 0;
+int Message_Interval = 0;
+int Npes = 0; /* non-zero if built as an mpp multi-pe app */
+int Vpe = -1; /* Virtual pe number if Npes >= 0 */
+int Reqno = 1; /* request # - used in some error messages */
+int Reqskipcnt = 0; /* count of I/O requests that are skipped */
+int Validation_Flags;
+char *(*Data_Check)(); /* function to call for data checking */
+int (*Data_Fill)(); /* function to call for data filling */
+int Nmemalloc = 0; /* number of memory allocation strategies */
+int delayop = 0; /* delay between operations - type of delay */
+int delaytime = 0; /* delay between operations - how long */
+
+struct wlog_file Wlog;
+
+int active_mmap_rw = 0; /* Indicates that mmapped I/O is occurring. */
+ /* Used by sigbus_action() in the child doio. */
+int havesigint = 0;
+
+#define SKIP_REQ -2 /* skip I/O request */
+
+#define NMEMALLOC 32
+#define MEM_DATA 1 /* data space */
+#define MEM_SHMEM 2 /* System V shared memory */
+#define MEM_T3ESHMEM 3 /* T3E Shared Memory */
+#define MEM_MMAP 4 /* mmap(2) */
+
+#define MEMF_PRIVATE 0001
+#define MEMF_AUTORESRV 0002
+#define MEMF_LOCAL 0004
+#define MEMF_SHARED 0010
+
+#define MEMF_FIXADDR 0100
+#define MEMF_ADDR 0200
+#define MEMF_AUTOGROW 0400
+#define MEMF_FILE 01000 /* regular file -- unlink on close */
+#define MEMF_MPIN 010000 /* use mpin(2) to lock pages in memory */
+
+struct memalloc {
+ int memtype;
+ int flags;
+ int nblks;
+ char *name;
+ void *space; /* memory address of allocated space */
+ int fd; /* FD open for mmaping */
+ int size;
+} Memalloc[NMEMALLOC];
+
+/*
+ * Global file descriptors
+ */
+
+int Wfd_Append; /* for appending to the write-log */
+int Wfd_Random; /* for overlaying write-log entries */
+
+/*
+ * Structure for maintaining open file test descriptors. Used by
+ * alloc_fd().
+ */
+
+struct fd_cache {
+ char c_file[MAX_FNAME_LENGTH+1];
+ int c_oflags;
+ int c_fd;
+ long c_rtc;
+#ifndef NO_XFS
+ int c_memalign; /* from xfsctl(XFS_IOC_DIOINFO) */
+ int c_miniosz;
+ int c_maxiosz;
+#endif
+#ifndef CRAY
+ void *c_memaddr; /* mmapped address */
+ int c_memlen; /* length of above region */
+#endif
+};
+
+#define FD_ALLOC_INCR 32 /* allocate this many fd_map structs */
+ /* at a time */
+
+/*
+ * Globals for tracking Sds and Core usage
+ */
+
+char *Memptr; /* ptr to core buffer space */
+int Memsize; /* # bytes pointed to by Memptr */
+ /* maintained by alloc_mem() */
+
+int Sdsptr; /* sds offset (always 0) */
+int Sdssize; /* # bytes of allocated sds space */
+ /* Maintained by alloc_sds() */
+char Host[16];
+char Pattern[128];
+int Pattern_Length;
+
+/*
+ * Signal handlers, and related globals
+ */
+
+void sigint_handler(); /* Catch SIGINT in parent doio, propagate
+ * to children, does not die. */
+
+void die_handler(); /* Bad sig in child doios, exit 1. */
+void cleanup_handler(); /* Normal kill, exit 0. */
+
+#ifndef CRAY
+void sigbus_handler(); /* Handle sigbus--check active_mmap_rw to
+ decide if this should be a normal exit. */
+#endif
+
+void cb_handler(); /* Posix aio callback handler. */
+void noop_handler(); /* Delayop alarm, does nothing. */
+char *hms();
+char *format_rw();
+char *format_sds();
+char *format_listio();
+char *check_file();
+int doio_fprintf(FILE *stream, char *format, ...);
+void doio_upanic();
+void doio();
+void help();
+void doio_delay();
+int alloc_fd( char *, int );
+int alloc_mem( int );
+int do_read( struct io_req * );
+int do_write( struct io_req * );
+int do_rw( struct io_req * );
+int do_sync( struct io_req * );
+int usage( FILE * );
+int aio_unregister( int );
+int parse_cmdline( int, char **, char * );
+int lock_file_region( char *, int, int, int, int );
+struct fd_cache *alloc_fdcache(char *, int);
+
+/*
+ * Upanic conditions, and a map from symbolics to values
+ */
+
+#define U_CORRUPTION 0001 /* upanic on data corruption */
+#define U_IOSW 0002 /* upanic on bad iosw */
+#define U_RVAL 0004 /* upanic on bad rval */
+
+#define U_ALL (U_CORRUPTION | U_IOSW | U_RVAL)
+
+/*
+ * Name-To-Value map
+ * Used to map cmdline arguments to values
+ */
+struct smap {
+ char *string;
+ int value;
+};
+
+struct smap Upanic_Args[] = {
+ { "corruption", U_CORRUPTION },
+ { "iosw", U_IOSW },
+ { "rval", U_RVAL },
+ { "all", U_ALL },
+ { NULL, 0 }
+};
+
+struct aio_info {
+ int busy;
+ int id;
+ int fd;
+ int strategy;
+ volatile int done;
+#ifdef CRAY
+ struct iosw iosw;
+#endif
+#ifdef sgi
+ aiocb_t aiocb;
+ int aio_ret; /* from aio_return */
+ int aio_errno; /* from aio_error */
+#endif
+ int sig;
+ int signalled;
+ struct sigaction osa;
+};
+
+struct aio_info Aio_Info[MAX_AIO];
+
+struct aio_info *aio_slot();
+int aio_done( struct aio_info * );
+
+/* -C data-fill/check type */
+#define C_DEFAULT 1
+struct smap checkmap[] = {
+ { "default", C_DEFAULT },
+ { NULL, 0 },
+};
+
+/* -d option delay types */
+#define DELAY_SELECT 1
+#define DELAY_SLEEP 2
+#define DELAY_SGINAP 3
+#define DELAY_ALARM 4
+#define DELAY_ITIMER 5 /* POSIX timer */
+
+struct smap delaymap[] = {
+ { "select", DELAY_SELECT },
+ { "sleep", DELAY_SLEEP },
+#ifdef sgi
+ { "sginap", DELAY_SGINAP },
+#endif
+ { "alarm", DELAY_ALARM },
+ { NULL, 0 },
+};
+
+/******
+*
+* strerror() does similar actions.
+
+char *
+syserrno(int err)
+{
+ static char sys_errno[10];
+ sprintf(sys_errno, "%d", errno);
+ return(sys_errno);
+}
+
+******/
+
+int
+main(argc, argv)
+int argc;
+char **argv;
+{
+ int i, pid, stat, ex_stat;
+#ifdef CRAY
+ sigset_t omask;
+#else
+ int omask;
+#endif
+ struct sigaction sa;
+
+ umask(0); /* force new file modes to known values */
+#if _CRAYMPP
+ Npes = sysconf(_SC_CRAY_NPES); /* must do this before parse_cmdline */
+ Vpe = sysconf(_SC_CRAY_VPE);
+#endif
+
+ TagName[0] = '\0';
+ parse_cmdline(argc, argv, OPTS);
+
+ random_range_seed(getpid()); /* initialize random number generator */
+
+ /*
+ * If this is a re-exec of doio, jump directly into the doio function.
+ */
+
+ if (Execd) {
+ doio();
+ exit(E_SETUP);
+ }
+
+ /*
+ * Stop on all but a few signals...
+ */
+ sigemptyset(&sa.sa_mask);
+ sa.sa_handler = sigint_handler;
+ sa.sa_flags = SA_RESETHAND; /* sigint is ignored after the */
+ /* first time */
+ for (i = 1; i <= NSIG; i++) {
+ switch(i) {
+#ifdef SIGRECOVERY
+ case SIGRECOVERY:
+ break;
+#endif
+#ifdef SIGCKPT
+ case SIGCKPT:
+#endif
+#ifdef SIGRESTART
+ case SIGRESTART:
+#endif
+ case SIGTSTP:
+ case SIGSTOP:
+ case SIGCONT:
+ case SIGCLD:
+ case SIGBUS:
+ case SIGSEGV:
+ case SIGQUIT:
+ break;
+ default:
+ sigaction(i, &sa, NULL);
+ }
+ }
+
+ /*
+ * If we're logging write operations, make a dummy call to wlog_open
+ * to initialize the write history file. This call must be done in
+ * the parent, to ensure that the history file exists and/or has
+ * been truncated before any children attempt to open it, as the doio
+ * children are not allowed to truncate the file.
+ */
+
+ if (w_opt) {
+ strcpy(Wlog.w_file, Write_Log);
+
+ if (wlog_open(&Wlog, 1, 0666) < 0) {
+ doio_fprintf(stderr,
+ "Could not create/truncate write log %s\n",
+ Write_Log);
+ exit(2);
+ }
+
+ wlog_close(&Wlog);
+ }
+
+ /*
+ * Malloc space for the children pid array. Initialize all entries
+ * to -1.
+ */
+
+ Children = (int *)malloc(sizeof(int) * Nprocs);
+ for (i = 0; i < Nprocs; i++) {
+ Children[i] = -1;
+ }
+
+ omask = sigblock(sigmask(SIGCLD));
+
+ /*
+ * Fork Nprocs. This [parent] process is a watchdog, to notify the
+ * invoker of procs which exit abnormally, and to make sure that all
+ * child procs get cleaned up. If the -e option was used, we will also
+ * re-exec. This is mostly for unicos/mk on mpp's, to ensure that not
+ * all of the doio's don't end up in the same pe.
+ *
+ * Note - if Nprocs is 1, or this doio is a multi-pe app (Npes > 1),
+ * jump directly to doio(). multi-pe apps can't fork(), and there is
+ * no reason to fork() for 1 proc.
+ */
+
+ if (Nprocs == 1 || Npes > 1) {
+ doio();
+ exit(0);
+ } else {
+ for (i = 0; i < Nprocs; i++) {
+ if ((pid = fork()) == -1) {
+ doio_fprintf(stderr,
+ "(parent) Could not fork %d children: %s (%d)\n",
+ i+1, SYSERR, errno);
+ exit(E_SETUP);
+ }
+
+ Children[Nchildren] = pid;
+ Nchildren++;
+
+ if (pid == 0) {
+ if (e_opt) {
+ char *exec_path;
+
+ exec_path = argv[0];
+ argv[0] = (char *)malloc(strlen(exec_path + 1));
+ sprintf(argv[0], "-%s", exec_path);
+
+ execvp(exec_path, argv);
+ doio_fprintf(stderr,
+ "(parent) Could not execvp %s: %s (%d)\n",
+ exec_path, SYSERR, errno);
+ exit(E_SETUP);
+ } else {
+ doio();
+ exit(E_SETUP);
+ }
+ }
+ }
+
+ /*
+ * Parent spins on wait(), until all children exit.
+ */
+
+ ex_stat = E_NORMAL;
+
+ while (Nprocs) {
+ if ((pid = wait(&stat)) == -1) {
+ if (errno == EINTR)
+ continue;
+ }
+
+ for (i = 0; i < Nchildren; i++)
+ if (Children[i] == pid)
+ Children[i] = -1;
+
+ Nprocs--;
+
+ if (WIFEXITED(stat)) {
+ switch (WEXITSTATUS(stat)) {
+ case E_NORMAL:
+ /* noop */
+ break;
+
+ case E_INTERNAL:
+ doio_fprintf(stderr,
+ "(parent) pid %d exited because of an internal error\n",
+ pid);
+ ex_stat |= E_INTERNAL;
+ break;
+
+ case E_SETUP:
+ doio_fprintf(stderr,
+ "(parent) pid %d exited because of a setup error\n",
+ pid);
+ ex_stat |= E_SETUP;
+ break;
+
+ case E_COMPARE:
+ doio_fprintf(stderr,
+ "(parent) pid %d exited because of data compare errors\n",
+ pid);
+
+ ex_stat |= E_COMPARE;
+
+ if (a_opt)
+ kill(0, SIGINT);
+
+ break;
+
+ case E_USAGE:
+ doio_fprintf(stderr,
+ "(parent) pid %d exited because of a usage error\n",
+ pid);
+
+ ex_stat |= E_USAGE;
+ break;
+
+ default:
+ doio_fprintf(stderr,
+ "(parent) pid %d exited with unknown status %d\n",
+ pid, WEXITSTATUS(stat));
+ ex_stat |= E_INTERNAL;
+ break;
+ }
+ } else if (WIFSIGNALED(stat) && WTERMSIG(stat) != SIGINT) {
+ doio_fprintf(stderr,
+ "(parent) pid %d terminated by signal %d\n",
+ pid, WTERMSIG(stat));
+
+ ex_stat |= E_SIGNAL;
+ }
+
+ fflush(NULL);
+ }
+ }
+
+ exit(ex_stat);
+
+} /* main */
+
+/*
+ * main doio function. Each doio child starts here, and never returns.
+ */
+
+void
+doio()
+{
+ int rval, i, infd, nbytes;
+ char *cp;
+ struct io_req ioreq;
+ struct sigaction sa, def_action, ignore_action, exit_action;
+#ifndef CRAY
+ struct sigaction sigbus_action;
+#endif
+
+ Memsize = Sdssize = 0;
+
+ /*
+ * Initialize the Pattern - write-type syscalls will replace Pattern[1]
+ * with the pattern passed in the request. Make sure that
+ * strlen(Pattern) is not mod 16 so that out of order words will be
+ * detected.
+ */
+
+ gethostname(Host, sizeof(Host));
+ if ((cp = strchr(Host, '.')) != NULL)
+ *cp = '\0';
+
+ Pattern_Length = sprintf(Pattern, "-:%d:%s:%s*", getpid(), Host, Prog);
+
+ if (!(Pattern_Length % 16)) {
+ Pattern_Length = sprintf(Pattern, "-:%d:%s:%s**",
+ getpid(), Host, Prog);
+ }
+
+ /*
+ * Open a couple of descriptors for the write-log file. One descriptor
+ * is for appending, one for random access. Write logging is done for
+ * file corruption detection. The program doio_check is capable of
+ * doing corruption detection based on a doio write-log.
+ */
+
+ if (w_opt) {
+
+ strcpy(Wlog.w_file, Write_Log);
+
+ if (wlog_open(&Wlog, 0, 0666) == -1) {
+ doio_fprintf(stderr,
+ "Could not open write log file (%s): wlog_open() failed\n",
+ Write_Log);
+ exit(E_SETUP);
+ }
+ }
+
+ /*
+ * Open the input stream - either a file or stdin
+ */
+
+ if (Infile == NULL) {
+ infd = 0;
+ } else {
+ if ((infd = open(Infile, O_RDWR)) == -1) {
+ doio_fprintf(stderr,
+ "Could not open input file (%s): %s (%d)\n",
+ Infile, SYSERR, errno);
+ exit(E_SETUP);
+ }
+ }
+
+ /*
+ * Define a set of signals that should never be masked. Receipt of
+ * these signals generally indicates a programming error, and we want
+ * a corefile at the point of error. We put SIGQUIT in this list so
+ * that ^\ will force a user core dump.
+ *
+ * Note: the handler for these should be SIG_DFL, all of them
+ * produce a corefile as the default action.
+ */
+
+ ignore_action.sa_handler = SIG_IGN;
+ ignore_action.sa_flags = 0;
+ sigemptyset(&ignore_action.sa_mask);
+
+ def_action.sa_handler = SIG_DFL;
+ def_action.sa_flags = 0;
+ sigemptyset(&def_action.sa_mask);
+
+#ifdef sgi
+ exit_action.sa_sigaction = cleanup_handler;
+ exit_action.sa_flags = SA_SIGINFO;
+ sigemptyset(&exit_action.sa_mask);
+
+ sa.sa_sigaction = die_handler;
+ sa.sa_flags = SA_SIGINFO;
+ sigemptyset(&sa.sa_mask);
+
+ sigbus_action.sa_sigaction = sigbus_handler;
+ sigbus_action.sa_flags = SA_SIGINFO;
+ sigemptyset(&sigbus_action.sa_mask);
+#else
+ exit_action.sa_handler = cleanup_handler;
+ exit_action.sa_flags = 0;
+ sigemptyset(&exit_action.sa_mask);
+
+ sa.sa_handler = die_handler;
+ sa.sa_flags = 0;
+ sigemptyset(&sa.sa_mask);
+
+#ifndef CRAY
+ sigbus_action.sa_handler = sigbus_handler;
+ sigbus_action.sa_flags = 0;
+ sigemptyset(&sigbus_action.sa_mask);
+#endif
+#endif
+
+ for (i = 1; i <= NSIG; i++) {
+ switch(i) {
+ /* Signals to terminate program on */
+ case SIGINT:
+ sigaction(i, &exit_action, NULL);
+ break;
+
+#ifndef CRAY
+ /* This depends on active_mmap_rw */
+ case SIGBUS:
+ sigaction(i, &sigbus_action, NULL);
+ break;
+#endif
+
+ /* Signals to Ignore... */
+ case SIGSTOP:
+ case SIGCONT:
+#ifdef SIGRECOVERY
+ case SIGRECOVERY:
+#endif
+ sigaction(i, &ignore_action, NULL);
+ break;
+
+ /* Signals to trap & report & die */
+ /*case SIGTRAP:*/
+ /*case SIGABRT:*/
+#ifdef SIGERR /* cray only signals */
+ case SIGERR:
+ case SIGBUFIO:
+ case SIGINFO:
+#endif
+ /*case SIGFPE:*/
+ case SIGURG:
+ case SIGHUP:
+ case SIGTERM:
+ case SIGPIPE:
+ case SIGIO:
+ case SIGUSR1:
+ case SIGUSR2:
+ sigaction(i, &sa, NULL);
+ break;
+
+
+ /* Default Action for all other signals */
+ default:
+ sigaction(i, &def_action, NULL);
+ break;
+ }
+ }
+
+ /*
+ * Main loop - each doio proc does this until the read returns eof (0).
+ * Call the appropriate io function based on the request type.
+ */
+
+ while ((nbytes = read(infd, (char *)&ioreq, sizeof(ioreq)))) {
+
+ /*
+ * Periodically check our ppid. If it is 1, the child exits to
+ * help clean up in the case that the main doio process was
+ * killed.
+ */
+
+ if (Reqno && ((Reqno % PPID_CHECK_INTERVAL) == 0)) {
+ if (getppid() == 1) {
+ doio_fprintf(stderr,
+ "Parent doio process has exited\n");
+ alloc_mem(-1);
+ exit(E_SETUP);
+ }
+ }
+
+ if (nbytes == -1) {
+ doio_fprintf(stderr,
+ "read of %d bytes from input failed: %s (%d)\n",
+ sizeof(ioreq), SYSERR, errno);
+ alloc_mem(-1);
+ exit(E_SETUP);
+ }
+
+ if (nbytes != sizeof(ioreq)) {
+ doio_fprintf(stderr,
+ "read wrong # bytes from input stream, expected %d, got %d\n",
+ sizeof(ioreq), nbytes);
+ alloc_mem(-1);
+ exit(E_SETUP);
+ }
+
+ if (ioreq.r_magic != DOIO_MAGIC) {
+ doio_fprintf(stderr,
+ "got a bad magic # from input stream. Expected 0%o, got 0%o\n",
+ DOIO_MAGIC, ioreq.r_magic);
+ alloc_mem(-1);
+ exit(E_SETUP);
+ }
+
+ /*
+ * If we're on a Release_Interval multiple, relase all ssd and
+ * core space, and close all fd's in Fd_Map[].
+ */
+
+ if (Reqno && Release_Interval && ! (Reqno%Release_Interval)) {
+ if (Memsize) {
+#ifdef NOTDEF
+ sbrk(-1 * Memsize);
+#else
+ alloc_mem(-1);
+#endif
+ }
+
+#ifdef _CRAY1
+ if (Sdssize) {
+ ssbreak(-1 * btoc(Sdssize));
+ Sdsptr = 0;
+ Sdssize = 0;
+ }
+#endif /* _CRAY1 */
+
+ alloc_fd(NULL, 0);
+ }
+
+ switch (ioreq.r_type) {
+ case READ:
+ case READA:
+ rval = do_read(&ioreq);
+ break;
+
+ case WRITE:
+ case WRITEA:
+ rval = do_write(&ioreq);
+ break;
+
+ case READV:
+ case AREAD:
+ case PREAD:
+ case LREAD:
+ case LREADA:
+ case LSREAD:
+ case LSREADA:
+ case WRITEV:
+ case AWRITE:
+ case PWRITE:
+ case MMAPR:
+ case MMAPW:
+ case LWRITE:
+ case LWRITEA:
+ case LSWRITE:
+ case LSWRITEA:
+ case LEREAD:
+ case LEREADA:
+ case LEWRITE:
+ case LEWRITEA:
+ rval = do_rw(&ioreq);
+ break;
+
+#ifdef CRAY
+ case SSREAD:
+ case SSWRITE:
+ rval = do_ssdio(&ioreq);
+ break;
+
+ case LISTIO:
+ rval = do_listio(&ioreq);
+ break;
+#endif
+
+#ifndef NO_XFS
+ case RESVSP:
+ case UNRESVSP:
+ rval = do_xfsctl(&ioreq);
+ break;
+#endif
+
+#ifndef CRAY
+ case FSYNC2:
+ case FDATASYNC:
+ rval = do_sync(&ioreq);
+ break;
+#endif
+ default:
+ doio_fprintf(stderr,
+ "Don't know how to handle io request type %d\n",
+ ioreq.r_type);
+ alloc_mem(-1);
+ exit(E_SETUP);
+ }
+
+ if (rval == SKIP_REQ){
+ Reqskipcnt++;
+ }
+ else if (rval != 0) {
+ alloc_mem(-1);
+ doio_fprintf(stderr,
+ "doio(): operation %d returned != 0\n",
+ ioreq.r_type);
+ exit(E_SETUP);
+ }
+
+ if (Message_Interval && Reqno % Message_Interval == 0) {
+ doio_fprintf(stderr, "Info: %d requests done (%d skipped) by this process\n", Reqno, Reqskipcnt);
+ }
+
+ Reqno++;
+
+ if(delayop != 0)
+ doio_delay();
+ }
+
+ /*
+ * Child exits normally
+ */
+ alloc_mem(-1);
+ exit(E_NORMAL);
+
+} /* doio */
+
+void
+doio_delay()
+{
+ struct timeval tv_delay;
+ struct sigaction sa_al, sa_old;
+ sigset_t al_mask;
+
+ switch(delayop) {
+ case DELAY_SELECT:
+ tv_delay.tv_sec = delaytime / 1000000;
+ tv_delay.tv_usec = delaytime % 1000000;
+ /*doio_fprintf(stdout, "delay_select: %d %d\n",
+ tv_delay.tv_sec, tv_delay.tv_usec);*/
+ select(0, NULL, NULL, NULL, &tv_delay);
+ break;
+
+ case DELAY_SLEEP:
+ sleep(delaytime);
+ break;
+
+#ifdef sgi
+ case DELAY_SGINAP:
+ sginap(delaytime);
+ break;
+#endif
+
+ case DELAY_ALARM:
+ sa_al.sa_flags = 0;
+ sa_al.sa_handler = noop_handler;
+ sigemptyset(&sa_al.sa_mask);
+ sigaction(SIGALRM, &sa_al, &sa_old);
+ sigemptyset(&al_mask);
+ alarm(delaytime);
+ sigsuspend(&al_mask);
+ sigaction(SIGALRM, &sa_old, 0);
+ break;
+ }
+}
+
+
+/*
+ * Format IO requests, returning a pointer to the formatted text.
+ *
+ * format_strat - formats the async i/o completion strategy
+ * format_rw - formats a read[a]/write[a] request
+ * format_sds - formats a ssread/sswrite request
+ * format_listio- formats a listio request
+ *
+ * ioreq is the doio io request structure.
+ */
+
+struct smap sysnames[] = {
+ { "READ", READ },
+ { "WRITE", WRITE },
+ { "READA", READA },
+ { "WRITEA", WRITEA },
+ { "SSREAD", SSREAD },
+ { "SSWRITE", SSWRITE },
+ { "LISTIO", LISTIO },
+ { "LREAD", LREAD },
+ { "LREADA", LREADA },
+ { "LWRITE", LWRITE },
+ { "LWRITEA", LWRITEA },
+ { "LSREAD", LSREAD },
+ { "LSREADA", LSREADA },
+ { "LSWRITE", LSWRITE },
+ { "LSWRITEA", LSWRITEA },
+
+ /* Irix System Calls */
+ { "PREAD", PREAD },
+ { "PWRITE", PWRITE },
+ { "AREAD", AREAD },
+ { "AWRITE", AWRITE },
+ { "LLREAD", LLREAD },
+ { "LLAREAD", LLAREAD },
+ { "LLWRITE", LLWRITE },
+ { "LLAWRITE", LLAWRITE },
+ { "RESVSP", RESVSP },
+ { "UNRESVSP", UNRESVSP },
+
+ /* Irix and Linux System Calls */
+ { "READV", READV },
+ { "WRITEV", WRITEV },
+ { "MMAPR", MMAPR },
+ { "MMAPW", MMAPW },
+ { "FSYNC2", FSYNC2 },
+ { "FDATASYNC", FDATASYNC },
+
+ { "unknown", -1 },
+};
+
+struct smap aionames[] = {
+ { "poll", A_POLL },
+ { "signal", A_SIGNAL },
+ { "recall", A_RECALL },
+ { "recalla", A_RECALLA },
+ { "recalls", A_RECALLS },
+ { "suspend", A_SUSPEND },
+ { "callback", A_CALLBACK },
+ { "synch", 0 },
+ { "unknown", -1 },
+};
+
+char *
+format_oflags(int oflags)
+{
+ char flags[255];
+
+
+ flags[0]='\0';
+ switch(oflags & 03) {
+ case O_RDONLY: strcat(flags,"O_RDONLY,"); break;
+ case O_WRONLY: strcat(flags,"O_WRONLY,"); break;
+ case O_RDWR: strcat(flags,"O_RDWR,"); break;
+ default: strcat(flags,"O_weird"); break;
+ }
+
+ if(oflags & O_EXCL)
+ strcat(flags,"O_EXCL,");
+
+ if(oflags & O_SYNC)
+ strcat(flags,"O_SYNC,");
+#ifdef CRAY
+ if(oflags & O_RAW)
+ strcat(flags,"O_RAW,");
+ if(oflags & O_WELLFORMED)
+ strcat(flags,"O_WELLFORMED,");
+#ifdef O_SSD
+ if(oflags & O_SSD)
+ strcat(flags,"O_SSD,");
+#endif
+ if(oflags & O_LDRAW)
+ strcat(flags,"O_LDRAW,");
+ if(oflags & O_PARALLEL)
+ strcat(flags,"O_PARALLEL,");
+ if(oflags & O_BIG)
+ strcat(flags,"O_BIG,");
+ if(oflags & O_PLACE)
+ strcat(flags,"O_PLACE,");
+ if(oflags & O_ASYNC)
+ strcat(flags,"O_ASYNC,");
+#endif
+
+ if(oflags & O_DIRECT)
+ strcat(flags,"O_DIRECT,");
+#ifdef sgi
+ if(oflags & O_DSYNC)
+ strcat(flags,"O_DSYNC,");
+ if(oflags & O_RSYNC)
+ strcat(flags,"O_RSYNC,");
+#endif
+
+ return(strdup(flags));
+}
+
+char *
+format_strat(int strategy)
+{
+ char msg[64];
+ char *aio_strat;
+
+ switch (strategy) {
+ case A_POLL: aio_strat = "POLL"; break;
+ case A_SIGNAL: aio_strat = "SIGNAL"; break;
+ case A_RECALL: aio_strat = "RECALL"; break;
+ case A_RECALLA: aio_strat = "RECALLA"; break;
+ case A_RECALLS: aio_strat = "RECALLS"; break;
+ case A_SUSPEND: aio_strat = "SUSPEND"; break;
+ case A_CALLBACK: aio_strat = "CALLBACK"; break;
+ case 0: aio_strat = "<zero>"; break;
+ default:
+ sprintf(msg, "<error:%#o>", strategy);
+ aio_strat = strdup(msg);
+ break;
+ }
+
+ return(aio_strat);
+}
+
+char *
+format_rw(
+ struct io_req *ioreq,
+ int fd,
+ void *buffer,
+ int signo,
+ char *pattern,
+#ifdef CRAY
+ struct iosw *iosw
+#else
+ void *iosw
+#endif
+ )
+{
+ static char *errbuf=NULL;
+ char *aio_strat, *cp;
+ struct read_req *readp = &ioreq->r_data.read;
+ struct write_req *writep = &ioreq->r_data.write;
+ struct read_req *readap = &ioreq->r_data.read;
+ struct write_req *writeap = &ioreq->r_data.write;
+
+ if(errbuf == NULL)
+ errbuf = (char *)malloc(32768);
+
+ cp = errbuf;
+ cp += sprintf(cp, "Request number %d\n", Reqno);
+
+ switch (ioreq->r_type) {
+ case READ:
+ cp += sprintf(cp, "syscall: read(%d, %#lo, %d)\n",
+ fd, (unsigned long) buffer, readp->r_nbytes);
+ cp += sprintf(cp, " fd %d is file %s - open flags are %#o\n",
+ fd, readp->r_file, readp->r_oflags);
+ cp += sprintf(cp, " read done at file offset %d\n",
+ readp->r_offset);
+ break;
+
+ case WRITE:
+ cp += sprintf(cp, "syscall: write(%d, %#lo, %d)\n",
+ fd, (unsigned long) buffer, writep->r_nbytes);
+ cp += sprintf(cp, " fd %d is file %s - open flags are %#o\n",
+ fd, writep->r_file, writep->r_oflags);
+ cp += sprintf(cp, " write done at file offset %d - pattern is %s\n",
+ writep->r_offset, pattern);
+ break;
+
+ case READA:
+ aio_strat = format_strat(readap->r_aio_strat);
+
+ cp += sprintf(cp, "syscall: reada(%d, %#lo, %d, %#lo, %d)\n",
+ fd, (unsigned long) buffer, readap->r_nbytes,
+ (unsigned long) iosw, signo);
+ cp += sprintf(cp, " fd %d is file %s - open flags are %#o\n",
+ fd, readap->r_file, readp->r_oflags);
+ cp += sprintf(cp, " reada done at file offset %d\n",
+ readap->r_offset);
+ cp += sprintf(cp, " async io completion strategy is %s\n",
+ aio_strat);
+ break;
+
+ case WRITEA:
+ aio_strat = format_strat(writeap->r_aio_strat);
+
+ cp += sprintf(cp, "syscall: writea(%d, %#lo, %d, %#lo, %d)\n",
+ fd, (unsigned long) buffer, writeap->r_nbytes,
+ (unsigned long) iosw, signo);
+ cp += sprintf(cp, " fd %d is file %s - open flags are %#o\n",
+ fd, writeap->r_file, writeap->r_oflags);
+ cp += sprintf(cp, " writea done at file offset %d - pattern is %s\n",
+ writeap->r_offset, pattern);
+ cp += sprintf(cp, " async io completion strategy is %s\n",
+ aio_strat);
+ break;
+
+ }
+
+ return errbuf;
+}
+
+#ifdef CRAY
+char *
+format_sds(
+ struct io_req *ioreq,
+ void *buffer,
+ int sds,
+ char *pattern
+ )
+{
+ int i;
+ static char *errbuf=NULL;
+ char *cp;
+
+ struct ssread_req *ssreadp = &ioreq->r_data.ssread;
+ struct sswrite_req *sswritep = &ioreq->r_data.sswrite;
+
+ if(errbuf == NULL)
+ errbuf = (char *)malloc(32768);
+
+ cp = errbuf;
+ cp += sprintf(cp, "Request number %d\n", Reqno);
+
+
+ switch (ioreq->r_type) {
+ case SSREAD:
+ cp += sprintf(cp, "syscall: ssread(%#o, %#o, %d)\n",
+ buffer, sds, ssreadp->r_nbytes);
+ break;
+
+ case SSWRITE:
+ cp += sprintf(cp, "syscall: sswrite(%#o, %#o, %d) - pattern was %s\n",
+ buffer, sds, sswritep->r_nbytes, pattern);
+ break;
+ }
+ return errbuf;
+}
+#endif /* CRAY */
+
+/*
+ * Perform the various sorts of disk reads
+ */
+
+int
+do_read(req)
+struct io_req *req;
+{
+ int fd, offset, nbytes, oflags, rval;
+ char *addr, *file;
+#ifdef CRAY
+ struct aio_info *aiop;
+ int aio_id, aio_strat, signo;
+#endif
+#ifndef NO_XFS
+ struct fd_cache *fdc;
+#endif
+
+ /*
+ * Initialize common fields - assumes r_oflags, r_file, r_offset, and
+ * r_nbytes are at the same offset in the read_req and reada_req
+ * structures.
+ */
+
+ file = req->r_data.read.r_file;
+ oflags = req->r_data.read.r_oflags;
+ offset = req->r_data.read.r_offset;
+ nbytes = req->r_data.read.r_nbytes;
+
+ /*printf("read: %s, %#o, %d %d\n", file, oflags, offset, nbytes);*/
+
+ /*
+ * Grab an open file descriptor
+ * Note: must be done before memory allocation so that the direct i/o
+ * information is available in mem. allocate
+ */
+
+ if ((fd = alloc_fd(file, oflags)) == -1)
+ return -1;
+
+ /*
+ * Allocate core or sds - based on the O_SSD flag
+ */
+
+#ifndef wtob
+#define wtob(x) (x * sizeof(UINT64_T))
+#endif
+
+#ifdef CRAY
+ if (oflags & O_SSD) {
+ if (alloc_sds(nbytes) == -1)
+ return -1;
+
+ addr = (char *)Sdsptr;
+ } else {
+ if ((rval = alloc_mem(nbytes + wtob(1) * 2 + MPP_BUMP * sizeof(UINT64_T))) < 0) {
+ return rval;
+ }
+
+ addr = Memptr;
+
+ /*
+ * if io is not raw, bump the offset by a random amount
+ * to generate non-word-aligned io.
+ */
+ if (! (req->r_data.read.r_uflags & F_WORD_ALIGNED)) {
+ addr += random_range(0, wtob(1) - 1, 1, NULL);
+ }
+ }
+#else
+#ifndef NO_XFS
+ /* get memory alignment for using DIRECT I/O */
+ fdc = alloc_fdcache(file, oflags);
+
+ if ((rval = alloc_mem(nbytes + wtob(1) * 2 + fdc->c_memalign)) < 0) {
+ return rval;
+ }
+
+ addr = Memptr;
+
+
+ if( (req->r_data.read.r_uflags & F_WORD_ALIGNED) ) {
+ /*
+ * Force memory alignment for Direct I/O
+ */
+ if( (oflags & O_DIRECT) && ((long)addr % fdc->c_memalign != 0) ) {
+ addr += fdc->c_memalign - ((long)addr % fdc->c_memalign);
+ }
+ } else {
+ addr += random_range(0, wtob(1) - 1, 1, NULL);
+ }
+#else
+ if ((rval = alloc_mem(nbytes + wtob(1) * 2)) < 0) {
+ return rval;
+ }
+
+ addr = Memptr;
+#endif /* !CRAY && sgi */
+#endif /* CRAY */
+
+
+ switch (req->r_type) {
+ case READ:
+ /* move to the desired file position. */
+ if (lseek(fd, offset, SEEK_SET) == -1) {
+ doio_fprintf(stderr,
+ "lseek(%d, %d, SEEK_SET) failed: %s (%d)\n",
+ fd, offset, SYSERR, errno);
+ return -1;
+ }
+
+ if ((rval = read(fd, addr, nbytes)) == -1) {
+ doio_fprintf(stderr,
+ "read() request failed: %s (%d)\n%s\n",
+ SYSERR, errno,
+ format_rw(req, fd, addr, -1, NULL, NULL));
+ doio_upanic(U_RVAL);
+ return -1;
+ } else if (rval != nbytes) {
+ doio_fprintf(stderr,
+ "read() request returned wrong # of bytes - expected %d, got %d\n%s\n",
+ nbytes, rval,
+ format_rw(req, fd, addr, -1, NULL, NULL));
+ doio_upanic(U_RVAL);
+ return -1;
+ }
+ break;
+
+#ifdef CRAY
+ case READA:
+ /*
+ * Async read
+ */
+
+ /* move to the desired file position. */
+ if (lseek(fd, offset, SEEK_SET) == -1) {
+ doio_fprintf(stderr,
+ "lseek(%d, %d, SEEK_SET) failed: %s (%d)\n",
+ fd, offset, SYSERR, errno);
+ return -1;
+ }
+
+ aio_strat = req->r_data.read.r_aio_strat;
+ signo = (aio_strat == A_SIGNAL) ? SIGUSR1 : 0;
+
+ aio_id = aio_register(fd, aio_strat, signo);
+ aiop = aio_slot(aio_id);
+
+ if (reada(fd, addr, nbytes, &aiop->iosw, signo) == -1) {
+ doio_fprintf(stderr, "reada() failed: %s (%d)\n%s\n",
+ SYSERR, errno,
+ format_rw(req, fd, addr, signo, NULL, &aiop->iosw));
+ aio_unregister(aio_id);
+ doio_upanic(U_RVAL);
+ rval = -1;
+ } else {
+ /*
+ * Wait for io to complete
+ */
+
+ aio_wait(aio_id);
+
+ /*
+ * make sure the io completed without error
+ */
+
+ if (aiop->iosw.sw_count != nbytes) {
+ doio_fprintf(stderr,
+ "Bad iosw from reada()\nExpected (%d,%d,%d), got (%d,%d,%d)\n%s\n",
+ 1, 0, nbytes,
+ aiop->iosw.sw_flag,
+ aiop->iosw.sw_error,
+ aiop->iosw.sw_count,
+ format_rw(req, fd, addr, signo, NULL, &aiop->iosw));
+ aio_unregister(aio_id);
+ doio_upanic(U_IOSW);
+ rval = -1;
+ } else {
+ aio_unregister(aio_id);
+ rval = 0;
+ }
+ }
+
+ if (rval == -1)
+ return rval;
+ break;
+#endif /* CRAY */
+ }
+
+ return 0; /* if we get here, everything went ok */
+}
+
+/*
+ * Perform the verious types of disk writes.
+ */
+
+int
+do_write(req)
+struct io_req *req;
+{
+ static int pid = -1;
+ int fd, nbytes, oflags, signo;
+ int logged_write, rval, got_lock;
+ long offset, woffset = 0;
+ char *addr, pattern, *file, *msg;
+ struct wlog_rec wrec;
+#ifdef CRAY
+ int aio_strat, aio_id;
+ struct aio_info *aiop;
+#endif
+#ifndef NO_XFS
+ struct fd_cache *fdc;
+#endif
+
+ /*
+ * Misc variable setup
+ */
+
+ signo = 0;
+ nbytes = req->r_data.write.r_nbytes;
+ offset = req->r_data.write.r_offset;
+ pattern = req->r_data.write.r_pattern;
+ file = req->r_data.write.r_file;
+ oflags = req->r_data.write.r_oflags;
+
+ /*printf("pwrite: %s, %#o, %d %d\n", file, oflags, offset, nbytes);*/
+
+ /*
+ * Allocate core memory and possibly sds space. Initialize the data
+ * to be written.
+ */
+
+ Pattern[0] = pattern;
+
+
+ /*
+ * Get a descriptor to do the io on
+ */
+
+ if ((fd = alloc_fd(file, oflags)) == -1)
+ return -1;
+
+ /*printf("write: %d, %s, %#o, %d %d\n",
+ fd, file, oflags, offset, nbytes);*/
+
+ /*
+ * Allocate SDS space for backdoor write if desired
+ */
+
+#ifdef CRAY
+ if (oflags & O_SSD) {
+#ifndef _CRAYMPP
+ if ((rval = alloc_mem(nbytes + wtob(1))) < 0) {
+ return rval;
+ }
+
+ (*Data_Fill)(Memptr, nbytes, Pattern, Pattern_Length, 0);
+ /*pattern_fill(Memptr, nbytes, Pattern, Pattern_Length, 0);*/
+
+ if (alloc_sds(nbytes) == -1)
+ return -1;
+
+ if (sswrite((long)Memptr, Sdsptr, btoc(nbytes)) == -1) {
+ doio_fprintf(stderr, "sswrite(%d, %d, %d) failed: %s (%d)\n",
+ (long)Memptr, Sdsptr, btoc(nbytes),
+ SYSERR, errno);
+ fflush(stderr);
+ return -1;
+ }
+
+ addr = (char *)Sdsptr;
+#else
+ doio_fprintf(stderr, "Invalid O_SSD flag was generated for MPP system\n");
+ fflush(stderr);
+ return -1;
+#endif /* !CRAYMPP */
+ } else {
+ if ((rval = alloc_mem(nbytes + wtob(1)) < 0)) {
+ return rval;
+ }
+
+ addr = Memptr;
+
+ /*
+ * if io is not raw, bump the offset by a random amount
+ * to generate non-word-aligned io.
+ */
+
+ if (! (req->r_data.write.r_uflags & F_WORD_ALIGNED)) {
+ addr += random_range(0, wtob(1) - 1, 1, NULL);
+ }
+
+ (*Data_Fill)(Memptr, nbytes, Pattern, Pattern_Length, 0);
+ if( addr != Memptr )
+ memmove( addr, Memptr, nbytes);
+ }
+#else /* CRAY */
+#ifndef NO_XFS
+ /* get memory alignment for using DIRECT I/O */
+ fdc = alloc_fdcache(file, oflags);
+
+ if ((rval = alloc_mem(nbytes + wtob(1) * 2 + fdc->c_memalign)) < 0) {
+ return rval;
+ }
+
+ addr = Memptr;
+
+ if( (req->r_data.write.r_uflags & F_WORD_ALIGNED) ) {
+ /*
+ * Force memory alignment for Direct I/O
+ */
+ if( (oflags & O_DIRECT) && ((long)addr % fdc->c_memalign != 0) ) {
+ addr += fdc->c_memalign - ((long)addr % fdc->c_memalign);
+ }
+ } else {
+ addr += random_range(0, wtob(1) - 1, 1, NULL);
+ }
+
+ (*Data_Fill)(Memptr, nbytes, Pattern, Pattern_Length, 0);
+ if( addr != Memptr )
+ memmove( addr, Memptr, nbytes);
+
+#else /* sgi */
+ if ((rval = alloc_mem(nbytes + wtob(1) * 2)) < 0) {
+ return rval;
+ }
+
+ addr = Memptr;
+
+ (*Data_Fill)(Memptr, nbytes, Pattern, Pattern_Length, 0);
+ if( addr != Memptr )
+ memmove( addr, Memptr, nbytes);
+#endif /* sgi */
+#endif /* CRAY */
+
+ rval = -1;
+ got_lock = 0;
+ logged_write = 0;
+
+ if (k_opt) {
+ if (lock_file_region(file, fd, F_WRLCK, offset, nbytes) < 0) {
+ alloc_mem(-1);
+ exit(E_INTERNAL);
+ }
+
+ got_lock = 1;
+ }
+
+ /*
+ * Write a preliminary write-log entry. This is done so that
+ * doio_check can do corruption detection across an interrupt/crash.
+ * Note that w_done is set to 0. If doio_check sees this, it
+ * re-creates the file extents as if the write completed, but does not
+ * do any checking - see comments in doio_check for more details.
+ */
+
+ if (w_opt) {
+ if (pid == -1) {
+ pid = getpid();
+ }
+ wrec.w_async = (req->r_type == WRITEA) ? 1 : 0;
+ wrec.w_oflags = oflags;
+ wrec.w_pid = pid;
+ wrec.w_offset = offset;
+ wrec.w_nbytes = nbytes;
+
+ wrec.w_pathlen = strlen(file);
+ memcpy(wrec.w_path, file, wrec.w_pathlen);
+ wrec.w_hostlen = strlen(Host);
+ memcpy(wrec.w_host, Host, wrec.w_hostlen);
+ wrec.w_patternlen = Pattern_Length;
+ memcpy(wrec.w_pattern, Pattern, wrec.w_patternlen);
+
+ wrec.w_done = 0;
+
+ if ((woffset = wlog_record_write(&Wlog, &wrec, -1)) == -1) {
+ doio_fprintf(stderr,
+ "Could not append to write-log: %s (%d)\n",
+ SYSERR, errno);
+ } else {
+ logged_write = 1;
+ }
+ }
+
+ switch (req->r_type ) {
+ case WRITE:
+ /*
+ * sync write
+ */
+
+ if (lseek(fd, offset, SEEK_SET) == -1) {
+ doio_fprintf(stderr,
+ "lseek(%d, %d, SEEK_SET) failed: %s (%d)\n",
+ fd, offset, SYSERR, errno);
+ return -1;
+ }
+
+ rval = write(fd, addr, nbytes);
+
+ if (rval == -1) {
+ doio_fprintf(stderr,
+ "write() failed: %s (%d)\n%s\n",
+ SYSERR, errno,
+ format_rw(req, fd, addr, -1, Pattern, NULL));
+#ifndef NO_XFS
+ doio_fprintf(stderr,
+ "write() failed: %s\n\twrite(%d, %#o, %d)\n\toffset %d, nbytes%%miniou(%d)=%d, oflags=%#o memalign=%d, addr%%memalign=%d\n",
+ strerror(errno),
+ fd, addr, nbytes,
+ offset,
+ fdc->c_miniosz, nbytes%fdc->c_miniosz,
+ oflags, fdc->c_memalign, (long)addr%fdc->c_memalign);
+#else
+ doio_fprintf(stderr,
+ "write() failed: %s\n\twrite(%d, %#o, %d)\n\toffset %d, nbytes%%1B=%d, oflags=%#o\n",
+ strerror(errno),
+ fd, addr, nbytes,
+ offset, nbytes%4096, oflags);
+#endif
+ doio_upanic(U_RVAL);
+ } else if (rval != nbytes) {
+ doio_fprintf(stderr,
+ "write() returned wrong # bytes - expected %d, got %d\n%s\n",
+ nbytes, rval,
+ format_rw(req, fd, addr, -1, Pattern, NULL));
+ doio_upanic(U_RVAL);
+ rval = -1;
+ }
+
+ break;
+
+#ifdef CRAY
+ case WRITEA:
+ /*
+ * async write
+ */
+ if (lseek(fd, offset, SEEK_SET) == -1) {
+ doio_fprintf(stderr,
+ "lseek(%d, %d, SEEK_SET) failed: %s (%d)\n",
+ fd, offset, SYSERR, errno);
+ return -1;
+ }
+
+ aio_strat = req->r_data.write.r_aio_strat;
+ signo = (aio_strat == A_SIGNAL) ? SIGUSR1 : 0;
+
+ aio_id = aio_register(fd, aio_strat, signo);
+ aiop = aio_slot(aio_id);
+
+ /*
+ * init iosw and do the async write
+ */
+
+ if (writea(fd, addr, nbytes, &aiop->iosw, signo) == -1) {
+ doio_fprintf(stderr,
+ "writea() failed: %s (%d)\n%s\n",
+ SYSERR, errno,
+ format_rw(req, fd, addr, -1, Pattern, NULL));
+ doio_upanic(U_RVAL);
+ aio_unregister(aio_id);
+ rval = -1;
+ } else {
+
+ /*
+ * Wait for io to complete
+ */
+
+ aio_wait(aio_id);
+
+ /*
+ * check that iosw is ok
+ */
+
+ if (aiop->iosw.sw_count != nbytes) {
+ doio_fprintf(stderr,
+ "Bad iosw from writea()\nExpected (%d,%d,%d), got (%d,%d,%d)\n%s\n",
+ 1, 0, nbytes,
+ aiop->iosw.sw_flag,
+ aiop->iosw.sw_error,
+ aiop->iosw.sw_count,
+ format_rw(req, fd, addr, -1, Pattern, &aiop->iosw));
+ aio_unregister(aio_id);
+ doio_upanic(U_IOSW);
+ rval = -1;
+ } else {
+ aio_unregister(aio_id);
+ rval = 0;
+ }
+ }
+ break;
+
+#endif /* CRAY */
+ }
+
+ /*
+ * Verify that the data was written correctly - check_file() returns
+ * a non-null pointer which contains an error message if there are
+ * problems.
+ */
+
+ if (v_opt) {
+ msg = check_file(file, offset, nbytes, Pattern, Pattern_Length,
+ 0, oflags & O_PARALLEL);
+ if (msg != NULL) {
+ doio_fprintf(stderr, "%s%s\n",
+ msg,
+#ifdef CRAY
+ format_rw(req, fd, addr, -1, Pattern, &aiop->iosw)
+#else
+ format_rw(req, fd, addr, -1, Pattern, NULL)
+#endif
+ );
+ doio_upanic(U_CORRUPTION);
+ exit(E_COMPARE);
+
+ }
+ }
+
+ /*
+ * General cleanup ...
+ *
+ * Write extent information to the write-log, so that doio_check can do
+ * corruption detection. Note that w_done is set to 1, indicating that
+ * the write has been verified as complete. We don't need to write the
+ * filename on the second logging.
+ */
+
+ if (w_opt && logged_write) {
+ wrec.w_done = 1;
+ wlog_record_write(&Wlog, &wrec, woffset);
+ }
+
+ /*
+ * Unlock file region if necessary
+ */
+
+ if (got_lock) {
+ if (lock_file_region(file, fd, F_UNLCK, offset, nbytes) < 0) {
+ alloc_mem(-1);
+ exit(E_INTERNAL);
+ }
+ }
+
+ return( (rval == -1) ? -1 : 0);
+}
+
+
+/*
+ * Simple routine to lock/unlock a file using fcntl()
+ */
+
+int
+lock_file_region(fname, fd, type, start, nbytes)
+char *fname;
+int fd;
+int type;
+int start;
+int nbytes;
+{
+ struct flock flk;
+
+ flk.l_type = type;
+ flk.l_whence = 0;
+ flk.l_start = start;
+ flk.l_len = nbytes;
+
+ if (fcntl(fd, F_SETLKW, &flk) < 0) {
+ doio_fprintf(stderr,
+ "fcntl(%d, %d, %#o) failed for file %s, lock type %d, offset %d, length %d: %s (%d), open flags: %#o\n",
+ fd, F_SETLKW, &flk, fname, type,
+ start, nbytes, SYSERR, errno,
+ fcntl(fd, F_GETFL, 0));
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * Perform a listio request.
+ */
+
+#ifdef CRAY
+char *
+format_listio(
+ struct io_req *ioreq,
+ int lcmd,
+ struct listreq *list,
+ int nent,
+ int fd,
+ char *pattern
+ )
+{
+ static char *errbuf=NULL;
+ struct listio_req *liop = &ioreq->r_data.listio;
+ struct listreq *listreq;
+ char *cp, *cmd, *opcode, *aio_strat;
+ int i;
+
+ switch (lcmd) {
+ case LC_START: cmd = "LC_START"; break;
+ case LC_WAIT: cmd = "LC_WAIT"; break;
+ default: cmd = "???"; break;
+ }
+
+ if(errbuf == NULL)
+ errbuf = (char *)malloc(32768);
+
+ cp = errbuf;
+ cp += sprintf(cp, "Request number %d\n", Reqno);
+
+ cp += sprintf(cp, "syscall: listio(%s, %#o, %d)\n\n",
+ cmd, list, nent);
+
+ aio_strat = format_strat(liop->r_aio_strat);
+
+ for (i = 0; i < nent; i++) {
+ cp += sprintf(cp, "struct lioreq for request element %d\n", i);
+ cp += sprintf(cp, "----------------------------------------\n");
+
+ listreq = list + i;
+
+ switch (listreq->li_opcode) {
+ case LO_READ: opcode = "LO_READ"; break;
+ case LO_WRITE: opcode = "LO_WRITE"; break;
+ default: opcode = "???"; break;
+ }
+
+ cp += sprintf(cp, " li_opcode = %s\n", opcode);
+ cp += sprintf(cp, " li_drvr = %#o\n", listreq->li_drvr);
+ cp += sprintf(cp, " li_flags = %#o\n", listreq->li_flags);
+ cp += sprintf(cp, " li_offset = %d\n", listreq->li_offset);
+ cp += sprintf(cp, " li_fildes = %d\n", listreq->li_fildes);
+ cp += sprintf(cp, " li_buf = %#o\n", listreq->li_buf);
+ cp += sprintf(cp, " li_nbyte = %d\n", listreq->li_nbyte);
+ cp += sprintf(cp, " li_status = %#o (%d, %d, %d)\n", listreq->li_status, listreq->li_status->sw_flag, listreq->li_status->sw_error, listreq->li_status->sw_count);
+ cp += sprintf(cp, " li_signo = %d\n", listreq->li_signo);
+ cp += sprintf(cp, " li_nstride = %d\n", listreq->li_nstride);
+ cp += sprintf(cp, " li_filstride = %d\n", listreq->li_filstride);
+ cp += sprintf(cp, " li_memstride = %d\n", listreq->li_memstride);
+ cp += sprintf(cp, " io completion strategy is %s\n", aio_strat);
+ }
+ return errbuf;
+}
+#endif /* CRAY */
+
+int
+do_listio(req)
+struct io_req *req;
+{
+#ifdef CRAY
+ struct listio_req *lio;
+ int fd, oflags, signo, nb, i;
+ int logged_write, rval, got_lock;
+ int aio_strat, aio_id;
+ int min_byte, max_byte;
+ int mem_needed;
+ int foffset, fstride, mstride, nstrides;
+ char *moffset;
+ long offset, woffset;
+ char *addr, *msg;
+ sigset_t block_mask, omask;
+ struct wlog_rec wrec;
+ struct aio_info *aiop;
+ struct listreq lio_req;
+
+ lio = &req->r_data.listio;
+
+ /*
+ * If bytes per stride is less than the stride size, drop the request
+ * since it will cause overlapping strides, and we cannot predict
+ * the order they will complete in.
+ */
+
+ if (lio->r_filestride && abs(lio->r_filestride) < lio->r_nbytes) {
+ doio_fprintf(stderr, "do_listio(): Bogus listio request - abs(filestride) [%d] < nbytes [%d]\n",
+ abs(lio->r_filestride), lio->r_nbytes);
+ return -1;
+ }
+
+ /*
+ * Allocate core memory. Initialize the data to be written. Make
+ * sure we get enough, based on the memstride.
+ */
+
+ mem_needed =
+ stride_bounds(0, lio->r_memstride, lio->r_nstrides,
+ lio->r_nbytes, NULL, NULL);
+
+ if ((rval = alloc_mem(mem_needed + wtob(1))) < 0) {
+ return rval;
+ }
+
+ /*
+ * Set the memory address pointer. If the io is not raw, adjust
+ * addr by a random amount, so that non-raw io is not necessarily
+ * word aligned.
+ */
+
+ addr = Memptr;
+
+ if (! (lio->r_uflags & F_WORD_ALIGNED)) {
+ addr += random_range(0, wtob(1) - 1, 1, NULL);
+ }
+
+ if (lio->r_opcode == LO_WRITE) {
+ Pattern[0] = lio->r_pattern;
+ (*Data_Fill)(Memptr, mem_needed, Pattern, Pattern_Length, 0);
+ if( addr != Memptr )
+ memmove( addr, Memptr, mem_needed);
+ }
+
+ /*
+ * Get a descriptor to do the io on. No need to do an lseek, as this
+ * is encoded in the listio request.
+ */
+
+ if ((fd = alloc_fd(lio->r_file, lio->r_oflags)) == -1) {
+ return -1;
+ }
+
+ rval = -1;
+ got_lock = 0;
+ logged_write = 0;
+
+ /*
+ * If the opcode is LO_WRITE, lock all regions of the file that
+ * are touched by this listio request. Currently, we use
+ * stride_bounds() to figure out the min and max bytes affected, and
+ * lock the entire region, regardless of the file stride.
+ */
+
+ if (lio->r_opcode == LO_WRITE && k_opt) {
+ stride_bounds(lio->r_offset,
+ lio->r_filestride, lio->r_nstrides,
+ lio->r_nbytes, &min_byte, &max_byte);
+
+ if (lock_file_region(lio->r_file, fd, F_WRLCK,
+ min_byte, (max_byte-min_byte+1)) < 0) {
+ doio_fprintf(stderr, "stride_bounds(%d, %d, %d, %d, ..., ...) set min_byte to %d, max_byte to %d\n",
+ lio->r_offset, lio->r_filestride,
+ lio->r_nstrides, lio->r_nbytes, min_byte,
+ max_byte);
+ return -1;
+ } else {
+ got_lock = 1;
+ }
+ }
+
+ /*
+ * async write
+ */
+
+ aio_strat = lio->r_aio_strat;
+ signo = (aio_strat == A_SIGNAL) ? SIGUSR1 : 0;
+
+ aio_id = aio_register(fd, aio_strat, signo);
+ aiop = aio_slot(aio_id);
+
+ /*
+ * Form the listio request, and make the call.
+ */
+
+ lio_req.li_opcode = lio->r_opcode;
+ lio_req.li_drvr = 0;
+ lio_req.li_flags = LF_LSEEK;
+ lio_req.li_offset = lio->r_offset;
+ lio_req.li_fildes = fd;
+
+ if (lio->r_memstride >= 0 || lio->r_nstrides <= 1) {
+ lio_req.li_buf = addr;
+ } else {
+ lio_req.li_buf = addr + mem_needed - lio->r_nbytes;
+ }
+
+ lio_req.li_nbyte = lio->r_nbytes;
+ lio_req.li_status = &aiop->iosw;
+ lio_req.li_signo = signo;
+ lio_req.li_nstride = lio->r_nstrides;
+ lio_req.li_filstride = lio->r_filestride;
+ lio_req.li_memstride = lio->r_memstride;
+
+ /*
+ * If signo != 0, block signo while we're in the system call, so that
+ * we don't get interrupted syscall failures.
+ */
+
+ if (signo) {
+ sigemptyset(&block_mask);
+ sigaddset(&block_mask, signo);
+ sigprocmask(SIG_BLOCK, &block_mask, &omask);
+ }
+
+ if (listio(lio->r_cmd, &lio_req, 1) < 0) {
+ doio_fprintf(stderr,
+ "listio() failed: %s (%d)\n%s\n",
+ SYSERR, errno,
+ format_listio(req, lio->r_cmd, &lio_req, 1, fd, Pattern));
+ aio_unregister(aio_id);
+ doio_upanic(U_RVAL);
+ goto lio_done;
+ }
+
+ if (signo) {
+ sigprocmask(SIG_SETMASK, &omask, NULL);
+ }
+
+ /*
+ * Wait for io to complete
+ */
+
+ aio_wait(aio_id);
+
+ nstrides = lio->r_nstrides ? lio->r_nstrides : 1;
+ if (aiop->iosw.sw_count != lio->r_nbytes * nstrides) {
+ doio_fprintf(stderr,
+ "Bad iosw from listio()\nExpected (%d,%d,%d), got (%d,%d,%d)\n%s\n",
+ 1, 0, lio->r_nbytes * lio->r_nstrides,
+ aiop->iosw.sw_flag,
+ aiop->iosw.sw_error, aiop->iosw.sw_count,
+ format_listio(req, lio->r_cmd, &lio_req, 1, fd, Pattern));
+ aio_unregister(aio_id);
+ doio_upanic(U_IOSW);
+ goto lio_done;
+ }
+
+ aio_unregister(aio_id);
+
+ /*
+ * Verify that the data was written correctly - check_file() returns
+ * a non-null pointer which contains an error message if there are
+ * problems.
+ *
+ * For listio, we basically have to make 1 call to check_file for each
+ * stride.
+ */
+
+ if (v_opt && lio_req.li_opcode == LO_WRITE) {
+ fstride = lio->r_filestride ? lio->r_filestride : lio->r_nbytes;
+ mstride = lio->r_memstride ? lio->r_memstride : lio->r_nbytes;
+ foffset = lio->r_offset;
+
+ if (mstride> 0 || lio->r_nstrides <= 1) {
+ moffset = addr;
+ } else {
+ moffset = addr + mem_needed - lio->r_nbytes;
+ }
+
+ for (i = 0; i < lio_req.li_nstride; i++) {
+ msg = check_file(lio->r_file,
+ foffset, lio->r_nbytes,
+ Pattern, Pattern_Length,
+ moffset - addr,
+ lio->r_oflags & O_PARALLEL);
+
+ if (msg != NULL) {
+ doio_fprintf(stderr, "%s\n%s\n",
+ msg,
+ format_listio(req, lio->r_cmd, &lio_req, 1, fd, Pattern));
+ doio_upanic(U_CORRUPTION);
+ exit(E_COMPARE);
+ }
+
+ moffset += mstride;
+ foffset += fstride;
+ }
+
+ }
+
+ rval = 0;
+
+ lio_done:
+
+ /*
+ * General cleanup ...
+ *
+ */
+
+ /*
+ * Release file locks if necessary
+ */
+
+ if (got_lock) {
+ if (lock_file_region(lio->r_file, fd, F_UNLCK,
+ min_byte, (max_byte-min_byte+1)) < 0) {
+ return -1;
+ }
+ }
+
+ return rval;
+#else
+ return -1;
+#endif
+}
+
+/*
+ * perform ssread/sswrite operations
+ */
+
+#ifdef _CRAY1
+
+int
+do_ssdio(req)
+struct io_req *req;
+{
+ int nbytes, nb;
+ char errbuf[BSIZE];
+
+ nbytes = req->r_data.ssread.r_nbytes;
+
+ /*
+ * Grab core and sds space
+ */
+
+ if ((nb = alloc_mem(nbytes)) < 0)
+ return nb;
+
+ if (alloc_sds(nbytes) == -1)
+ return -1;
+
+ if (req->r_type == SSWRITE) {
+
+ /*
+ * Init data and ship it to the ssd
+ */
+
+ Pattern[0] = req->r_data.sswrite.r_pattern;
+ /*pattern_fill(Memptr, nbytes, Pattern, Pattern_Length, 0);*/
+ (*Data_Fill)(Memptr, nbytes, Pattern, Pattern_Length, 0);
+
+ if (sswrite((long)Memptr, (long)Sdsptr, btoc(nbytes)) == -1) {
+ doio_fprintf(stderr, "sswrite() failed: %s (%d)\n%s\n",
+ SYSERR, errno,
+ format_sds(req, Memptr, Sdsptr, Pattern));
+ doio_upanic(U_RVAL);
+ return -1;
+ }
+ } else {
+ /*
+ * read from sds
+ */
+
+ if (ssread((long)Memptr, (long)Sdsptr, btoc(nbytes)) == -1) {
+ doio_fprintf(stderr, "ssread() failed: %s (%d)\n%s\n",
+ SYSERR, errno,
+ format_sds(req, Memptr, Sdsptr, Pattern));
+
+ doio_upanic(U_RVAL);
+ return -1;
+ }
+ }
+
+ /*
+ * Verify data if SSWRITE and v_opt
+ */
+
+ if (v_opt && req->r_type == SSWRITE) {
+ ssread((long)Memptr, (long)Sdsptr, btoc(nbytes));
+
+ if (pattern_check(Memptr, nbytes, Pattern, Pattern_Length, 0) == -1) {
+ doio_fprintf(stderr,
+ "sds DATA COMPARE ERROR - ABORTING\n%s\n",
+ format_sds(req, Memptr, Sdsptr, Pattern));
+
+ doio_upanic(U_CORRUPTION);
+ exit(E_COMPARE);
+ }
+ }
+}
+
+#else
+
+#ifdef CRAY
+
+int
+do_ssdio(req)
+struct io_req *req;
+{
+ doio_fprintf(stderr,
+ "Internal Error - do_ssdio() called on a non-cray1 system\n");
+ alloc_mem(-1);
+ exit(E_INTERNAL);
+}
+
+#endif
+
+#endif /* _CRAY1 */
+
+\f
+/* ---------------------------------------------------------------------------
+ *
+ * A new paradigm of doing the r/w system call where there is a "stub"
+ * function that builds the info for the system call, then does the system
+ * call; this is called by code that is common to all system calls and does
+ * the syscall return checking, async I/O wait, iosw check, etc.
+ *
+ * Flags:
+ * WRITE, ASYNC, SSD/SDS,
+ * FILE_LOCK, WRITE_LOG, VERIFY_DATA,
+ */
+
+struct status {
+ int rval; /* syscall return */
+ int err; /* errno */
+ int *aioid; /* list of async I/O structures */
+};
+
+struct syscall_info {
+ char *sy_name;
+ int sy_type;
+ struct status *(*sy_syscall)();
+ int (*sy_buffer)();
+ char *(*sy_format)();
+ int sy_flags;
+ int sy_bits;
+};
+
+#define SY_WRITE 00001
+#define SY_ASYNC 00010
+#define SY_IOSW 00020
+#define SY_SDS 00100
+
+char *
+fmt_ioreq(struct io_req *ioreq, struct syscall_info *sy, int fd)
+{
+ static char *errbuf=NULL;
+ char *cp;
+ struct rw_req *io;
+ struct smap *aname;
+#ifdef CRAY
+ struct stat sbuf;
+#endif
+
+ if(errbuf == NULL)
+ errbuf = (char *)malloc(32768);
+
+ io = &ioreq->r_data.io;
+
+ /*
+ * Look up async I/O completion strategy
+ */
+ for(aname=aionames;
+ aname->value != -1 && aname->value != io->r_aio_strat;
+ aname++)
+ ;
+
+ cp = errbuf;
+ cp += sprintf(cp, "Request number %d\n", Reqno);
+
+ cp += sprintf(cp, " fd %d is file %s - open flags are %#o %s\n",
+ fd, io->r_file, io->r_oflags, format_oflags(io->r_oflags));
+
+ if(sy->sy_flags & SY_WRITE) {
+ cp += sprintf(cp, " write done at file offset %d - pattern is %c (%#o)\n",
+ io->r_offset,
+ (io->r_pattern == '\0') ? '?' : io->r_pattern,
+ io->r_pattern);
+ } else {
+ cp += sprintf(cp, " read done at file offset %d\n",
+ io->r_offset);
+ }
+
+ if(sy->sy_flags & SY_ASYNC) {
+ cp += sprintf(cp, " async io completion strategy is %s\n",
+ aname->string);
+ }
+
+ cp += sprintf(cp, " number of requests is %d, strides per request is %d\n",
+ io->r_nent, io->r_nstrides);
+
+ cp += sprintf(cp, " i/o byte count = %d\n",
+ io->r_nbytes);
+
+ cp += sprintf(cp, " memory alignment is %s\n",
+ (io->r_uflags & F_WORD_ALIGNED) ? "aligned" : "unaligned");
+
+#ifdef CRAY
+ if(io->r_oflags & O_RAW) {
+ cp += sprintf(cp, " RAW I/O: offset %% 4096 = %d length %% 4096 = %d\n",
+ io->r_offset % 4096, io->r_nbytes % 4096);
+ fstat(fd, &sbuf);
+ cp += sprintf(cp, " optimal file xfer size: small: %d large: %d\n",
+ sbuf.st_blksize, sbuf.st_oblksize);
+ cp += sprintf(cp, " cblks %d cbits %#o\n",
+ sbuf.st_cblks, sbuf.st_cbits);
+ }
+#endif
+#ifndef NO_XFS
+ if(io->r_oflags & O_DIRECT) {
+ struct dioattr finfo;
+
+ if(xfsctl(io->r_file, fd, XFS_IOC_DIOINFO, &finfo) == -1) {
+ cp += sprintf(cp, " Error %s (%d) getting direct I/O info\n",
+ strerror(errno), errno);
+ finfo.d_mem = 1;
+ finfo.d_miniosz = 1;
+ finfo.d_maxiosz = 1;
+ }
+
+ cp += sprintf(cp, " DIRECT I/O: offset %% %d = %d length %% %d = %d\n",
+ finfo.d_miniosz,
+ io->r_offset % finfo.d_miniosz,
+ io->r_nbytes,
+ io->r_nbytes % finfo.d_miniosz);
+ cp += sprintf(cp, " mem alignment 0x%x xfer size: small: %d large: %d\n",
+ finfo.d_mem, finfo.d_miniosz, finfo.d_maxiosz);
+ }
+#endif
+
+ return(errbuf);
+}
+
+/*
+ * Issue listio requests
+ */
+#ifdef CRAY
+struct status *
+sy_listio(req, sysc, fd, addr)
+struct io_req *req;
+struct syscall_info *sysc;
+int fd;
+char *addr;
+{
+ int offset, nbytes, nstrides, nents, aio_strat;
+ int aio_id, signo, o, i, lc;
+ char *a;
+ struct listreq *lio_req, *l;
+ struct aio_info *aiop;
+ struct status *status;
+
+ /*
+ * Initialize common fields - assumes r_oflags, r_file, r_offset, and
+ * r_nbytes are at the same offset in the read_req and reada_req
+ * structures.
+ */
+ offset = req->r_data.io.r_offset;
+ nbytes = req->r_data.io.r_nbytes;
+ nstrides = req->r_data.io.r_nstrides;
+ nents = req->r_data.io.r_nent;
+ aio_strat = req->r_data.io.r_aio_strat;
+
+ lc = (sysc->sy_flags & SY_ASYNC) ? LC_START : LC_WAIT;
+
+ status = (struct status *)malloc(sizeof(struct status));
+ if( status == NULL ){
+ doio_fprintf(stderr, "malloc failed, %s/%d\n",
+ __FILE__, __LINE__);
+ return NULL;
+ }
+ status->aioid = (int *)malloc( (nents+1) * sizeof(int) );
+ if( status->aioid == NULL ){
+ doio_fprintf(stderr, "malloc failed, %s/%d\n",
+ __FILE__, __LINE__);
+ return NULL;
+ }
+
+ signo = (aio_strat == A_SIGNAL) ? SIGUSR1 : 0;
+
+ lio_req = (struct listreq *)malloc(nents * sizeof(struct listreq));
+ if( lio_req == NULL ){
+ doio_fprintf(stderr, "malloc failed, %s/%d\n",
+ __FILE__, __LINE__);
+ return NULL;
+ }
+ for(l=lio_req,a=addr,o=offset,i=0;
+ i < nents;
+ l++, a+=nbytes, o+=nbytes, i++) {
+
+ aio_id = aio_register(fd, aio_strat, signo);
+ aiop = aio_slot(aio_id);
+ status->aioid[i] = aio_id;
+
+ l->li_opcode = (sysc->sy_flags & SY_WRITE) ? LO_WRITE : LO_READ;
+ l->li_offset = o;
+ l->li_fildes = fd;
+ l->li_buf = a;
+ l->li_nbyte = nbytes;
+ l->li_status = &aiop->iosw;
+ l->li_signo = signo;
+ l->li_nstride = nstrides;
+ l->li_filstride = 0;
+ l->li_memstride = 0;
+ l->li_drvr = 0;
+ l->li_flags = LF_LSEEK;
+ }
+
+ status->aioid[nents] = -1; /* end sentinel */
+
+ if( (status->rval = listio(lc, lio_req, nents)) == -1) {
+ status->err = errno;
+ }
+
+ free(lio_req);
+ return(status);
+}
+
+/*
+ * Calculate the size of a request in bytes and min/max boundaries
+ *
+ * This assumes filestride & memstride = 0.
+ */
+int
+listio_mem(struct io_req *req, int offset, int fmstride,
+ int *min, int *max)
+{
+ int i, size;
+
+ size = stride_bounds(offset, fmstride,
+ req->r_data.io.r_nstrides*req->r_data.io.r_nent,
+ req->r_data.io.r_nbytes, min, max);
+ return(size);
+}
+
+char *
+fmt_listio(struct io_req *req, struct syscall_info *sy, int fd, char *addr)
+{
+ static char *errbuf = NULL;
+ char *cp;
+ char *c, *opcode;
+ int i;
+
+ if(errbuf == NULL){
+ errbuf = (char *)malloc(32768);
+ if( errbuf == NULL ){
+ doio_fprintf(stderr, "malloc failed, %s/%d\n",
+ __FILE__, __LINE__);
+ return NULL;
+ }
+ }
+
+ c = (sy->sy_flags & SY_ASYNC) ? "lc_wait" : "lc_start";
+
+ cp = errbuf;
+ cp += sprintf(cp, "syscall: listio(%s, (?), %d)\n",
+ c, req->r_data.io.r_nent);
+
+ cp += sprintf(cp, " data buffer at %#o\n", addr);
+
+ return(errbuf);
+}
+#endif /* CRAY */
+
+struct status *
+sy_pread(req, sysc, fd, addr)
+struct io_req *req;
+struct syscall_info *sysc;
+int fd;
+char *addr;
+{
+ int rc;
+ struct status *status;
+
+ rc = pread(fd, addr, req->r_data.io.r_nbytes,
+ req->r_data.io.r_offset);
+
+ status = (struct status *)malloc(sizeof(struct status));
+ if( status == NULL ){
+ doio_fprintf(stderr, "malloc failed, %s/%d\n",
+ __FILE__, __LINE__);
+ return NULL;
+ }
+ status->aioid = NULL;
+ status->rval = rc;
+ status->err = errno;
+
+ return(status);
+}
+
+struct status *
+sy_pwrite(req, sysc, fd, addr)
+struct io_req *req;
+struct syscall_info *sysc;
+int fd;
+char *addr;
+{
+ int rc;
+ struct status *status;
+
+ rc = pwrite(fd, addr, req->r_data.io.r_nbytes,
+ req->r_data.io.r_offset);
+
+ status = (struct status *)malloc(sizeof(struct status));
+ if( status == NULL ){
+ doio_fprintf(stderr, "malloc failed, %s/%d\n",
+ __FILE__, __LINE__);
+ return NULL;
+ }
+ status->aioid = NULL;
+ status->rval = rc;
+ status->err = errno;
+
+ return(status);
+}
+
+char *
+fmt_pread(struct io_req *req, struct syscall_info *sy, int fd, char *addr)
+{
+ static char *errbuf = NULL;
+ char *cp;
+
+ if(errbuf == NULL){
+ errbuf = (char *)malloc(32768);
+ if( errbuf == NULL ){
+ doio_fprintf(stderr, "malloc failed, %s/%d\n",
+ __FILE__, __LINE__);
+ return NULL;
+ }
+ }
+
+ cp = errbuf;
+ cp += sprintf(cp, "syscall: %s(%d, 0x%p, %d)\n",
+ sy->sy_name, fd, addr, req->r_data.io.r_nbytes);
+ return(errbuf);
+}
+
+#ifndef CRAY
+struct status *
+sy_readv(req, sysc, fd, addr)
+struct io_req *req;
+struct syscall_info *sysc;
+int fd;
+char *addr;
+{
+ struct status *sy_rwv();
+ return sy_rwv(req, sysc, fd, addr, 0);
+}
+
+struct status *
+sy_writev(req, sysc, fd, addr)
+struct io_req *req;
+struct syscall_info *sysc;
+int fd;
+char *addr;
+{
+ struct status *sy_rwv();
+ return sy_rwv(req, sysc, fd, addr, 1);
+}
+
+struct status *
+sy_rwv(req, sysc, fd, addr, rw)
+struct io_req *req;
+struct syscall_info *sysc;
+int fd;
+char *addr;
+int rw;
+{
+ int rc;
+ struct status *status;
+ struct iovec iov[2];
+
+ status = (struct status *)malloc(sizeof(struct status));
+ if( status == NULL ){
+ doio_fprintf(stderr, "malloc failed, %s/%d\n",
+ __FILE__, __LINE__);
+ return NULL;
+ }
+ status->aioid = NULL;
+
+ /* move to the desired file position. */
+ if ((rc=lseek(fd, req->r_data.io.r_offset, SEEK_SET)) == -1) {
+ status->rval = rc;
+ status->err = errno;
+ return(status);
+ }
+
+ iov[0].iov_base = addr;
+ iov[0].iov_len = req->r_data.io.r_nbytes;
+
+ if(rw)
+ rc = writev(fd, iov, 1);
+ else
+ rc = readv(fd, iov, 1);
+ status->aioid = NULL;
+ status->rval = rc;
+ status->err = errno;
+ return(status);
+}
+
+char *
+fmt_readv(struct io_req *req, struct syscall_info *sy, int fd, char *addr)
+{
+ static char errbuf[32768];
+ char *cp;
+
+ cp = errbuf;
+ cp += sprintf(cp, "syscall: %s(%d, (iov on stack), 1)\n",
+ sy->sy_name, fd);
+ return(errbuf);
+}
+#endif /* !CRAY */
+
+#ifdef sgi
+struct status *
+sy_aread(req, sysc, fd, addr)
+struct io_req *req;
+struct syscall_info *sysc;
+int fd;
+char *addr;
+{
+ struct status *sy_arw();
+ return sy_arw(req, sysc, fd, addr, 0);
+}
+
+struct status *
+sy_awrite(req, sysc, fd, addr)
+struct io_req *req;
+struct syscall_info *sysc;
+int fd;
+char *addr;
+{
+ struct status *sy_arw();
+ return sy_arw(req, sysc, fd, addr, 1);
+}
+
+/*
+ #define sy_aread(A, B, C, D) sy_arw(A, B, C, D, 0)
+ #define sy_awrite(A, B, C, D) sy_arw(A, B, C, D, 1)
+ */
+
+struct status *
+sy_arw(req, sysc, fd, addr, rw)
+struct io_req *req;
+struct syscall_info *sysc;
+int fd;
+char *addr;
+int rw;
+{
+ /* POSIX 1003.1b-1993 Async read */
+ struct status *status;
+ int rc;
+ int aio_id, aio_strat, signo;
+ struct aio_info *aiop;
+
+ status = (struct status *)malloc(sizeof(struct status));
+ if( status == NULL ){
+ doio_fprintf(stderr, "malloc failed, %s/%d\n",
+ __FILE__, __LINE__);
+ return NULL;
+ }
+ aio_strat = req->r_data.io.r_aio_strat;
+ signo = (aio_strat == A_SIGNAL) ? SIGUSR1 : 0;
+
+ aio_id = aio_register(fd, aio_strat, signo);
+ aiop = aio_slot(aio_id);
+
+ memset( (void *)&aiop->aiocb, 0, sizeof(aiocb_t));
+
+ aiop->aiocb.aio_fildes = fd;
+ aiop->aiocb.aio_nbytes = req->r_data.io.r_nbytes;
+ aiop->aiocb.aio_offset = req->r_data.io.r_offset;
+ aiop->aiocb.aio_buf = addr;
+ aiop->aiocb.aio_reqprio = 0; /* must be 0 */
+ aiop->aiocb.aio_lio_opcode = 0;
+
+ if(aio_strat == A_SIGNAL) { /* siginfo(2) stuff */
+ aiop->aiocb.aio_sigevent.sigev_notify = SIGEV_SIGNAL;
+ aiop->aiocb.aio_sigevent.sigev_signo = signo;
+ } else if(aio_strat == A_CALLBACK) {
+ aiop->aiocb.aio_sigevent.sigev_signo = 0;
+ aiop->aiocb.aio_sigevent.sigev_notify = SIGEV_CALLBACK;
+ aiop->aiocb.aio_sigevent.sigev_func = cb_handler;
+ aiop->aiocb.aio_sigevent.sigev_value.sival_int = aio_id;
+ } else {
+ aiop->aiocb.aio_sigevent.sigev_notify = SIGEV_NONE;
+ aiop->aiocb.aio_sigevent.sigev_signo = 0;
+ }
+
+ if(rw)
+ rc = aio_write(&aiop->aiocb);
+ else
+ rc = aio_read(&aiop->aiocb);
+
+ status->aioid = (int *)malloc( 2 * sizeof(int) );
+ if( status->aioid == NULL ){
+ doio_fprintf(stderr, "malloc failed, %s/%d\n",
+ __FILE__, __LINE__);
+ return NULL;
+ }
+ status->aioid[0] = aio_id;
+ status->aioid[1] = -1;
+ status->rval = rc;
+ status->err = errno;
+ return(status);
+}
+
+char *
+fmt_aread(struct io_req *req, struct syscall_info *sy, int fd, char *addr)
+{
+ static char errbuf[32768];
+ char *cp;
+
+ cp = errbuf;
+ cp += sprintf(cp, "syscall: %s(&aiop->aiocb)\n",
+ sy->sy_name);
+ return(errbuf);
+}
+#endif /* sgi */
+
+#ifndef CRAY
+
+struct status *
+sy_mmread(req, sysc, fd, addr)
+struct io_req *req;
+struct syscall_info *sysc;
+int fd;
+char *addr;
+{
+ struct status *sy_mmrw();
+ return sy_mmrw(req, sysc, fd, addr, 0);
+}
+
+struct status *
+sy_mmwrite(req, sysc, fd, addr)
+struct io_req *req;
+struct syscall_info *sysc;
+int fd;
+char *addr;
+{
+ struct status *sy_mmrw();
+ return sy_mmrw(req, sysc, fd, addr, 1);
+}
+
+struct status *
+sy_mmrw(req, sysc, fd, addr, rw)
+struct io_req *req;
+struct syscall_info *sysc;
+int fd;
+char *addr;
+int rw;
+{
+ /*
+ * mmap read/write
+ * This version is oriented towards mmaping the file to memory
+ * ONCE and keeping it mapped.
+ */
+ struct status *status;
+ void *mrc, *memaddr;
+ struct fd_cache *fdc;
+ struct stat sbuf;
+
+ status = (struct status *)malloc(sizeof(struct status));
+ if( status == NULL ){
+ doio_fprintf(stderr, "malloc failed, %s/%d\n",
+ __FILE__, __LINE__);
+ return NULL;
+ }
+ status->aioid = NULL;
+ status->rval = -1;
+
+ fdc = alloc_fdcache(req->r_data.io.r_file, req->r_data.io.r_oflags);
+
+ if( fdc->c_memaddr == NULL ) {
+ if( fstat(fd, &sbuf) < 0 ){
+ doio_fprintf(stderr, "fstat failed, errno=%d\n",
+ errno);
+ status->err = errno;
+ return(status);
+ }
+
+ fdc->c_memlen = (int)sbuf.st_size;
+ mrc = mmap(NULL, (int)sbuf.st_size,
+ rw ? PROT_WRITE|PROT_READ : PROT_READ,
+ MAP_SHARED, fd, 0);
+
+ if( mrc == MAP_FAILED ) {
+ doio_fprintf(stderr, "mmap() failed - 0x%lx %d\n",
+ mrc, errno);
+ status->err = errno;
+ return(status);
+ }
+
+ fdc->c_memaddr = mrc;
+ }
+
+ memaddr = (void *)((char *)fdc->c_memaddr + req->r_data.io.r_offset);
+
+ active_mmap_rw = 1;
+ if(rw)
+ memcpy(memaddr, addr, req->r_data.io.r_nbytes);
+ else
+ memcpy(addr, memaddr, req->r_data.io.r_nbytes);
+ active_mmap_rw = 0;
+
+ status->rval = req->r_data.io.r_nbytes;
+ status->err = 0;
+ return(status);
+}
+
+char *
+fmt_mmrw(struct io_req *req, struct syscall_info *sy, int fd, char *addr)
+{
+ static char errbuf[32768];
+ char *cp;
+ struct fd_cache *fdc;
+ void *memaddr;
+
+ fdc = alloc_fdcache(req->r_data.io.r_file, req->r_data.io.r_oflags);
+
+ cp = errbuf;
+ cp += sprintf(cp, "syscall: %s(NULL, %d, %s, MAP_SHARED, %d, 0)\n",
+ sy->sy_name,
+ fdc->c_memlen,
+ (sy->sy_flags & SY_WRITE) ? "PROT_WRITE" : "PROT_READ",
+ fd);
+
+ cp += sprintf(cp, "\tfile is mmaped to: 0x%lx\n",
+ (unsigned long) fdc->c_memaddr);
+
+ memaddr = (void *)((char *)fdc->c_memaddr + req->r_data.io.r_offset);
+
+ cp += sprintf(cp, "\tfile-mem=0x%lx, length=%d, buffer=0x%lx\n",
+ (unsigned long) memaddr, req->r_data.io.r_nbytes,
+ (unsigned long) addr);
+
+ return(errbuf);
+}
+#endif /* !CRAY */
+
+struct syscall_info syscalls[] = {
+#ifdef CRAY
+ { "listio-read-sync", LREAD,
+ sy_listio, NULL, fmt_listio,
+ SY_IOSW
+ },
+ { "listio-read-strides-sync", LSREAD,
+ sy_listio, listio_mem, fmt_listio,
+ SY_IOSW
+ },
+ { "listio-read-reqs-sync", LEREAD,
+ sy_listio, listio_mem, fmt_listio,
+ SY_IOSW
+ },
+ { "listio-read-async", LREADA,
+ sy_listio, NULL, fmt_listio,
+ SY_IOSW | SY_ASYNC
+ },
+ { "listio-read-strides-async", LSREADA,
+ sy_listio, listio_mem, fmt_listio,
+ SY_IOSW | SY_ASYNC
+ },
+ { "listio-read-reqs-async", LEREADA,
+ sy_listio, listio_mem, fmt_listio,
+ SY_IOSW | SY_ASYNC
+ },
+ { "listio-write-sync", LWRITE,
+ sy_listio, listio_mem, fmt_listio,
+ SY_IOSW | SY_WRITE
+ },
+ { "listio-write-strides-sync", LSWRITE,
+ sy_listio, listio_mem, fmt_listio,
+ SY_IOSW | SY_WRITE
+ },
+ { "listio-write-reqs-sync", LEWRITE,
+ sy_listio, listio_mem, fmt_listio,
+ SY_IOSW | SY_WRITE
+ },
+ { "listio-write-async", LWRITEA,
+ sy_listio, listio_mem, fmt_listio,
+ SY_IOSW | SY_WRITE | SY_ASYNC
+ },
+ { "listio-write-strides-async", LSWRITEA,
+ sy_listio, listio_mem, fmt_listio,
+ SY_IOSW | SY_WRITE | SY_ASYNC
+ },
+ { "listio-write-reqs-async", LEWRITEA,
+ sy_listio, listio_mem, fmt_listio,
+ SY_IOSW | SY_WRITE | SY_ASYNC
+ },
+#endif
+
+#ifdef sgi
+ { "aread", AREAD,
+ sy_aread, NULL, fmt_aread,
+ SY_IOSW | SY_ASYNC
+ },
+ { "awrite", AWRITE,
+ sy_awrite, NULL, fmt_aread,
+ SY_IOSW | SY_WRITE | SY_ASYNC
+ },
+#endif
+ { "pread", PREAD,
+ sy_pread, NULL, fmt_pread,
+ 0
+ },
+ { "pwrite", PWRITE,
+ sy_pwrite, NULL, fmt_pread,
+ SY_WRITE
+ },
+
+#ifndef CRAY
+ { "readv", READV,
+ sy_readv, NULL, fmt_readv,
+ 0
+ },
+ { "writev", WRITEV,
+ sy_writev, NULL, fmt_readv,
+ SY_WRITE
+ },
+ { "mmap-read", MMAPR,
+ sy_mmread, NULL, fmt_mmrw,
+ 0
+ },
+ { "mmap-write", MMAPW,
+ sy_mmwrite, NULL, fmt_mmrw,
+ SY_WRITE
+ },
+#endif
+
+ { NULL, 0,
+ 0, 0, 0,
+ 0
+ },
+};
+
+int
+do_rw(req)
+ struct io_req *req;
+{
+ static int pid = -1;
+ int fd, offset, nbytes, nstrides, nents, oflags;
+ int rval, mem_needed, i;
+ int logged_write, got_lock, woffset = 0, pattern;
+ int min_byte, max_byte;
+ char *addr, *file, *msg;
+ struct status *s;
+ struct wlog_rec wrec;
+ struct syscall_info *sy;
+#if defined(CRAY) || defined(sgi)
+ struct aio_info *aiop;
+ struct iosw *iosw;
+#endif
+#ifndef NO_XFS
+ struct fd_cache *fdc;
+#endif
+
+ /*
+ * Initialize common fields - assumes r_oflags, r_file, r_offset, and
+ * r_nbytes are at the same offset in the read_req and reada_req
+ * structures.
+ */
+ file = req->r_data.io.r_file;
+ oflags = req->r_data.io.r_oflags;
+ offset = req->r_data.io.r_offset;
+ nbytes = req->r_data.io.r_nbytes;
+ nstrides= req->r_data.io.r_nstrides;
+ nents = req->r_data.io.r_nent;
+ pattern = req->r_data.io.r_pattern;
+
+ if( nents >= MAX_AIO ) {
+ doio_fprintf(stderr, "do_rw: too many list requests, %d. Maximum is %d\n",
+ nents, MAX_AIO);
+ return(-1);
+ }
+
+ /*
+ * look up system call info
+ */
+ for(sy=syscalls; sy->sy_name != NULL && sy->sy_type != req->r_type; sy++)
+ ;
+
+ if(sy->sy_name == NULL) {
+ doio_fprintf(stderr, "do_rw: unknown r_type %d.\n",
+ req->r_type);
+ return(-1);
+ }
+
+ /*
+ * Get an open file descriptor
+ * Note: must be done before memory allocation so that the direct i/o
+ * information is available in mem. allocate
+ */
+
+ if ((fd = alloc_fd(file, oflags)) == -1)
+ return -1;
+
+ /*
+ * Allocate core memory and possibly sds space. Initialize the
+ * data to be written. Make sure we get enough, based on the
+ * memstride.
+ *
+ * need:
+ * 1 extra word for possible partial-word address "bump"
+ * 1 extra word for dynamic pattern overrun
+ * MPP_BUMP extra words for T3E non-hw-aligned memory address.
+ */
+
+ if( sy->sy_buffer != NULL ) {
+ mem_needed = (*sy->sy_buffer)(req, 0, 0, NULL, NULL);
+ } else {
+ mem_needed = nbytes;
+ }
+
+#ifdef CRAY
+ if ((rval = alloc_mem(mem_needed + wtob(1) * 2 + MPP_BUMP * sizeof(UINT64_T))) < 0) {
+ return rval;
+ }
+#else
+#ifndef NO_XFS
+ /* get memory alignment for using DIRECT I/O */
+ fdc = alloc_fdcache(file, oflags);
+
+ if ((rval = alloc_mem(mem_needed + wtob(1) * 2 + fdc->c_memalign)) < 0) {
+ return rval;
+ }
+#else
+ if ((rval = alloc_mem(mem_needed + wtob(1) * 2)) < 0) {
+ return rval;
+ }
+#endif
+#endif /* CRAY */
+
+ Pattern[0] = pattern;
+
+ /*
+ * Allocate SDS space for backdoor write if desired
+ */
+
+ if (oflags & O_SSD) {
+#ifdef CRAY
+#ifndef _CRAYMPP
+ if (alloc_sds(nbytes) == -1)
+ return -1;
+
+ if( sy->sy_flags & SY_WRITE ) {
+ /*pattern_fill(Memptr, mem_needed, Pattern, Pattern_Length, 0);*/
+ (*Data_Fill)(Memptr, nbytes, Pattern, Pattern_Length, 0);
+
+ if (sswrite((long)Memptr, Sdsptr, btoc(mem_needed)) == -1) {
+ doio_fprintf(stderr, "sswrite(%d, %d, %d) failed: %s (%d)\n",
+ (long)Memptr, Sdsptr,
+ btoc(mem_needed), SYSERR, errno);
+ fflush(stderr);
+ return -1;
+ }
+ }
+
+ addr = (char *)Sdsptr;
+#else
+ doio_fprintf(stderr, "Invalid O_SSD flag was generated for MPP system\n");
+ fflush(stderr);
+ return -1;
+#endif /* _CRAYMPP */
+#else /* CRAY */
+ doio_fprintf(stderr, "Invalid O_SSD flag was generated for non-Cray system\n");
+ fflush(stderr);
+ return -1;
+#endif /* CRAY */
+ } else {
+ addr = Memptr;
+
+ /*
+ * if io is not raw, bump the offset by a random amount
+ * to generate non-word-aligned io.
+ *
+ * On MPP systems, raw I/O must start on an 0x80 byte boundary.
+ * For non-aligned I/O, bump the address from 1 to 8 words.
+ */
+
+ if (! (req->r_data.io.r_uflags & F_WORD_ALIGNED)) {
+#ifdef _CRAYMPP
+ addr += random_range(0, MPP_BUMP, 1, NULL) * sizeof(int);
+#endif
+ addr += random_range(0, wtob(1) - 1, 1, NULL);
+ }
+
+#ifndef NO_XFS
+ /*
+ * Force memory alignment for Direct I/O
+ */
+ if( (oflags & O_DIRECT) && ((long)addr % fdc->c_memalign != 0) ) {
+ addr += fdc->c_memalign - ((long)addr % fdc->c_memalign);
+ }
+#endif
+
+ /*
+ * FILL must be done on a word-aligned buffer.
+ * Call the fill function with Memptr which is aligned,
+ * then memmove it to the right place.
+ */
+ if (sy->sy_flags & SY_WRITE) {
+ (*Data_Fill)(Memptr, mem_needed, Pattern, Pattern_Length, 0);
+ if( addr != Memptr )
+ memmove( addr, Memptr, mem_needed);
+ }
+ }
+
+ rval = 0;
+ got_lock = 0;
+ logged_write = 0;
+
+ /*
+ * Lock data if this is a write and locking option is set
+ */
+ if (sy->sy_flags & SY_WRITE && k_opt) {
+ if( sy->sy_buffer != NULL ) {
+ (*sy->sy_buffer)(req, offset, 0, &min_byte, &max_byte);
+ } else {
+ min_byte = offset;
+ max_byte = offset + (nbytes * nstrides * nents);
+ }
+
+ if (lock_file_region(file, fd, F_WRLCK,
+ min_byte, (max_byte-min_byte+1)) < 0) {
+ doio_fprintf(stderr,
+ "file lock failed:\n%s\n",
+ fmt_ioreq(req, sy, fd));
+ doio_fprintf(stderr,
+ " buffer(req, %d, 0, 0x%x, 0x%x)\n",
+ offset, min_byte, max_byte);
+ alloc_mem(-1);
+ exit(E_INTERNAL);
+ }
+
+ got_lock = 1;
+ }
+
+ /*
+ * Write a preliminary write-log entry. This is done so that
+ * doio_check can do corruption detection across an interrupt/crash.
+ * Note that w_done is set to 0. If doio_check sees this, it
+ * re-creates the file extents as if the write completed, but does not
+ * do any checking - see comments in doio_check for more details.
+ */
+
+ if (sy->sy_flags & SY_WRITE && w_opt) {
+ if (pid == -1) {
+ pid = getpid();
+ }
+
+ wrec.w_async = (sy->sy_flags & SY_ASYNC) ? 1 : 0;
+ wrec.w_oflags = oflags;
+ wrec.w_pid = pid;
+ wrec.w_offset = offset;
+ wrec.w_nbytes = nbytes; /* mem_needed -- total length */
+
+ wrec.w_pathlen = strlen(file);
+ memcpy(wrec.w_path, file, wrec.w_pathlen);
+ wrec.w_hostlen = strlen(Host);
+ memcpy(wrec.w_host, Host, wrec.w_hostlen);
+ wrec.w_patternlen = Pattern_Length;
+ memcpy(wrec.w_pattern, Pattern, wrec.w_patternlen);
+
+ wrec.w_done = 0;
+
+ if ((woffset = wlog_record_write(&Wlog, &wrec, -1)) == -1) {
+ doio_fprintf(stderr,
+ "Could not append to write-log: %s (%d)\n",
+ SYSERR, errno);
+ } else {
+ logged_write = 1;
+ }
+ }
+
+ s = (*sy->sy_syscall)(req, sy, fd, addr);
+
+ if( s->rval == -1 ) {
+ doio_fprintf(stderr,
+ "%s() request failed: %s (%d)\n%s\n%s\n",
+ sy->sy_name, SYSERR, errno,
+ fmt_ioreq(req, sy, fd),
+ (*sy->sy_format)(req, sy, fd, addr));
+
+ doio_upanic(U_RVAL);
+
+ for(i=0; i < nents; i++) {
+ if(s->aioid == NULL)
+ break;
+ aio_unregister(s->aioid[i]);
+ }
+ rval = -1;
+ } else {
+ /*
+ * If the syscall was async, wait for I/O to complete
+ */
+#ifndef linux
+ if(sy->sy_flags & SY_ASYNC) {
+ for(i=0; i < nents; i++) {
+ aio_wait(s->aioid[i]);
+ }
+ }
+#endif
+
+ /*
+ * Check the syscall how-much-data-written return. Look
+ * for this in either the return value or the 'iosw'
+ * structure.
+ */
+
+ if( sy->sy_flags & SY_IOSW ) {
+#ifdef CRAY
+ for( i=0; i < nents; i++ ) {
+ if(s->aioid == NULL)
+ break; /* >>> error condition? */
+ aiop = aio_slot(s->aioid[i]);
+ iosw = &aiop->iosw;
+ if(iosw->sw_error != 0) {
+ doio_fprintf(stderr,
+ "%s() iosw error set: %s\n%s\n%s\n",
+ sy->sy_name,
+ strerror(iosw->sw_error),
+ fmt_ioreq(req, sy, fd),
+ (*sy->sy_format)(req, sy, fd, addr));
+ doio_upanic(U_IOSW);
+ rval = -1;
+ } else if(iosw->sw_count != nbytes*nstrides) {
+ doio_fprintf(stderr,
+ "Bad iosw from %s() #%d\nExpected (%d,%d,%d), got (%d,%d,%d)\n%s\n%s\n",
+ sy->sy_name, i,
+ 1, 0, nbytes*nstrides,
+ iosw->sw_flag,
+ iosw->sw_error,
+ iosw->sw_count,
+ fmt_ioreq(req, sy, fd),
+ (*sy->sy_format)(req, sy, fd, addr));
+ doio_upanic(U_IOSW);
+ rval = -1;
+ }
+
+ aio_unregister(s->aioid[i]);
+ }
+#endif /* CRAY */
+#ifdef sgi
+ for( i=0; s->aioid[i] != -1; i++ ) {
+ if(s->aioid == NULL) {
+ doio_fprintf(stderr,
+ "aioid == NULL!\n");
+ break;
+ }
+ aiop = aio_slot(s->aioid[i]);
+
+ /*
+ * make sure the io completed without error
+ */
+ if (aiop->aio_errno != 0) {
+ doio_fprintf(stderr,
+ "%s() aio error set: %s (%d)\n%s\n%s\n",
+ sy->sy_name,
+ strerror(aiop->aio_errno),
+ aiop->aio_errno,
+ fmt_ioreq(req, sy, fd),
+ (*sy->sy_format)(req, sy, fd, addr));
+ doio_upanic(U_IOSW);
+ rval = -1;
+ } else if (aiop->aio_ret != nbytes) {
+ doio_fprintf(stderr,
+ "Bad aio return from %s() #%d\nExpected (%d,%d), got (%d,%d)\n%s\n%s\n",
+ sy->sy_name, i,
+ 0, nbytes,
+ aiop->aio_errno,
+ aiop->aio_ret,
+ fmt_ioreq(req, sy, fd),
+ (*sy->sy_format)(req, sy, fd, addr));
+ aio_unregister(s->aioid[i]);
+ doio_upanic(U_IOSW);
+ return -1;
+ } else {
+ aio_unregister(s->aioid[i]);
+ rval = 0;
+ }
+ }
+#endif /* sgi */
+ } else {
+
+ if(s->rval != mem_needed) {
+ doio_fprintf(stderr,
+ "%s() request returned wrong # of bytes - expected %d, got %d\n%s\n%s\n",
+ sy->sy_name, nbytes, s->rval,
+ fmt_ioreq(req, sy, fd),
+ (*sy->sy_format)(req, sy, fd, addr));
+ rval = -1;
+ doio_upanic(U_RVAL);
+ }
+ }
+ }
+
+
+ /*
+ * Verify that the data was written correctly - check_file() returns
+ * a non-null pointer which contains an error message if there are
+ * problems.
+ */
+
+ if ( rval == 0 && sy->sy_flags & SY_WRITE && v_opt) {
+ msg = check_file(file, offset, nbytes*nstrides*nents,
+ Pattern, Pattern_Length, 0,
+ oflags & O_PARALLEL);
+ if (msg != NULL) {
+ doio_fprintf(stderr, "%s\n%s\n%s\n",
+ msg,
+ fmt_ioreq(req, sy, fd),
+ (*sy->sy_format)(req, sy, fd, addr));
+ doio_upanic(U_CORRUPTION);
+ exit(E_COMPARE);
+ }
+ }
+
+ /*
+ * General cleanup ...
+ *
+ * Write extent information to the write-log, so that doio_check can do
+ * corruption detection. Note that w_done is set to 1, indicating that
+ * the write has been verified as complete. We don't need to write the
+ * filename on the second logging.
+ */
+
+ if (w_opt && logged_write) {
+ wrec.w_done = 1;
+ wlog_record_write(&Wlog, &wrec, woffset);
+ }
+
+ /*
+ * Unlock file region if necessary
+ */
+
+ if (got_lock) {
+ if (lock_file_region(file, fd, F_UNLCK,
+ min_byte, (max_byte-min_byte+1)) < 0) {
+ alloc_mem(-1);
+ exit(E_INTERNAL);
+ }
+ }
+
+ if(s->aioid != NULL)
+ free(s->aioid);
+ free(s);
+ return (rval == -1) ? -1 : 0;
+}
+
+
+/*
+ * xfsctl-based requests
+ * - XFS_IOC_RESVSP
+ * - XFS_IOC_UNRESVSP
+ */
+#ifndef NO_XFS
+int
+do_xfsctl(req)
+ struct io_req *req;
+{
+ int fd, oflags, offset, nbytes;
+ int rval, op = 0;
+ int got_lock;
+ int min_byte = 0, max_byte = 0;
+ char *file, *msg = NULL;
+ struct xfs_flock64 flk;
+
+ /*
+ * Initialize common fields - assumes r_oflags, r_file, r_offset, and
+ * r_nbytes are at the same offset in the read_req and reada_req
+ * structures.
+ */
+ file = req->r_data.io.r_file;
+ oflags = req->r_data.io.r_oflags;
+ offset = req->r_data.io.r_offset;
+ nbytes = req->r_data.io.r_nbytes;
+
+ flk.l_type=0;
+ flk.l_whence=SEEK_SET;
+ flk.l_start=offset;
+ flk.l_len=nbytes;
+
+ /*
+ * Get an open file descriptor
+ */
+
+ if ((fd = alloc_fd(file, oflags)) == -1)
+ return -1;
+
+ rval = 0;
+ got_lock = 0;
+
+ /*
+ * Lock data if this is locking option is set
+ */
+ if (k_opt) {
+ min_byte = offset;
+ max_byte = offset + nbytes;
+
+ if (lock_file_region(file, fd, F_WRLCK,
+ min_byte, (nbytes+1)) < 0) {
+ doio_fprintf(stderr,
+ "file lock failed:\n");
+ doio_fprintf(stderr,
+ " buffer(req, %d, 0, 0x%x, 0x%x)\n",
+ offset, min_byte, max_byte);
+ alloc_mem(-1);
+ exit(E_INTERNAL);
+ }
+
+ got_lock = 1;
+ }
+
+ switch (req->r_type) {
+ case RESVSP: op=XFS_IOC_RESVSP; msg="resvsp"; break;
+ case UNRESVSP: op=XFS_IOC_UNRESVSP; msg="unresvsp"; break;
+ }
+
+ rval = xfsctl(file, fd, op, &flk);
+
+ if( rval == -1 ) {
+ doio_fprintf(stderr,
+"xfsctl %s request failed: %s (%d)\n\txfsctl(%d, %s %d, {%d %lld ==> %lld}\n",
+ msg, SYSERR, errno,
+ fd, msg, op, flk.l_whence,
+ (long long)flk.l_start,
+ (long long)flk.l_len);
+
+ doio_upanic(U_RVAL);
+ rval = -1;
+ }
+
+ /*
+ * Unlock file region if necessary
+ */
+
+ if (got_lock) {
+ if (lock_file_region(file, fd, F_UNLCK,
+ min_byte, (max_byte-min_byte+1)) < 0) {
+ alloc_mem(-1);
+ exit(E_INTERNAL);
+ }
+ }
+
+ return (rval == -1) ? -1 : 0;
+}
+#endif
+
+/*
+ * fsync(2) and fdatasync(2)
+ */
+#ifndef CRAY
+int
+do_sync(req)
+ struct io_req *req;
+{
+ int fd, oflags;
+ int rval;
+ char *file;
+
+ /*
+ * Initialize common fields - assumes r_oflags, r_file, r_offset, and
+ * r_nbytes are at the same offset in the read_req and reada_req
+ * structures.
+ */
+ file = req->r_data.io.r_file;
+ oflags = req->r_data.io.r_oflags;
+
+ /*
+ * Get an open file descriptor
+ */
+
+ if ((fd = alloc_fd(file, oflags)) == -1)
+ return -1;
+
+ rval = 0;
+ switch(req->r_type) {
+ case FSYNC2:
+ rval = fsync(fd);
+ break;
+ case FDATASYNC:
+ rval = fdatasync(fd);
+ break;
+ default:
+ rval = -1;
+ }
+ return (rval == -1) ? -1 : 0;
+}
+#endif
+
+
+int
+doio_pat_fill(char *addr, int mem_needed, char *Pattern, int Pattern_Length,
+ int shift)
+{
+ return pattern_fill(addr, mem_needed, Pattern, Pattern_Length, 0);
+}
+
+char *
+doio_pat_check(buf, offset, length, pattern, pattern_length, patshift)
+char *buf;
+int offset;
+int length;
+char *pattern;
+int pattern_length;
+int patshift;
+{
+ static char errbuf[4096];
+ int nb, i, pattern_index;
+ char *cp, *bufend, *ep;
+ char actual[33], expected[33];
+
+ if (pattern_check(buf, length, pattern, pattern_length, patshift) != 0) {
+ ep = errbuf;
+ ep += sprintf(ep, "Corrupt regions follow - unprintable chars are represented as '.'\n");
+ ep += sprintf(ep, "-----------------------------------------------------------------\n");
+
+ pattern_index = patshift % pattern_length;;
+ cp = buf;
+ bufend = buf + length;
+
+ while (cp < bufend) {
+ if (*cp != pattern[pattern_index]) {
+ nb = bufend - cp;
+ if (nb > sizeof(expected)-1) {
+ nb = sizeof(expected)-1;
+ }
+
+ ep += sprintf(ep, "corrupt bytes starting at file offset %d\n", offset + (int)(cp-buf));
+
+ /*
+ * Fill in the expected and actual patterns
+ */
+ bzero(expected, sizeof(expected));
+ bzero(actual, sizeof(actual));
+
+ for (i = 0; i < nb; i++) {
+ expected[i] = pattern[(pattern_index + i) % pattern_length];
+ if (! isprint(expected[i])) {
+ expected[i] = '.';
+ }
+
+ actual[i] = cp[i];
+ if (! isprint(actual[i])) {
+ actual[i] = '.';
+ }
+ }
+
+ ep += sprintf(ep, " 1st %2d expected bytes: %s\n", nb, expected);
+ ep += sprintf(ep, " 1st %2d actual bytes: %s\n", nb, actual);
+ fflush(stderr);
+ return errbuf;
+ } else {
+ cp++;
+ pattern_index++;
+
+ if (pattern_index == pattern_length) {
+ pattern_index = 0;
+ }
+ }
+ }
+ return errbuf;
+ }
+
+ return(NULL);
+}
+
+
+/*
+ * Check the contents of a file beginning at offset, for length bytes. It
+ * is assumed that there is a string of pattern bytes in this area of the
+ * file. Use normal buffered reads to do the verification.
+ *
+ * If there is a data mismatch, write a detailed message into a static buffer
+ * suitable for the caller to print. Otherwise print NULL.
+ *
+ * The fsa flag is set to non-zero if the buffer should be read back through
+ * the FSA (unicos/mk). This implies the file will be opened
+ * O_PARALLEL|O_RAW|O_WELLFORMED to do the validation. We must do this because
+ * FSA will not allow the file to be opened for buffered io if it was
+ * previously opened for O_PARALLEL io.
+ */
+
+char *
+check_file(file, offset, length, pattern, pattern_length, patshift, fsa)
+char *file;
+int offset;
+int length;
+char *pattern;
+int pattern_length;
+int patshift;
+int fsa;
+{
+ static char errbuf[4096];
+ int fd, nb, flags;
+ char *buf, *em, *ep;
+#ifndef NO_XFS
+ struct fd_cache *fdc;
+#endif
+
+ buf = Memptr;
+
+ if (V_opt) {
+ flags = Validation_Flags | O_RDONLY;
+ } else {
+ flags = O_RDONLY;
+ if (fsa) {
+#ifdef CRAY
+ flags |= O_PARALLEL | O_RAW | O_WELLFORMED;
+#endif
+ }
+ }
+
+ if ((fd = alloc_fd(file, flags)) == -1) {
+ sprintf(errbuf,
+ "Could not open file %s with flags %#o (%s) for data comparison: %s (%d)\n",
+ file, flags, format_oflags(flags),
+ SYSERR, errno);
+ return errbuf;
+ }
+
+ if (lseek(fd, offset, SEEK_SET) == -1) {
+ sprintf(errbuf,
+ "Could not lseek to offset %d in %s for verification: %s (%d)\n",
+ offset, file, SYSERR, errno);
+ return errbuf;
+ }
+
+#ifndef NO_XFS
+ /* Guarantee a properly aligned address on Direct I/O */
+ fdc = alloc_fdcache(file, flags);
+ if( (flags & O_DIRECT) && ((long)buf % fdc->c_memalign != 0) ) {
+ buf += fdc->c_memalign - ((long)buf % fdc->c_memalign);
+ }
+#endif
+
+ if ((nb = read(fd, buf, length)) == -1) {
+#ifndef NO_XFS
+ sprintf(errbuf,
+ "Could not read %d bytes from %s for verification: %s (%d)\n\tread(%d, 0x%p, %d)\n\tbuf %% alignment(%d) = %ld\n",
+ length, file, SYSERR, errno,
+ fd, buf, length,
+ fdc->c_memalign, (long)buf % fdc->c_memalign);
+#else
+ sprintf(errbuf,
+ "Could not read %d bytes from %s for verification: %s (%d)\n",
+ length, file, SYSERR, errno);
+
+#endif
+ return errbuf;
+ }
+
+ if (nb != length) {
+ sprintf(errbuf,
+ "Read wrong # bytes from %s. Expected %d, got %d\n",
+ file, length, nb);
+ return errbuf;
+ }
+
+ if( (em = (*Data_Check)(buf, offset, length, pattern, pattern_length, patshift)) != NULL ) {
+ ep = errbuf;
+ ep += sprintf(ep, "*** DATA COMPARISON ERROR ***\n");
+ ep += sprintf(ep, "check_file(%s, %d, %d, %s, %d, %d) failed\n\n",
+ file, offset, length, pattern, pattern_length, patshift);
+ ep += sprintf(ep, "Comparison fd is %d, with open flags %#o\n",
+ fd, flags);
+ strcpy(ep, em);
+ return(errbuf);
+ }
+ return NULL;
+}
+
+/*
+ * Function to single-thread stdio output.
+ */
+
+int
+doio_fprintf(FILE *stream, char *format, ...)
+{
+ static int pid = -1;
+ char *date;
+ int rval;
+ struct flock flk;
+ va_list arglist;
+
+ date = hms(time(0));
+
+ if (pid == -1) {
+ pid = getpid();
+ }
+
+ flk.l_whence = flk.l_start = flk.l_len = 0;
+ flk.l_type = F_WRLCK;
+ fcntl(fileno(stream), F_SETLKW, &flk);
+
+ va_start(arglist, format);
+ rval = fprintf(stream, "\n%s%s (%5d) %s\n", Prog, TagName, pid, date);
+ rval += fprintf(stream, "---------------------\n");
+ vfprintf(stream, format, arglist);
+ va_end(arglist);
+
+ fflush(stream);
+
+ flk.l_type = F_UNLCK;
+ fcntl(fileno(stream), F_SETLKW, &flk);
+
+ return rval;
+}
+
+/*
+ * Simple function for allocating core memory. Uses Memsize and Memptr to
+ * keep track of the current amount allocated.
+ */
+#ifndef CRAY
+int
+alloc_mem(nbytes)
+int nbytes;
+{
+ char *cp;
+ void *addr;
+ int me = 0, flags, key, shmid;
+ static int mturn = 0; /* which memory type to use */
+ struct memalloc *M;
+ char filename[255];
+#ifdef linux
+ struct shmid_ds shm_ds;
+#endif
+
+#ifdef linux
+ bzero( &shm_ds, sizeof(struct shmid_ds) );
+#endif
+
+ /* nbytes = -1 means "free all allocated memory" */
+ if( nbytes == -1 ) {
+
+ for(me=0; me < Nmemalloc; me++) {
+ if(Memalloc[me].space == NULL)
+ continue;
+
+ switch(Memalloc[me].memtype) {
+ case MEM_DATA:
+#ifdef sgi
+ if(Memalloc[me].flags & MEMF_MPIN)
+ munpin(Memalloc[me].space,
+ Memalloc[me].size);
+#endif
+ free(Memalloc[me].space);
+ Memalloc[me].space = NULL;
+ Memptr = NULL;
+ Memsize = 0;
+ break;
+ case MEM_SHMEM:
+#ifdef sgi
+ if(Memalloc[me].flags & MEMF_MPIN)
+ munpin(Memalloc[me].space,
+ Memalloc[me].size);
+#endif
+ shmdt(Memalloc[me].space);
+ Memalloc[me].space = NULL;
+#ifdef sgi
+ shmctl(Memalloc[me].fd, IPC_RMID);
+#else
+ shmctl(Memalloc[me].fd, IPC_RMID, &shm_ds);
+#endif
+ break;
+ case MEM_MMAP:
+#ifdef sgi
+ if(Memalloc[me].flags & MEMF_MPIN)
+ munpin(Memalloc[me].space,
+ Memalloc[me].size);
+#endif
+ munmap(Memalloc[me].space,
+ Memalloc[me].size);
+ close(Memalloc[me].fd);
+ if(Memalloc[me].flags & MEMF_FILE) {
+ unlink(Memalloc[me].name);
+ }
+ Memalloc[me].space = NULL;
+ break;
+ default:
+ doio_fprintf(stderr, "alloc_mem: HELP! Unknown memory space type %d index %d\n",
+ Memalloc[me].memtype, me);
+ break;
+ }
+ }
+ return 0;
+ }
+
+ /*
+ * Select a memory area (currently round-robbin)
+ */
+
+ if(mturn >= Nmemalloc)
+ mturn=0;
+
+ M = &Memalloc[mturn];
+
+ switch(M->memtype) {
+ case MEM_DATA:
+ if( nbytes > M->size ) {
+ if( M->space != NULL ){
+#ifdef sgi
+ if( M->flags & MEMF_MPIN )
+ munpin( M->space, M->size );
+#endif
+ free(M->space);
+ }
+ M->space = NULL;
+ M->size = 0;
+ }
+
+ if( M->space == NULL ) {
+ if( (cp = malloc( nbytes )) == NULL ) {
+ doio_fprintf(stderr, "malloc(%d) failed: %s (%d)\n",
+ nbytes, SYSERR, errno);
+ return -1;
+ }
+#ifdef sgi
+ if(M->flags & MEMF_MPIN) {
+ if( mpin(cp, nbytes) == -1 ) {
+ doio_fprintf(stderr, "mpin(0x%lx, %d) failed: %s (%d)\n",
+ cp, nbytes, SYSERR, errno);
+ }
+ }
+#endif
+ M->space = (void *)cp;
+ M->size = nbytes;
+ }
+ break;
+
+ case MEM_MMAP:
+ if( nbytes > M->size ) {
+ if( M->space != NULL ) {
+#ifdef sgi
+ if( M->flags & MEMF_MPIN )
+ munpin(M->space, M->size);
+#endif
+ munmap(M->space, M->size);
+ close(M->fd);
+ if( M->flags & MEMF_FILE )
+ unlink( M->name );
+ }
+ M->space = NULL;
+ M->size = 0;
+ }
+
+ if( M->space == NULL ) {
+ if(strchr(M->name, '%')) {
+ sprintf(filename, M->name, getpid());
+ M->name = strdup(filename);
+ }
+
+ if( (M->fd = open(M->name, O_CREAT|O_RDWR, 0666)) == -1) {
+ doio_fprintf(stderr, "alloc_mmap: error %d (%s) opening '%s'\n",
+ errno, SYSERR,
+ M->name);
+ return(-1);
+ }
+
+ addr = NULL;
+ flags = 0;
+ M->size = nbytes * 4;
+
+ /* bias addr if MEMF_ADDR | MEMF_FIXADDR */
+ /* >>> how to pick a memory address? */
+
+ /* bias flags on MEMF_PRIVATE etc */
+ if(M->flags & MEMF_PRIVATE)
+ flags |= MAP_PRIVATE;
+#ifdef sgi
+ if(M->flags & MEMF_LOCAL)
+ flags |= MAP_LOCAL;
+ if(M->flags & MEMF_AUTORESRV)
+ flags |= MAP_AUTORESRV;
+ if(M->flags & MEMF_AUTOGROW)
+ flags |= MAP_AUTOGROW;
+#endif
+ if(M->flags & MEMF_SHARED)
+ flags |= MAP_SHARED;
+
+/*printf("alloc_mem, about to mmap, fd=%d, name=(%s)\n", M->fd, M->name);*/
+ if( (M->space = mmap(addr, M->size,
+ PROT_READ|PROT_WRITE,
+ flags, M->fd, 0))
+ == MAP_FAILED) {
+ doio_fprintf(stderr, "alloc_mem: mmap error. errno %d (%s)\n\tmmap(addr 0x%x, size %d, read|write 0x%x, mmap flags 0x%x [%#o], fd %d, 0)\n\tfile %s\n",
+ errno, SYSERR,
+ addr, M->size,
+ PROT_READ|PROT_WRITE,
+ flags, M->flags, M->fd,
+ M->name);
+ doio_fprintf(stderr, "\t%s%s%s%s%s",
+ (flags & MAP_PRIVATE) ? "private " : "",
+#ifdef sgi
+ (flags & MAP_LOCAL) ? "local " : "",
+ (flags & MAP_AUTORESRV) ? "autoresrv " : "",
+ (flags & MAP_AUTOGROW) ? "autogrow " : "",
+#endif
+ (flags & MAP_SHARED) ? "shared" : "");
+ return(-1);
+ }
+ }
+ break;
+
+ case MEM_SHMEM:
+ if( nbytes > M->size ) {
+ if( M->space != NULL ) {
+#ifdef sgi
+ if( M->flags & MEMF_MPIN )
+ munpin(M->space, M->size);
+#endif
+ shmdt( M->space );
+#ifdef sgi
+ shmctl( M->fd, IPC_RMID );
+#else
+ shmctl( M->fd, IPC_RMID, &shm_ds );
+#endif
+ }
+ M->space = NULL;
+ M->size = 0;
+ }
+
+ if(M->space == NULL) {
+ if(!strcmp(M->name, "private")) {
+ key = IPC_PRIVATE;
+ } else {
+ sscanf(M->name, "%i", &key);
+ }
+
+ M->size = M->nblks ? M->nblks * 512 : nbytes;
+
+ if( nbytes > M->size ){
+#ifdef DEBUG
+ doio_fprintf(stderr, "MEM_SHMEM: nblks(%d) too small: nbytes=%d Msize=%d, skipping this req.\n",
+ M->nblks, nbytes, M->size );
+#endif
+ return SKIP_REQ;
+ }
+
+ shmid = shmget(key, M->size, IPC_CREAT|0666);
+ if( shmid == -1 ) {
+ doio_fprintf(stderr, "shmget(0x%x, %d, CREAT) failed: %s (%d)\n",
+ key, M->size, SYSERR, errno);
+ return(-1);
+ }
+ M->fd = shmid;
+ M->space = shmat(shmid, NULL, SHM_RND);
+ if( M->space == (void *)-1 ) {
+ doio_fprintf(stderr, "shmat(0x%x, NULL, SHM_RND) failed: %s (%d)\n",
+ shmid, SYSERR, errno);
+ return(-1);
+ }
+#ifdef sgi
+ if(M->flags & MEMF_MPIN) {
+ if( mpin(M->space, M->size) == -1 ) {
+ doio_fprintf(stderr, "mpin(0x%lx, %d) failed: %s (%d)\n",
+ M->space, M->size, SYSERR, errno);
+ }
+ }
+#endif
+ }
+ break;
+
+ default:
+ doio_fprintf(stderr, "alloc_mem: HELP! Unknown memory space type %d index %d\n",
+ Memalloc[me].memtype, mturn);
+ break;
+ }
+
+ Memptr = M->space;
+ Memsize = M->size;
+
+ mturn++;
+ return 0;
+}
+#endif /* !CRAY */
+
+#ifdef CRAY
+int
+alloc_mem(nbytes)
+int nbytes;
+{
+ char *cp;
+ int ip;
+ static char *malloc_space;
+
+ /*
+ * The "unicos" version of this did some stuff with sbrk;
+ * this caused problems with async I/O on irix, and now appears
+ * to be causing problems with FSA I/O on unicos/mk.
+ */
+#ifdef NOTDEF
+ if (nbytes > Memsize) {
+ if ((cp = (char *)sbrk(nbytes - Memsize)) == (char *)-1) {
+ doio_fprintf(stderr, "sbrk(%d) failed: %s (%d)\n",
+ nbytes - Memsize, SYSERR, errno);
+ return -1;
+ }
+
+ if (Memsize == 0)
+ Memptr = cp;
+ Memsize += nbytes - Memsize;
+ }
+#else
+
+ /* nbytes = -1 means "free all allocated memory" */
+ if( nbytes == -1 ) {
+ free( malloc_space );
+ Memptr = NULL;
+ Memsize = 0;
+ return 0;
+ }
+
+ if( nbytes > Memsize ) {
+ if( Memsize != 0 )
+ free( malloc_space );
+
+ if( (cp = malloc_space = malloc( nbytes )) == NULL ) {
+ doio_fprintf(stderr, "malloc(%d) failed: %s (%d)\n",
+ nbytes, SYSERR, errno);
+ return -1;
+ }
+
+#ifdef _CRAYT3E
+ /* T3E requires memory to be aligned on 0x40 word boundaries */
+ ip = (int)cp;
+ if( ip & 0x3F != 0 ) {
+ doio_fprintf(stderr, "malloc(%d) = 0x%x(0x%x) not aligned by 0x%x\n",
+ nbytes, cp, ip, ip & 0x3f);
+
+ free(cp);
+ if( (cp = malloc_space = malloc( nbytes + 0x40 )) == NULL ) {
+ doio_fprintf(stderr, "malloc(%d) failed: %s (%d)\n",
+ nbytes, SYSERR, errno);
+ return -1;
+ }
+ ip = (int)cp;
+ cp += (0x40 - (ip & 0x3F));
+ }
+#endif /* _CRAYT3E */
+ Memptr = cp;
+ Memsize = nbytes;
+ }
+#endif /* NOTDEF */
+ return 0;
+}
+#endif /* CRAY */
+
+/*
+ * Simple function for allocating sds space. Uses Sdssize and Sdsptr to
+ * keep track of location and size of currently allocated chunk.
+ */
+
+#ifdef _CRAY1
+
+int
+alloc_sds(nbytes)
+int nbytes;
+{
+ int nblks;
+
+ if (nbytes > Sdssize) {
+ if ((nblks = ssbreak(btoc(nbytes - Sdssize))) == -1) {
+ doio_fprintf(stderr, "ssbreak(%d) failed: %s (%d)\n",
+ btoc(nbytes - Sdssize), SYSERR, errno);
+ return -1;
+ }
+
+ Sdssize = ctob(nblks);
+ Sdsptr = 0;
+ }
+
+ return 0;
+}
+
+#else
+
+#ifdef CRAY
+
+int
+alloc_sds(nbytes)
+int nbytes;
+{
+ doio_fprintf(stderr,
+ "Internal Error - alloc_sds() called on a CRAY2 system\n");
+ alloc_mem(-1);
+ exit(E_INTERNAL);
+}
+
+#endif
+
+#endif /* _CRAY1 */
+
+/*
+ * Function to maintain a file descriptor cache, so that doio does not have
+ * to do so many open() and close() calls. Descriptors are stored in the
+ * cache by file name, and open flags. Each entry also has a _rtc value
+ * associated with it which is used in aging. If doio cannot open a file
+ * because it already has too many open (ie. system limit hit) it will close
+ * the one in the cache that has the oldest _rtc value.
+ *
+ * If alloc_fd() is called with a file of NULL, it will close all descriptors
+ * in the cache, and free the memory in the cache.
+ */
+
+int
+alloc_fd(file, oflags)
+char *file;
+int oflags;
+{
+ struct fd_cache *fdc;
+ struct fd_cache *alloc_fdcache(char *file, int oflags);
+
+ fdc = alloc_fdcache(file, oflags);
+ if(fdc != NULL)
+ return(fdc->c_fd);
+ else
+ return(-1);
+}
+
+struct fd_cache *
+alloc_fdcache(file, oflags)
+char *file;
+int oflags;
+{
+ int fd;
+ struct fd_cache *free_slot, *oldest_slot, *cp;
+ static int cache_size = 0;
+ static struct fd_cache *cache = NULL;
+#ifndef NO_XFS
+ struct dioattr finfo;
+#endif
+
+ /*
+ * If file is NULL, it means to free up the fd cache.
+ */
+
+ if (file == NULL && cache != NULL) {
+ for (cp = cache; cp < &cache[cache_size]; cp++) {
+ if (cp->c_fd != -1) {
+ close(cp->c_fd);
+ }
+#ifndef CRAY
+ if (cp->c_memaddr != NULL) {
+ munmap(cp->c_memaddr, cp->c_memlen);
+ }
+#endif
+ }
+
+ free(cache);
+ cache = NULL;
+ cache_size = 0;
+ return 0;
+ }
+
+ free_slot = NULL;
+ oldest_slot = NULL;
+
+ /*
+ * Look for a fd in the cache. If one is found, return it directly.
+ * Otherwise, when this loop exits, oldest_slot will point to the
+ * oldest fd slot in the cache, and free_slot will point to an
+ * unoccupied slot if there are any.
+ */
+
+ for (cp = cache; cp != NULL && cp < &cache[cache_size]; cp++) {
+ if (cp->c_fd != -1 &&
+ cp->c_oflags == oflags &&
+ strcmp(cp->c_file, file) == 0) {
+#ifdef CRAY
+ cp->c_rtc = _rtc();
+#else
+ cp->c_rtc = Reqno;
+#endif
+ return cp;
+ }
+
+ if (cp->c_fd == -1) {
+ if (free_slot == NULL) {
+ free_slot = cp;
+ }
+ } else {
+ if (oldest_slot == NULL ||
+ cp->c_rtc < oldest_slot->c_rtc) {
+ oldest_slot = cp;
+ }
+ }
+ }
+
+ /*
+ * No matching file/oflags pair was found in the cache. Attempt to
+ * open a new fd.
+ */
+
+ if ((fd = open(file, oflags, 0666)) < 0) {
+ if (errno != EMFILE) {
+ doio_fprintf(stderr,
+ "Could not open file %s with flags %#o (%s): %s (%d)\n",
+ file, oflags, format_oflags(oflags),
+ SYSERR, errno);
+ alloc_mem(-1);
+ exit(E_SETUP);
+ }
+
+ /*
+ * If we get here, we have as many open fd's as we can have.
+ * Close the oldest one in the cache (pointed to by
+ * oldest_slot), and attempt to re-open.
+ */
+
+ close(oldest_slot->c_fd);
+ oldest_slot->c_fd = -1;
+ free_slot = oldest_slot;
+
+ if ((fd = open(file, oflags, 0666)) < 0) {
+ doio_fprintf(stderr,
+ "Could not open file %s with flags %#o (%s): %s (%d)\n",
+ file, oflags, format_oflags(oflags),
+ SYSERR, errno);
+ alloc_mem(-1);
+ exit(E_SETUP);
+ }
+ }
+
+/*printf("alloc_fd: new file %s flags %#o fd %d\n", file, oflags, fd);*/
+
+ /*
+ * If we get here, fd is our open descriptor. If free_slot is NULL,
+ * we need to grow the cache, otherwise free_slot is the slot that
+ * should hold the fd info.
+ */
+
+ if (free_slot == NULL) {
+ cache = (struct fd_cache *)realloc(cache, sizeof(struct fd_cache) * (FD_ALLOC_INCR + cache_size));
+ if (cache == NULL) {
+ doio_fprintf(stderr, "Could not malloc() space for fd chace");
+ alloc_mem(-1);
+ exit(E_SETUP);
+ }
+
+ cache_size += FD_ALLOC_INCR;
+
+ for (cp = &cache[cache_size-FD_ALLOC_INCR];
+ cp < &cache[cache_size]; cp++) {
+ cp->c_fd = -1;
+ }
+
+ free_slot = &cache[cache_size - FD_ALLOC_INCR];
+ }
+
+ /*
+ * finally, fill in the cache slot info
+ */
+
+ free_slot->c_fd = fd;
+ free_slot->c_oflags = oflags;
+ strcpy(free_slot->c_file, file);
+#ifdef CRAY
+ free_slot->c_rtc = _rtc();
+#else
+ free_slot->c_rtc = Reqno;
+#endif
+
+#ifndef NO_XFS
+ if (oflags & O_DIRECT) {
+ if (xfsctl(file, fd, XFS_IOC_DIOINFO, &finfo) == -1) {
+ finfo.d_mem = 1;
+ finfo.d_miniosz = 1;
+ finfo.d_maxiosz = 1;
+ }
+ } else {
+ finfo.d_mem = 1;
+ finfo.d_miniosz = 1;
+ finfo.d_maxiosz = 1;
+ }
+
+ free_slot->c_memalign = finfo.d_mem;
+ free_slot->c_miniosz = finfo.d_miniosz;
+ free_slot->c_maxiosz = finfo.d_maxiosz;
+#endif
+#ifndef CRAY
+ free_slot->c_memaddr = NULL;
+ free_slot->c_memlen = 0;
+#endif
+
+ return free_slot;
+}
+
+/*
+ *
+ * Signal Handling Section
+ *
+ *
+ */
+
+#ifdef sgi
+/*
+ * "caller-id" for signals
+ */
+void
+signal_info(int sig, siginfo_t *info, void *v)
+{
+ int haveit = 0;
+
+ if(info != NULL) {
+ switch(info->si_code) {
+ case SI_USER:
+ doio_fprintf(stderr,
+ "signal_info: si_signo %d si_errno %d si_code SI_USER pid %d uid %d\n",
+ info->si_signo, info->si_errno,
+ info->si_pid, info->si_uid);
+ haveit = 1;
+ break;
+
+ case SI_QUEUE:
+ doio_fprintf(stderr, "signal_info si_signo %d si_code = SI_QUEUE\n",
+ info->si_signo);
+ haveit = 1;
+ break;
+ }
+
+ if( ! haveit ){
+ if( (info->si_signo == SIGSEGV) ||
+ (info->si_signo == SIGBUS) ){
+ doio_fprintf(stderr, "signal_info si_signo %d si_errno %d si_code = %d si_addr=%p active_mmap_rw=%d havesigint=%d\n",
+ info->si_signo, info->si_errno,
+ info->si_code, info->si_addr,
+ active_mmap_rw,
+ havesigint);
+ haveit = 1;
+ }
+ }
+
+ if( !haveit ){
+ doio_fprintf(stderr, "signal_info: si_signo %d si_errno %d unknown code %d\n",
+ info->si_signo, info->si_errno,
+ info->si_code);
+ }
+ } else {
+ doio_fprintf(stderr, "signal_info: sig %d\n", sig);
+ }
+}
+#endif
+
+#ifdef sgi
+void
+cleanup_handler(int sig, siginfo_t *info, void *v)
+{
+ havesigint=1; /* in case there's a followup signal */
+ /*signal_info(sig, info, v);*/ /* be quiet on "normal" kill */
+ alloc_mem(-1);
+ exit(0);
+}
+
+
+void
+die_handler(int sig, siginfo_t *info, void *v)
+{
+ doio_fprintf(stderr, "terminating on signal %d\n", sig);
+ signal_info(sig, info, v);
+ alloc_mem(-1);
+ exit(1);
+}
+
+void
+sigbus_handler(int sig, siginfo_t *info, void *v)
+{
+ /* While we are doing a memcpy to/from an mmapped region we can
+ get a SIGBUS for a variety of reasons--and not all of them
+ should be considered failures.
+
+ Under normal conditions if we get a SIGINT it means we've been
+ told to shutdown. However, if we're currently doing the above-
+ mentioned memcopy then the kernel will follow that SIGINT with
+ a SIGBUS. We can guess that we're in this situation by seeing
+ that the si_errno field in the siginfo structure has EINTR as
+ an errno. (We might make the guess stronger by looking at the
+ si_addr field to see that it's not faulting off the end of the
+ mmapped region, but it seems that in such a case havesigint
+ would not have been set so maybe that doesn't make the guess
+ stronger.)
+ */
+
+
+ if( active_mmap_rw && havesigint && (info->si_errno == EINTR) ){
+ cleanup_handler( sig, info, v );
+ }
+ else{
+ die_handler( sig, info, v );
+ }
+}
+#else
+
+void
+cleanup_handler()
+{
+ havesigint=1; /* in case there's a followup signal */
+ alloc_mem(-1);
+ exit(0);
+}
+
+void
+die_handler(sig)
+int sig;
+{
+ doio_fprintf(stderr, "terminating on signal %d\n", sig);
+ alloc_mem(-1);
+ exit(1);
+}
+
+#ifndef CRAY
+void
+sigbus_handler(sig)
+int sig;
+{
+ /* See sigbus_handler() in the 'ifdef sgi' case for details. Here,
+ we don't have the siginfo stuff so the guess is weaker but we'll
+ do it anyway.
+ */
+
+ if( active_mmap_rw && havesigint )
+ cleanup_handler();
+ else
+ die_handler(sig);
+}
+#endif /* !CRAY */
+#endif /* sgi */
+
+
+void
+noop_handler(sig)
+int sig;
+{
+ return;
+}
+
+
+/*
+ * SIGINT handler for the parent (original doio) process. It simply sends
+ * a SIGINT to all of the doio children. Since they're all in the same
+ * pgrp, this can be done with a single kill().
+ */
+
+void
+sigint_handler()
+{
+ int i;
+
+ for (i = 0; i < Nchildren; i++) {
+ if (Children[i] != -1) {
+ kill(Children[i], SIGINT);
+ }
+ }
+}
+
+/*
+ * Signal handler used to inform a process when async io completes. Referenced
+ * in do_read() and do_write(). Note that the signal handler is not
+ * re-registered.
+ */
+
+void
+aio_handler(sig)
+int sig;
+{
+ int i;
+ struct aio_info *aiop;
+
+ for (i = 0; i < sizeof(Aio_Info) / sizeof(Aio_Info[0]); i++) {
+ aiop = &Aio_Info[i];
+
+ if (aiop->strategy == A_SIGNAL && aiop->sig == sig) {
+ aiop->signalled++;
+
+ if (aio_done(aiop)) {
+ aiop->done++;
+ }
+ }
+ }
+}
+
+/*
+ * dump info on all open aio slots
+ */
+void
+dump_aio()
+{
+ int i, count;
+
+ count=0;
+ for (i = 0; i < sizeof(Aio_Info) / sizeof(Aio_Info[0]); i++) {
+ if (Aio_Info[i].busy) {
+ count++;
+ fprintf(stderr,
+ "Aio_Info[%03d] id=%d fd=%d signal=%d signaled=%d\n",
+ i, Aio_Info[i].id,
+ Aio_Info[i].fd,
+ Aio_Info[i].sig,
+ Aio_Info[i].signalled);
+ fprintf(stderr, "\tstrategy=%s\n",
+ format_strat(Aio_Info[i].strategy));
+ }
+ }
+ fprintf(stderr, "%d active async i/os\n", count);
+}
+
+
+#ifdef sgi
+/*
+ * Signal handler called as a callback, not as a signal.
+ * 'val' is the value from sigev_value and is assumed to be the
+ * Aio_Info[] index.
+ */
+void
+cb_handler(val)
+sigval_t val;
+{
+ struct aio_info *aiop;
+
+/*printf("cb_handler requesting slot %d\n", val.sival_int);*/
+ aiop = aio_slot( val.sival_int );
+/*printf("cb_handler, aiop=%p\n", aiop);*/
+
+/*printf("%d in cb_handler\n", getpid() );*/
+ if (aiop->strategy == A_CALLBACK) {
+ aiop->signalled++;
+
+ if (aio_done(aiop)) {
+ aiop->done++;
+ }
+ }
+}
+#endif
+
+struct aio_info *
+aio_slot(aio_id)
+int aio_id;
+{
+ int i;
+ static int id = 1;
+ struct aio_info *aiop;
+
+ aiop = NULL;
+
+ for (i = 0; i < sizeof(Aio_Info) / sizeof(Aio_Info[0]); i++) {
+ if (aio_id == -1) {
+ if (! Aio_Info[i].busy) {
+ aiop = &Aio_Info[i];
+ aiop->busy = 1;
+ aiop->id = id++;
+ break;
+ }
+ } else {
+ if (Aio_Info[i].busy && Aio_Info[i].id == aio_id) {
+ aiop = &Aio_Info[i];
+ break;
+ }
+ }
+ }
+
+ if( aiop == NULL ){
+ doio_fprintf(stderr,"aio_slot(%d) not found. Request %d\n",
+ aio_id, Reqno);
+ dump_aio();
+ alloc_mem(-1);
+ exit(E_INTERNAL);
+ }
+
+ return aiop;
+}
+
+int
+aio_register(fd, strategy, sig)
+int fd;
+int strategy;
+int sig;
+{
+ struct aio_info *aiop;
+ void aio_handler();
+ struct sigaction sa;
+
+ aiop = aio_slot(-1);
+
+ aiop->fd = fd;
+ aiop->strategy = strategy;
+ aiop->done = 0;
+#ifdef CRAY
+ bzero((char *)&aiop->iosw, sizeof(aiop->iosw));
+#endif
+
+ if (strategy == A_SIGNAL) {
+ aiop->sig = sig;
+ aiop->signalled = 0;
+
+ sa.sa_handler = aio_handler;
+ sa.sa_flags = 0;
+ sigemptyset(&sa.sa_mask);
+
+ sigaction(sig, &sa, &aiop->osa);
+ } else {
+ aiop->sig = -1;
+ aiop->signalled = 0;
+ }
+
+ return aiop->id;
+}
+
+int
+aio_unregister(aio_id)
+int aio_id;
+{
+ struct aio_info *aiop;
+
+ aiop = aio_slot(aio_id);
+
+ if (aiop->strategy == A_SIGNAL) {
+ sigaction(aiop->sig, &aiop->osa, NULL);
+ }
+
+ aiop->busy = 0;
+ return 0;
+}
+
+#ifndef linux
+int
+aio_wait(aio_id)
+int aio_id;
+{
+#ifdef RECALL_SIZEOF
+ long mask[RECALL_SIZEOF];
+#endif
+ sigset_t sigset;
+ struct aio_info *aiop;
+#ifdef CRAY
+ struct iosw *ioswlist[1];
+#endif
+#ifdef sgi
+ const aiocb_t *aioary[1];
+#endif
+ int r, cnt;
+
+
+ aiop = aio_slot(aio_id);
+/*printf("%d aiop B =%p\n", getpid(), aiop);*/
+
+ switch (aiop->strategy) {
+ case A_POLL:
+ while (! aio_done(aiop))
+ ;
+ break;
+
+ case A_SIGNAL:
+ sigemptyset(&sigset);
+ sighold( aiop->sig );
+
+ while ( !aiop->signalled || !aiop->done ) {
+ sigsuspend(&sigset);
+ sighold( aiop->sig );
+ }
+ break;
+
+#ifdef CRAY
+ case A_RECALL:
+ ioswlist[0] = &aiop->iosw;
+ if (recall(aiop->fd, 1, ioswlist) < 0) {
+ doio_fprintf(stderr, "recall() failed: %s (%d)\n",
+ SYSERR, errno);
+ exit(E_SETUP);
+ }
+ break;
+
+#ifdef RECALL_SIZEOF
+
+ case A_RECALLA:
+ RECALL_INIT(mask);
+ RECALL_SET(mask, aiop->fd);
+ if (recalla(mask) < 0) {
+ doio_fprintf(stderr, "recalla() failed: %s (%d)\n",
+ SYSERR, errno);
+ exit(E_SETUP);
+ }
+
+ RECALL_CLR(mask, aiop->fd);
+ break;
+#endif
+
+ case A_RECALLS:
+ ioswlist[0] = &aiop->iosw;
+ if (recalls(1, ioswlist) < 0) {
+ doio_fprintf(stderr, "recalls failed: %s (%d)\n",
+ SYSERR, errno);
+ exit(E_SETUP);
+ }
+ break;
+#endif /* CRAY */
+
+#ifdef sgi
+ case A_CALLBACK:
+ aioary[0] = &aiop->aiocb;
+ cnt=0;
+ do {
+ r = aio_suspend(aioary, 1, NULL);
+ if( r == -1 ){
+ doio_fprintf(stderr, "aio_suspend failed: %s (%d)\n",
+ SYSERR, errno );
+ exit(E_SETUP);
+ }
+ cnt++;
+ } while(aiop->done == 0);
+
+#if 0
+ /*
+ * after having this set for a while, I've decided that
+ * it's too noisy
+ */
+ if(cnt > 1)
+ doio_fprintf(stderr, "aio_wait: callback wait took %d tries\n", cnt);
+#endif
+
+ /*
+ * Note: cb_handler already calls aio_done
+ */
+ break;
+
+
+ case A_SUSPEND:
+ aioary[0] = &aiop->aiocb;
+ r = aio_suspend(aioary, 1, NULL);
+ if( r == -1 ){
+ doio_fprintf(stderr, "aio_suspend failed: %s (%d)\n",
+ SYSERR, errno );
+ exit(E_SETUP);
+ }
+
+ aio_done(aiop);
+ break;
+#endif
+ }
+
+/*printf("aio_wait: errno %d return %d\n", aiop->aio_errno, aiop->aio_ret);*/
+
+ return 0;
+}
+#endif /* !linux */
+
+/*
+ * Format specified time into HH:MM:SS format. t is the time to format
+ * in seconds (as returned from time(2)).
+ */
+
+char *
+hms(t)
+time_t t;
+{
+ static char ascii_time[9];
+ struct tm *ltime;
+
+ ltime = localtime(&t);
+ strftime(ascii_time, sizeof(ascii_time), "%H:%M:%S", ltime);
+
+ return ascii_time;
+}
+
+/*
+ * Simple routine to check if an async io request has completed.
+ */
+
+int
+aio_done(struct aio_info *ainfo)
+{
+#ifdef CRAY
+ return ainfo->iosw.sw_flag;
+#endif
+
+#ifdef sgi
+ if( (ainfo->aio_errno = aio_error(&ainfo->aiocb)) == -1 ){
+ doio_fprintf(stderr, "aio_done: aio_error failed: %s (%d)\n",
+ SYSERR, errno );
+ exit(E_SETUP);
+ }
+ /*printf("%d aio_done aio_errno=%d\n", getpid(), ainfo->aio_errno);*/
+ if( ainfo->aio_errno != EINPROGRESS ){
+ if( (ainfo->aio_ret = aio_return(&ainfo->aiocb)) == -1 ){
+ doio_fprintf(stderr, "aio_done: aio_return failed: %s (%d)\n",
+ SYSERR, errno );
+ exit(E_SETUP);
+ }
+ }
+
+ return (ainfo->aio_errno != EINPROGRESS);
+#else
+ return -1; /* invalid */
+#endif
+}
+
+/*
+ * Routine to handle upanic() - it first attempts to set the panic flag. If
+ * the flag cannot be set, an error message is issued. A call to upanic
+ * with PA_PANIC is then done unconditionally, in case the panic flag was set
+ * from outside the program (as with the panic(8) program).
+ *
+ * Note - we only execute the upanic code if -U was used, and the passed in
+ * mask is set in the Upanic_Conditions bitmask.
+ */
+
+void
+doio_upanic(mask)
+int mask;
+{
+ if (U_opt == 0 || (mask & Upanic_Conditions) == 0) {
+ return;
+ }
+
+#ifdef CRAY
+ if (upanic(PA_SET) < 0) {
+ doio_fprintf(stderr, "WARNING - Could not set the panic flag - upanic(PA_SET) failed: %s (%d)\n",
+ SYSERR, errno);
+ }
+
+ upanic(PA_PANIC);
+#endif
+#ifdef sgi
+ syssgi(1005); /* syssgi test panic - DEBUG kernels only */
+#endif
+ doio_fprintf(stderr, "WARNING - upanic() failed\n");
+}
+
+/*
+ * Parse cmdline options/arguments and set appropriate global variables.
+ * If the cmdline is valid, return 0 to caller. Otherwise exit with a status
+ * of 1.
+ */
+
+int
+parse_cmdline(argc, argv, opts)
+int argc;
+char **argv;
+char *opts;
+{
+ int c;
+ char cc, *cp, *tok = NULL;
+ extern int opterr;
+ extern int optind;
+ extern char *optarg;
+ struct smap *s;
+ char *memargs[NMEMALLOC];
+ int nmemargs, ma;
+ void parse_memalloc(char *arg);
+ void parse_delay(char *arg);
+ void dump_memalloc();
+
+ if (*argv[0] == '-') {
+ argv[0]++;
+ Execd = 1;
+ }
+
+ if ((Prog = strrchr(argv[0], '/')) == NULL) {
+ Prog = argv[0];
+ } else {
+ Prog++;
+ }
+
+ opterr = 0;
+ while ((c = getopt(argc, argv, opts)) != EOF) {
+ switch ((char)c) {
+ case 'a':
+ a_opt++;
+ break;
+
+ case 'C':
+ C_opt++;
+ for(s=checkmap; s->string != NULL; s++)
+ if(!strcmp(s->string, optarg))
+ break;
+ if (s->string == NULL) {
+ fprintf(stderr,
+ "%s%s: Illegal -C arg (%s). Must be one of: ",
+ Prog, TagName, tok);
+
+ for (s = checkmap; s->string != NULL; s++)
+ fprintf(stderr, "%s ", s->string);
+ fprintf(stderr, "\n");
+ exit(1);
+ }
+
+ switch(s->value) {
+ case C_DEFAULT:
+ Data_Fill = doio_pat_fill;
+ Data_Check = doio_pat_check;
+ break;
+ default:
+ fprintf(stderr,
+ "%s%s: Unrecognised -C arg '%s' %d",
+ Prog, TagName, s->string, s->value);
+ exit(1);
+ }
+ break;
+
+ case 'd': /* delay between i/o ops */
+ parse_delay(optarg);
+ break;
+
+ case 'e':
+ if (Npes > 1 && Nprocs > 1) {
+ fprintf(stderr, "%s%s: Warning - Program is a multi-pe application - exec option is ignored.\n", Prog, TagName);
+ }
+ e_opt++;
+ break;
+
+ case 'h':
+ help(stdout);
+ exit(0);
+ break;
+
+ case 'k':
+ k_opt++;
+ break;
+
+ case 'm':
+ Message_Interval = strtol(optarg, &cp, 10);
+ if (*cp != '\0' || Message_Interval < 0) {
+ fprintf(stderr, "%s%s: Illegal -m arg (%s): Must be an integer >= 0\n", Prog, TagName, optarg);
+ exit(1);
+ }
+ m_opt++;
+ break;
+
+ case 'M': /* memory allocation types */
+#ifndef CRAY
+ nmemargs = string_to_tokens(optarg, memargs, 32, ",");
+ for(ma=0; ma < nmemargs; ma++) {
+ parse_memalloc(memargs[ma]);
+ }
+ /*dump_memalloc();*/
+#else
+ fprintf(stderr, "%s%s: Error: -M isn't supported on this platform\n", Prog, TagName);
+ exit(1);
+#endif
+ M_opt++;
+ break;
+
+ case 'N':
+ sprintf( TagName, "(%.39s)", optarg );
+ break;
+
+ case 'n':
+ Nprocs = strtol(optarg, &cp, 10);
+ if (*cp != '\0' || Nprocs < 1) {
+ fprintf(stderr,
+ "%s%s: Illegal -n arg (%s): Must be integer > 0\n",
+ Prog, TagName, optarg);
+ exit(E_USAGE);
+ }
+
+ if (Npes > 1 && Nprocs > 1) {
+ fprintf(stderr, "%s%s: Program has been built as a multi-pe app. -n1 is the only nprocs value allowed\n", Prog, TagName);
+ exit(E_SETUP);
+ }
+ n_opt++;
+ break;
+
+ case 'r':
+ Release_Interval = strtol(optarg, &cp, 10);
+ if (*cp != '\0' || Release_Interval < 0) {
+ fprintf(stderr,
+ "%s%s: Illegal -r arg (%s): Must be integer >= 0\n",
+ Prog, TagName, optarg);
+ exit(E_USAGE);
+ }
+
+ r_opt++;
+ break;
+
+ case 'w':
+ Write_Log = optarg;
+ w_opt++;
+ break;
+
+ case 'v':
+ v_opt++;
+ break;
+
+ case 'V':
+ if (strcasecmp(optarg, "sync") == 0) {
+ Validation_Flags = O_SYNC;
+ } else if (strcasecmp(optarg, "buffered") == 0) {
+ Validation_Flags = 0;
+#ifdef CRAY
+ } else if (strcasecmp(optarg, "parallel") == 0) {
+ Validation_Flags = O_PARALLEL;
+ } else if (strcasecmp(optarg, "ldraw") == 0) {
+ Validation_Flags = O_LDRAW;
+ } else if (strcasecmp(optarg, "raw") == 0) {
+ Validation_Flags = O_RAW;
+#endif
+ } else if (strcasecmp(optarg, "direct") == 0) {
+ Validation_Flags = O_DIRECT;
+ } else {
+ if (sscanf(optarg, "%i%c", &Validation_Flags, &cc) != 1) {
+ fprintf(stderr, "%s: Invalid -V argument (%s) - must be a decimal, hex, or octal\n", Prog, optarg);
+ fprintf(stderr, " number, or one of the following strings: 'sync',\n");
+ fprintf(stderr, " 'buffered', 'parallel', 'ldraw', or 'raw'\n");
+ exit(E_USAGE);
+ }
+ }
+ V_opt++;
+ break;
+ case 'U':
+ tok = strtok(optarg, ",");
+ while (tok != NULL) {
+ for (s = Upanic_Args; s->string != NULL; s++)
+ if (strcmp(s->string, tok) == 0)
+ break;
+
+ if (s->string == NULL) {
+ fprintf(stderr,
+ "%s%s: Illegal -U arg (%s). Must be one of: ",
+ Prog, TagName, tok);
+
+ for (s = Upanic_Args; s->string != NULL; s++)
+ fprintf(stderr, "%s ", s->string);
+
+ fprintf(stderr, "\n");
+
+ exit(1);
+ }
+
+ Upanic_Conditions |= s->value;
+ tok = strtok(NULL, ",");
+ }
+
+ U_opt++;
+ break;
+
+ case '?':
+ usage(stderr);
+ exit(E_USAGE);
+ break;
+ }
+ }
+
+ /*
+ * Supply defaults
+ */
+
+ if (! C_opt) {
+ Data_Fill = doio_pat_fill;
+ Data_Check = doio_pat_check;
+ }
+
+ if (! U_opt)
+ Upanic_Conditions = 0;
+
+ if (! n_opt)
+ Nprocs = 1;
+
+ if (! r_opt)
+ Release_Interval = DEF_RELEASE_INTERVAL;
+
+ if (! M_opt) {
+ Memalloc[Nmemalloc].memtype = MEM_DATA;
+ Memalloc[Nmemalloc].flags = 0;
+ Memalloc[Nmemalloc].name = NULL;
+ Memalloc[Nmemalloc].space = NULL;
+ Nmemalloc++;
+ }
+
+ /*
+ * Initialize input stream
+ */
+
+ if (argc == optind) {
+ Infile = NULL;
+ } else {
+ Infile = argv[optind++];
+ }
+
+ if (argc != optind) {
+ usage(stderr);
+ exit(E_USAGE);
+ }
+
+ return 0;
+}
+
+
+
+/*
+ * Parse memory allocation types
+ *
+ * Types are:
+ * Data
+ * T3E-shmem:blksize[:nblks]
+ * SysV-shmem:shmid:blksize:nblks
+ * if shmid is "private", use IPC_PRIVATE
+ * and nblks is not required
+ *
+ * mmap:flags:filename:blksize[:nblks]
+ * flags are one of:
+ * p - private (MAP_PRIVATE)
+ * a - private, MAP_AUTORESRV
+ * l - local (MAP_LOCAL)
+ * s - shared (nblks required)
+ *
+ * plus any of:
+ * f - fixed address (MAP_FIXED)
+ * A - use an address without MAP_FIXED
+ * a - autogrow (map once at startup)
+ *
+ * mmap:flags:devzero
+ * mmap /dev/zero (shared not allowd)
+ * maps the first 4096 bytes of /dev/zero
+ *
+ * - put a directory at the beginning of the shared
+ * regions saying what pid has what region.
+ * DIRMAGIC
+ * BLKSIZE
+ * NBLKS
+ * nblks worth of directories - 1 int pids
+ */
+#ifndef CRAY
+void
+parse_memalloc(char *arg)
+{
+ char *allocargs[NMEMALLOC];
+ int nalloc;
+ struct memalloc *M;
+
+ if(Nmemalloc >= NMEMALLOC) {
+ doio_fprintf(stderr, "Error - too many memory types (%d).\n",
+ Nmemalloc);
+ return;
+ }
+
+ M = &Memalloc[Nmemalloc];
+
+ nalloc = string_to_tokens(arg, allocargs, 32, ":");
+ if(!strcmp(allocargs[0], "data")) {
+ M->memtype = MEM_DATA;
+ M->flags = 0;
+ M->name = NULL;
+ M->space = NULL;
+ Nmemalloc++;
+ if(nalloc >= 2) {
+ if(strchr(allocargs[1], 'p'))
+ M->flags |= MEMF_MPIN;
+ }
+ } else if(!strcmp(allocargs[0], "mmap")) {
+ /* mmap:flags:filename[:size] */
+ M->memtype = MEM_MMAP;
+ M->flags = 0;
+ M->space = NULL;
+ if(nalloc >= 1) {
+ if(strchr(allocargs[1], 'p'))
+ M->flags |= MEMF_PRIVATE;
+ if(strchr(allocargs[1], 'a'))
+ M->flags |= MEMF_AUTORESRV;
+ if(strchr(allocargs[1], 'l'))
+ M->flags |= MEMF_LOCAL;
+ if(strchr(allocargs[1], 's'))
+ M->flags |= MEMF_SHARED;
+
+ if(strchr(allocargs[1], 'f'))
+ M->flags |= MEMF_FIXADDR;
+ if(strchr(allocargs[1], 'A'))
+ M->flags |= MEMF_ADDR;
+ if(strchr(allocargs[1], 'G'))
+ M->flags |= MEMF_AUTOGROW;
+
+ if(strchr(allocargs[1], 'U'))
+ M->flags |= MEMF_FILE;
+ } else {
+ M->flags |= MEMF_PRIVATE;
+ }
+
+ if(nalloc > 2) {
+ if(!strcmp(allocargs[2], "devzero")) {
+ M->name = "/dev/zero";
+ if(M->flags &
+ ((MEMF_PRIVATE|MEMF_LOCAL) == 0))
+ M->flags |= MEMF_PRIVATE;
+ } else {
+ M->name = allocargs[2];
+ }
+ } else {
+ M->name = "/dev/zero";
+ if(M->flags &
+ ((MEMF_PRIVATE|MEMF_LOCAL) == 0))
+ M->flags |= MEMF_PRIVATE;
+ }
+ Nmemalloc++;
+
+ } else if(!strcmp(allocargs[0], "shmem")) {
+ /* shmem:shmid:size */
+ M->memtype = MEM_SHMEM;
+ M->flags = 0;
+ M->space = NULL;
+ if(nalloc >= 2) {
+ M->name = allocargs[1];
+ } else {
+ M->name = NULL;
+ }
+ if(nalloc >= 3) {
+ sscanf(allocargs[2], "%i", &M->nblks);
+ } else {
+ M->nblks = 0;
+ }
+ if(nalloc >= 4) {
+ if(strchr(allocargs[3], 'p'))
+ M->flags |= MEMF_MPIN;
+ }
+
+ Nmemalloc++;
+ } else {
+ doio_fprintf(stderr, "Error - unknown memory type '%s'.\n",
+ allocargs[0]);
+ exit(1);
+ }
+}
+
+void
+dump_memalloc()
+{
+ int ma;
+ char *mt;
+
+ if(Nmemalloc == 0) {
+ printf("No memory allocation strategies devined\n");
+ return;
+ }
+
+ for(ma=0; ma < Nmemalloc; ma++) {
+ switch(Memalloc[ma].memtype) {
+ case MEM_DATA: mt = "data"; break;
+ case MEM_SHMEM: mt = "shmem"; break;
+ case MEM_MMAP: mt = "mmap"; break;
+ default: mt = "unknown"; break;
+ }
+ printf("mstrat[%d] = %d %s\n", ma, Memalloc[ma].memtype, mt);
+ printf("\tflags=%#o name='%s' nblks=%d\n",
+ Memalloc[ma].flags,
+ Memalloc[ma].name,
+ Memalloc[ma].nblks);
+ }
+}
+
+#endif /* !CRAY */
+
+/*
+ * -d <op>:<time> - doio inter-operation delay
+ * currently this permits ONE type of delay between operations.
+ */
+
+void
+parse_delay(char *arg)
+{
+ char *delayargs[NMEMALLOC];
+ int ndelay;
+ struct smap *s;
+
+ ndelay = string_to_tokens(arg, delayargs, 32, ":");
+ if(ndelay < 2) {
+ doio_fprintf(stderr,
+ "Illegal delay arg (%s). Must be operation:time\n", arg);
+ exit(1);
+ }
+ for(s=delaymap; s->string != NULL; s++)
+ if(!strcmp(s->string, delayargs[0]))
+ break;
+ if (s->string == NULL) {
+ fprintf(stderr,
+ "Illegal Delay arg (%s). Must be one of: ", arg);
+
+ for (s = delaymap; s->string != NULL; s++)
+ fprintf(stderr, "%s ", s->string);
+ fprintf(stderr, "\n");
+ exit(1);
+ }
+
+ delayop = s->value;
+
+ sscanf(delayargs[1], "%i", &delaytime);
+
+ if(ndelay > 2) {
+ fprintf(stderr,
+ "Warning: extra delay arguments ignored.\n");
+ }
+}
+
+
+/*
+ * Usage clause - obvious
+ */
+
+int
+usage(stream)
+FILE *stream;
+{
+ /*
+ * Only do this if we are on vpe 0, to avoid seeing it from every
+ * process in the application.
+ */
+
+ if (Npes > 1 && Vpe != 0) {
+ return 0;
+ }
+
+ fprintf(stream, "usage%s: %s [-aekv] [-m message_interval] [-n nprocs] [-r release_interval] [-w write_log] [-V validation_ftype] [-U upanic_cond] [infile]\n", TagName, Prog);
+ return 0;
+}
+
+void
+help(stream)
+FILE *stream;
+{
+ /*
+ * Only the app running on vpe 0 gets to issue help - this prevents
+ * everybody in the application from doing this.
+ */
+
+ if (Npes > 1 && Vpe != 0) {
+ return;
+ }
+
+ usage(stream);
+ fprintf(stream, "\n");
+ fprintf(stream, "\t-a abort - kill all doio processes on data compare\n");
+ fprintf(stream, "\t errors. Normally only the erroring process exits\n");
+ fprintf(stream, "\t-C data-pattern-type \n");
+ fprintf(stream, "\t Available data patterns are:\n");
+ fprintf(stream, "\t default - repeating pattern\n");
+ fprintf(stream, "\t-d Operation:Time Inter-operation delay.\n");
+ fprintf(stream, "\t Operations are:\n");
+ fprintf(stream, "\t select:time (1 second=1000000)\n");
+ fprintf(stream, "\t sleep:time (1 second=1)\n");
+#ifdef sgi
+ fprintf(stream, "\t sginap:time (1 second=CLK_TCK=100)\n");
+#endif
+ fprintf(stream, "\t alarm:time (1 second=1)\n");
+ fprintf(stream, "\t-e Re-exec children before entering the main\n");
+ fprintf(stream, "\t loop. This is useful for spreading\n");
+ fprintf(stream, "\t procs around on multi-pe systems.\n");
+ fprintf(stream, "\t-k Lock file regions during writes using fcntl()\n");
+ fprintf(stream, "\t-v Verify writes - this is done by doing a buffered\n");
+ fprintf(stream, "\t read() of the data if file io was done, or\n");
+ fprintf(stream, "\t an ssread()of the data if sds io was done\n");
+#ifndef CRAY
+ fprintf(stream, "\t-M Data buffer allocation method\n");
+ fprintf(stream, "\t alloc-type[,type]\n");
+#ifdef sgi
+ fprintf(stream, "\t data:flags\n");
+ fprintf(stream, "\t p - mpin buffer\n");
+ fprintf(stream, "\t shmem:shmid:size:flags\n");
+ fprintf(stream, "\t p - mpin buffer\n");
+#else
+ fprintf(stream, "\t data\n");
+ fprintf(stream, "\t shmem:shmid:size\n");
+#endif /* sgi */
+ fprintf(stream, "\t mmap:flags:filename\n");
+ fprintf(stream, "\t p - private\n");
+#ifdef sgi
+ fprintf(stream, "\t s - shared\n");
+ fprintf(stream, "\t l - local\n");
+ fprintf(stream, "\t a - autoresrv\n");
+ fprintf(stream, "\t G - autogrow\n");
+#else
+ fprintf(stream, "\t s - shared (shared file must exist\n"),
+ fprintf(stream, "\t and have needed length)\n");
+#endif
+ fprintf(stream, "\t f - fixed address (not used)\n");
+ fprintf(stream, "\t a - specify address (not used)\n");
+ fprintf(stream, "\t U - Unlink file when done\n");
+ fprintf(stream, "\t The default flag is private\n");
+ fprintf(stream, "\n");
+#endif /* !CRAY */
+ fprintf(stream, "\t-m message_interval Generate a message every 'message_interval'\n");
+ fprintf(stream, "\t requests. An interval of 0 suppresses\n");
+ fprintf(stream, "\t messages. The default is 0.\n");
+ fprintf(stream, "\t-N tagname Tag name, for Monster.\n");
+ fprintf(stream, "\t-n nprocs # of processes to start up\n");
+ fprintf(stream, "\t-r release_interval Release all memory and close\n");
+ fprintf(stream, "\t files every release_interval operations.\n");
+ fprintf(stream, "\t By default procs never release memory\n");
+ fprintf(stream, "\t or close fds unless they have to.\n");
+ fprintf(stream, "\t-V validation_ftype The type of file descriptor to use for doing data\n");
+ fprintf(stream, "\t validation. validation_ftype may be an octal,\n");
+ fprintf(stream, "\t hex, or decimal number representing the open()\n");
+ fprintf(stream, "\t flags, or may be one of the following strings:\n");
+ fprintf(stream, "\t 'buffered' - validate using bufferd read\n");
+ fprintf(stream, "\t 'sync' - validate using O_SYNC read\n");
+ fprintf(stream, "\t 'direct - validate using O_DIRECT read'\n");
+#ifdef CRAY
+ fprintf(stream, "\t 'ldraw' - validate using O_LDRAW read\n");
+ fprintf(stream, "\t 'parallel' - validate using O_PARALLEL read\n");
+ fprintf(stream, "\t 'raw' - validate using O_RAW read\n");
+#endif
+ fprintf(stream, "\t By default, 'parallel'\n");
+ fprintf(stream, "\t is used if the write was done with O_PARALLEL\n");
+ fprintf(stream, "\t or 'buffered' for all other writes.\n");
+ fprintf(stream, "\t-w write_log File to log file writes to. The doio_check\n");
+ fprintf(stream, "\t program can reconstruct datafiles using the\n");
+ fprintf(stream, "\t write_log, and detect if a file is corrupt\n");
+ fprintf(stream, "\t after all procs have exited.\n");
+ fprintf(stream, "\t-U upanic_cond Comma separated list of conditions that will\n");
+ fprintf(stream, "\t cause a call to upanic(PA_PANIC).\n");
+ fprintf(stream, "\t 'corruption' -> upanic on bad data comparisons\n");
+ fprintf(stream, "\t 'iosw' ---> upanic on unexpected async iosw\n");
+ fprintf(stream, "\t 'rval' ---> upanic on unexpected syscall rvals\n");
+ fprintf(stream, "\t 'all' ---> all of the above\n");
+ fprintf(stream, "\n");
+ fprintf(stream, "\tinfile Input stream - default is stdin - must be a list\n");
+ fprintf(stream, "\t of io_req structures (see doio.h). Currently\n");
+ fprintf(stream, "\t only the iogen program generates the proper\n");
+ fprintf(stream, "\t format\n");
+}
+
--- /dev/null
+/*
+ * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like. Any license provided herein, whether implied or
+ * otherwise, applies only to this software file. Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+ * Mountain View, CA 94043, or:
+ *
+ * http://www.sgi.com
+ *
+ * For further information regarding this notice, see:
+ *
+ * http://oss.sgi.com/projects/GenInfo/NoticeExplan/
+ */
+/*
+ * Define io syscalls supported by doio
+ */
+
+#define READ 1
+#define WRITE 2
+#define READA 3
+#define WRITEA 4
+#define SSREAD 5
+#define SSWRITE 6
+#define LISTIO 7
+#define LREAD 10 /* listio - single stride, single entry */
+#define LREADA 11
+#define LWRITE 12
+#define LWRITEA 13
+#define LSREAD 14 /* listio - multi-stride, single entry */
+#define LSREADA 15
+#define LSWRITE 16
+#define LSWRITEA 17
+#define LEREAD 18 /* listio - single stride, multiple entry */
+#define LEREADA 19
+#define LEWRITE 20
+#define LEWRITEA 21
+
+/* System Calls */
+#define PREAD 100
+#define PWRITE 101
+#define READV 102
+#define WRITEV 103
+#define AREAD 104
+#define AWRITE 105
+#define LLREAD 110
+#define LLAREAD 111
+#define LLWRITE 112
+#define LLAWRITE 113
+#define MMAPR 120
+#define MMAPW 121
+#define RESVSP 122 /* xfsctl(XFS_IOC_RESVSP) */
+#define UNRESVSP 123 /* xfsctl(XFS_IOC_UNRESVSP) */
+#define FSYNC2 125 /* fsync(2) */
+#define FDATASYNC 126 /* fdatasync(2) */
+
+#ifdef CRAY
+/* used: <<doio>> 1.? <<DOIO>> 1.5 <-DOIO-> 1.7*/
+#define DOIO_MAGIC '<[DOIO]>'
+#else
+#define DOIO_MAGIC 07116601
+#endif
+
+/*
+ * Define various user flags (r_uflag field) that io requests can have
+ * specified.
+ */
+
+#define F_WORD_ALIGNED 0001 /* force request to be word aligned */
+
+/*
+ * define various doio exit status's
+ */
+
+#define E_NORMAL 000 /* normal completion */
+#define E_USAGE 001 /* cmdline usage error */
+#define E_SETUP 002 /* any of a million setup conditions */
+#define E_COMPARE 004 /* data compare error from doio child */
+#define E_INTERNAL 010 /* various internal errors */
+#define E_LOCKD 020 /* lockd startup/timeout errors */
+#define E_SIGNAL 040 /* killed by signal */
+
+/*
+ * Define async io completion strategies supported by doio.
+ */
+
+#define A_POLL 1 /* poll iosw for completion */
+#define A_SIGNAL 2 /* get signal for completion */
+#define A_RECALL 3 /* use recall(2) to wait */
+#define A_RECALLA 4 /* use recalla(2) to wait */
+#define A_RECALLS 5 /* use recalls(2) to wait */
+#define A_SUSPEND 6 /* use aio_suspend(2) to wait */
+#define A_CALLBACK 7 /* use a callback signal op. */
+
+/*
+ * Define individual structures for each syscall type. These will all be
+ * unionized into a single io_req structure which io generators fill in and
+ * pass to doio.
+ *
+ * Note: It is VERY important that the r_file, r_oflags, r_offset, and
+ * r_nbytes fields occupy the same record positions in the
+ * read_req, reada_req, write_req, and writea_req structures and
+ * that they have the same type. It is also that r_pattern
+ * has the same type/offset in the write_req and writea_req
+ * structures.
+ *
+ * Since doio.c accesses all information through the r_data
+ * union in io_req, if the above assumptions hold, the above
+ * fields can be accessed without regard to structure type.
+ * This is an allowed assumption in C.
+ */
+
+#define MAX_FNAME_LENGTH 128
+
+struct read_req {
+ char r_file[MAX_FNAME_LENGTH];
+ int r_oflags; /* open flags */
+ int r_offset;
+ int r_nbytes;
+ int r_uflags; /* user flags: mem alignment */
+ int r_aio_strat; /* asynch read completion strategy */
+ int r_nstrides; /* listio: multiple strides */
+ int r_nent; /* listio: multiple list entries */
+};
+
+struct write_req {
+ char r_file[MAX_FNAME_LENGTH];
+ int r_oflags;
+ int r_offset;
+ int r_nbytes;
+ char r_pattern;
+ int r_uflags; /* user flags: mem alignment */
+ int r_aio_strat; /* asynch write completion strategy */
+ int r_nstrides; /* listio: multiple strides */
+ int r_nent; /* listio: multiple list entries */
+};
+
+struct ssread_req {
+ int r_nbytes;
+};
+
+struct sswrite_req {
+ int r_nbytes;
+ char r_pattern;
+};
+
+struct listio_req {
+ char r_file[MAX_FNAME_LENGTH];
+ int r_cmd; /* LC_START or LC_WAIT */
+ int r_offset; /* file offset */
+ int r_opcode; /* LO_READ, or LO_WRITE */
+ int r_nbytes; /* bytes per stride */
+ int r_nstrides; /* how many strides to make */
+ int r_nent; /* how many listreq entries to make */
+ int r_filestride; /* always 0 for now */
+ int r_memstride; /* always 0 for now */
+ char r_pattern; /* for LO_WRITE operations */
+ int r_oflags; /* open(2) flags */
+ int r_aio_strat; /* async I/O completion strategy */
+ int r_uflags; /* user flags: memory alignment */
+};
+
+#define rw_req listio_req /* listio is superset of everything */
+
+/*
+ * Main structure for sending a request to doio. Any tools which form IO
+ * for doio must present it using one of these structures.
+ */
+
+struct io_req {
+ int r_type; /* must be one of the #defines above */
+ int r_magic; /* must be set to DOIO_MAGIC by requestor */
+ union {
+ struct read_req read;
+ struct write_req write;
+ struct ssread_req ssread;
+ struct sswrite_req sswrite;
+ struct listio_req listio;
+ struct rw_req io;
+ } r_data;
+};
--- /dev/null
+/*
+ * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like. Any license provided herein, whether implied or
+ * otherwise, applies only to this software file. Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+ * Mountain View, CA 94043, or:
+ *
+ * http://www.sgi.com
+ *
+ * For further information regarding this notice, see:
+ *
+ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
+ */
+
+#include <xfs/libxfs.h>
+#include <attr/xattr.h>
+#include <attr/attributes.h>
+#include <sys/statvfs.h>
+#include <sys/time.h>
+#include <sys/wait.h>
+#include <dirent.h>
+
+#define XFS_ERRTAG_MAX 17
+
+typedef enum {
+ OP_ALLOCSP,
+ OP_ATTR_REMOVE,
+ OP_ATTR_SET,
+ OP_BULKSTAT,
+ OP_BULKSTAT1,
+ OP_CHOWN,
+ OP_CREAT,
+ OP_DREAD,
+ OP_DWRITE,
+ OP_FDATASYNC,
+ OP_FREESP,
+ OP_FSYNC,
+ OP_GETDENTS,
+ OP_LINK,
+ OP_MKDIR,
+ OP_MKNOD,
+ OP_READ,
+ OP_READLINK,
+ OP_RENAME,
+ OP_RESVSP,
+ OP_RMDIR,
+ OP_STAT,
+ OP_SYMLINK,
+ OP_SYNC,
+ OP_TRUNCATE,
+ OP_UNLINK,
+ OP_UNRESVSP,
+ OP_WRITE,
+ OP_LAST
+} opty_t;
+
+typedef void (*opfnc_t)(int, long);
+
+typedef struct opdesc {
+ opty_t op;
+ char *name;
+ opfnc_t func;
+ int freq;
+ int iswrite;
+} opdesc_t;
+
+typedef struct fent {
+ int id;
+ int parent;
+} fent_t;
+
+typedef struct flist {
+ int nfiles;
+ int nslots;
+ int tag;
+ fent_t *fents;
+} flist_t;
+
+typedef struct pathname {
+ int len;
+ char *path;
+} pathname_t;
+
+#define FT_DIR 0
+#define FT_DIRm (1 << FT_DIR)
+#define FT_REG 1
+#define FT_REGm (1 << FT_REG)
+#define FT_SYM 2
+#define FT_SYMm (1 << FT_SYM)
+#define FT_DEV 3
+#define FT_DEVm (1 << FT_DEV)
+#define FT_RTF 4
+#define FT_RTFm (1 << FT_RTF)
+#define FT_nft 5
+#define FT_ANYm ((1 << FT_nft) - 1)
+#define FT_REGFILE (FT_REGm | FT_RTFm)
+#define FT_NOTDIR (FT_ANYm & ~FT_DIRm)
+
+#define FLIST_SLOT_INCR 16
+#define NDCACHE 64
+
+#define MAXFSIZE ((1ULL << 63) - 1ULL)
+#define MAXFSIZE32 ((1ULL << 40) - 1ULL)
+
+void allocsp_f(int, long);
+void attr_remove_f(int, long);
+void attr_set_f(int, long);
+void bulkstat_f(int, long);
+void bulkstat1_f(int, long);
+void chown_f(int, long);
+void creat_f(int, long);
+void dread_f(int, long);
+void dwrite_f(int, long);
+void fdatasync_f(int, long);
+void freesp_f(int, long);
+void fsync_f(int, long);
+void getdents_f(int, long);
+void link_f(int, long);
+void mkdir_f(int, long);
+void mknod_f(int, long);
+void read_f(int, long);
+void readlink_f(int, long);
+void rename_f(int, long);
+void resvsp_f(int, long);
+void rmdir_f(int, long);
+void stat_f(int, long);
+void symlink_f(int, long);
+void sync_f(int, long);
+void truncate_f(int, long);
+void unlink_f(int, long);
+void unresvsp_f(int, long);
+void write_f(int, long);
+
+opdesc_t ops[] = {
+ { OP_ALLOCSP, "allocsp", allocsp_f, 1, 1 },
+ { OP_ATTR_REMOVE, "attr_remove", attr_remove_f, /* 1 */ 0, 1 },
+ { OP_ATTR_SET, "attr_set", attr_set_f, /* 2 */ 0, 1 },
+ { OP_BULKSTAT, "bulkstat", bulkstat_f, 1, 0 },
+ { OP_BULKSTAT1, "bulkstat1", bulkstat1_f, 1, 0 },
+ { OP_CHOWN, "chown", chown_f, 3, 1 },
+ { OP_CREAT, "creat", creat_f, 4, 1 },
+ { OP_DREAD, "dread", dread_f, 4, 0 },
+ { OP_DWRITE, "dwrite", dwrite_f, 4, 1 },
+ { OP_FDATASYNC, "fdatasync", fdatasync_f, 1, 1 },
+ { OP_FREESP, "freesp", freesp_f, 1, 1 },
+ { OP_FSYNC, "fsync", fsync_f, 1, 1 },
+ { OP_GETDENTS, "getdents", getdents_f, 1, 0 },
+ { OP_LINK, "link", link_f, 1, 1 },
+ { OP_MKDIR, "mkdir", mkdir_f, 2, 1 },
+ { OP_MKNOD, "mknod", mknod_f, 2, 1 },
+ { OP_READ, "read", read_f, 1, 0 },
+ { OP_READLINK, "readlink", readlink_f, 1, 0 },
+ { OP_RENAME, "rename", rename_f, 2, 1 },
+ { OP_RESVSP, "resvsp", resvsp_f, 1, 1 },
+ { OP_RMDIR, "rmdir", rmdir_f, 1, 1 },
+ { OP_STAT, "stat", stat_f, 1, 0 },
+ { OP_SYMLINK, "symlink", symlink_f, 2, 1 },
+ { OP_SYNC, "sync", sync_f, 1, 0 },
+ { OP_TRUNCATE, "truncate", truncate_f, 2, 1 },
+ { OP_UNLINK, "unlink", unlink_f, 1, 1 },
+ { OP_UNRESVSP, "unresvsp", unresvsp_f, 1, 1 },
+ { OP_WRITE, "write", write_f, 4, 1 },
+}, *ops_end;
+
+flist_t flist[FT_nft] = {
+ { 0, 0, 'd', NULL },
+ { 0, 0, 'f', NULL },
+ { 0, 0, 'l', NULL },
+ { 0, 0, 'c', NULL },
+ { 0, 0, 'r', NULL },
+};
+
+int dcache[NDCACHE];
+int errrange;
+int errtag;
+opty_t *freq_table;
+int freq_table_size;
+xfs_fsop_geom_t geom;
+char *homedir;
+int *ilist;
+int ilistlen;
+off64_t maxfsize;
+char *myprog;
+int namerand;
+int nameseq;
+int nops;
+int nproc = 1;
+int operations = 1;
+int procid;
+int rtpct;
+unsigned long seed = 0;
+ino_t top_ino;
+int verbose = 0;
+
+void add_to_flist(int, int, int);
+void append_pathname(pathname_t *, char *);
+int attr_list_path(pathname_t *, char *, const int, int);
+int attr_remove_path(pathname_t *, const char *, int);
+int attr_set_path(pathname_t *, const char *, const char *, const int, int);
+void check_cwd(void);
+int creat_path(pathname_t *, mode_t);
+void dcache_enter(int, int);
+void dcache_init(void);
+fent_t *dcache_lookup(int);
+void dcache_purge(int);
+void del_from_flist(int, int);
+int dirid_to_name(char *, int);
+void doproc(void);
+void fent_to_name(pathname_t *, flist_t *, fent_t *);
+void fix_parent(int, int);
+void free_pathname(pathname_t *);
+int generate_fname(fent_t *, int, pathname_t *, int *, int *);
+int get_fname(int, long, pathname_t *, flist_t **, fent_t **, int *);
+void init_pathname(pathname_t *);
+int lchown_path(pathname_t *, uid_t, gid_t);
+int link_path(pathname_t *, pathname_t *);
+int lstat64_path(pathname_t *, struct stat64 *);
+void make_freq_table(void);
+int mkdir_path(pathname_t *, mode_t);
+int mknod_path(pathname_t *, mode_t, dev_t);
+void namerandpad(int, char *, int);
+int open_path(pathname_t *, int);
+DIR *opendir_path(pathname_t *);
+void process_freq(char *);
+int readlink_path(pathname_t *, char *, size_t);
+int rename_path(pathname_t *, pathname_t *);
+int rmdir_path(pathname_t *);
+void separate_pathname(pathname_t *, char *, pathname_t *);
+void show_ops(int, char *);
+int stat64_path(pathname_t *, struct stat64 *);
+int symlink_path(const char *, pathname_t *);
+int truncate64_path(pathname_t *, off64_t);
+int unlink_path(pathname_t *);
+void usage(void);
+void write_freq(void);
+void zero_freq(void);
+
+int main(int argc, char **argv)
+{
+ char buf[10];
+ int c;
+ char *dirname = NULL;
+ int fd;
+ int i;
+ int j;
+ char *p;
+ int stat;
+ struct timeval t;
+ ptrdiff_t srval;
+ int nousage=0;
+ xfs_error_injection_t err_inj;
+
+ errrange = errtag = 0;
+ umask(0);
+ nops = sizeof(ops) / sizeof(ops[0]);
+ ops_end = &ops[nops];
+ myprog = argv[0];
+ while ((c = getopt(argc, argv, "d:e:f:i:n:p:rs:vwzHS")) != -1) {
+ switch (c) {
+ case 'd':
+ dirname = optarg;
+ break;
+ case 'e':
+ sscanf(optarg, "%d", &errtag);
+ if (errtag < 0) {
+ errtag = -errtag;
+ errrange = 1;
+ } else if (errtag == 0)
+ errtag = -1;
+ if (errtag >= XFS_ERRTAG_MAX) {
+ fprintf(stderr,
+ "error tag %d too large (max %d)\n",
+ errtag, XFS_ERRTAG_MAX - 1);
+ exit(1);
+ }
+ break;
+ case 'f':
+ process_freq(optarg);
+ break;
+ case 'i':
+ ilist = realloc(ilist, ++ilistlen * sizeof(*ilist));
+ ilist[ilistlen - 1] = strtol(optarg, &p, 16);
+ break;
+ case 'n':
+ operations = atoi(optarg);
+ break;
+ case 'p':
+ nproc = atoi(optarg);
+ break;
+ case 'r':
+ namerand = 1;
+ break;
+ case 's':
+ seed = strtoul(optarg, NULL, 0);
+ break;
+ case 'v':
+ verbose = 1;
+ break;
+ case 'w':
+ write_freq();
+ break;
+ case 'z':
+ zero_freq();
+ break;
+ case 'S':
+ show_ops(0, NULL);
+ printf("\n");
+ nousage=1;
+ break;
+ case '?':
+ fprintf(stderr, "%s - invalid parameters\n",
+ myprog);
+ /* fall through */
+ case 'H':
+ usage();
+ exit(1);
+ }
+ }
+
+ if (!dirname) {
+ /* no directory specified */
+ if (!nousage) usage();
+ exit(1);
+ }
+
+ (void)mkdir(dirname, 0777);
+ if (chdir(dirname) < 0) {
+ perror(dirname);
+ exit(1);
+ }
+ sprintf(buf, "fss%x", getpid());
+ fd = creat(buf, 0666);
+ if (lseek64(fd, (off64_t)(MAXFSIZE32 + 1ULL), SEEK_SET) < 0)
+ maxfsize = (off64_t)MAXFSIZE32;
+ else
+ maxfsize = (off64_t)MAXFSIZE;
+ make_freq_table();
+ dcache_init();
+ setlinebuf(stdout);
+ if (!seed) {
+ gettimeofday(&t, (void *)NULL);
+ seed = (int)t.tv_sec ^ (int)t.tv_usec;
+ printf("seed = %ld\n", seed);
+ }
+ i = xfsctl(buf, fd, XFS_IOC_FSGEOMETRY, &geom);
+ if (i >= 0 && geom.rtblocks)
+ rtpct = MIN(MAX(geom.rtblocks * 100 /
+ (geom.rtblocks + geom.datablocks), 1), 99);
+ else
+ rtpct = 0;
+ if (errtag != 0) {
+ if (errrange == 0) {
+ if (errtag <= 0) {
+ srandom(seed);
+ j = random() % 100;
+
+ for (i = 0; i < j; i++)
+ (void) random();
+
+ errtag = (random() % (XFS_ERRTAG_MAX-1)) + 1;
+ }
+ } else {
+ srandom(seed);
+ j = random() % 100;
+
+ for (i = 0; i < j; i++)
+ (void) random();
+
+ errtag += (random() % (XFS_ERRTAG_MAX - errtag));
+ }
+ printf("Injecting failure on tag #%d\n", errtag);
+ err_inj.errtag = errtag;
+ err_inj.fd = fd;
+ srval = xfsctl(buf, fd, XFS_IOC_ERROR_INJECTION, &err_inj);
+ if (srval < -1) {
+ perror("fsstress - XFS_SYSSGI error injection call");
+ close(fd);
+ unlink(buf);
+ exit(1);
+ }
+ } else
+ close(fd);
+ for (i = 0; i < nproc; i++) {
+ if (fork() == 0) {
+ procid = i;
+ doproc();
+ return 0;
+ }
+ }
+ while (wait(&stat) > 0)
+ continue;
+ if (errtag != 0) {
+ err_inj.errtag = 0;
+ err_inj.fd = fd;
+ srval = xfsctl(buf, fd, XFS_IOC_ERROR_CLEARALL, &err_inj);
+ if (srval != 0) {
+ fprintf(stderr, "Bad ej clear on %s fd=%d (%d).\n",
+ buf, fd, errno);
+ perror("xfsctl(XFS_IOC_ERROR_CLEARALL)");
+ close(fd);
+ exit(1);
+ }
+ close(fd);
+ }
+
+ unlink(buf);
+ return 0;
+}
+
+void
+add_to_flist(int ft, int id, int parent)
+{
+ fent_t *fep;
+ flist_t *ftp;
+
+ ftp = &flist[ft];
+ if (ftp->nfiles == ftp->nslots) {
+ ftp->nslots += FLIST_SLOT_INCR;
+ ftp->fents = realloc(ftp->fents, ftp->nslots * sizeof(fent_t));
+ }
+ fep = &ftp->fents[ftp->nfiles++];
+ fep->id = id;
+ fep->parent = parent;
+}
+
+void
+append_pathname(pathname_t *name, char *str)
+{
+ int len;
+
+ len = strlen(str);
+#ifdef DEBUG
+ if (len && *str == '/' && name->len == 0) {
+ fprintf(stderr, "fsstress: append_pathname failure\n");
+ chdir(homedir);
+ abort();
+ /* NOTREACHED */
+ }
+#endif
+ name->path = realloc(name->path, name->len + 1 + len);
+ strcpy(&name->path[name->len], str);
+ name->len += len;
+}
+
+int
+attr_list_path(pathname_t *name, char *buffer, const int buffersize, int flags)
+{
+ char buf[MAXNAMELEN];
+ pathname_t newname;
+ int rval;
+
+ if (flags != ATTR_DONTFOLLOW) {
+ errno = EINVAL;
+ return -1;
+ }
+ rval = llistxattr(name->path, buffer, buffersize);
+ if (rval >= 0 || errno != ENAMETOOLONG)
+ return rval;
+ separate_pathname(name, buf, &newname);
+ if (chdir(buf) == 0) {
+ rval = attr_list_path(&newname, buffer, buffersize, flags);
+ chdir("..");
+ }
+ free_pathname(&newname);
+ return rval;
+}
+
+int
+attr_remove_path(pathname_t *name, const char *attrname, int flags)
+{
+ char buf[MAXNAMELEN];
+ pathname_t newname;
+ int rval;
+
+ rval = attr_remove(name->path, attrname, flags);
+ if (rval >= 0 || errno != ENAMETOOLONG)
+ return rval;
+ separate_pathname(name, buf, &newname);
+ if (chdir(buf) == 0) {
+ rval = attr_remove_path(&newname, attrname, flags);
+ chdir("..");
+ }
+ free_pathname(&newname);
+ return rval;
+}
+
+int
+attr_set_path(pathname_t *name, const char *attrname, const char *attrvalue,
+ const int valuelength, int flags)
+{
+ char buf[MAXNAMELEN];
+ pathname_t newname;
+ int rval;
+
+ rval = attr_set(name->path, attrname, attrvalue, valuelength, flags);
+ if (rval >= 0 || errno != ENAMETOOLONG)
+ return rval;
+ separate_pathname(name, buf, &newname);
+ if (chdir(buf) == 0) {
+ rval = attr_set_path(&newname, attrname, attrvalue, valuelength,
+ flags);
+ chdir("..");
+ }
+ free_pathname(&newname);
+ return rval;
+}
+
+void
+check_cwd(void)
+{
+#ifdef DEBUG
+ struct stat64 statbuf;
+
+ if (stat64(".", &statbuf) == 0 && statbuf.st_ino == top_ino)
+ return;
+ chdir(homedir);
+ fprintf(stderr, "fsstress: check_cwd failure\n");
+ abort();
+ /* NOTREACHED */
+#endif
+}
+
+int
+creat_path(pathname_t *name, mode_t mode)
+{
+ char buf[MAXNAMELEN];
+ pathname_t newname;
+ int rval;
+
+ rval = creat(name->path, mode);
+ if (rval >= 0 || errno != ENAMETOOLONG)
+ return rval;
+ separate_pathname(name, buf, &newname);
+ if (chdir(buf) == 0) {
+ rval = creat_path(&newname, mode);
+ chdir("..");
+ }
+ free_pathname(&newname);
+ return rval;
+}
+
+void
+dcache_enter(int dirid, int slot)
+{
+ dcache[dirid % NDCACHE] = slot;
+}
+
+void
+dcache_init(void)
+{
+ int i;
+
+ for (i = 0; i < NDCACHE; i++)
+ dcache[i] = -1;
+}
+
+fent_t *
+dcache_lookup(int dirid)
+{
+ fent_t *fep;
+ int i;
+
+ i = dcache[dirid % NDCACHE];
+ if (i >= 0 && (fep = &flist[FT_DIR].fents[i])->id == dirid)
+ return fep;
+ return NULL;
+}
+
+void
+dcache_purge(int dirid)
+{
+ int *dcp;
+
+ dcp = &dcache[dirid % NDCACHE];
+ if (*dcp >= 0 && flist[FT_DIR].fents[*dcp].id == dirid)
+ *dcp = -1;
+}
+
+void
+del_from_flist(int ft, int slot)
+{
+ flist_t *ftp;
+
+ ftp = &flist[ft];
+ if (ft == FT_DIR)
+ dcache_purge(ftp->fents[slot].id);
+ if (slot != ftp->nfiles - 1) {
+ if (ft == FT_DIR)
+ dcache_purge(ftp->fents[ftp->nfiles - 1].id);
+ ftp->fents[slot] = ftp->fents[--ftp->nfiles];
+ } else
+ ftp->nfiles--;
+}
+
+fent_t *
+dirid_to_fent(int dirid)
+{
+ fent_t *efep;
+ fent_t *fep;
+ flist_t *flp;
+
+ if ((fep = dcache_lookup(dirid)))
+ return fep;
+ flp = &flist[FT_DIR];
+ for (fep = flp->fents, efep = &fep[flp->nfiles]; fep < efep; fep++) {
+ if (fep->id == dirid) {
+ dcache_enter(dirid, fep - flp->fents);
+ return fep;
+ }
+ }
+ return NULL;
+}
+
+void
+doproc(void)
+{
+ struct stat64 statbuf;
+ char buf[10];
+ int opno;
+ int rval;
+ opdesc_t *p;
+
+ sprintf(buf, "p%x", procid);
+ (void)mkdir(buf, 0777);
+ if (chdir(buf) < 0 || stat64(".", &statbuf) < 0) {
+ perror(buf);
+ _exit(1);
+ }
+ top_ino = statbuf.st_ino;
+ homedir = getcwd(NULL, -1);
+ seed += procid;
+ srandom(seed);
+ if (namerand)
+ namerand = random();
+ for (opno = 0; opno < operations; opno++) {
+ p = &ops[freq_table[random() % freq_table_size]];
+ p->func(opno, random());
+ /*
+ * test for forced shutdown by stat'ing the test
+ * directory. If this stat returns EIO, assume
+ * the forced shutdown happened.
+ */
+ if (errtag != 0 && opno % 100 == 0) {
+ rval = stat64(".", &statbuf);
+ if (rval == EIO) {
+ fprintf(stderr, "Detected EIO\n");
+ return;
+ }
+ }
+ }
+}
+
+void
+fent_to_name(pathname_t *name, flist_t *flp, fent_t *fep)
+{
+ char buf[MAXNAMELEN];
+ int i;
+ fent_t *pfep;
+
+ if (fep == NULL)
+ return;
+ if (fep->parent != -1) {
+ pfep = dirid_to_fent(fep->parent);
+ fent_to_name(name, &flist[FT_DIR], pfep);
+ append_pathname(name, "/");
+ }
+ i = sprintf(buf, "%c%x", flp->tag, fep->id);
+ namerandpad(fep->id, buf, i);
+ append_pathname(name, buf);
+}
+
+void
+fix_parent(int oldid, int newid)
+{
+ fent_t *fep;
+ flist_t *flp;
+ int i;
+ int j;
+
+ for (i = 0, flp = flist; i < FT_nft; i++, flp++) {
+ for (j = 0, fep = flp->fents; j < flp->nfiles; j++, fep++) {
+ if (fep->parent == oldid)
+ fep->parent = newid;
+ }
+ }
+}
+
+void
+free_pathname(pathname_t *name)
+{
+ if (name->path) {
+ free(name->path);
+ name->path = NULL;
+ name->len = 0;
+ }
+}
+
+int
+generate_fname(fent_t *fep, int ft, pathname_t *name, int *idp, int *v)
+{
+ char buf[MAXNAMELEN];
+ flist_t *flp;
+ int id;
+ int j;
+ int len;
+
+ flp = &flist[ft];
+ len = sprintf(buf, "%c%x", flp->tag, id = nameseq++);
+ namerandpad(id, buf, len);
+ if (fep) {
+ fent_to_name(name, &flist[FT_DIR], fep);
+ append_pathname(name, "/");
+ }
+ append_pathname(name, buf);
+ *idp = id;
+ *v = verbose;
+ for (j = 0; !*v && j < ilistlen; j++) {
+ if (ilist[j] == id) {
+ *v = 1;
+ break;
+ }
+ }
+ return 1;
+}
+
+int
+get_fname(int which, long r, pathname_t *name, flist_t **flpp, fent_t **fepp,
+ int *v)
+{
+ int c;
+ fent_t *fep;
+ flist_t *flp;
+ int i;
+ int j;
+ int x;
+
+ for (i = 0, c = 0, flp = flist; i < FT_nft; i++, flp++) {
+ if (which & (1 << i))
+ c += flp->nfiles;
+ }
+ if (c == 0) {
+ if (flpp)
+ *flpp = NULL;
+ if (fepp)
+ *fepp = NULL;
+ *v = verbose;
+ return 0;
+ }
+ x = (int)(r % c);
+ for (i = 0, c = 0, flp = flist; i < FT_nft; i++, flp++) {
+ if (which & (1 << i)) {
+ if (x < c + flp->nfiles) {
+ fep = &flp->fents[x - c];
+ if (name)
+ fent_to_name(name, flp, fep);
+ if (flpp)
+ *flpp = flp;
+ if (fepp)
+ *fepp = fep;
+ *v = verbose;
+ for (j = 0; !*v && j < ilistlen; j++) {
+ if (ilist[j] == fep->id) {
+ *v = 1;
+ break;
+ }
+ }
+ return 1;
+ }
+ c += flp->nfiles;
+ }
+ }
+#ifdef DEBUG
+ fprintf(stderr, "fsstress: get_fname failure\n");
+ abort();
+#endif
+ return -1;
+ /* NOTREACHED */
+}
+
+void
+init_pathname(pathname_t *name)
+{
+ name->len = 0;
+ name->path = NULL;
+}
+
+int
+lchown_path(pathname_t *name, uid_t owner, gid_t group)
+{
+ char buf[MAXNAMELEN];
+ pathname_t newname;
+ int rval;
+
+ rval = lchown(name->path, owner, group);
+ if (rval >= 0 || errno != ENAMETOOLONG)
+ return rval;
+ separate_pathname(name, buf, &newname);
+ if (chdir(buf) == 0) {
+ rval = lchown_path(&newname, owner, group);
+ chdir("..");
+ }
+ free_pathname(&newname);
+ return rval;
+}
+
+int
+link_path(pathname_t *name1, pathname_t *name2)
+{
+ char buf1[MAXNAMELEN];
+ char buf2[MAXNAMELEN];
+ int down1;
+ pathname_t newname1;
+ pathname_t newname2;
+ int rval;
+
+ rval = link(name1->path, name2->path);
+ if (rval >= 0 || errno != ENAMETOOLONG)
+ return rval;
+ separate_pathname(name1, buf1, &newname1);
+ separate_pathname(name2, buf2, &newname2);
+ if (strcmp(buf1, buf2) == 0) {
+ if (chdir(buf1) == 0) {
+ rval = link_path(&newname1, &newname2);
+ chdir("..");
+ }
+ } else {
+ if (strcmp(buf1, "..") == 0)
+ down1 = 0;
+ else if (strcmp(buf2, "..") == 0)
+ down1 = 1;
+ else if (strlen(buf1) == 0)
+ down1 = 0;
+ else if (strlen(buf2) == 0)
+ down1 = 1;
+ else
+ down1 = MAX(newname1.len, 3 + name2->len) <=
+ MAX(3 + name1->len, newname2.len);
+ if (down1) {
+ free_pathname(&newname2);
+ append_pathname(&newname2, "../");
+ append_pathname(&newname2, name2->path);
+ if (chdir(buf1) == 0) {
+ rval = link_path(&newname1, &newname2);
+ chdir("..");
+ }
+ } else {
+ free_pathname(&newname1);
+ append_pathname(&newname1, "../");
+ append_pathname(&newname1, name1->path);
+ if (chdir(buf2) == 0) {
+ rval = link_path(&newname1, &newname2);
+ chdir("..");
+ }
+ }
+ }
+ free_pathname(&newname1);
+ free_pathname(&newname2);
+ return rval;
+}
+
+int
+lstat64_path(pathname_t *name, struct stat64 *sbuf)
+{
+ char buf[MAXNAMELEN];
+ pathname_t newname;
+ int rval;
+
+ rval = lstat64(name->path, sbuf);
+ if (rval >= 0 || errno != ENAMETOOLONG)
+ return rval;
+ separate_pathname(name, buf, &newname);
+ if (chdir(buf) == 0) {
+ rval = lstat64_path(&newname, sbuf);
+ chdir("..");
+ }
+ free_pathname(&newname);
+ return rval;
+}
+
+void
+make_freq_table(void)
+{
+ int f;
+ int i;
+ opdesc_t *p;
+
+ for (p = ops, f = 0; p < ops_end; p++)
+ f += p->freq;
+ freq_table = malloc(f * sizeof(*freq_table));
+ freq_table_size = f;
+ for (p = ops, i = 0; p < ops_end; p++) {
+ for (f = 0; f < p->freq; f++, i++)
+ freq_table[i] = p->op;
+ }
+}
+
+int
+mkdir_path(pathname_t *name, mode_t mode)
+{
+ char buf[MAXNAMELEN];
+ pathname_t newname;
+ int rval;
+
+ rval = mkdir(name->path, mode);
+ if (rval >= 0 || errno != ENAMETOOLONG)
+ return rval;
+ separate_pathname(name, buf, &newname);
+ if (chdir(buf) == 0) {
+ rval = mkdir_path(&newname, mode);
+ chdir("..");
+ }
+ free_pathname(&newname);
+ return rval;
+}
+
+int
+mknod_path(pathname_t *name, mode_t mode, dev_t dev)
+{
+ char buf[MAXNAMELEN];
+ pathname_t newname;
+ int rval;
+
+ rval = mknod(name->path, mode, dev);
+ if (rval >= 0 || errno != ENAMETOOLONG)
+ return rval;
+ separate_pathname(name, buf, &newname);
+ if (chdir(buf) == 0) {
+ rval = mknod_path(&newname, mode, dev);
+ chdir("..");
+ }
+ free_pathname(&newname);
+ return rval;
+}
+
+void
+namerandpad(int id, char *buf, int i)
+{
+ int bucket;
+ static int buckets[] =
+ { 2, 4, 8, 16, 32, 64, 128, MAXNAMELEN - 1 };
+ int padlen;
+ int padmod;
+
+ if (namerand == 0)
+ return;
+ bucket = (id ^ namerand) % (sizeof(buckets) / sizeof(buckets[0]));
+ padmod = buckets[bucket] + 1 - i;
+ if (padmod <= 0)
+ return;
+ padlen = (id ^ namerand) % padmod;
+ if (padlen) {
+ memset(&buf[i], 'X', padlen);
+ buf[i + padlen] = '\0';
+ }
+}
+
+int
+open_path(pathname_t *name, int oflag)
+{
+ char buf[MAXNAMELEN];
+ pathname_t newname;
+ int rval;
+
+ rval = open(name->path, oflag);
+ if (rval >= 0 || errno != ENAMETOOLONG)
+ return rval;
+ separate_pathname(name, buf, &newname);
+ if (chdir(buf) == 0) {
+ rval = open_path(&newname, oflag);
+ chdir("..");
+ }
+ free_pathname(&newname);
+ return rval;
+}
+
+DIR *
+opendir_path(pathname_t *name)
+{
+ char buf[MAXNAMELEN];
+ pathname_t newname;
+ DIR *rval;
+
+ rval = opendir(name->path);
+ if (rval || errno != ENAMETOOLONG)
+ return rval;
+ separate_pathname(name, buf, &newname);
+ if (chdir(buf) == 0) {
+ rval = opendir_path(&newname);
+ chdir("..");
+ }
+ free_pathname(&newname);
+ return rval;
+}
+
+void
+process_freq(char *arg)
+{
+ opdesc_t *p;
+ char *s;
+
+ s = strchr(arg, '=');
+ if (s == NULL) {
+ fprintf(stderr, "bad argument '%s'\n", arg);
+ exit(1);
+ }
+ *s++ = '\0';
+ for (p = ops; p < ops_end; p++) {
+ if (strcmp(arg, p->name) == 0) {
+ p->freq = atoi(s);
+ return;
+ }
+ }
+ fprintf(stderr, "can't find op type %s for -f\n", arg);
+ exit(1);
+}
+
+int
+readlink_path(pathname_t *name, char *lbuf, size_t lbufsiz)
+{
+ char buf[MAXNAMELEN];
+ pathname_t newname;
+ int rval;
+
+ rval = readlink(name->path, lbuf, lbufsiz);
+ if (rval >= 0 || errno != ENAMETOOLONG)
+ return rval;
+ separate_pathname(name, buf, &newname);
+ if (chdir(buf) == 0) {
+ rval = readlink_path(&newname, lbuf, lbufsiz);
+ chdir("..");
+ }
+ free_pathname(&newname);
+ return rval;
+}
+
+int
+rename_path(pathname_t *name1, pathname_t *name2)
+{
+ char buf1[MAXNAMELEN];
+ char buf2[MAXNAMELEN];
+ int down1;
+ pathname_t newname1;
+ pathname_t newname2;
+ int rval;
+
+ rval = rename(name1->path, name2->path);
+ if (rval >= 0 || errno != ENAMETOOLONG)
+ return rval;
+ separate_pathname(name1, buf1, &newname1);
+ separate_pathname(name2, buf2, &newname2);
+ if (strcmp(buf1, buf2) == 0) {
+ if (chdir(buf1) == 0) {
+ rval = rename_path(&newname1, &newname2);
+ chdir("..");
+ }
+ } else {
+ if (strcmp(buf1, "..") == 0)
+ down1 = 0;
+ else if (strcmp(buf2, "..") == 0)
+ down1 = 1;
+ else if (strlen(buf1) == 0)
+ down1 = 0;
+ else if (strlen(buf2) == 0)
+ down1 = 1;
+ else
+ down1 = MAX(newname1.len, 3 + name2->len) <=
+ MAX(3 + name1->len, newname2.len);
+ if (down1) {
+ free_pathname(&newname2);
+ append_pathname(&newname2, "../");
+ append_pathname(&newname2, name2->path);
+ if (chdir(buf1) == 0) {
+ rval = rename_path(&newname1, &newname2);
+ chdir("..");
+ }
+ } else {
+ free_pathname(&newname1);
+ append_pathname(&newname1, "../");
+ append_pathname(&newname1, name1->path);
+ if (chdir(buf2) == 0) {
+ rval = rename_path(&newname1, &newname2);
+ chdir("..");
+ }
+ }
+ }
+ free_pathname(&newname1);
+ free_pathname(&newname2);
+ return rval;
+}
+
+int
+rmdir_path(pathname_t *name)
+{
+ char buf[MAXNAMELEN];
+ pathname_t newname;
+ int rval;
+
+ rval = rmdir(name->path);
+ if (rval >= 0 || errno != ENAMETOOLONG)
+ return rval;
+ separate_pathname(name, buf, &newname);
+ if (chdir(buf) == 0) {
+ rval = rmdir_path(&newname);
+ chdir("..");
+ }
+ free_pathname(&newname);
+ return rval;
+}
+
+void
+separate_pathname(pathname_t *name, char *buf, pathname_t *newname)
+{
+ char *slash;
+
+ init_pathname(newname);
+ slash = strchr(name->path, '/');
+ if (slash == NULL) {
+ buf[0] = '\0';
+ return;
+ }
+ *slash = '\0';
+ strcpy(buf, name->path);
+ *slash = '/';
+ append_pathname(newname, slash + 1);
+}
+
+#define WIDTH 80
+
+void
+show_ops(int flag, char *lead_str)
+{
+ opdesc_t *p;
+
+ if (flag<0) {
+ /* print in list form */
+ int x = WIDTH;
+
+ for (p = ops; p < ops_end; p++) {
+ if (lead_str != NULL && x+strlen(p->name)>=WIDTH-5)
+ x=printf("%s%s", (p==ops)?"":"\n", lead_str);
+ x+=printf("%s ", p->name);
+ }
+ printf("\n");
+ } else {
+ int f;
+ for (f = 0, p = ops; p < ops_end; p++)
+ f += p->freq;
+
+ if (f == 0)
+ flag = 1;
+
+ for (p = ops; p < ops_end; p++) {
+ if (flag != 0 || p->freq > 0) {
+ if (lead_str != NULL)
+ printf("%s", lead_str);
+ printf("%20s %d/%d %s\n",
+ p->name, p->freq, f,
+ (p->iswrite == 0) ? " " : "write op");
+ }
+ }
+ }
+}
+
+int
+stat64_path(pathname_t *name, struct stat64 *sbuf)
+{
+ char buf[MAXNAMELEN];
+ pathname_t newname;
+ int rval;
+
+ rval = stat64(name->path, sbuf);
+ if (rval >= 0 || errno != ENAMETOOLONG)
+ return rval;
+ separate_pathname(name, buf, &newname);
+ if (chdir(buf) == 0) {
+ rval = stat64_path(&newname, sbuf);
+ chdir("..");
+ }
+ free_pathname(&newname);
+ return rval;
+}
+
+int
+symlink_path(const char *name1, pathname_t *name)
+{
+ char buf[MAXNAMELEN];
+ pathname_t newname;
+ int rval;
+
+ if (!strcmp(name1, name->path)) {
+ printf("yikes! %s %s\n", name1, name->path);
+ return 0;
+ }
+
+ rval = symlink(name1, name->path);
+ if (rval >= 0 || errno != ENAMETOOLONG)
+ return rval;
+ separate_pathname(name, buf, &newname);
+ if (chdir(buf) == 0) {
+ rval = symlink_path(name1, &newname);
+ chdir("..");
+ }
+ free_pathname(&newname);
+ return rval;
+}
+
+int
+truncate64_path(pathname_t *name, off64_t length)
+{
+ char buf[MAXNAMELEN];
+ pathname_t newname;
+ int rval;
+
+ rval = truncate64(name->path, length);
+ if (rval >= 0 || errno != ENAMETOOLONG)
+ return rval;
+ separate_pathname(name, buf, &newname);
+ if (chdir(buf) == 0) {
+ rval = truncate64_path(&newname, length);
+ chdir("..");
+ }
+ free_pathname(&newname);
+ return rval;
+}
+
+int
+unlink_path(pathname_t *name)
+{
+ char buf[MAXNAMELEN];
+ pathname_t newname;
+ int rval;
+
+ rval = unlink(name->path);
+ if (rval >= 0 || errno != ENAMETOOLONG)
+ return rval;
+ separate_pathname(name, buf, &newname);
+ if (chdir(buf) == 0) {
+ rval = unlink_path(&newname);
+ chdir("..");
+ }
+ free_pathname(&newname);
+ return rval;
+}
+
+void
+usage(void)
+{
+ printf("Usage: %s -H or\n", myprog);
+ printf(" %s [-d dir][-e errtg][-f op_name=freq][-n nops]\n",
+ myprog);
+ printf(" [-p nproc][-r len][-s seed][-v][-w][-z][-S]\n");
+ printf("where\n");
+ printf(" -d dir specifies the base directory for operations\n");
+ printf(" -e errtg specifies error injection stuff\n");
+ printf(" -f op_name=freq changes the frequency of option name to freq\n");
+ printf(" the valid operation names are:\n");
+ show_ops(-1, " ");
+ printf(" -n nops specifies the no. of operations per process (default 1)\n");
+ printf(" -p nproc specifies the no. of processes (default 1)\n");
+ printf(" -r specifies random name padding\n");
+ printf(" -s seed specifies the seed for the random generator (default random)\n");
+ printf(" -v specifies verbose mode\n");
+ printf(" -w zeros frequencies of non-write operations\n");
+ printf(" -z zeros frequencies of all operations\n");
+ printf(" -S prints the table of operations (omitting zero frequency)\n");
+ printf(" -H prints usage and exits\n");
+}
+
+void
+write_freq(void)
+{
+ opdesc_t *p;
+
+ for (p = ops; p < ops_end; p++) {
+ if (!p->iswrite)
+ p->freq = 0;
+ }
+}
+
+void
+zero_freq(void)
+{
+ opdesc_t *p;
+
+ for (p = ops; p < ops_end; p++)
+ p->freq = 0;
+}
+
+void
+allocsp_f(int opno, long r)
+{
+ int e;
+ pathname_t f;
+ int fd;
+ struct flock64 fl;
+ __int64_t lr;
+ off64_t off;
+ struct stat64 stb;
+ int v;
+
+ init_pathname(&f);
+ if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) {
+ if (v)
+ printf("%d/%d: allocsp - no filename\n", procid, opno);
+ free_pathname(&f);
+ return;
+ }
+ fd = open_path(&f, O_RDWR);
+ e = fd < 0 ? errno : 0;
+ check_cwd();
+ if (fd < 0) {
+ if (v)
+ printf("%d/%d: allocsp - open %s failed %d\n",
+ procid, opno, f.path, e);
+ free_pathname(&f);
+ return;
+ }
+ if (fstat64(fd, &stb) < 0) {
+ if (v)
+ printf("%d/%d: allocsp - fstat64 %s failed %d\n",
+ procid, opno, f.path, errno);
+ free_pathname(&f);
+ close(fd);
+ return;
+ }
+ lr = ((__int64_t)random() << 32) + random();
+ off = (off64_t)(lr % MIN(stb.st_size + (1024 * 1024), MAXFSIZE));
+ off %= maxfsize;
+ fl.l_whence = SEEK_SET;
+ fl.l_start = off;
+ fl.l_len = 0;
+ e = xfsctl(f.path, fd, XFS_IOC_ALLOCSP64, &fl) < 0 ? errno : 0;
+ if (v)
+ printf("%d/%d: xfsctl(XFS_IOC_ALLOCSP64) %s %lld 0 %d\n",
+ procid, opno, f.path, (long long)off, e);
+ free_pathname(&f);
+ close(fd);
+}
+
+void
+attr_remove_f(int opno, long r)
+{
+ char *aname, *l;
+ char buf[4096];
+ int e;
+ int ent;
+ pathname_t f;
+ int total;
+ int v;
+ int which;
+
+ init_pathname(&f);
+ if (!get_fname(FT_ANYm, r, &f, NULL, NULL, &v))
+ append_pathname(&f, ".");
+ total = 0;
+ e = attr_list_path(&f, buf, sizeof(buf), ATTR_DONTFOLLOW);
+ check_cwd();
+ if (e > 0) {
+ for (l = buf; l - buf <= e; l += strlen(l)+1)
+ if (strncmp(l, "user.",5) == 0)
+ total++;
+ }
+ if (total == 0) {
+ if (v)
+ printf("%d/%d: attr_remove - no attrs for %s\n",
+ procid, opno, f.path);
+ free_pathname(&f);
+ return;
+ }
+ which = (int)(random() % total);
+ ent = 0;
+ aname = NULL;
+ e = attr_list_path(&f, buf, sizeof(buf), ATTR_DONTFOLLOW);
+ check_cwd();
+ if (e <= 0)
+ return;
+ for (l = buf; l - buf <= e; l += strlen(l)+1) {
+ if (strncmp(l, "user.",5) == 0) {
+ if (++ent == which) {
+ aname = l;
+ break;
+ }
+ }
+ }
+ if (aname == NULL) {
+ if (v)
+ printf(
+ "%d/%d: attr_remove - name %d not found at %s\n",
+ procid, opno, which, f.path);
+ free_pathname(&f);
+ return;
+ }
+ e = attr_remove_path(&f, aname, ATTR_DONTFOLLOW) < 0 ? errno : 0;
+ check_cwd();
+ if (v)
+ printf("%d/%d: attr_remove %s %s %d\n",
+ procid, opno, f.path, aname, e);
+ free_pathname(&f);
+}
+
+void
+attr_set_f(int opno, long r)
+{
+ char aname[10];
+ char *aval;
+ int e;
+ pathname_t f;
+ int len;
+ static int lengths[] = { 10, 100, 1000, 10000 };
+ int li;
+ int v;
+
+ init_pathname(&f);
+ if (!get_fname(FT_ANYm, r, &f, NULL, NULL, &v))
+ append_pathname(&f, ".");
+ sprintf(aname, "a%x", nameseq++);
+ li = (int)(random() % (sizeof(lengths) / sizeof(lengths[0])));
+ len = (int)(random() % lengths[li]);
+ if (len == 0)
+ len = 1;
+ aval = malloc(len);
+ memset(aval, nameseq & 0xff, len);
+ e = attr_set_path(&f, aname, aval, len, ATTR_DONTFOLLOW) < 0 ?
+ errno : 0;
+ check_cwd();
+ free(aval);
+ if (v)
+ printf("%d/%d: attr_set %s %s %d\n", procid, opno, f.path,
+ aname, e);
+ free_pathname(&f);
+}
+
+void
+bulkstat_f(int opno, long r)
+{
+ int count;
+ int fd;
+ __uint64_t last;
+ int nent;
+ xfs_bstat_t *t;
+ __int64_t total;
+ xfs_fsop_bulkreq_t bsr;
+
+ last = 0;
+ nent = (r % 999) + 2;
+ t = malloc(nent * sizeof(*t));
+ fd = open(".", O_RDONLY);
+ total = 0;
+
+ bsr.lastip=&last;
+ bsr.icount=nent;
+ bsr.ubuffer=t;
+ bsr.ocount=&count;
+
+ while (xfsctl(".", fd, XFS_IOC_FSBULKSTAT, &bsr) == 0 && count > 0)
+ total += count;
+ free(t);
+ if (verbose)
+ printf("%d/%d: bulkstat nent %d total %llu\n",
+ procid, opno, nent, (long long)total);
+ close(fd);
+}
+
+void
+bulkstat1_f(int opno, long r)
+{
+ int e;
+ pathname_t f;
+ int fd;
+ int good;
+ __uint64_t ino;
+ struct stat64 s;
+ xfs_bstat_t t;
+ int v;
+ xfs_fsop_bulkreq_t bsr;
+
+
+ good = random() & 1;
+ if (good) {
+ /* use an inode we know exists */
+ init_pathname(&f);
+ if (!get_fname(FT_ANYm, r, &f, NULL, NULL, &v))
+ append_pathname(&f, ".");
+ ino = stat64_path(&f, &s) < 0 ? (ino64_t)r : s.st_ino;
+ check_cwd();
+ free_pathname(&f);
+ } else {
+ /*
+ * pick a random inode
+ *
+ * note this can generate kernel warning messages
+ * since bulkstat_one will read the disk block that
+ * would contain a given inode even if that disk
+ * block doesn't contain inodes.
+ *
+ * this is detected later, but not until after the
+ * warning is displayed.
+ *
+ * "XFS: device 0x825- bad inode magic/vsn daddr 0x0 #0"
+ *
+ */
+ ino = (ino64_t)r;
+ v = verbose;
+ }
+ fd = open(".", O_RDONLY);
+
+ bsr.lastip=&ino;
+ bsr.icount=1;
+ bsr.ubuffer=&t;
+ bsr.ocount=NULL;
+
+ e = xfsctl(".", fd, XFS_IOC_FSBULKSTAT_SINGLE, &bsr) < 0 ? errno : 0;
+ if (v)
+ printf("%d/%d: bulkstat1 %s ino %lld %d\n",
+ procid, opno, good?"real":"random", (long long)ino, e);
+ close(fd);
+}
+
+void
+chown_f(int opno, long r)
+{
+ int e;
+ pathname_t f;
+ int nbits;
+ uid_t u;
+ int v;
+
+ init_pathname(&f);
+ if (!get_fname(FT_ANYm, r, &f, NULL, NULL, &v))
+ append_pathname(&f, ".");
+ u = (uid_t)random();
+ nbits = (int)(random() % 32);
+ u &= (1 << nbits) - 1;
+ e = lchown_path(&f, u, -1) < 0 ? errno : 0;
+ check_cwd();
+ if (v)
+ printf("%d/%d: chown %s %d %d\n", procid, opno, f.path, u, e);
+ free_pathname(&f);
+}
+
+void
+creat_f(int opno, long r)
+{
+ struct fsxattr a;
+ int e;
+ int e1;
+ int extsize;
+ pathname_t f;
+ int fd;
+ fent_t *fep;
+ int id;
+ int parid;
+ int type;
+ int v;
+ int v1;
+
+ if (!get_fname(FT_DIRm, r, NULL, NULL, &fep, &v1))
+ parid = -1;
+ else
+ parid = fep->id;
+ init_pathname(&f);
+ type = rtpct ? ((random() % 100) > rtpct ? FT_REG : FT_RTF) : FT_REG;
+ if (type == FT_RTF)
+ extsize = (random() % 10) + 1;
+ else
+ extsize = 0;
+ e = generate_fname(fep, type, &f, &id, &v);
+ v |= v1;
+ if (!e) {
+ if (v) {
+ fent_to_name(&f, &flist[FT_DIR], fep);
+ printf("%d/%d: creat - no filename from %s\n",
+ procid, opno, f.path);
+ }
+ free_pathname(&f);
+ return;
+ }
+ fd = creat_path(&f, 0666);
+ e = fd < 0 ? errno : 0;
+ e1 = 0;
+ check_cwd();
+ if (fd >= 0) {
+ if (extsize &&
+ xfsctl(f.path, fd, XFS_IOC_FSGETXATTR, &a) >= 0) {
+ a.fsx_xflags |= XFS_XFLAG_REALTIME;
+ a.fsx_extsize =
+ geom.rtextsize * geom.blocksize * extsize;
+ if (xfsctl(f.path, fd, XFS_IOC_FSSETXATTR, &a) < 0)
+ e1 = errno;
+ }
+ add_to_flist(type, id, parid);
+ close(fd);
+ }
+ if (v)
+ printf("%d/%d: creat %s x:%d %d %d\n", procid, opno, f.path,
+ extsize ? a.fsx_extsize : 0, e, e1);
+ free_pathname(&f);
+}
+
+void
+dread_f(int opno, long r)
+{
+ __int64_t align;
+ char *buf;
+ struct dioattr diob;
+ int e;
+ pathname_t f;
+ int fd;
+ size_t len;
+ __int64_t lr;
+ off64_t off;
+ struct stat64 stb;
+ int v;
+
+ init_pathname(&f);
+ if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) {
+ if (v)
+ printf("%d/%d: dread - no filename\n", procid, opno);
+ free_pathname(&f);
+ return;
+ }
+ fd = open_path(&f, O_RDONLY|O_DIRECT);
+ e = fd < 0 ? errno : 0;
+ check_cwd();
+ if (fd < 0) {
+ if (v)
+ printf("%d/%d: dread - open %s failed %d\n",
+ procid, opno, f.path, e);
+ free_pathname(&f);
+ return;
+ }
+ if (fstat64(fd, &stb) < 0) {
+ if (v)
+ printf("%d/%d: dread - fstat64 %s failed %d\n",
+ procid, opno, f.path, errno);
+ free_pathname(&f);
+ close(fd);
+ return;
+ }
+ if (stb.st_size == 0) {
+ if (v)
+ printf("%d/%d: dread - %s zero size\n", procid, opno,
+ f.path);
+ free_pathname(&f);
+ close(fd);
+ return;
+ }
+ if (xfsctl(f.path, fd, XFS_IOC_DIOINFO, &diob) < 0) {
+ if (v)
+ printf(
+ "%d/%d: dread - xfsctl(XFS_IOC_DIOINFO) %s failed %d\n",
+ procid, opno, f.path, errno);
+ free_pathname(&f);
+ close(fd);
+ return;
+ }
+ align = (__int64_t)diob.d_miniosz;
+ lr = ((__int64_t)random() << 32) + random();
+ off = (off64_t)(lr % stb.st_size);
+ off -= (off % align);
+ lseek64(fd, off, SEEK_SET);
+ len = (random() % (getpagesize() * 32)) + 1;
+ len -= (len % align);
+ if (len <= 0)
+ len = align;
+ else if (len > diob.d_maxiosz)
+ len = diob.d_maxiosz;
+ buf = memalign(diob.d_mem, len);
+ e = read(fd, buf, len) < 0 ? errno : 0;
+ free(buf);
+ if (v)
+ printf("%d/%d: dread %s [%lld,%d] %d\n",
+ procid, opno, f.path, (long long)off, (int)len, e);
+ free_pathname(&f);
+ close(fd);
+}
+
+void
+dwrite_f(int opno, long r)
+{
+ __int64_t align;
+ char *buf;
+ struct dioattr diob;
+ int e;
+ pathname_t f;
+ int fd;
+ size_t len;
+ __int64_t lr;
+ off64_t off;
+ struct stat64 stb;
+ int v;
+
+ init_pathname(&f);
+ if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) {
+ if (v)
+ printf("%d/%d: dwrite - no filename\n", procid, opno);
+ free_pathname(&f);
+ return;
+ }
+ fd = open_path(&f, O_WRONLY|O_DIRECT);
+ e = fd < 0 ? errno : 0;
+ check_cwd();
+ if (fd < 0) {
+ if (v)
+ printf("%d/%d: dwrite - open %s failed %d\n",
+ procid, opno, f.path, e);
+ free_pathname(&f);
+ return;
+ }
+ if (fstat64(fd, &stb) < 0) {
+ if (v)
+ printf("%d/%d: dwrite - fstat64 %s failed %d\n",
+ procid, opno, f.path, errno);
+ free_pathname(&f);
+ close(fd);
+ return;
+ }
+ if (xfsctl(f.path, fd, XFS_IOC_DIOINFO, &diob) < 0) {
+ if (v)
+ printf("%d/%d: dwrite - xfsctl(XFS_IOC_DIOINFO)"
+ " %s failed %d\n",
+ procid, opno, f.path, errno);
+ free_pathname(&f);
+ close(fd);
+ return;
+ }
+ align = (__int64_t)diob.d_miniosz;
+ lr = ((__int64_t)random() << 32) + random();
+ off = (off64_t)(lr % MIN(stb.st_size + (1024 * 1024), MAXFSIZE));
+ off -= (off % align);
+ lseek64(fd, off, SEEK_SET);
+ len = (random() % (getpagesize() * 32)) + 1;
+ len -= (len % align);
+ if (len <= 0)
+ len = align;
+ else if (len > diob.d_maxiosz)
+ len = diob.d_maxiosz;
+ buf = memalign(diob.d_mem, len);
+ off %= maxfsize;
+ lseek64(fd, off, SEEK_SET);
+ memset(buf, nameseq & 0xff, len);
+ e = write(fd, buf, len) < 0 ? errno : 0;
+ free(buf);
+ if (v)
+ printf("%d/%d: dwrite %s [%lld,%d] %d\n",
+ procid, opno, f.path, (long long)off, (int)len, e);
+ free_pathname(&f);
+ close(fd);
+}
+
+void
+fdatasync_f(int opno, long r)
+{
+ int e;
+ pathname_t f;
+ int fd;
+ int v;
+
+ init_pathname(&f);
+ if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) {
+ if (v)
+ printf("%d/%d: fdatasync - no filename\n",
+ procid, opno);
+ free_pathname(&f);
+ return;
+ }
+ fd = open_path(&f, O_WRONLY);
+ e = fd < 0 ? errno : 0;
+ check_cwd();
+ if (fd < 0) {
+ if (v)
+ printf("%d/%d: fdatasync - open %s failed %d\n",
+ procid, opno, f.path, e);
+ free_pathname(&f);
+ return;
+ }
+ e = fdatasync(fd) < 0 ? errno : 0;
+ if (v)
+ printf("%d/%d: fdatasync %s %d\n", procid, opno, f.path, e);
+ free_pathname(&f);
+ close(fd);
+}
+
+void
+freesp_f(int opno, long r)
+{
+ int e;
+ pathname_t f;
+ int fd;
+ struct flock64 fl;
+ __int64_t lr;
+ off64_t off;
+ struct stat64 stb;
+ int v;
+
+ init_pathname(&f);
+ if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) {
+ if (v)
+ printf("%d/%d: freesp - no filename\n", procid, opno);
+ free_pathname(&f);
+ return;
+ }
+ fd = open_path(&f, O_RDWR);
+ e = fd < 0 ? errno : 0;
+ check_cwd();
+ if (fd < 0) {
+ if (v)
+ printf("%d/%d: freesp - open %s failed %d\n",
+ procid, opno, f.path, e);
+ free_pathname(&f);
+ return;
+ }
+ if (fstat64(fd, &stb) < 0) {
+ if (v)
+ printf("%d/%d: freesp - fstat64 %s failed %d\n",
+ procid, opno, f.path, errno);
+ free_pathname(&f);
+ close(fd);
+ return;
+ }
+ lr = ((__int64_t)random() << 32) + random();
+ off = (off64_t)(lr % MIN(stb.st_size + (1024 * 1024), MAXFSIZE));
+ off %= maxfsize;
+ fl.l_whence = SEEK_SET;
+ fl.l_start = off;
+ fl.l_len = 0;
+ e = xfsctl(f.path, fd, XFS_IOC_FREESP64, &fl) < 0 ? errno : 0;
+ if (v)
+ printf("%d/%d: xfsctl(XFS_IOC_FREESP64) %s %lld 0 %d\n",
+ procid, opno, f.path, (long long)off, e);
+ free_pathname(&f);
+ close(fd);
+}
+
+void
+fsync_f(int opno, long r)
+{
+ int e;
+ pathname_t f;
+ int fd;
+ int v;
+
+ init_pathname(&f);
+ if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) {
+ if (v)
+ printf("%d/%d: fsync - no filename\n", procid, opno);
+ free_pathname(&f);
+ return;
+ }
+ fd = open_path(&f, O_WRONLY);
+ e = fd < 0 ? errno : 0;
+ check_cwd();
+ if (fd < 0) {
+ if (v)
+ printf("%d/%d: fsync - open %s failed %d\n",
+ procid, opno, f.path, e);
+ free_pathname(&f);
+ return;
+ }
+ e = fsync(fd) < 0 ? errno : 0;
+ if (v)
+ printf("%d/%d: fsync %s %d\n", procid, opno, f.path, e);
+ free_pathname(&f);
+ close(fd);
+}
+
+void
+getdents_f(int opno, long r)
+{
+ DIR *dir;
+ pathname_t f;
+ int v;
+
+ init_pathname(&f);
+ if (!get_fname(FT_DIRm, r, &f, NULL, NULL, &v))
+ append_pathname(&f, ".");
+ dir = opendir_path(&f);
+ check_cwd();
+ if (dir == NULL) {
+ if (v)
+ printf("%d/%d: getdents - can't open %s\n",
+ procid, opno, f.path);
+ free_pathname(&f);
+ return;
+ }
+ while (readdir64(dir) != NULL)
+ continue;
+ if (v)
+ printf("%d/%d: getdents %s 0\n", procid, opno, f.path);
+ free_pathname(&f);
+ closedir(dir);
+}
+
+void
+link_f(int opno, long r)
+{
+ int e;
+ pathname_t f;
+ fent_t *fep;
+ flist_t *flp;
+ int id;
+ pathname_t l;
+ int parid;
+ int v;
+ int v1;
+
+ init_pathname(&f);
+ if (!get_fname(FT_NOTDIR, r, &f, &flp, NULL, &v1)) {
+ if (v1)
+ printf("%d/%d: link - no file\n", procid, opno);
+ free_pathname(&f);
+ return;
+ }
+ if (!get_fname(FT_DIRm, random(), NULL, NULL, &fep, &v))
+ parid = -1;
+ else
+ parid = fep->id;
+ v |= v1;
+ init_pathname(&l);
+ e = generate_fname(fep, flp - flist, &l, &id, &v1);
+ v |= v1;
+ if (!e) {
+ if (v) {
+ fent_to_name(&l, &flist[FT_DIR], fep);
+ printf("%d/%d: link - no filename from %s\n",
+ procid, opno, l.path);
+ }
+ free_pathname(&l);
+ free_pathname(&f);
+ return;
+ }
+ e = link_path(&f, &l) < 0 ? errno : 0;
+ check_cwd();
+ if (e == 0)
+ add_to_flist(flp - flist, id, parid);
+ if (v)
+ printf("%d/%d: link %s %s %d\n", procid, opno, f.path, l.path,
+ e);
+ free_pathname(&l);
+ free_pathname(&f);
+}
+
+void
+mkdir_f(int opno, long r)
+{
+ int e;
+ pathname_t f;
+ fent_t *fep;
+ int id;
+ int parid;
+ int v;
+ int v1;
+
+ if (!get_fname(FT_DIRm, r, NULL, NULL, &fep, &v))
+ parid = -1;
+ else
+ parid = fep->id;
+ init_pathname(&f);
+ e = generate_fname(fep, FT_DIR, &f, &id, &v1);
+ v |= v1;
+ if (!e) {
+ if (v) {
+ fent_to_name(&f, &flist[FT_DIR], fep);
+ printf("%d/%d: mkdir - no filename from %s\n",
+ procid, opno, f.path);
+ }
+ free_pathname(&f);
+ return;
+ }
+ e = mkdir_path(&f, 0777) < 0 ? errno : 0;
+ check_cwd();
+ if (e == 0)
+ add_to_flist(FT_DIR, id, parid);
+ if (v)
+ printf("%d/%d: mkdir %s %d\n", procid, opno, f.path, e);
+ free_pathname(&f);
+}
+
+void
+mknod_f(int opno, long r)
+{
+ int e;
+ pathname_t f;
+ fent_t *fep;
+ int id;
+ int parid;
+ int v;
+ int v1;
+
+ if (!get_fname(FT_DIRm, r, NULL, NULL, &fep, &v))
+ parid = -1;
+ else
+ parid = fep->id;
+ init_pathname(&f);
+ e = generate_fname(fep, FT_DEV, &f, &id, &v1);
+ v |= v1;
+ if (!e) {
+ if (v) {
+ fent_to_name(&f, &flist[FT_DIR], fep);
+ printf("%d/%d: mknod - no filename from %s\n",
+ procid, opno, f.path);
+ }
+ free_pathname(&f);
+ return;
+ }
+ e = mknod_path(&f, S_IFCHR|0444, 0) < 0 ? errno : 0;
+ check_cwd();
+ if (e == 0)
+ add_to_flist(FT_DEV, id, parid);
+ if (v)
+ printf("%d/%d: mknod %s %d\n", procid, opno, f.path, e);
+ free_pathname(&f);
+}
+
+void
+read_f(int opno, long r)
+{
+ char *buf;
+ int e;
+ pathname_t f;
+ int fd;
+ size_t len;
+ __int64_t lr;
+ off64_t off;
+ struct stat64 stb;
+ int v;
+
+ init_pathname(&f);
+ if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) {
+ if (v)
+ printf("%d/%d: read - no filename\n", procid, opno);
+ free_pathname(&f);
+ return;
+ }
+ fd = open_path(&f, O_RDONLY);
+ e = fd < 0 ? errno : 0;
+ check_cwd();
+ if (fd < 0) {
+ if (v)
+ printf("%d/%d: read - open %s failed %d\n",
+ procid, opno, f.path, e);
+ free_pathname(&f);
+ return;
+ }
+ if (fstat64(fd, &stb) < 0) {
+ if (v)
+ printf("%d/%d: read - fstat64 %s failed %d\n",
+ procid, opno, f.path, errno);
+ free_pathname(&f);
+ close(fd);
+ return;
+ }
+ if (stb.st_size == 0) {
+ if (v)
+ printf("%d/%d: read - %s zero size\n", procid, opno,
+ f.path);
+ free_pathname(&f);
+ close(fd);
+ return;
+ }
+ lr = ((__int64_t)random() << 32) + random();
+ off = (off64_t)(lr % stb.st_size);
+ lseek64(fd, off, SEEK_SET);
+ len = (random() % (getpagesize() * 32)) + 1;
+ buf = malloc(len);
+ e = read(fd, buf, len) < 0 ? errno : 0;
+ free(buf);
+ if (v)
+ printf("%d/%d: read %s [%lld,%d] %d\n",
+ procid, opno, f.path, (long long)off, (int)len, e);
+ free_pathname(&f);
+ close(fd);
+}
+
+void
+readlink_f(int opno, long r)
+{
+ char buf[PATH_MAX];
+ int e;
+ pathname_t f;
+ int v;
+
+ init_pathname(&f);
+ if (!get_fname(FT_SYMm, r, &f, NULL, NULL, &v)) {
+ if (v)
+ printf("%d/%d: readlink - no filename\n", procid, opno);
+ free_pathname(&f);
+ return;
+ }
+ e = readlink_path(&f, buf, PATH_MAX) < 0 ? errno : 0;
+ check_cwd();
+ if (v)
+ printf("%d/%d: readlink %s %d\n", procid, opno, f.path, e);
+ free_pathname(&f);
+}
+
+void
+rename_f(int opno, long r)
+{
+ fent_t *dfep;
+ int e;
+ pathname_t f;
+ fent_t *fep;
+ flist_t *flp;
+ int id;
+ pathname_t newf;
+ int oldid;
+ int parid;
+ int v;
+ int v1;
+
+ init_pathname(&f);
+ if (!get_fname(FT_ANYm, r, &f, &flp, &fep, &v1)) {
+ if (v1)
+ printf("%d/%d: rename - no filename\n", procid, opno);
+ free_pathname(&f);
+ return;
+ }
+ if (!get_fname(FT_DIRm, random(), NULL, NULL, &dfep, &v))
+ parid = -1;
+ else
+ parid = dfep->id;
+ v |= v1;
+ init_pathname(&newf);
+ e = generate_fname(dfep, flp - flist, &newf, &id, &v1);
+ v |= v1;
+ if (!e) {
+ if (v) {
+ fent_to_name(&f, &flist[FT_DIR], dfep);
+ printf("%d/%d: rename - no filename from %s\n",
+ procid, opno, f.path);
+ }
+ free_pathname(&newf);
+ free_pathname(&f);
+ return;
+ }
+ e = rename_path(&f, &newf) < 0 ? errno : 0;
+ check_cwd();
+ if (e == 0) {
+ if (flp - flist == FT_DIR) {
+ oldid = fep->id;
+ fix_parent(oldid, id);
+ }
+ del_from_flist(flp - flist, fep - flp->fents);
+ add_to_flist(flp - flist, id, parid);
+ }
+ if (v)
+ printf("%d/%d: rename %s to %s %d\n", procid, opno, f.path,
+ newf.path, e);
+ free_pathname(&newf);
+ free_pathname(&f);
+}
+
+void
+resvsp_f(int opno, long r)
+{
+ int e;
+ pathname_t f;
+ int fd;
+ struct flock64 fl;
+ __int64_t lr;
+ off64_t off;
+ struct stat64 stb;
+ int v;
+
+ init_pathname(&f);
+ if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) {
+ if (v)
+ printf("%d/%d: resvsp - no filename\n", procid, opno);
+ free_pathname(&f);
+ return;
+ }
+ fd = open_path(&f, O_RDWR);
+ e = fd < 0 ? errno : 0;
+ check_cwd();
+ if (fd < 0) {
+ if (v)
+ printf("%d/%d: resvsp - open %s failed %d\n",
+ procid, opno, f.path, e);
+ free_pathname(&f);
+ return;
+ }
+ if (fstat64(fd, &stb) < 0) {
+ if (v)
+ printf("%d/%d: resvsp - fstat64 %s failed %d\n",
+ procid, opno, f.path, errno);
+ free_pathname(&f);
+ close(fd);
+ return;
+ }
+ lr = ((__int64_t)random() << 32) + random();
+ off = (off64_t)(lr % MIN(stb.st_size + (1024 * 1024), MAXFSIZE));
+ off %= maxfsize;
+ fl.l_whence = SEEK_SET;
+ fl.l_start = off;
+ fl.l_len = (off64_t)(random() % (1024 * 1024));
+ e = xfsctl(f.path, fd, XFS_IOC_RESVSP64, &fl) < 0 ? errno : 0;
+ if (v)
+ printf("%d/%d: xfsctl(XFS_IOC_RESVSP64) %s %lld %lld %d\n",
+ procid, opno, f.path,
+ (long long)off, (long long)fl.l_len, e);
+ free_pathname(&f);
+ close(fd);
+}
+
+void
+rmdir_f(int opno, long r)
+{
+ int e;
+ pathname_t f;
+ fent_t *fep;
+ int v;
+
+ init_pathname(&f);
+ if (!get_fname(FT_DIRm, r, &f, NULL, &fep, &v)) {
+ if (v)
+ printf("%d/%d: rmdir - no directory\n", procid, opno);
+ free_pathname(&f);
+ return;
+ }
+ e = rmdir_path(&f) < 0 ? errno : 0;
+ check_cwd();
+ if (e == 0)
+ del_from_flist(FT_DIR, fep - flist[FT_DIR].fents);
+ if (v)
+ printf("%d/%d: rmdir %s %d\n", procid, opno, f.path, e);
+ free_pathname(&f);
+}
+
+void
+stat_f(int opno, long r)
+{
+ int e;
+ pathname_t f;
+ struct stat64 stb;
+ int v;
+
+ init_pathname(&f);
+ if (!get_fname(FT_ANYm, r, &f, NULL, NULL, &v)) {
+ if (v)
+ printf("%d/%d: stat - no entries\n", procid, opno);
+ free_pathname(&f);
+ return;
+ }
+ e = lstat64_path(&f, &stb) < 0 ? errno : 0;
+ check_cwd();
+ if (v)
+ printf("%d/%d: stat %s %d\n", procid, opno, f.path, e);
+ free_pathname(&f);
+}
+
+void
+symlink_f(int opno, long r)
+{
+ int e;
+ pathname_t f;
+ fent_t *fep;
+ int i;
+ int id;
+ int len;
+ int parid;
+ int v;
+ int v1;
+ char *val;
+
+ if (!get_fname(FT_DIRm, r, NULL, NULL, &fep, &v))
+ parid = -1;
+ else
+ parid = fep->id;
+ init_pathname(&f);
+ e = generate_fname(fep, FT_SYM, &f, &id, &v1);
+ v |= v1;
+ if (!e) {
+ if (v) {
+ fent_to_name(&f, &flist[FT_DIR], fep);
+ printf("%d/%d: symlink - no filename from %s\n",
+ procid, opno, f.path);
+ }
+ free_pathname(&f);
+ return;
+ }
+ len = (int)(random() % PATH_MAX);
+ val = malloc(len + 1);
+ if (len)
+ memset(val, 'x', len);
+ val[len] = '\0';
+ for (i = 10; i < len - 1; i += 10)
+ val[i] = '/';
+ e = symlink_path(val, &f) < 0 ? errno : 0;
+ check_cwd();
+ if (e == 0)
+ add_to_flist(FT_SYM, id, parid);
+ free(val);
+ if (v)
+ printf("%d/%d: symlink %s %d\n", procid, opno, f.path, e);
+ free_pathname(&f);
+}
+
+/* ARGSUSED */
+void
+sync_f(int opno, long r)
+{
+ sync();
+ if (verbose)
+ printf("%d/%d: sync\n", procid, opno);
+}
+
+void
+truncate_f(int opno, long r)
+{
+ int e;
+ pathname_t f;
+ __int64_t lr;
+ off64_t off;
+ struct stat64 stb;
+ int v;
+
+ init_pathname(&f);
+ if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) {
+ if (v)
+ printf("%d/%d: truncate - no filename\n", procid, opno);
+ free_pathname(&f);
+ return;
+ }
+ e = stat64_path(&f, &stb) < 0 ? errno : 0;
+ check_cwd();
+ if (e > 0) {
+ if (v)
+ printf("%d/%d: truncate - stat64 %s failed %d\n",
+ procid, opno, f.path, e);
+ free_pathname(&f);
+ return;
+ }
+ lr = ((__int64_t)random() << 32) + random();
+ off = (off64_t)(lr % MIN(stb.st_size + (1024 * 1024), MAXFSIZE));
+ off %= maxfsize;
+ e = truncate64_path(&f, off) < 0 ? errno : 0;
+ check_cwd();
+ if (v)
+ printf("%d/%d: truncate %s %lld %d\n", procid, opno, f.path,
+ (long long)off, e);
+ free_pathname(&f);
+}
+
+void
+unlink_f(int opno, long r)
+{
+ int e;
+ pathname_t f;
+ fent_t *fep;
+ flist_t *flp;
+ int v;
+
+ init_pathname(&f);
+ if (!get_fname(FT_NOTDIR, r, &f, &flp, &fep, &v)) {
+ if (v)
+ printf("%d/%d: unlink - no file\n", procid, opno);
+ free_pathname(&f);
+ return;
+ }
+ e = unlink_path(&f) < 0 ? errno : 0;
+ check_cwd();
+ if (e == 0)
+ del_from_flist(flp - flist, fep - flp->fents);
+ if (v)
+ printf("%d/%d: unlink %s %d\n", procid, opno, f.path, e);
+ free_pathname(&f);
+}
+
+void
+unresvsp_f(int opno, long r)
+{
+ int e;
+ pathname_t f;
+ int fd;
+ struct flock64 fl;
+ __int64_t lr;
+ off64_t off;
+ struct stat64 stb;
+ int v;
+
+ init_pathname(&f);
+ if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) {
+ if (v)
+ printf("%d/%d: unresvsp - no filename\n", procid, opno);
+ free_pathname(&f);
+ return;
+ }
+ fd = open_path(&f, O_RDWR);
+ e = fd < 0 ? errno : 0;
+ check_cwd();
+ if (fd < 0) {
+ if (v)
+ printf("%d/%d: unresvsp - open %s failed %d\n",
+ procid, opno, f.path, e);
+ free_pathname(&f);
+ return;
+ }
+ if (fstat64(fd, &stb) < 0) {
+ if (v)
+ printf("%d/%d: unresvsp - fstat64 %s failed %d\n",
+ procid, opno, f.path, errno);
+ free_pathname(&f);
+ close(fd);
+ return;
+ }
+ lr = ((__int64_t)random() << 32) + random();
+ off = (off64_t)(lr % MIN(stb.st_size + (1024 * 1024), MAXFSIZE));
+ off %= maxfsize;
+ fl.l_whence = SEEK_SET;
+ fl.l_start = off;
+ fl.l_len = (off64_t)(random() % (1 << 20));
+ e = xfsctl(f.path, fd, XFS_IOC_UNRESVSP64, &fl) < 0 ? errno : 0;
+ if (v)
+ printf("%d/%d: xfsctl(XFS_IOC_UNRESVSP64) %s %lld %lld %d\n",
+ procid, opno, f.path,
+ (long long)off, (long long)fl.l_len, e);
+ free_pathname(&f);
+ close(fd);
+}
+
+void
+write_f(int opno, long r)
+{
+ char *buf;
+ int e;
+ pathname_t f;
+ int fd;
+ size_t len;
+ __int64_t lr;
+ off64_t off;
+ struct stat64 stb;
+ int v;
+
+ init_pathname(&f);
+ if (!get_fname(FT_REGm, r, &f, NULL, NULL, &v)) {
+ if (v)
+ printf("%d/%d: write - no filename\n", procid, opno);
+ free_pathname(&f);
+ return;
+ }
+ fd = open_path(&f, O_WRONLY);
+ e = fd < 0 ? errno : 0;
+ check_cwd();
+ if (fd < 0) {
+ if (v)
+ printf("%d/%d: write - open %s failed %d\n",
+ procid, opno, f.path, e);
+ free_pathname(&f);
+ return;
+ }
+ if (fstat64(fd, &stb) < 0) {
+ if (v)
+ printf("%d/%d: write - fstat64 %s failed %d\n",
+ procid, opno, f.path, errno);
+ free_pathname(&f);
+ close(fd);
+ return;
+ }
+ lr = ((__int64_t)random() << 32) + random();
+ off = (off64_t)(lr % MIN(stb.st_size + (1024 * 1024), MAXFSIZE));
+ off %= maxfsize;
+ lseek64(fd, off, SEEK_SET);
+ len = (random() % (getpagesize() * 32)) + 1;
+ buf = malloc(len);
+ memset(buf, nameseq & 0xff, len);
+ e = write(fd, buf, len) < 0 ? errno : 0;
+ free(buf);
+ if (v)
+ printf("%d/%d: write %s [%lld,%d] %d\n",
+ procid, opno, f.path, (long long)off, (int)len, e);
+ free_pathname(&f);
+ close(fd);
+}
--- /dev/null
+/*
+ * Copyright (C) 1991, NeXT Computer, Inc. All Rights Reserverd.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ *
+ *
+ * File: fsx.c
+ * Author: Avadis Tevanian, Jr.
+ *
+ * File system exerciser.
+ *
+ * Rewritten 8/98 by Conrad Minshall.
+ *
+ * Small changes to work under Linux -- davej.
+ *
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+#include <limits.h>
+#include <time.h>
+#include <strings.h>
+#include <sys/file.h>
+#include <sys/mman.h>
+#include <limits.h>
+#include <err.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <errno.h>
+
+#ifndef MAP_FILE
+# define MAP_FILE 0
+#endif
+
+#define NUMPRINTCOLUMNS 32 /* # columns of data to print on each line */
+
+/*
+ * A log entry is an operation and a bunch of arguments.
+ */
+
+struct log_entry {
+ int operation;
+ int args[3];
+};
+
+#define LOGSIZE 1000
+
+struct log_entry oplog[LOGSIZE]; /* the log */
+int logptr = 0; /* current position in log */
+int logcount = 0; /* total ops */
+
+/*
+ * Define operations
+ */
+
+#define OP_READ 1
+#define OP_WRITE 2
+#define OP_TRUNCATE 3
+#define OP_CLOSEOPEN 4
+#define OP_MAPREAD 5
+#define OP_MAPWRITE 6
+#define OP_SKIPPED 7
+
+#ifndef PAGE_SIZE
+#define PAGE_SIZE getpagesize()
+#endif
+#define PAGE_MASK (PAGE_SIZE - 1)
+
+char *original_buf; /* a pointer to the original data */
+char *good_buf; /* a pointer to the correct data */
+char *temp_buf; /* a pointer to the current data */
+char *fname; /* name of our test file */
+int fd; /* fd for our test file */
+
+off_t file_size = 0;
+off_t biggest = 0;
+char state[256];
+unsigned long testcalls = 0; /* calls to function "test" */
+
+unsigned long simulatedopcount = 0; /* -b flag */
+int closeprob = 0; /* -c flag */
+int debug = 0; /* -d flag */
+unsigned long debugstart = 0; /* -D flag */
+unsigned long maxfilelen = 256 * 1024; /* -l flag */
+int sizechecks = 1; /* -n flag disables them */
+int maxoplen = 64 * 1024; /* -o flag */
+int quiet = 0; /* -q flag */
+unsigned long progressinterval = 0; /* -p flag */
+int readbdy = 1; /* -r flag */
+int style = 0; /* -s flag */
+int truncbdy = 1; /* -t flag */
+int writebdy = 1; /* -w flag */
+long monitorstart = -1; /* -m flag */
+long monitorend = -1; /* -m flag */
+int lite = 0; /* -L flag */
+long numops = -1; /* -N flag */
+int randomoplen = 1; /* -O flag disables it */
+int seed = 1; /* -S flag */
+int mapped_writes = 1; /* -W flag disables */
+int mapped_reads = 1; /* -R flag disables it */
+int fsxgoodfd = 0;
+FILE * fsxlogf = NULL;
+int badoff = -1;
+int closeopen = 0;
+
+
+void
+prt(char *fmt, ...)
+{
+ va_list args;
+
+ va_start(args, fmt);
+ vfprintf(stdout, fmt, args);
+ if (fsxlogf)
+ vfprintf(fsxlogf, fmt, args);
+ va_end(args);
+}
+
+void
+prterr(char *prefix)
+{
+ prt("%s%s%s\n", prefix, prefix ? ": " : "", strerror(errno));
+}
+
+
+void
+log4(int operation, int arg0, int arg1, int arg2)
+{
+ struct log_entry *le;
+
+ le = &oplog[logptr];
+ le->operation = operation;
+ if (closeopen)
+ le->operation = ~ le->operation;
+ le->args[0] = arg0;
+ le->args[1] = arg1;
+ le->args[2] = arg2;
+ logptr++;
+ logcount++;
+ if (logptr >= LOGSIZE)
+ logptr = 0;
+}
+
+
+void
+logdump(void)
+{
+ int i, count, down;
+ struct log_entry *lp;
+
+ prt("LOG DUMP (%d total operations):\n", logcount);
+ if (logcount < LOGSIZE) {
+ i = 0;
+ count = logcount;
+ } else {
+ i = logptr;
+ count = LOGSIZE;
+ }
+ for ( ; count > 0; count--) {
+ int opnum;
+
+ opnum = i+1 + (logcount/LOGSIZE)*LOGSIZE;
+ prt("%d(%d mod 256): ", opnum, opnum%256);
+ lp = &oplog[i];
+ if ((closeopen = lp->operation < 0))
+ lp->operation = ~ lp->operation;
+
+ switch (lp->operation) {
+ case OP_MAPREAD:
+ prt("MAPREAD\t0x%x thru 0x%x\t(0x%x bytes)",
+ lp->args[0], lp->args[0] + lp->args[1] - 1,
+ lp->args[1]);
+ if (badoff >= lp->args[0] && badoff <
+ lp->args[0] + lp->args[1])
+ prt("\t***RRRR***");
+ break;
+ case OP_MAPWRITE:
+ prt("MAPWRITE 0x%x thru 0x%x\t(0x%x bytes)",
+ lp->args[0], lp->args[0] + lp->args[1] - 1,
+ lp->args[1]);
+ if (badoff >= lp->args[0] && badoff <
+ lp->args[0] + lp->args[1])
+ prt("\t******WWWW");
+ break;
+ case OP_READ:
+ prt("READ\t0x%x thru 0x%x\t(0x%x bytes)",
+ lp->args[0], lp->args[0] + lp->args[1] - 1,
+ lp->args[1]);
+ if (badoff >= lp->args[0] &&
+ badoff < lp->args[0] + lp->args[1])
+ prt("\t***RRRR***");
+ break;
+ case OP_WRITE:
+ prt("WRITE\t0x%x thru 0x%x\t(0x%x bytes)",
+ lp->args[0], lp->args[0] + lp->args[1] - 1,
+ lp->args[1]);
+ if (lp->args[0] > lp->args[2])
+ prt(" HOLE");
+ else if (lp->args[0] + lp->args[1] > lp->args[2])
+ prt(" EXTEND");
+ if ((badoff >= lp->args[0] || badoff >=lp->args[2]) &&
+ badoff < lp->args[0] + lp->args[1])
+ prt("\t***WWWW");
+ break;
+ case OP_TRUNCATE:
+ down = lp->args[0] < lp->args[1];
+ prt("TRUNCATE %s\tfrom 0x%x to 0x%x",
+ down ? "DOWN" : "UP", lp->args[1], lp->args[0]);
+ if (badoff >= lp->args[!down] &&
+ badoff < lp->args[!!down])
+ prt("\t******WWWW");
+ break;
+ case OP_SKIPPED:
+ prt("SKIPPED (no operation)");
+ break;
+ default:
+ prt("BOGUS LOG ENTRY (operation code = %d)!",
+ lp->operation);
+ }
+ if (closeopen)
+ prt("\n\t\tCLOSE/OPEN");
+ prt("\n");
+ i++;
+ if (i == LOGSIZE)
+ i = 0;
+ }
+}
+
+
+void
+save_buffer(char *buffer, off_t bufferlength, int fd)
+{
+ off_t ret;
+ ssize_t byteswritten;
+
+ if (fd <= 0 || bufferlength == 0)
+ return;
+
+ if (bufferlength > SSIZE_MAX) {
+ prt("fsx flaw: overflow in save_buffer\n");
+ exit(67);
+ }
+ if (lite) {
+ off_t size_by_seek = lseek(fd, (off_t)0, L_XTND);
+ if (size_by_seek == (off_t)-1)
+ prterr("save_buffer: lseek eof");
+ else if (bufferlength > size_by_seek) {
+ fprintf(stderr, "save_buffer: .fsxgood file too short... will save 0x%qx bytes instead of 0x%qx\n", (unsigned long long)size_by_seek,
+ (unsigned long long)bufferlength);
+ bufferlength = size_by_seek;
+ }
+ }
+
+ ret = lseek(fd, (off_t)0, SEEK_SET);
+ if (ret == (off_t)-1)
+ prterr("save_buffer: lseek 0");
+
+ byteswritten = write(fd, buffer, (size_t)bufferlength);
+ if (byteswritten != bufferlength) {
+ if (byteswritten == -1)
+ prterr("save_buffer write");
+ else
+ fprintf(stderr, "save_buffer: short write, 0x%x bytes instead of 0x%qx\n",
+ (unsigned)byteswritten,
+ (unsigned long long)bufferlength);
+ }
+}
+
+
+void
+report_failure(int status)
+{
+ logdump();
+
+ if (fsxgoodfd) {
+ if (good_buf) {
+ save_buffer(good_buf, file_size, fsxgoodfd);
+ prt("Correct content saved for comparison\n");
+ prt("(maybe hexdump \"%s\" vs \"%s.fsxgood\")\n",
+ fname, fname);
+ }
+ close(fsxgoodfd);
+ }
+ exit(status);
+}
+
+
+#define short_at(cp) ((unsigned short)((*((unsigned char *)(cp)) << 8) | \
+ *(((unsigned char *)(cp)) + 1)))
+
+void
+check_buffers(unsigned offset, unsigned size)
+{
+ unsigned char c, t;
+ unsigned i = 0;
+ unsigned n = 0;
+ unsigned op = 0;
+ unsigned bad = 0;
+
+ if (bcmp(good_buf + offset, temp_buf, size) != 0) {
+ prt("READ BAD DATA: offset = 0x%x, size = 0x%x\n",
+ offset, size);
+ prt("OFFSET\tGOOD\tBAD\tRANGE\n");
+ while (size > 0) {
+ c = good_buf[offset];
+ t = temp_buf[i];
+ if (c != t) {
+ if (n == 0) {
+ bad = short_at(&temp_buf[i]);
+ prt("0x%5x\t0x%04x\t0x%04x", offset,
+ short_at(&good_buf[offset]), bad);
+ op = temp_buf[offset & 1 ? i+1 : i];
+ }
+ n++;
+ badoff = offset;
+ }
+ offset++;
+ i++;
+ size--;
+ }
+ if (n) {
+ prt("\t0x%5x\n", n);
+ if (bad)
+ prt("operation# (mod 256) for the bad data may be %u\n", ((unsigned)op & 0xff));
+ else
+ prt("operation# (mod 256) for the bad data unknown, check HOLE and EXTEND ops\n");
+ } else
+ prt("????????????????\n");
+ report_failure(110);
+ }
+}
+
+
+void
+check_size(void)
+{
+ struct stat statbuf;
+ off_t size_by_seek;
+
+ if (fstat(fd, &statbuf)) {
+ prterr("check_size: fstat");
+ statbuf.st_size = -1;
+ }
+ size_by_seek = lseek(fd, (off_t)0, L_XTND);
+ if (file_size != statbuf.st_size || file_size != size_by_seek) {
+ prt("Size error: expected 0x%qx stat 0x%qx seek 0x%qx\n",
+ (unsigned long long)file_size,
+ (unsigned long long)statbuf.st_size,
+ (unsigned long long)size_by_seek);
+ report_failure(120);
+ }
+}
+
+
+void
+check_trunc_hack(void)
+{
+ struct stat statbuf;
+
+ ftruncate(fd, (off_t)0);
+ ftruncate(fd, (off_t)100000);
+ fstat(fd, &statbuf);
+ if (statbuf.st_size != (off_t)100000) {
+ prt("no extend on truncate! not posix!\n");
+ exit(130);
+ }
+ ftruncate(fd, 0);
+}
+
+
+void
+doread(unsigned offset, unsigned size)
+{
+ off_t ret;
+ unsigned iret;
+
+ offset -= offset % readbdy;
+ if (size == 0) {
+ if (!quiet && testcalls > simulatedopcount)
+ prt("skipping zero size read\n");
+ log4(OP_SKIPPED, OP_READ, offset, size);
+ return;
+ }
+ if (size + offset > file_size) {
+ if (!quiet && testcalls > simulatedopcount)
+ prt("skipping seek/read past end of file\n");
+ log4(OP_SKIPPED, OP_READ, offset, size);
+ return;
+ }
+
+ log4(OP_READ, offset, size, 0);
+
+ if (testcalls <= simulatedopcount)
+ return;
+
+ if (!quiet && ((progressinterval && !(testcalls % progressinterval)) ||
+ (debug &&
+ (monitorstart == -1 ||
+ (offset + size > monitorstart &&
+ (monitorend == -1 || offset <= monitorend))))))
+ prt("%lu read\t0x%x thru\t0x%x\t(0x%x bytes)\n", testcalls,
+ offset, offset + size - 1, size);
+ ret = lseek(fd, (off_t)offset, SEEK_SET);
+ if (ret == (off_t)-1) {
+ prterr("doread: lseek");
+ report_failure(140);
+ }
+ iret = read(fd, temp_buf, size);
+ if (iret != size) {
+ if (iret == -1)
+ prterr("doread: read");
+ else
+ prt("short read: 0x%x bytes instead of 0x%x\n",
+ iret, size);
+ report_failure(141);
+ }
+ check_buffers(offset, size);
+}
+
+
+void
+domapread(unsigned offset, unsigned size)
+{
+ unsigned pg_offset;
+ unsigned map_size;
+ char *p;
+
+ offset -= offset % readbdy;
+ if (size == 0) {
+ if (!quiet && testcalls > simulatedopcount)
+ prt("skipping zero size read\n");
+ log4(OP_SKIPPED, OP_MAPREAD, offset, size);
+ return;
+ }
+ if (size + offset > file_size) {
+ if (!quiet && testcalls > simulatedopcount)
+ prt("skipping seek/read past end of file\n");
+ log4(OP_SKIPPED, OP_MAPREAD, offset, size);
+ return;
+ }
+
+ log4(OP_MAPREAD, offset, size, 0);
+
+ if (testcalls <= simulatedopcount)
+ return;
+
+ if (!quiet && ((progressinterval && !(testcalls % progressinterval)) ||
+ (debug &&
+ (monitorstart == -1 ||
+ (offset + size > monitorstart &&
+ ((monitorend == -1 || offset <= monitorend)))))))
+ prt("%lu mapread\t0x%x thru\t0x%x\t(0x%x bytes)\n", testcalls,
+ offset, offset + size - 1, size);
+
+ pg_offset = offset & PAGE_MASK;
+ map_size = pg_offset + size;
+
+ if ((p = (char *)mmap(0, map_size, PROT_READ, MAP_SHARED, fd,
+ (off_t)(offset - pg_offset))) == (char *)-1) {
+ prterr("domapread: mmap");
+ report_failure(190);
+ }
+ memcpy(temp_buf, p + pg_offset, size);
+ if (munmap(p, map_size) != 0) {
+ prterr("domapread: munmap");
+ report_failure(191);
+ }
+
+ check_buffers(offset, size);
+}
+
+
+void
+gendata(char *original_buf, char *good_buf, unsigned offset, unsigned size)
+{
+ while (size--) {
+ good_buf[offset] = testcalls % 256;
+ if (offset % 2)
+ good_buf[offset] += original_buf[offset];
+ offset++;
+ }
+}
+
+
+void
+dowrite(unsigned offset, unsigned size)
+{
+ off_t ret;
+ unsigned iret;
+
+ offset -= offset % writebdy;
+ if (size == 0) {
+ if (!quiet && testcalls > simulatedopcount)
+ prt("skipping zero size write\n");
+ log4(OP_SKIPPED, OP_WRITE, offset, size);
+ return;
+ }
+
+ log4(OP_WRITE, offset, size, file_size);
+
+ gendata(original_buf, good_buf, offset, size);
+ if (file_size < offset + size) {
+ if (file_size < offset)
+ bzero(good_buf + file_size, offset - file_size);
+ file_size = offset + size;
+ if (lite) {
+ fprintf(stderr, "Lite file size bug in fsx!");
+ report_failure(149);
+ }
+ }
+
+ if (testcalls <= simulatedopcount)
+ return;
+ if (!quiet && ((progressinterval && !(testcalls % progressinterval)) ||
+ (debug &&
+ (monitorstart == -1 ||
+ (offset + size > monitorstart &&
+ ((monitorend == -1 || offset <= monitorend)))))))
+ prt("%lu write\t0x%x thru\t0x%x\t(0x%x bytes)\n", testcalls,
+ offset, offset + size - 1, size);
+ ret = lseek(fd, (off_t)offset, SEEK_SET);
+ if (ret == (off_t)-1) {
+ prterr("dowrite: lseek");
+ report_failure(150);
+ }
+ iret = write(fd, good_buf + offset, size);
+ if (iret != size) {
+ if (iret == -1)
+ prterr("dowrite: write");
+ else
+ prt("short write: 0x%x bytes instead of 0x%x\n",
+ iret, size);
+ report_failure(151);
+ }
+}
+
+
+void
+domapwrite(unsigned offset, unsigned size)
+{
+ unsigned pg_offset;
+ unsigned map_size;
+ off_t cur_filesize;
+ char *p;
+
+ offset -= offset % writebdy;
+ if (size == 0) {
+ if (!quiet && testcalls > simulatedopcount)
+ prt("skipping zero size write\n");
+ log4(OP_SKIPPED, OP_MAPWRITE, offset, size);
+ return;
+ }
+ cur_filesize = file_size;
+
+ log4(OP_MAPWRITE, offset, size, 0);
+
+ gendata(original_buf, good_buf, offset, size);
+ if (file_size < offset + size) {
+ if (file_size < offset)
+ bzero(good_buf + file_size, offset - file_size);
+ file_size = offset + size;
+ if (lite) {
+ fprintf(stderr, "Lite file size bug in fsx!");
+ report_failure(200);
+ }
+ }
+
+ if (testcalls <= simulatedopcount)
+ return;
+
+ if (!quiet && ((progressinterval && !(testcalls % progressinterval)) ||
+ (debug &&
+ (monitorstart == -1 ||
+ (offset + size > monitorstart &&
+ (monitorend == -1 || offset <= monitorend))))))
+ prt("%lu mapwrite\t0x%x thru\t0x%x\t(0x%x bytes)\n", testcalls,
+ offset, offset + size - 1, size);
+
+ if (file_size > cur_filesize) {
+ if (ftruncate(fd, file_size) == -1) {
+ prterr("domapwrite: ftruncate");
+ exit(201);
+ }
+ }
+ pg_offset = offset & PAGE_MASK;
+ map_size = pg_offset + size;
+
+ if ((p = (char *)mmap(0, map_size, PROT_READ | PROT_WRITE,
+ MAP_FILE | MAP_SHARED, fd,
+ (off_t)(offset - pg_offset))) == (char *)-1) {
+ prterr("domapwrite: mmap");
+ report_failure(202);
+ }
+ memcpy(p + pg_offset, good_buf + offset, size);
+ if (msync(p, map_size, 0) != 0) {
+ prterr("domapwrite: msync");
+ report_failure(203);
+ }
+ if (munmap(p, map_size) != 0) {
+ prterr("domapwrite: munmap");
+ report_failure(204);
+ }
+}
+
+
+void
+dotruncate(unsigned size)
+{
+ int oldsize = file_size;
+
+ size -= size % truncbdy;
+ if (size > biggest) {
+ biggest = size;
+ if (!quiet && testcalls > simulatedopcount)
+ prt("truncating to largest ever: 0x%x\n", size);
+ }
+
+ log4(OP_TRUNCATE, size, (unsigned)file_size, 0);
+
+ if (size > file_size)
+ bzero(good_buf + file_size, size - file_size);
+ file_size = size;
+
+ if (testcalls <= simulatedopcount)
+ return;
+
+ if ((progressinterval && !(testcalls % progressinterval)) ||
+ (debug && (monitorstart == -1 || monitorend == -1 ||
+ size <= monitorend)))
+ prt("%lu trunc\tfrom 0x%x to 0x%x\n", testcalls, oldsize, size);
+ if (ftruncate(fd, (off_t)size) == -1) {
+ prt("ftruncate1: %x\n", size);
+ prterr("dotruncate: ftruncate");
+ report_failure(160);
+ }
+}
+
+
+void
+writefileimage()
+{
+ ssize_t iret;
+
+ if (lseek(fd, (off_t)0, SEEK_SET) == (off_t)-1) {
+ prterr("writefileimage: lseek");
+ report_failure(171);
+ }
+ iret = write(fd, good_buf, file_size);
+ if ((off_t)iret != file_size) {
+ if (iret == -1)
+ prterr("writefileimage: write");
+ else
+ prt("short write: 0x%x bytes instead of 0x%qx\n",
+ iret, (unsigned long long)file_size);
+ report_failure(172);
+ }
+ if (lite ? 0 : ftruncate(fd, file_size) == -1) {
+ prt("ftruncate2: %qx\n", (unsigned long long)file_size);
+ prterr("writefileimage: ftruncate");
+ report_failure(173);
+ }
+}
+
+
+void
+docloseopen(void)
+{
+ if (testcalls <= simulatedopcount)
+ return;
+
+ if (debug)
+ prt("%lu close/open\n", testcalls);
+ if (close(fd)) {
+ prterr("docloseopen: close");
+ report_failure(180);
+ }
+ fd = open(fname, O_RDWR, 0);
+ if (fd < 0) {
+ prterr("docloseopen: open");
+ report_failure(181);
+ }
+}
+
+
+void
+test(void)
+{
+ unsigned long offset;
+ unsigned long size = maxoplen;
+ unsigned long rv = random();
+ unsigned long op = rv % (3 + !lite + mapped_writes);
+
+ /* turn off the map read if necessary */
+
+ if (op == 2 && !mapped_reads)
+ op = 0;
+
+ if (simulatedopcount > 0 && testcalls == simulatedopcount)
+ writefileimage();
+
+ testcalls++;
+
+ if (closeprob)
+ closeopen = (rv >> 3) < (1 << 28) / closeprob;
+
+ if (debugstart > 0 && testcalls >= debugstart)
+ debug = 1;
+
+ if (!quiet && testcalls < simulatedopcount && testcalls % 100000 == 0)
+ prt("%lu...\n", testcalls);
+
+ /*
+ * READ: op = 0
+ * WRITE: op = 1
+ * MAPREAD: op = 2
+ * TRUNCATE: op = 3
+ * MAPWRITE: op = 3 or 4
+ */
+ if (lite ? 0 : op == 3 && (style & 1) == 0) /* vanilla truncate? */
+ dotruncate(random() % maxfilelen);
+ else {
+ if (randomoplen)
+ size = random() % (maxoplen+1);
+ if (lite ? 0 : op == 3)
+ dotruncate(size);
+ else {
+ offset = random();
+ if (op == 1 || op == (lite ? 3 : 4)) {
+ offset %= maxfilelen;
+ if (offset + size > maxfilelen)
+ size = maxfilelen - offset;
+ if (op != 1)
+ domapwrite(offset, size);
+ else
+ dowrite(offset, size);
+ } else {
+ if (file_size)
+ offset %= file_size;
+ else
+ offset = 0;
+ if (offset + size > file_size)
+ size = file_size - offset;
+ if (op != 0)
+ domapread(offset, size);
+ else
+ doread(offset, size);
+ }
+ }
+ }
+ if (sizechecks && testcalls > simulatedopcount)
+ check_size();
+ if (closeopen)
+ docloseopen();
+}
+
+
+void
+cleanup(sig)
+ int sig;
+{
+ if (sig)
+ prt("signal %d\n", sig);
+ prt("testcalls = %lu\n", testcalls);
+ exit(sig);
+}
+
+
+void
+usage(void)
+{
+ fprintf(stdout, "usage: %s",
+ "fsx [-dnqLOW] [-b opnum] [-c Prob] [-l flen] [-m start:end] [-o oplen] [-p progressinterval] [-r readbdy] [-s style] [-t truncbdy] [-w writebdy] [-D startingop] [-N numops] [-P dirpath] [-S seed] fname\n\
+ -b opnum: beginning operation number (default 1)\n\
+ -c P: 1 in P chance of file close+open at each op (default infinity)\n\
+ -d: debug output for all operations\n\
+ -l flen: the upper bound on file size (default 262144)\n\
+ -m startop:endop: monitor (print debug output) specified byte range (default 0:infinity)\n\
+ -n: no verifications of file size\n\
+ -o oplen: the upper bound on operation size (default 65536)\n\
+ -p progressinterval: debug output at specified operation interval\n\
+ -q: quieter operation\n\
+ -r readbdy: 4096 would make reads page aligned (default 1)\n\
+ -s style: 1 gives smaller truncates (default 0)\n\
+ -t truncbdy: 4096 would make truncates page aligned (default 1)\n\
+ -w writebdy: 4096 would make writes page aligned (default 1)\n\
+ -D startingop: debug output starting at specified operation\n\
+ -L: fsxLite - no file creations & no file size changes\n\
+ -N numops: total # operations to do (default infinity)\n\
+ -O: use oplen (see -o flag) for every op (default random)\n\
+ -P: save .fsxlog and .fsxgood files in dirpath (default ./)\n\
+ -S seed: for random # generator (default 1) 0 gets timestamp\n\
+ -W: mapped write operations DISabled\n\
+ -R: read() system calls only (mapped reads disabled)\n\
+ fname: this filename is REQUIRED (no default)\n");
+ exit(90);
+}
+
+
+int
+getnum(char *s, char **e)
+{
+ int ret = -1;
+
+ *e = (char *) 0;
+ ret = strtol(s, e, 0);
+ if (*e)
+ switch (**e) {
+ case 'b':
+ case 'B':
+ ret *= 512;
+ *e = *e + 1;
+ break;
+ case 'k':
+ case 'K':
+ ret *= 1024;
+ *e = *e + 1;
+ break;
+ case 'm':
+ case 'M':
+ ret *= 1024*1024;
+ *e = *e + 1;
+ break;
+ case 'w':
+ case 'W':
+ ret *= 4;
+ *e = *e + 1;
+ break;
+ }
+ return (ret);
+}
+
+
+int
+main(int argc, char **argv)
+{
+ int i, style, ch;
+ char *endp;
+ char goodfile[1024];
+ char logfile[1024];
+
+ goodfile[0] = 0;
+ logfile[0] = 0;
+
+ setvbuf(stdout, (char *)0, _IOLBF, 0); /* line buffered stdout */
+
+ while ((ch = getopt(argc, argv, "b:c:dl:m:no:p:qr:s:t:w:D:LN:OP:RS:W"))
+ != EOF)
+ switch (ch) {
+ case 'b':
+ simulatedopcount = getnum(optarg, &endp);
+ if (!quiet)
+ fprintf(stdout, "Will begin at operation %ld\n",
+ simulatedopcount);
+ if (simulatedopcount == 0)
+ usage();
+ simulatedopcount -= 1;
+ break;
+ case 'c':
+ closeprob = getnum(optarg, &endp);
+ if (!quiet)
+ fprintf(stdout,
+ "Chance of close/open is 1 in %d\n",
+ closeprob);
+ if (closeprob <= 0)
+ usage();
+ break;
+ case 'd':
+ debug = 1;
+ break;
+ case 'l':
+ maxfilelen = getnum(optarg, &endp);
+ if (maxfilelen <= 0)
+ usage();
+ break;
+ case 'm':
+ monitorstart = getnum(optarg, &endp);
+ if (monitorstart < 0)
+ usage();
+ if (!endp || *endp++ != ':')
+ usage();
+ monitorend = getnum(endp, &endp);
+ if (monitorend < 0)
+ usage();
+ if (monitorend == 0)
+ monitorend = -1; /* aka infinity */
+ debug = 1;
+ case 'n':
+ sizechecks = 0;
+ break;
+ case 'o':
+ maxoplen = getnum(optarg, &endp);
+ if (maxoplen <= 0)
+ usage();
+ break;
+ case 'p':
+ progressinterval = getnum(optarg, &endp);
+ if (progressinterval < 0)
+ usage();
+ break;
+ case 'q':
+ quiet = 1;
+ break;
+ case 'r':
+ readbdy = getnum(optarg, &endp);
+ if (readbdy <= 0)
+ usage();
+ break;
+ case 's':
+ style = getnum(optarg, &endp);
+ if (style < 0 || style > 1)
+ usage();
+ break;
+ case 't':
+ truncbdy = getnum(optarg, &endp);
+ if (truncbdy <= 0)
+ usage();
+ break;
+ case 'w':
+ writebdy = getnum(optarg, &endp);
+ if (writebdy <= 0)
+ usage();
+ break;
+ case 'D':
+ debugstart = getnum(optarg, &endp);
+ if (debugstart < 1)
+ usage();
+ break;
+ case 'L':
+ lite = 1;
+ break;
+ case 'N':
+ numops = getnum(optarg, &endp);
+ if (numops < 0)
+ usage();
+ break;
+ case 'O':
+ randomoplen = 0;
+ break;
+ case 'P':
+ strncpy(goodfile, optarg, sizeof(goodfile));
+ strcat(goodfile, "/");
+ strncpy(logfile, optarg, sizeof(logfile));
+ strcat(logfile, "/");
+ break;
+ case 'R':
+ mapped_reads = 0;
+ break;
+ case 'S':
+ seed = getnum(optarg, &endp);
+ if (seed == 0)
+ seed = time(0) % 10000;
+ if (!quiet)
+ fprintf(stdout, "Seed set to %d\n", seed);
+ if (seed < 0)
+ usage();
+ break;
+ case 'W':
+ mapped_writes = 0;
+ if (!quiet)
+ fprintf(stdout, "mapped writes DISABLED\n");
+ break;
+
+ default:
+ usage();
+ /* NOTREACHED */
+ }
+ argc -= optind;
+ argv += optind;
+ if (argc != 1)
+ usage();
+ fname = argv[0];
+
+
+ signal(SIGHUP, cleanup);
+ signal(SIGINT, cleanup);
+ signal(SIGPIPE, cleanup);
+ signal(SIGALRM, cleanup);
+ signal(SIGTERM, cleanup);
+ signal(SIGXCPU, cleanup);
+ signal(SIGXFSZ, cleanup);
+ signal(SIGVTALRM, cleanup);
+ signal(SIGUSR1, cleanup);
+ signal(SIGUSR2, cleanup);
+
+ initstate(seed, state, 256);
+ setstate(state);
+ fd = open(fname, O_RDWR|(lite ? 0 : O_CREAT|O_TRUNC), 0666);
+ if (fd < 0) {
+ prterr(fname);
+ exit(91);
+ }
+ strncat(goodfile, fname, 256);
+ strcat (goodfile, ".fsxgood");
+ fsxgoodfd = open(goodfile, O_RDWR|O_CREAT|O_TRUNC, 0666);
+ if (fsxgoodfd < 0) {
+ prterr(goodfile);
+ exit(92);
+ }
+ strncat(logfile, fname, 256);
+ strcat (logfile, ".fsxlog");
+ fsxlogf = fopen(logfile, "w");
+ if (fsxlogf == NULL) {
+ prterr(logfile);
+ exit(93);
+ }
+ if (lite) {
+ off_t ret;
+ file_size = maxfilelen = lseek(fd, (off_t)0, L_XTND);
+ if (file_size == (off_t)-1) {
+ prterr(fname);
+ fprintf(stderr, "main: lseek eof");
+ exit(94);
+ }
+ ret = lseek(fd, (off_t)0, SEEK_SET);
+ if (ret == (off_t)-1) {
+ prterr(fname);
+ fprintf(stderr, "main: lseek 0");
+ exit(95);
+ }
+ }
+ original_buf = (char *) malloc(maxfilelen);
+ for (i = 0; i < maxfilelen; i++)
+ original_buf[i] = random() % 256;
+ good_buf = (char *) malloc(maxfilelen);
+ bzero(good_buf, maxfilelen);
+ temp_buf = (char *) malloc(maxoplen);
+ bzero(temp_buf, maxoplen);
+ if (lite) { /* zero entire existing file */
+ ssize_t written;
+
+ written = write(fd, good_buf, (size_t)maxfilelen);
+ if (written != maxfilelen) {
+ if (written == -1) {
+ prterr(fname);
+ fprintf(stderr, "main: error on write");
+ } else
+ fprintf(stderr, "main: short write, 0x%x bytes instead of 0x%lx\n",
+ (unsigned)written, maxfilelen);
+ exit(98);
+ }
+ } else
+ check_trunc_hack();
+
+ while (numops == -1 || numops--)
+ test();
+
+ if (close(fd)) {
+ prterr("close");
+ report_failure(99);
+ }
+ prt("All operations completed A-OK!\n");
+
+ exit(0);
+ return 0;
+}
--- /dev/null
+/*
+ * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like. Any license provided herein, whether implied or
+ * otherwise, applies only to this software file. Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+ * Mountain View, CA 94043, or:
+ *
+ * http://www.sgi.com
+ *
+ * For further information regarding this notice, see:
+ *
+ * http://oss.sgi.com/projects/GenInfo/NoticeExplan/
+ */
+/*
+ * This program will grow a list of files.
+ * Each file will grow by grow_incr before the same
+ * file grows twice. Each file is open and closed before next file is opened.
+ *
+ * To just verify file contents: growfiles -g 0 -c 1 filename
+ *
+ * See help and prt_examples functions below.
+ *
+ * Basic code layout
+ * process cmdline
+ * print debug message about options used
+ * setup signal handlers
+ * return control to user (if wanted - default action)
+ * fork number of desired childern (if wanted)
+ * re-exec self (if wanted)
+ * Determine number of files
+ * malloc space or i/o buffer
+ * Loop until stop is set
+ * Determine if hit iteration, time, max errors or num bytes reached
+ * Loop through each file
+ * open file
+ * fstat file - to determine if file is a fifo
+ * prealloc file space (if wanted)
+ * growfile
+ * check last write
+ * check whole file
+ * shrink file
+ * close file
+ * delay (if wanted)
+ * End loop
+ * End loop
+ * remove all files (if wanted)
+ *
+ * Author: Richard Logan
+ *
+ */
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <time.h>
+#include <sys/file.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/param.h>
+#include <sys/signal.h>
+#include <errno.h>
+#include <string.h>
+#include "dataascii.h"
+#include "random_range.h"
+#include "databin.h"
+
+#ifndef NO_XFS
+#include <xfs/libxfs.h>
+#endif
+
+#ifdef CRAY
+#include <sys/panic.h>
+#include <sys/category.h>
+#endif
+
+extern char *openflags2symbols();
+
+extern int parse_open_flags();
+extern int background();
+extern int forker();
+extern int datapidgen();
+extern void databingen();
+extern int datapidchk();
+extern int databinchk();
+extern int file_lock();
+
+int file_size();
+int check_write();
+int shrinkfile();
+int check_file();
+int growfile();
+int cleanup();
+int handle_error();
+int lkfile();
+void usage();
+void help();
+void prt_examples();
+int set_sig();
+void sig_handler();
+static void notify_others();
+#ifndef NO_XFS
+int pre_alloc();
+#endif
+
+
+#define NEWIO 1 /* Use the tlibio.c functions */
+
+#ifndef NEWIO
+#define NEWIO 0 /* specifies to use original iowrite.c */
+ /* functions instead of tlibio.c functions */
+ /* Once it is proven tlibio.c functions work properly, */
+ /* only tlibio.c functions will be used */
+#else
+#include "tlibio.h"
+#endif
+
+#ifndef PATH_MAX
+#define PATH_MAX 1023
+#endif
+
+
+#define DEF_DIR "."
+#define DEF_FILE "gf"
+
+char *Progname;
+int Debug = 1;
+
+int Pid=0;
+
+int io_type = 0; /* I/O type -sync */
+int open_flags = O_RDWR|O_CREAT; /* open flags */
+
+#define MAX_FC_READ 196608 /* 4096 * 48 - 48 blocks */
+
+#define PATTERN_ASCII 1 /* repeating alphabet letter pattern */
+ /* allows multiple writers and to be checked */
+#define PATTERN_PID 2 /* <pid><words byte offset><pid> */
+ /* Assumes 64 bit word. Only allows single */
+ /* process to write and check */
+/*
+ * 1234567890123456789012345678901234567890123456789012345678901234
+ * ________________________________________________________________
+ * < pid >< offset in file of this word >< pid >
+ */
+
+#define PATTERN_OFFSET 3 /* Like PATTERN_PID but has a fixed number */
+ /* (STATIC_NUM) instead of pid. */
+ /* Allows multiple processes to write/read */
+#define PATTERN_ALT 4 /* alternating bit pattern (i.e. 0x5555555...) */
+#define PATTERN_CHKER 5 /* checkerboard pattern (i.e. 0xff00ff00ff00...) */
+#define PATTERN_CNTING 6 /* counting pattern (i.e. 0 - 07, 0 - 07, ...) */
+#define PATTERN_ONES 7 /* all bits set (i.e. 0xffffffffffffff...) */
+#define PATTERN_ZEROS 8 /* all bits cleared (i.e. 0x000000000...) */
+#define PATTERN_RANDOM 9 /* random integers - can not be checked */
+#define STATIC_NUM 221849 /* used instead of pid when PATTERN_OFFSET */
+
+#define MODE_RAND_SIZE 1 /* random write and trunc */
+#define MODE_RAND_LSEEK 2 /* random lseek before write */
+#define MODE_GROW_BY_LSEEK 4 /* lseek beyond end of file then write a byte */
+#define RANDOM_OPEN 999876 /* if Open_flags set to this value, open flags */
+ /* will be randomly choosen from Open_flags[] */
+#define MODE_FIFO S_IFIFO /* defined in stat.h 0010000 */
+
+int num_files = 0; /* num_auto_files + cmd line files */
+char *filenames; /* pointer to space containing filenames */
+int remove_files = 0; /* if set, cleanup default is not to cleanup */
+int bytes_consumed = 0; /* total bytes consumed, all files */
+int bytes_to_consume = 0; /* non-zero if -B was specified, total bytes */
+int Maxerrs = 100; /* Max number errors before forced exit */
+int Errors = 0; /* number of encountered errors */
+int Upanic_on_error = 0; /* call upanic if error and this variable set */
+
+/* The *_size variables are only used when random iosize option (-r) is used */
+int max_size=5000;
+int min_size=1; /* also set in option parsing */
+int mult_size=1; /* when random iosz, iosz must be mult of mult_size */
+/* the *_lseek variables are only used when radon lseek option (-R) is used */
+int min_lseek=0; /* also set in option parsing */
+int max_lseek=-1; /* -1 means size of file */
+#ifdef CRAY
+int Pattern=PATTERN_OFFSET; /* This pattern is 64 bit word based */
+#else
+int Pattern=PATTERN_ASCII;
+#endif
+int Seed=-1; /* random number seed, < 0 == uninitialized */
+int Nseeds=0; /* Number of seed specified by the user */
+int *Seeds; /* malloc'ed arrary of ints holding user spec seeds */
+
+int using_random=0; /* flag indicating randomization is being used */
+float delaysecs=0.0; /* delay between iterations (in seconds) */
+int delaytime; /* delay between iterations in clocks/uses */
+int lockfile=0; /* if set, do file locking */
+ /* 1 = do file locking around write, trunc */
+ /* and reads. */
+ /* 2 = write lock around all file operations */
+
+int Woffset=0; /* offset before last write */
+int Grow_incr=4096; /* sz of last write */
+int Mode=0; /* bitmask of write/trunc mode */
+ /* also knows if dealing with fifo */
+char *Buffer = NULL; /* buffer used by write and write check */
+int Alignment=0; /* if non word multiple, io will not be word aligned */
+int Opid=0; /* original pid */
+
+int Sync_with_others = 0; /* Flag indicating to stop other if we stop before DONE */
+int Iter_cnt = 0; /* contains current iteration count value */
+char TagName[40]; /* name of this growfiles (see Monster) */
+
+struct fileinfo_t {
+ char *filename;
+ int fd;
+ int openflags;
+ int mode;
+} Fileinfo;
+
+/*
+ * Define open flags that will be used when '-o random' option is used.
+ * Note: If there is more than one growfiles doing its thing to the same
+ * file, O_TRUNC will cause data mismatches. How you ask?
+ * timing of events, example:
+ * Process one Process two
+ * --------------- -------------
+ * get write lock
+ * fstat file
+ * lseek
+ * generate pattern
+ * open with O_TRUNC
+ * write with wrong pattern
+ * because offset is wrong
+ *
+ * The second process truncated the file after the pattern was
+ * determined, thus the pattern is wrong for the file location.
+ *
+ * There can also be a timing problem with open flag O_APPEND if
+ * file locks are not being used (-l option). Things could happen
+ * between the fstat and the write. Thus, writing the wrong pattern.
+ * If all processes observe the file locks, O_APPEND should be ok
+ * to use.
+ */
+int Open_flags[] = {
+#ifdef CRAY
+ O_RDWR|O_CREAT,
+ O_RDWR|O_CREAT|O_RAW,
+ O_RDWR|O_CREAT|O_BIG,
+ O_RDWR|O_CREAT|O_APPEND,
+ O_RDWR|O_CREAT|O_NDELAY,
+ O_RDWR|O_CREAT|O_PLACE,
+ O_RDWR|O_CREAT|O_SYNC,
+ O_RDWR|O_CREAT|O_RAW|O_SYNC,
+ O_RDWR|O_CREAT|O_NDELAY|O_SYNC,
+ O_RDWR|O_CREAT|O_NDELAY|O_SYNC|O_BIG,
+ O_RDWR|O_CREAT|O_RAW,
+ O_RDWR|O_CREAT|O_RAW|O_APPEND,
+ O_RDWR|O_CREAT|O_RAW|O_BIG,
+ O_RDWR|O_CREAT|O_RAW|O_APPEND|O_BIG,
+/***
+ * O_WELLFORMED makes -o random require well formed i/o
+ ***/
+#if ALLOW_O_WELLFORMED
+#if O_PARALLEL
+ O_RDWR|O_CREAT|O_PARALLEL|O_WELLFORMED|O_RAW,
+ O_RDWR|O_CREAT|O_PARALLEL|O_WELLFORMED|O_RAW|O_TRUNC,
+#endif /* O_PARALLEL */
+#endif
+
+#else /* CRAY */
+ O_RDWR|O_CREAT,
+ O_RDWR|O_CREAT|O_APPEND,
+ O_RDWR|O_CREAT|O_NDELAY,
+ O_RDWR|O_CREAT|O_SYNC,
+ O_RDWR|O_CREAT|O_SYNC|O_NDELAY,
+ O_RDWR|O_CREAT|O_APPEND|O_NDELAY,
+
+#endif /* CRAY */
+};
+
+#define REXEC_INIT 0 /* don't do re-exec of childern */
+#define REXEC_DOIT 1 /* Do re-exec of childern */
+#define REXEC_DONE 2 /* We've already been re-exec'ed */
+
+#ifndef BSIZE
+#ifdef CRAY
+#define BSIZE 1024
+#else
+#define BSIZE 512
+#endif /* CRAY */
+#endif /* BSIZE */
+
+#define USECS_PER_SEC 1000000 /* microseconds per second */
+
+/*
+ * Define marcos used when dealing with file locks.
+ */
+#define LKLVL0 1 /* file lock around write/read/trunc */
+#define LKLVL1 2 /* file lock after open to before close */
+
+/*
+ * Define special max lseek values
+ */
+#define LSK_EOF -1 /* set fptr up to EOF */
+#define LSK_EOFPLUSGROW -2 /* set fptr up to EOF + grow - leave whole */
+#define LSK_EOFMINUSGROW -3 /* set fptr up to EOF-grow - no grow */
+
+
+/***********************************************************************
+ * MAIN
+ ***********************************************************************/
+int
+main(argc, argv)
+int argc;
+char **argv;
+{
+extern char *optarg; /* used by getopt */
+extern int optind;
+extern int opterr;
+
+int ind;
+int first_file_ind = 0;
+int num_auto_files = 0; /* files created by tool */
+int seq_auto_files = 0; /* auto files created by tool created by tool */
+char *auto_dir = DEF_DIR;
+char *auto_file = DEF_FILE;
+int grow_incr = 4096;
+int trunc_incr = 4096;
+int trunc_inter = 0; /* 0 means none, */
+int unlink_inter = 0; /* 0 means none, 1 means always unlink */
+int unlink_inter_ran = -1; /* -1 -use unlink_inter, otherwise randomly choose */
+ /* between unlink_inter and unlink_inter_ran */
+int file_check_inter = 0; /* 0 means never, 1 means always */
+int write_check_inter = 1; /* 0 means never, 1 means always */
+int iterations = 1; /* number of increments to be added */
+int no_file_check = 0; /* if set, no whole file checking will be done */
+int num;
+int fd; /* file descriptor */
+int stop = 0; /* loop stopper if set */
+int tmp;
+char chr;
+int ret;
+int pre_alloc_space = 0;
+#ifndef NO_XFS
+int total_grow_value = 0; /* used in pre-allocations */
+#endif
+int backgrnd = 1; /* return control to user */
+struct stat statbuf;
+int time_iterval = -1;
+time_t start_time = 0;
+char reason[40]; /* reason for loop termination */
+int num_procs=1;
+int forker_mode=0;
+int reexec=REXEC_INIT; /* reexec info */
+char *exec_path=NULL;
+
+char *strrchr();
+
+char *filename; /* name of file specified by user */
+char *cptr; /* temp char pointer */
+extern int Forker_npids; /* num of forked pid, defined in forker.c */
+
+
+ if ( argv[0][0] == '-' )
+ reexec=REXEC_DONE;
+ /*
+ * Determine name of file used to invoke this program
+ */
+ if ((Progname=strrchr(argv[0], '/')) != NULL)
+ Progname++;
+ else
+ Progname=argv[0];
+
+ TagName[0] = '\0';
+
+ /*
+ * Process options
+ */
+ while ((ind=getopt(argc, argv,
+ "hB:C:c:bd:D:e:Ef:g:H:I:i:lL:n:N:O:o:pP:q:wt:r:R:s:S:T:uU:W:xy")) != EOF) {
+ switch(ind) {
+
+ case 'h' :
+ help();
+ exit(0);
+
+ case 'B':
+ switch (sscanf(optarg, "%i%c",
+ &bytes_to_consume, &chr)) {
+ case 1: /* noop */
+ break;
+
+ case 2:
+ if (chr == 'b') {
+ bytes_to_consume *= BSIZE;
+ } else {
+ fprintf(stderr,
+ "%s%s: --B option arg invalid\n",
+ Progname, TagName);
+ usage();
+ exit(1);
+ }
+ break;
+
+ default:
+ fprintf(stderr, "%s%s: --B option arg invalid\n",
+ Progname, TagName);
+ usage();
+ exit(1);
+ break;
+ }
+
+ break;
+
+ case 'E' :
+ prt_examples(stdout);
+ exit(0);
+
+ case 'b' : /* batch */
+ backgrnd=0;
+ break;
+
+ case 'C':
+ if (sscanf(optarg, "%i", &write_check_inter) != 1 ) {
+ fprintf(stderr, "%s%s: --c option arg invalid\n",
+ Progname, TagName);
+ usage();
+ exit(1);
+ }
+ break;
+
+ case 'c':
+ if (sscanf(optarg, "%i", &file_check_inter) != 1 ) {
+ fprintf(stderr, "%s%s: --c option arg invalid\n",
+ Progname, TagName);
+ usage();
+ exit(1);
+ }
+ break;
+
+
+ case 'd':
+ auto_dir=optarg;
+#ifdef CRAY
+ unsetenv("TMPDIR"); /* force the use of auto_dir */
+#endif
+ if ( stat(auto_dir, &statbuf) == -1 ) {
+ if ( mkdir(auto_dir, 0777) == -1 ) {
+ if ( errno != EEXIST ) {
+ fprintf(stderr,
+ "%s%s: Unable to make dir %s\n",
+ Progname, TagName, auto_dir);
+ exit(1);
+ }
+ }
+ }
+ else {
+ if ( ! (statbuf.st_mode & S_IFDIR) ) {
+ fprintf(stderr,
+ "%s%s: %s already exists and is not a directory\n",
+ Progname, TagName, auto_dir);
+ exit(1);
+ }
+ }
+ break;
+
+ case 'D':
+ if (sscanf(optarg, "%i", &Debug) != 1 ) {
+ fprintf(stderr, "%s%s: --D option arg invalid\n",
+ Progname, TagName);
+ usage();
+ exit(1);
+ }
+ break;
+
+ case 'e':
+ if (sscanf(optarg, "%i", &Maxerrs) != 1 ) {
+ fprintf(stderr, "%s%s: --e option arg invalid\n",
+ Progname, TagName);
+ usage();
+ exit(1);
+ }
+ break;
+
+ case 'f':
+ auto_file=optarg;
+ break;
+
+ case 'g':
+ if ((ret=sscanf(optarg, "%i%c", &grow_incr, &chr)) < 1 ||
+ grow_incr < 0 ) {
+
+ fprintf(stderr, "%s%s: --g option arg invalid\n",
+ Progname, TagName);
+ usage();
+ exit(1);
+ }
+ if ( ret == 2 ) {
+ if ( chr == 'b' || chr == 'B' )
+ grow_incr *= 4096;
+ else {
+ fprintf(stderr,
+ "%s%s: --g option arg invalid\n",
+ Progname, TagName);
+ usage();
+ exit(1);
+ }
+ }
+ break;
+
+ case 'H':
+ if (sscanf(optarg, "%f", &delaysecs) != 1 || delaysecs < 0 ) {
+
+ fprintf(stderr, "%s%s: --H option arg invalid\n",
+ Progname, TagName);
+ usage();
+ exit(1);
+ }
+ break;
+
+ case 'i':
+ if (sscanf(optarg, "%i", &iterations) != 1 ||
+ iterations < 0 ) {
+
+ fprintf(stderr, "%s%s: --i option arg invalid\n",
+ Progname, TagName);
+ usage();
+ exit(1);
+ }
+ break;
+
+ case 'I':
+#if NEWIO
+ if((io_type=lio_parse_io_arg1(optarg)) == -1 ) {
+ fprintf(stderr,
+ "%s%s: --I arg is invalid, must be s, p, f, a, l, L or r.\n",
+ Progname, TagName);
+ exit(1);
+ }
+ if( io_type & LIO_RANDOM )
+ using_random++;
+#else
+ if((io_type=parse_io_arg(optarg)) == -1 ) {
+ fprintf(stderr,
+ "%s%s: --I arg is invalid, must be s, p, f, a, l, L or r.\n",
+ Progname, TagName);
+ exit(1);
+ }
+ if( io_type == 99 ) /* hold-over until tlibio.h */
+ using_random++;
+#endif
+ break;
+
+ case 'l':
+ lockfile++;
+ if ( lockfile > 2 )
+ lockfile=2; /* lockfile can only be 1 or 2 */
+ break;
+
+ case 'L':
+ if (sscanf(optarg, "%i", &time_iterval) != 1 ||
+ time_iterval < 0 ) {
+ fprintf(stderr, "%s%s: --L option arg invalid\n",
+ Progname, TagName);
+ usage();
+ exit(1);
+ }
+ break;
+
+ case 'n':
+ if (sscanf(optarg, "%i:%i", &num_procs, &forker_mode) < 1 ||
+ num_procs < 0 ) {
+
+ fprintf(stderr, "%s%s: --n option arg invalid\n",
+ Progname, TagName);
+ usage();
+ exit(1);
+ }
+
+ break;
+
+ case 'N':
+ if (sscanf(optarg, "%i", &num_auto_files) != 1 ||
+ num_auto_files < 0 ) {
+
+ fprintf(stderr, "%s%s: --N option arg invalid\n",
+ Progname, TagName);
+ usage();
+ exit(1);
+ }
+ break;
+
+ case 'O':
+ if (sscanf(optarg, "%i", &Alignment) != 1 ||
+ num_auto_files < 0 ) {
+
+ fprintf(stderr, "%s%s: --O option arg invalid\n",
+ Progname, TagName);
+ usage();
+ exit(1);
+ }
+ break;
+
+ case 'o':
+ if ( strcmp(optarg, "random") == 0 ){
+ open_flags=RANDOM_OPEN;
+ using_random++;
+
+ } else if ((open_flags=parse_open_flags(optarg, NULL)) == -1 ) {
+ fprintf(stderr, "%s%s: --o arg contains invalid flag\n",
+ Progname, TagName);
+ exit(1);
+ }
+ break;
+
+
+ case 'p' : /* pre allocate space */
+#ifdef NO_XFS
+ printf("%s%s: --p is illegal option on this system\n",
+ Progname, TagName);
+ exit(1);
+#else
+ pre_alloc_space++;
+#endif
+ break;
+
+ case 'P':
+#ifdef CRAY
+ if (strcmp(optarg, "PANIC") != 0 ) {
+ fprintf(stderr, "%s%s: --P arg must be PANIC\n", Progname, TagName);
+ exit(1);
+ }
+ Upanic_on_error++;
+ printf("%s: Will call upanic after writes\n");
+#else
+ printf("%s%s: --P is illegal option on non-cray system\n",
+ Progname, TagName);
+ exit(1);
+#endif
+ break;
+
+ case 'q': /* file content or pattern */
+ switch(optarg[0]) {
+ case 'A':
+ Pattern = PATTERN_ALT;
+ break;
+ case 'a':
+ Pattern = PATTERN_ASCII;
+ break;
+ case 'p':
+ Pattern = PATTERN_PID;
+ break;
+ case 'o':
+ Pattern = PATTERN_OFFSET;
+ break;
+ case 'c':
+ Pattern = PATTERN_CHKER;
+ break;
+ case 'C':
+ Pattern = PATTERN_CNTING;
+ break;
+ case 'r':
+ Pattern = PATTERN_RANDOM;
+ using_random++;
+ break;
+ case 'z':
+ Pattern = PATTERN_ZEROS;
+ break;
+ case 'O':
+ Pattern = PATTERN_ONES;
+ break;
+ default:
+ fprintf(stderr,
+ "%s%s: --C option arg invalid, A, a, p, o, c, C, r, z, or 0\n",
+ Progname, TagName);
+ usage();
+ exit(1);
+ }
+ break;
+
+ case 'R': /* random lseek before write arg: [min-]max*/
+ if (sscanf(optarg, "%i-%i", &min_lseek, &max_lseek) != 2 ) {
+ min_lseek=1; /* same as default in define */
+ if (sscanf(optarg, "%i%c", &max_lseek, &chr) != 1 ) {
+ fprintf(stderr, "%s%s: --R option arg invalid: [min-]max\n",
+ Progname, TagName);
+ exit(1);
+ }
+ }
+ if ( max_lseek < LSK_EOFMINUSGROW ) {
+ fprintf(stderr, "%s%s: --R option, max_lseek is invalid\n",
+ Progname, TagName);
+ exit(1);
+ }
+ Mode |= MODE_RAND_LSEEK;
+ using_random++;
+ break;
+
+ case 'r': /* random io size arg: [min-]max[:mult] */
+
+ /* min-max:mult format */
+ if (sscanf(optarg, "%i-%i:%i%c", &min_size, &max_size,
+ &mult_size, &chr) != 3 ) {
+ min_size=1;
+ /* max:mult format */
+ if (sscanf(optarg, "%i:%i%c", &max_size,
+ &mult_size, &chr) != 2 ) {
+ /* min-max format */
+ if (sscanf(optarg, "%i-%i%c", &min_size,
+ &max_size, &chr) != 2 ) {
+ min_size=1;
+ if (sscanf(optarg, "%i%c", &max_size, &chr) != 1 ) {
+ fprintf(stderr,
+ "%s%s: --r option arg invalid: [min-]max[:mult]\n",
+ Progname, TagName);
+ exit(1);
+ }
+ }
+ }
+ }
+
+ if ( max_size < 0 ) {
+ fprintf(stderr, "%s%s: --r option, max_size is invalid\n",
+ Progname, TagName);
+ exit(1);
+ }
+ /*
+ * If min and max are the same, no randomness
+ */
+ if ( min_size != max_size ) {
+ Mode |= MODE_RAND_SIZE;
+ using_random++;
+ }
+ break;
+
+ case 'S':
+ if (sscanf(optarg, "%i", &seq_auto_files) != 1 ||
+ seq_auto_files < 0 ) {
+
+ fprintf(stderr, "%s%s: --S option arg invalid\n",
+ Progname, TagName);
+ usage();
+ exit(1);
+ }
+ break;
+
+ case 's': /* format: seed[,seed...] */
+
+ /* count the number of seeds */
+ cptr=optarg;
+ for(Nseeds=1; *cptr ; Nseeds++) {
+ if ( (filename=strchr(cptr, ',')) == NULL )
+ break;
+ cptr=filename;
+ cptr++;
+ }
+ Seeds=(int *)malloc(Nseeds*sizeof(int));
+
+ /*
+ * check that each seed is valid and put them in
+ * the newly malloc'ed Seeds arrary.
+ */
+ filename=cptr=optarg;
+ for(Nseeds=0; *cptr; Nseeds++) {
+ if ( (filename=strchr(cptr, ',')) == NULL ) {
+ if ( sscanf(cptr, "%i", &Seeds[Nseeds]) < 1 ) {
+ fprintf(stderr, "%s%s: --s option arg %s invalid\n",
+ Progname, TagName, cptr);
+ usage();
+ exit(1);
+ }
+ Nseeds++;
+ break;
+ }
+
+ *filename='\0';
+ if ( sscanf(cptr, "%i", &Seeds[Nseeds]) < 1 ) {
+ fprintf(stderr, "%s%s: --s option arg %s invalid\n",
+ Progname, TagName, cptr);
+ usage();
+ exit(1);
+ }
+ *filename=','; /* restore string */
+ cptr=filename;
+ cptr++;
+ }
+ break;
+
+ case 't':
+ if ((ret=sscanf(optarg, "%i%c", &trunc_incr, &chr)) < 1 ||
+ trunc_incr < 0 ) {
+
+ fprintf(stderr, "%s%s: --t option arg invalid\n",
+ Progname, TagName);
+ usage();
+ exit(1);
+ }
+ if ( ret == 2 ) {
+ if ( chr == 'b' || chr == 'B' )
+ trunc_incr *= 4096;
+ else {
+ fprintf(stderr,
+ "%s%s: --t option arg invalid\n",
+ Progname, TagName);
+ usage();
+ exit(1);
+ }
+ }
+ break;
+
+ case 'T': /* truncate interval */
+ if (sscanf(optarg, "%i%c", &trunc_inter, &chr) != 1 ||
+ trunc_inter < 0 ) {
+
+ fprintf(stderr, "%s%s: --T option arg invalid\n",
+ Progname, TagName);
+ usage();
+ exit(1);
+ }
+ break;
+
+ case 'u':
+ remove_files++;
+ break;
+
+ case 'U': /* how often to unlink file */
+ /*
+ * formats:
+ * A-B - randomly pick interval between A and B
+ * X - unlink file every X iteration
+ */
+ if (sscanf(optarg, "%i-%i", &unlink_inter,
+ &unlink_inter_ran) == 2 ) {
+
+ if ( unlink_inter < 0 || unlink_inter_ran < 0 ) {
+ fprintf(stderr, "%s%s: --U option arg invalid\n",
+ Progname, TagName);
+ usage();
+ exit(1);
+ }
+ /* ensure unlink_inter contains smaller value */
+ if ( unlink_inter > unlink_inter_ran ) {
+ tmp=unlink_inter_ran;
+ unlink_inter_ran=unlink_inter;
+ unlink_inter=tmp;
+ }
+ using_random++;
+
+ } else if (sscanf(optarg, "%i%c", &unlink_inter, &chr) != 1 ||
+ unlink_inter < 0 ) {
+
+ fprintf(stderr, "%s%s: --U option arg invalid\n",
+ Progname, TagName);
+ usage();
+ exit(1);
+ }
+ break;
+
+ case 'x':
+ if ( reexec != REXEC_DONE )
+ reexec=REXEC_DOIT;
+ break;
+
+ case 'w':
+ Mode |= MODE_GROW_BY_LSEEK;
+ break;
+
+ case 'W':
+ sprintf( TagName, "(%.39s)", optarg );
+ break;
+
+ case 'y':
+ Sync_with_others=1;
+ break;
+
+ case '?':
+ usage();
+ exit(1);
+ break;
+ }
+ }
+
+ if( Debug == 1 ){
+ cptr = getenv("TOUTPUT");
+ if( (cptr != NULL) && (strcmp( cptr, "NOPASS" ) == 0) ){
+ Debug = 0;
+ }
+ }
+
+ if ( Pattern == PATTERN_RANDOM ) {
+ no_file_check=1;
+ if ( write_check_inter || file_check_inter )
+ printf("%s%s: %d Using random pattern - no data checking will be performed!\n",
+ Progname, TagName, getpid());
+ }
+ else if ( max_lseek == LSK_EOFPLUSGROW || Mode & MODE_GROW_BY_LSEEK ) {
+ no_file_check=1;
+
+ if ( file_check_inter )
+ printf("%s%s: %d Using random lseek beyond EOF or lseek grow,\n\
+no whole file checking will be performed!\n", Progname, TagName, getpid());
+
+ }
+
+ if ( Mode & MODE_RAND_SIZE )
+ grow_incr=max_size;
+
+ set_sig();
+
+ Opid=getpid();
+ Pid=Opid;
+
+ if ( backgrnd ) {
+ if ( Debug > 1 )
+ printf("%s: %d DEBUG2 forking, returning control to the user\n",
+ Progname, Opid);
+ background(Progname); /* give user their prompt back */
+ }
+
+#if CRAY
+ if ( Sync_with_others )
+ setpgrp();
+#endif
+
+ if ( Debug > 3 ) {
+#if NEWIO
+ lio_set_debug(Debug-3);
+#else
+ set_iowrite_debug(Debug-3);
+#endif
+ }
+
+ /*
+ * Print some program information here if debug is turned on to
+ * level 3 or higher.
+ */
+
+ if ( Debug > 2 ) {
+
+ if ( Mode & MODE_GROW_BY_LSEEK )
+ printf("%s: %d DEBUG lseeking past end of file, writting a \"w\"\n",
+ Progname, Pid);
+ else if ( Pattern == PATTERN_OFFSET )
+ printf("%s: %d DEBUG3 %d<byteoffset>%d per word pattern multi-writers.\n",
+ Progname, Pid, STATIC_NUM, STATIC_NUM);
+ else if ( Pattern == PATTERN_PID )
+ printf("%s: %d DEBUG3 <pid><byteoffset><pid> per word pattern - 1 writer\n",
+ Progname, Pid);
+ else if ( Pattern == PATTERN_ASCII )
+ printf("%s: %d DEBUG3 ascii pattern (vi'able)- allows multiple writers\n",
+ Progname, Pid);
+ else if ( Pattern == PATTERN_ALT )
+ printf("%s: %d DEBUG3 alt bit pattern - allows multiple writers\n",
+ Progname, Pid);
+ else if ( Pattern == PATTERN_CHKER )
+ printf("%s: %d DEBUG3 checkerboard pattern - allows multiple writers\n",
+ Progname, Pid);
+ else if ( Pattern == PATTERN_CNTING )
+ printf("%s: %d DEBUG3 counting pattern - allows multiple writers\n",
+ Progname, Pid);
+ else if ( Pattern == PATTERN_RANDOM )
+ printf("%s: %d DEBUG3 random integer pattern - no write/file checking\n",
+ Progname, Pid);
+ else if ( Pattern == PATTERN_ONES )
+ printf("%s: %d DEBUG3 all ones pattern - allows multiple writers\n",
+ Progname, Pid);
+ else if ( Pattern == PATTERN_ZEROS )
+ printf("%s: %d DEBUG3 all zeros pattern - allows multiple writers\n",
+ Progname, Pid);
+
+ else
+ printf("%s: %d DEBUG3 unknown pattern\n",
+ Progname, Pid);
+ if ( bytes_to_consume )
+ printf("%s: %d DEBUG3 bytes_to_consume = %d\n",
+ Progname, Pid, bytes_to_consume);
+ printf("%s: %d DEBUG3 Maxerrs = %d, pre_alloc_space = %d, filelocking = %d\n",
+ Progname, Pid, Maxerrs, pre_alloc_space, lockfile);
+
+ printf("%s: %d DEBUG3 Debug = %d, remove files in cleanup : %d\n",
+ Progname, Pid, Debug, remove_files);
+
+ printf("%s: %d DEBUG3 Mode = %#o\n", Progname, Pid, Mode);
+
+ if ( open_flags == RANDOM_OPEN )
+ printf("%s: %d DEBUG3 open_flags = (random), io_type = %#o\n", Progname,
+ Pid, io_type);
+ else
+ printf("%s: %d DEBUG3 open_flags = %#o, io_type = %#o\n", Progname,
+ Pid, open_flags, io_type);
+
+ if ( Mode & MODE_RAND_SIZE ) {
+ printf("%s: %d DEBUG3 random write/trunc: min=%d, max=%d, mult = %d\n",
+ Progname, Pid, min_size, max_size, mult_size);
+ }
+ else {
+ printf("%s: %d DEBUG3 grow_incr = %d\n",
+ Progname, Pid, grow_incr);
+ }
+ if ( Mode & MODE_RAND_LSEEK ) {
+ if ( max_lseek == LSK_EOF )
+ printf("%s: %d DEBUG3 random lseek: min=%d, max=<endoffile>\n",
+ Progname, Pid, min_lseek);
+ else if ( max_lseek == LSK_EOFPLUSGROW )
+ printf("%s: %d DEBUG3 random lseek: min=%d, max=<endoffile+iosize>\n",
+ Progname, Pid, min_lseek);
+ else if ( max_lseek == LSK_EOFMINUSGROW )
+ printf("%s: %d DEBUG3 random lseek: min=%d, max=<endoffile-iosize>\n",
+ Progname, Pid, min_lseek);
+ else
+ printf("%s: %d DEBUG3 random lseek: min=%d, max=%d\n",
+ Progname, Pid, min_lseek, max_lseek);
+ }
+
+ printf("%s: %d DEBUG3 check write interval = %d, check file interval = %d\n",
+ Progname, Pid, write_check_inter, file_check_inter);
+
+ printf("%s: %d DEBUG3 trunc interval = %d, trunc_incr = %d\n",
+ Progname, Pid, trunc_inter, trunc_incr);
+
+ if ( no_file_check )
+ printf("%s: %d DEBUG3 no whole file checking will be done\n",
+ Progname, Pid);
+
+ if ( unlink_inter_ran == -1 ) {
+ printf("%s: %d DEBUG3 unlink_inter = %d\n",
+ Progname, Pid, unlink_inter);
+ } else {
+ printf("%s: %d DEBUG3 unlink_inter = %d, unlink_inter_ran = %d\n",
+ Progname, Pid, unlink_inter, unlink_inter_ran);
+ }
+
+ if ( Debug > 8 ) {
+ num=sizeof(Open_flags)/sizeof(int);
+ printf("%s: %d DEBUG9 random open flags values:\n", Progname, Pid);
+ for(ind=0; ind<num; ind++) {
+ printf("\t%#o\n", Open_flags[ind]);
+ }
+ }
+ } /* end of DEBUG > 2 */
+
+ if ( Debug > 1 && num_procs > 1 ) {
+ printf("%s: %d DEBUG2 about to fork %d more copies\n", Progname,
+ Opid, num_procs-1);
+ }
+
+ fflush(stdout); /* ensure pending i/o is flushed before forking */
+ fflush(stderr);
+
+ forker(num_procs, forker_mode, Progname);
+
+ Pid=getpid(); /* reset after the forks */
+ /*
+ * If user specified random seed(s), get that random seed value.
+ * get random seed if it was not specified by the user.
+ * This is done after the forks, because pid is used to get the seed.
+ */
+ if ( Nseeds == 1 ) {
+ /*
+ * If only one seed specified, all processes will get that seed.
+ */
+ Seed=Seeds[0];
+ } else if ( Nseeds > 1 ) {
+ /*
+ * More than one seed was specified.
+ * The original process gets the first seed. Each
+ * process will be get the next seed in the specified list.
+ */
+ if ( Opid == Pid ) {
+ Seed=Seeds[0];
+ } else {
+ /*
+ * If user didn't specify enough seeds, use default method.
+ */
+ if ( Forker_npids >= Nseeds )
+ Seed=time(0) + Pid; /* default random seed */
+ else {
+ Seed=Seeds[Forker_npids];
+ }
+ }
+ } else {
+ /*
+ * Generate a random seed based on time and pid.
+ * It has a good chance of being unique for each pid.
+ */
+ Seed=time(0) + Pid; /* default random seed */
+ }
+
+ random_range_seed(Seed);
+
+ if ( using_random && Debug > 0 )
+ printf("%s%s: %d DEBUG1 Using random seed of %d\n",
+ Progname, TagName, Pid, Seed);
+
+ if ( unlink_inter_ran > 0 ) {
+ /*
+ * Find unlinking file interval. This must be done after
+ * the seed was set. This allows multiple copies to
+ * get different intervals.
+ */
+ tmp=unlink_inter;
+ unlink_inter=random_range(tmp, unlink_inter_ran, 1, NULL);
+
+ if ( Debug > 2 )
+ printf("%s: %d DEBUG3 Unlink interval is %d (random %d - %d)\n",
+ Progname, Pid, unlink_inter, tmp, unlink_inter_ran);
+ }
+
+ /*
+ * re-exec all childern if reexec is set to REXEC_DOIT.
+ * This is useful on MPP systems to get the
+ * child process on another PE.
+ */
+ if ( reexec == REXEC_DOIT && Opid != Pid ) {
+ if ( exec_path == NULL ) {
+ exec_path = argv[0];
+ /* Get space for cmd (2 extra, 1 for - and 1 fro NULL */
+ argv[0] = (char *)malloc(strlen(exec_path) + 2);
+ sprintf(argv[0], "-%s", exec_path);
+ }
+
+ if ( Debug > 2 )
+ printf("%s: %d DEBUG3 %s/%d: execvp(%s, argv)\n",
+ Progname, Pid, __FILE__, __LINE__, argv[0]);
+
+ execvp(argv[0], argv);
+ }
+
+ /*** begin filename stuff here *****/
+ /*
+ * Determine the number of files to be dealt with
+ */
+ if ( optind == argc ) {
+ /*
+ * no cmd line files, therfore, set
+ * the default number of auto created files
+ */
+ if ( ! num_auto_files && ! seq_auto_files )
+ num_auto_files=1;
+ }
+ else {
+ first_file_ind=optind;
+ num_files += argc-optind;
+ }
+
+ if ( num_auto_files ) {
+ num_files += num_auto_files;
+ }
+
+ if ( seq_auto_files ) {
+ num_files += seq_auto_files;
+ }
+
+ /*
+ * get space for file names
+ */
+ if ((filenames=(char *)malloc(num_files*PATH_MAX)) == NULL) {
+ fprintf(stderr, "%s%s: %d %s/%d: malloc(%d) failed: %s\n",
+ Progname, TagName, Pid, __FILE__, __LINE__, num_files*PATH_MAX,
+ strerror(errno));
+ exit(1);
+ }
+
+ /*
+ * fill in filename cmd files then auto files.
+ */
+
+ num=0;
+ if ( first_file_ind ) {
+ for(ind=first_file_ind; ind<argc; ind++, num++) {
+ strcpy((char *)filenames+(num*PATH_MAX), argv[ind]);
+ }
+ }
+
+ /*
+ * construct auto filename and insert them into filenames space
+ */
+
+ for(ind=0;ind<num_auto_files; ind++, num++) {
+ sprintf((char *)filenames+(num*PATH_MAX), "%s.%d",
+ tempnam(auto_dir, auto_file), ind );
+ }
+
+ /*
+ * construct auto seq filenames
+ */
+ for(ind=1; ind<=seq_auto_files; ind++, num++) {
+ sprintf((char *)filenames+(num*PATH_MAX), "%s/%s%d",
+ auto_dir, auto_file, ind);
+ }
+
+/**** end filename stuff ****/
+
+ if ( time_iterval > 0 )
+ start_time=time(0);
+
+ /*
+ * get space for I/O buffer
+ */
+ if ( grow_incr ) {
+ if ((Buffer=(char *)malloc(grow_incr+Alignment)) == NULL) {
+ fprintf(stderr, "%s%s: %d %s/%d: malloc(%d) failed: %s\n",
+ Progname, TagName, Pid, __FILE__, __LINE__, grow_incr, strerror(errno));
+ exit(1);
+ }
+ if ( Alignment )
+ Buffer = Buffer + Alignment;
+
+ }
+
+ if ( Debug > 2 ) {
+ printf("%s: %d DEBUG3 num_files = %d\n",
+ Progname, Pid, num_files);
+ }
+
+#ifndef NO_XFS
+ if ( pre_alloc_space ) {
+ if ( iterations == 0 ) {
+ fprintf(stderr, "%s%s: %d %s/%d: can NOT pre-alloc and grow forever\n",
+ Progname, TagName, Pid, __FILE__, __LINE__);
+ exit(1);
+ }
+ if ( Mode & MODE_RAND_SIZE ) {
+ fprintf(stderr,
+ "%s%s: %d %s/%d: can NOT pre-alloc and do random io size\n",
+ Progname, TagName, Pid, __FILE__, __LINE__);
+ exit(1);
+ }
+
+ total_grow_value=grow_incr * iterations;
+
+ /*
+ * attempt to limit
+ */
+ if ( bytes_to_consume && bytes_to_consume < total_grow_value ) {
+ total_grow_value=bytes_to_consume;
+ }
+ }
+#endif
+
+ /*
+ * If delaying between iterations, get amount time to
+ * delaysecs in clocks or usecs.
+ * If on the CRAY, delaytime is in clocks since
+ * _rtc() will be used, which does not have the overhead
+ * of gettimeofday(2).
+ */
+ if ( delaysecs ) {
+#if CRAY
+ int hz;
+ hz=sysconf(_SC_CLK_TCK);
+ delaytime=(int)((float)hz * delaysecs);
+#else
+ delaytime=(int)((float)USECS_PER_SEC * delaysecs);
+#endif
+ }
+
+ /*
+ * This is the main iteration loop.
+ * Each iteration, all files can be opened, written to,
+ * read to check the write, check the whole file,
+ * truncated, and closed.
+ */
+ for(Iter_cnt=1; ! stop ; Iter_cnt++) {
+
+ if ( iterations && Iter_cnt >= iterations+1 ) {
+ strcpy(reason, "Hit iteration value");
+ stop=1;
+ continue;
+ }
+
+ if ( (time_iterval > 0) && (start_time + time_iterval < time(0)) ) {
+ sprintf(reason, "Hit time value of %d", time_iterval);
+ stop=1;
+ continue;
+ }
+
+ if ( bytes_to_consume && bytes_consumed >= bytes_to_consume) {
+ sprintf(reason, "Hit bytes consumed value of %d", bytes_to_consume);
+ stop=1;
+ continue;
+ }
+
+ /*
+ * This loop will loop through all files.
+ * Each iteration, a single file can be opened, written to,
+ * read to check the write, check the whole file,
+ * truncated, and closed.
+ */
+ for(ind=0; ind<num_files; ind++) {
+
+ fflush(stdout);
+ fflush(stderr);
+
+ filename=(char *)filenames+(ind*PATH_MAX);
+ Fileinfo.filename=(char *)filenames+(ind*PATH_MAX);
+
+
+ if ( open_flags == RANDOM_OPEN ) {
+ ret=Open_flags[random_range(0, sizeof(Open_flags)/sizeof(int)-1, 1, NULL)];
+ }
+
+ else
+ ret=open_flags;
+
+ Fileinfo.openflags=ret;
+
+ if ( Debug > 3 ) {
+ printf("%s: %d DEBUG3 %s/%d: %d Open filename = %s, open flags = %#o %s\n",
+ Progname, Pid, __FILE__, __LINE__, Iter_cnt, filename, ret,
+ openflags2symbols(ret, ",", NULL));
+ } else if ( Debug > 2 ) {
+ printf("%s: %d DEBUG3 %s/%d: %d filename = %s, open flags = %#o\n",
+ Progname, Pid, __FILE__, __LINE__, Iter_cnt, filename, ret);
+ }
+
+ /*
+ * open file with desired flags.
+ */
+ if ( (fd=open(filename, ret, 0777)) == -1 ) {
+ fprintf(stderr,
+ "%s%s: %d %s/%d: open(%s, %#o, 0777) returned -1, errno:%d %s\n",
+ Progname, TagName, Pid, __FILE__, __LINE__, filename, ret, errno, strerror(errno));
+ handle_error();
+ continue;
+ }
+
+ Fileinfo.fd=fd;
+
+ lkfile(fd, LOCK_EX, LKLVL1); /* lock if lockfile is LKLVL1 */
+
+#ifndef NO_XFS
+ /*
+ * preallocation is only done once, if specified.
+ */
+ if ( pre_alloc_space ) {
+ if (pre_alloc(filename, fd, total_grow_value) != 0 ) {
+ cleanup();
+ exit(2);
+ }
+ if ( Debug > 1 ) {
+ printf("%s: %d DEBUG2 %s/%d: pre_allocated %d for file %s\n",
+ Progname, Pid, __FILE__, __LINE__, total_grow_value, filename);
+ }
+ lkfile(fd, LOCK_UN, LKLVL1); /* release lock */
+ close(fd);
+ Iter_cnt=0; /* reset outside loop to restart from one */
+ continue;
+ }
+#endif
+
+ /*
+ * grow file by desired amount.
+ * growfile() will set the Grow_incr variable and
+ * possiblly update the Mode variable indicating
+ * if we are dealing with a FIFO file.
+ */
+
+ if (growfile(fd, filename, grow_incr, Buffer) != 0 ) {
+ handle_error();
+ lkfile(fd, LOCK_UN, LKLVL1); /* release lock */
+ close(fd);
+ continue;
+ }
+
+ /*
+ * check if last write is not corrupted
+ */
+ if ( check_write(fd, write_check_inter, filename,
+ Mode) != 0 ) {
+ handle_error();
+ }
+
+ /*
+ * Check that whole file is not corrupted.
+ */
+ if ( check_file(fd, file_check_inter, filename,
+ no_file_check) != 0 ) {
+ handle_error();
+ }
+
+ /*
+ * shrink file by desired amount if it is time
+ */
+
+ if ( shrinkfile(fd, filename, trunc_incr, trunc_inter, Mode) != 0 ) {
+ handle_error();
+ }
+
+ lkfile(fd, LOCK_UN, LKLVL1); /* release lock */
+
+ if ( Debug > 4 )
+ printf("%s: %d DEBUG5 %s/%d: %d Closing file %s fd:%d \n",
+ Progname, Pid, __FILE__, __LINE__, Iter_cnt, filename, fd);
+ close(fd);
+
+ /*
+ * Unlink the file if that is desired
+ */
+ if ( unlink_inter && (Iter_cnt % unlink_inter == 0) ) {
+
+ if ( Debug > 4 )
+ printf("%s: %d DEBUG5 %s/%d: %d Unlinking file %s\n",
+ Progname, Pid, __FILE__, __LINE__, Iter_cnt, filename);
+
+ unlink(filename);
+ }
+
+ /*
+ * delay while staying active for "delaysecs" seconds.
+ */
+ if ( delaytime ) {
+
+ int ct, end;
+#ifdef CRAY
+ ct=_rtc();
+ end=ct+delaytime;
+ while ( ct < end ) {
+ ct = _rtc();
+ }
+#else
+ struct timeval curtime;
+ gettimeofday(&curtime, NULL);
+ ct=curtime.tv_sec*USECS_PER_SEC + curtime.tv_usec;
+ end=ct+delaytime;
+ while ( ct < end ) {
+
+ gettimeofday(&curtime, NULL);
+ ct=curtime.tv_sec*USECS_PER_SEC + curtime.tv_usec;
+ }
+#endif
+ }
+ }
+#ifndef NO_XFS
+ /*
+ * if Iter_cnt == 0, then we pre allocated space to all files
+ * and we are starting outside loop over. Set pre_alloc_space
+ * to zero otherwise we get in infinite loop
+ */
+ if ( Iter_cnt == 0 ) {
+ pre_alloc_space=0;
+ }
+#endif
+
+
+ } /* end iteration for loop */
+
+
+ if ( Debug ) {
+ printf("%s%s: %d %s/%d: DONE %d iterations to %d files. %s\n",
+ Progname, TagName, Pid, __FILE__, __LINE__, Iter_cnt, num_files, reason);
+ }
+ fflush(stdout);
+ fflush(stderr);
+
+ cleanup();
+
+ if ( Errors ) {
+ if ( Debug > 2 ) {
+ printf("%s%s: %d DEBUG3 %d error(s) encountered\n",
+ Progname, TagName, Pid, Errors);
+ printf("%s%s: %d DEBUG3 %s/%d: exiting with value of 1\n", Progname, TagName, Pid, __FILE__, __LINE__);
+ }
+ exit(1);
+ }
+ if ( Debug > 2 )
+ printf("%s%s: %d DEBUG3 %s/%d: no errors, exiting with value of 0\n", Progname, TagName, Pid, __FILE__, __LINE__);
+ exit(0);
+}
+
+/***********************************************************************
+ *
+ ***********************************************************************/
+int
+set_sig()
+{
+ int sig;
+
+
+ /*
+ * now loop through all signals and set the handlers
+ */
+
+ for (sig = 1; sig < NSIG; sig++) {
+ switch (sig) {
+ case SIGKILL:
+ case SIGSTOP:
+ case SIGCONT:
+#ifdef CRAY
+ case SIGINFO:
+ case SIGRECOVERY:
+#endif /* CRAY */
+#ifdef SIGCKPT
+ case SIGCKPT:
+#endif /* SIGCKPT */
+#ifdef SIGRESTART
+ case SIGRESTART:
+#endif /* SIGRESTART */
+ case SIGCLD:
+ break;
+
+ default:
+#ifdef sgi
+ sigset( sig, sig_handler );
+#else
+/* linux and cray */
+ signal(sig, sig_handler);
+#endif
+ break;
+ }
+ } /* endfor */
+
+
+ return 0;
+}
+
+/***********************************************************************
+ *
+ ***********************************************************************/
+void
+sig_handler(sig)
+int sig;
+{
+ int exit_stat = 2;
+
+ if ( sig == SIGUSR2 ) {
+ fprintf(stdout, "%s%s: %d %s/%d: received SIGUSR2 (%d) - stopping.\n",
+ Progname, TagName, Pid, __FILE__, __LINE__, sig);
+#ifndef sgi
+ signal(sig, sig_handler); /* allow us to get this signal more than once */
+#endif
+
+ } else if( sig == SIGINT ){
+ /* The user has told us to cleanup, don't pretend it's an error. */
+ exit_stat=0;
+ if ( Debug != 0 ){
+ fprintf(stderr, "%s%s: %d %s/%d: received unexpected signal: %d\n", Progname, TagName,
+ Pid, __FILE__, __LINE__, sig);
+ }
+ } else {
+ fprintf(stderr, "%s%s: %d %s/%d: received unexpected signal: %d\n", Progname, TagName,
+ Pid, __FILE__, __LINE__, sig);
+ }
+
+ notify_others();
+ cleanup();
+ if ( Debug > 2 ){
+ printf("%s%s: %d DEBUG3 %s/%d: Exiting with a value of %d\n",
+ Progname, TagName, Pid, __FILE__, __LINE__, exit_stat);
+ }
+ exit(exit_stat);
+}
+
+/***********************************************************************
+ * this function attempts to send SIGUSR2 to other growfiles processes
+ * telling them to stop.
+ *
+ ***********************************************************************/
+static void
+notify_others()
+{
+ static int send_signals = 0;
+ int ind;
+ extern int Forker_pids[];
+ extern int Forker_npids;
+
+ if ( Sync_with_others && send_signals == 0 ) {
+
+#if CRAY
+ send_signals=1; /* only send signals once */
+ if ( Debug > 1 )
+ printf("%s%s: %d DEBUG2 %s/%d: Sending SIGUSR2 to pgrp\n",
+ Progname, TagName, Pid, __FILE__, __LINE__);
+ killm(C_PGRP, getpgrp(), SIGUSR2);
+#else
+ send_signals=1; /* only send signals once */
+
+ for (ind=0; ind< Forker_npids; ind++) {
+ if ( Forker_pids[ind] != Pid )
+ if ( Debug > 1 )
+ printf("%s%s: %d DEBUG2 %s/%d: Sending SIGUSR2 to pid %d\n",
+ Progname, TagName, Pid, __FILE__, __LINE__, Forker_pids[ind]);
+ kill(Forker_pids[ind], SIGUSR2);
+ }
+#endif
+ }
+
+}
+
+/***********************************************************************
+ * this function will count the number of errors encountered.
+ * This function will call upanic if wanted or cleanup and
+ * and exit is Maxerrs were encountered.
+ ***********************************************************************/
+int
+handle_error()
+{
+ Errors++;
+
+#ifdef CRAY
+ if ( Errors & Upanic_on_error ) {
+ upanic(PA_PANIC);
+ }
+#endif
+
+ if ( Maxerrs && Errors >= Maxerrs ) {
+ printf("%s%s: %d %s/%d: %d Hit max errors value of %d\n",
+ Progname, TagName, Pid, __FILE__, __LINE__, Iter_cnt, Maxerrs);
+ notify_others();
+ cleanup();
+
+ if ( Debug > 2 ) {
+ printf("%s%s: %d DEBUG3 %d error(s) encountered\n",
+ Progname, TagName, Pid, Errors);
+ printf("%s%s: %d DEBUG3 %s/%d: exiting with value of 1\n", Progname, TagName, Pid, __FILE__, __LINE__);
+ }
+
+ exit(1);
+ }
+
+ return 0;
+}
+
+/***********************************************************************
+ *
+ ***********************************************************************/
+int
+cleanup()
+{
+ int ind;
+
+ if ( remove_files ) {
+ if ( Debug > 2 )
+ printf("%s: %d DEBUG3 Removing all %d files\n",
+ Progname, Pid, num_files);
+ for(ind=0; ind<=num_files; ind++) {
+ unlink(filenames+(ind*PATH_MAX));
+ }
+ }
+ if ( using_random && Debug > 1 )
+ printf("%s%s: %d DEBUG2 Used random seed: %d\n",
+ Progname, TagName, Pid, Seed);
+ return 0;
+}
+
+/***********************************************************************
+ *
+ ***********************************************************************/
+void
+usage()
+{
+ fprintf(stderr,
+ "Usage: %s%s [-bhEluy][[-g grow_incr][-i num][-t trunc_incr][-T trunc_inter]\n",
+ Progname, TagName );
+ fprintf(stderr,
+ "[-d auto_dir][-e maxerrs][-f auto_file][-N num_files][-w][-c chk_inter][-D debug]\n");
+ fprintf(stderr,
+ "[-s seed][-S seq_auto_files][-p][-P PANIC][-I io_type][-o open_flags][-B maxbytes]\n");
+ fprintf(stderr,
+ "[-r iosizes][-R lseeks][-U unlk_inter][-W tagname] [files]\n");
+
+ return;
+
+} /* end of usage */
+
+/***********************************************************************
+ *
+ ***********************************************************************/
+void
+help()
+{
+ usage();
+
+fprintf(stdout, "\
+ -h Specfied to print this help and exit.\n\
+ -b Specfied to execute in sync mode.(def async mode)\n\
+ -B maxbytes Max bytes to consume by all files. growfiles exits when more\n\
+ than maxbytes have been consumed. (def no chk) If maxbytes ends\n\
+ with the letter 'b', maxbytes is multiplied by BSIZE\n\
+ -C write_chk Specifies how often to check the last write (default 1)\n\
+ -c file_chk Specifies how often to check whole file (default 0)\n\
+ -d auto_dir Specifies the directory to auto created files. (default .)\n\
+ -D debug_lvl Specifies the debug level (default 1)\n\
+ -E Print examples and exit\n\
+ -e errs The number errors that will terminate this program (def 100)\n\
+ -f auto_file Specifies the base filename files created. (default \"gf\")\n\
+ -g grow_incr Specfied to grow by incr for each num. (default 4096)\n\
+ grow_incr may end in b for blocks\n\
+ If -r option is used, this option is ignored and size is random\n\
+ -H delay Amount of time to delay between each file (default 0.0)\n\
+ -I io_type Specifies io type: s - sync, p - polled async, a - async (def s)\n\
+ l - listio sync, L - listio async, r - random\n\
+ -i iteration Specfied to grow each file num times. 0 means forever (default 1)\n\
+ -l Specfied to do file locking around write/read/trunc\n\
+ If specified twice, file locking after open to just before close\n\
+ -L time Specfied to exit after time secs, must be used with -i.\n\
+ -N num_files Specifies the number of files to be created.\n\
+ The default is zero if cmd line files.\n\
+ The default is one if no cmd line files.\n\
+ -n num_procs Specifies the number of copies of this cmd.\n\
+ -o op_type Specifies open flages: (def O_RDWR,O_CREAT) op_type can be 'random'\n\
+ -O offset adjust i/o buffer alignment by offset bytes\n\
+ -P PANIC Specifies to call upanic on error.\n\
+ -p Specifies to pre-allocate space\n\
+ -q pattern pattern can be a - ascii, p - pid with boff, o boff (def)\n\
+ A - Alternating bits, r - random, O - all ones, z - all zeros,\n\
+ c - checkboard, C - counting\n\
+ -R [min-]max random lseek before write and trunc, max of -1 means filesz,\n\
+ -2 means filesz+grow, -3 filesz-grow. (min def is 0)\n\
+ -r [min-]max random io write size (min def is 1)\n\
+ -S seq_auto_files Specifies the number of seqental auto files (default 0)\n\
+ -s seed[,seed...] Specifies the random number seed (default time(0)+pid)\n\
+ -t trunc_incr Specfied the amount to shrink file. (default 4096)\n\
+ trunc_inter may end in b for blocks\n\
+ If -R option is used, this option is ignored and trunc is random\n\
+ -T trunc_inter Specfied the how many grows happen before shrink. (default 0)\n\
+ -u unlink files before exit\n\
+ -U ui[-ui2] Unlink files each ui iteration (def 0)\n\
+ -w Specfied to grow via lseek instead of writes.\n\
+ -W tag-name Who-am-i. My Monster tag name. (used by Monster).\n\
+ -x Re-exec children before continuing - useful on MPP systems\n\
+ -y Attempt to sync copies - if one fails it will send sigusr2 to others\n\
+ Action to each file every iteration is open, write, write check\n\
+ file check, trunc and closed.\n");
+
+ return;
+}
+
+/***********************************************************************
+ *
+ ***********************************************************************/
+void
+prt_examples(FILE *stream)
+{
+ /* This example creates 200 files in directory dir1. It writes */
+ /* 4090 bytes 100 times then truncates 408990 bytes off the file */
+ /* The file contents are checked every 1000 grow. */
+ fprintf(stream,
+ "# run forever: writes of 4090 bytes then on every 100 iterval\n\
+# truncate file by 408990 bytes. Done to 200 files in dir1.\n\
+%s -i 0 -g 4090 -T 100 -t 408990 -l -C 10 -c 1000 -d dir1 -S 200\n\n", Progname);
+
+ /* same as above with 5000 byte grow and a 499990 byte tuncate */
+ fprintf(stream,
+ "# same as above with writes of 5000 bytes and truncs of 499990\n\
+%s -i 0 -g 5000 -T 100 -t 499990 -l -C 10 -c 1000 -d dir2 -S 200\n\n", Progname);
+
+ /* This example beats on opens and closes */
+ fprintf(stream,
+ "# runs forever: beats on opens and closes of file ocfile - no io\n\
+%s -i 0 -g 0 -c 0 -C 0 ocfile\n\n", Progname);
+
+ fprintf(stream,
+ "# writes 4096 to files until 50 blocks are written\n\
+%s -i 0 -g 4096 -B 50b file1 file2\n\n", Progname);
+
+ fprintf(stream,
+ "# write one byte to 750 files in gdir then unlinks them\n\
+%s -g 1 -C 0 -d gdir -u -S 750\n\n", Progname);
+
+ fprintf(stream,
+ "# run 30 secs: random iosize, random lseek up to eof\n\
+%s -r 1-5000 -R 0--1 -i 0 -L 30 -C 1 g_rand1 g_rand2\n\n", Progname);
+
+ fprintf(stream,
+ "# run 30 secs: grow by lseek then write single byte, trunc every 10 itervals\n\
+%s -g 5000 -wlu -i 0 -L 30 -C 1 -T 10 g_sleek1 g_lseek2\n\n", Progname);
+
+ fprintf(stream,
+ "# run forever: 5 copies of random iosize, random lseek to beyond eof,\n\
+# rand io types doing a trunc every 5 iterations, with unlinks.\n\
+%s -i0 -r 1-50000 -R 0--2 -I r -C1 -l -n5 -u -U 100-200 gf_rana gf_ranb\n\n",
+ Progname);
+
+ fprintf(stream,
+ "# run forever: 5 copies of random iosize, random lseek to beyond eof,\n\
+# random open flags, rand io types doing a trunc every 10 iterations.\n\
+%s -i0 -r 1-50000 -R 0--2 -o random -I r -C0 -l -T 20 -uU100-200 -n 5 gf_rand1 gf_rand2\n",
+ Progname);
+
+
+ return;
+}
+
+/***********************************************************************
+ *
+ * The file descriptor current offset is assumed to be the end of the
+ * file.
+ * Woffset will be set to the offset before the write.
+ * Grow_incr will be set to the size of the write or lseek write.
+ ***********************************************************************/
+int
+growfile(fd, file, grow_incr, buf)
+int fd;
+char *file;
+int grow_incr;
+char *buf;
+{
+ int noffset;
+ int ret;
+ int cur_offset;
+ char *errmsg;
+ int fsize; /* current size of file */
+ int size_grew; /* size the file grew */
+ struct stat stbuf;
+ int tmp = 0;
+
+ /*
+ * Do a stat on the open file.
+ * If the file is a fifo, set the bit in Mode variable.
+ * This fifo check must be done prior to growfile() returning.
+ * Also get the current size of the file.
+ */
+ if ( fstat(fd, &stbuf) != -1 ) {
+ if ( S_ISFIFO(stbuf.st_mode) ) {
+ Fileinfo.mode |= MODE_FIFO;
+ Mode |= MODE_FIFO;
+ if ( Debug > 3 )
+ printf("%s: %d DEBUG4 %s/%d: file is a fifo - no lseek or truncs,\n",
+ Progname, Pid, __FILE__, __LINE__);
+ }
+ fsize = stbuf.st_size;
+
+ } else {
+ fprintf(stderr, "%s%s: %d %s/%d: Unable to fstat(%d, &buf), errno:%d %s\n",
+ Progname, TagName, Pid, __FILE__, __LINE__, fd, errno, strerror(errno));
+
+ return -1;
+ }
+
+
+ if ( grow_incr <= 0 ) { /* don't attempt i/o if grow_incr <= 0 */
+
+ Grow_incr=grow_incr;
+ if ( Debug > 2 )
+ printf("%s: %d DEBUG3 %s/%d: Not attempting to grow, growsize == %d\n",
+ Progname, Pid, __FILE__, __LINE__, grow_incr);
+ return grow_incr;
+ }
+
+ if ( Mode & MODE_RAND_SIZE ) {
+ grow_incr=random_range(min_size, max_size, mult_size, &errmsg);
+ if (errmsg != NULL) {
+ fprintf(stderr, "%s%s: %d %s/%d: random_range() failed - %s\n", Progname, TagName, Pid, __FILE__, __LINE__, errmsg);
+ return -1;
+ }
+ Grow_incr=grow_incr;
+ }
+ else
+ Grow_incr=grow_incr;
+
+ if ( ! (Mode & MODE_FIFO) ) {
+ if ((cur_offset=lseek(fd,0,SEEK_CUR)) == -1 ) {
+ fprintf(stderr, "%s%s: %d %s/%d: tell failed: %s\n",
+ Progname, TagName, Pid, __FILE__, __LINE__, strerror(errno));
+ return -1;
+ }
+ }
+
+ if ( Mode & MODE_GROW_BY_LSEEK ) {
+ Woffset=fsize;
+ if ( Debug > 2 ) {
+ printf("%s: %d DEBUG3 %s/%d: Current size of file is %d\n", Progname,
+ Pid, __FILE__, __LINE__, Woffset);
+ printf("%s: %d DEBUG3 %s/%d: lseeking to %d byte with SEEK_END\n", Progname,
+ Pid, __FILE__, __LINE__, grow_incr-1);
+ }
+
+ if ((noffset=lseek(fd, grow_incr-1, SEEK_END)) == -1 ) {
+ fprintf(stderr, "%s%s: %s/%d: lseek(fd, %d, SEEK_END) failed: %s\n",
+ Progname, TagName, __FILE__, __LINE__, grow_incr-1, strerror(errno));
+ return -1;
+ }
+
+ lkfile(fd, LOCK_EX, LKLVL0); /* get exclusive lock */
+
+#if NEWIO
+ ret=lio_write_buffer(fd, io_type, "w", 1, SIGUSR1, &errmsg,0);
+#else
+ ret=write_buffer(fd, io_type, "w", 1, 0, &errmsg);
+#endif
+
+ if ( ret != 1 ) {
+ fprintf(stderr, "%s%s: %d %s/%d: %d %s\n",
+ Progname, TagName, Pid, __FILE__, __LINE__, Iter_cnt, errmsg);
+ if ( ret == -ENOSPC ) {
+ cleanup();
+ exit(2);
+ }
+ }
+/***
+ write(fd, "w", 1);
+****/
+
+ lkfile(fd, LOCK_UN, LKLVL0);
+
+ if ( Debug > 2 )
+ printf("%s: %d DEBUG3 %s/%d: %d wrote 1 byte to file\n",
+ Progname, Pid, __FILE__, __LINE__, Iter_cnt);
+
+ } else { /* end of grow by lseek */
+
+ if ( Fileinfo.openflags & O_APPEND ) {
+ /*
+ * Deal with special case of the open flag containing O_APPEND.
+ * If it does, the current offset does not matter since the write
+ * will be done end of the file.
+ */
+ if ( Debug > 4 )
+ printf("%s: %d DEBUG5 %s/%d: dealing with O_APPEND condition\n",
+ Progname, Pid, __FILE__, __LINE__ );
+ lkfile(fd, LOCK_EX, LKLVL0); /* get exclusive lock */
+
+ /*
+ * do fstat again to get size of the file.
+ * This is done inside a file lock (if locks are being used).
+ */
+ if ( fstat(fd, &stbuf) != -1 ) {
+ Woffset = stbuf.st_size;
+ } else {
+ fprintf(stderr, "%s%s: %d %s/%d: Unable to fstat(%d, &buf), errno:%d %s\n",
+ Progname, TagName, Pid, __FILE__, __LINE__, fd, errno, strerror(errno));
+
+ lkfile(fd, LOCK_UN, LKLVL0); /* release lock */
+ return -1;
+ }
+ if ( Debug > 2 )
+ printf("%s: %d DEBUG3 %s/%d: dealing with O_APPEND condition (offset:fsz:%d)\n",
+ Progname, Pid, __FILE__, __LINE__, (int)stbuf.st_size);
+
+
+ } else if ( Mode & MODE_RAND_LSEEK ) {
+ if ( max_lseek == LSK_EOF ) { /* within file size */
+ noffset=random_range(min_lseek, fsize, 1, NULL);
+ }
+ else if ( max_lseek == LSK_EOFPLUSGROW ) {
+ /* max to beyond file size */
+ noffset=random_range(min_lseek, fsize+grow_incr, 1, NULL);
+ }
+ else if ( max_lseek == LSK_EOFMINUSGROW ) {
+ /*
+ * Attempt to not grow the file.
+ * If the i/o will fit from min_lseek to EOF,
+ * pick offset to allow it to fit.
+ * Otherwise, pick the min_lseek offset and grow
+ * file by smallest amount.
+ * If min_lseek is != 0, there will be a problem
+ * with whole file checking if file is ever smaller
+ * than min_lseek.
+ */
+ if ( fsize <= min_lseek + grow_incr )
+ noffset=min_lseek; /* file will still grow */
+ else
+ noffset=random_range(min_lseek, fsize-grow_incr, 1, NULL);
+ }
+ else {
+ noffset=random_range(min_lseek, max_lseek, 1, NULL);
+ }
+
+ if ((Woffset=lseek(fd, noffset, SEEK_SET)) == -1 ) {
+ fprintf(stderr, "%s%s: %d %s/%d: lseek(%d, %d, SEEK_SET) l2 failed: %s\n",
+ Progname, TagName, Pid, __FILE__, __LINE__, fd, noffset, strerror(errno));
+ return -1;
+ }
+ else if ( Debug > 2 )
+ printf("%s: %d DEBUG3 %s/%d: lseeked to random offset %d (fsz:%d)\n",
+ Progname, Pid, __FILE__, __LINE__, Woffset,
+ (int)stbuf.st_size);
+
+ }
+
+ /*
+ * lseek to end of file only if not fifo
+ */
+ else if ( ! (Mode & MODE_FIFO) ) {
+ if ((Woffset=lseek(fd, 0, SEEK_END)) == -1 ) {
+ fprintf(stderr, "%s%s: %d %s/%d: lseek(fd, 0, SEEK_END) failed: %s\n",
+ Progname, TagName, Pid, __FILE__, __LINE__, strerror(errno));
+ return -1;
+ }
+ else if ( Debug > 2 )
+ printf("%s: %d DEBUG3 %s/%d: lseeked to end of file, offset %d\n",
+ Progname, Pid, __FILE__, __LINE__, Woffset);
+ }
+
+ if ( Pattern == PATTERN_OFFSET )
+ datapidgen(STATIC_NUM, buf, grow_incr, Woffset);
+ else if ( Pattern == PATTERN_PID )
+ datapidgen(Pid, buf, grow_incr, Woffset);
+ else if ( Pattern == PATTERN_ASCII )
+ dataasciigen(NULL, buf, grow_incr, Woffset);
+ else if ( Pattern == PATTERN_RANDOM )
+ databingen('r', buf, grow_incr, Woffset);
+ else if ( Pattern == PATTERN_ALT )
+ databingen('a', buf, grow_incr, Woffset);
+ else if ( Pattern == PATTERN_CHKER )
+ databingen('c', buf, grow_incr, Woffset);
+ else if ( Pattern == PATTERN_CNTING )
+ databingen('C', buf, grow_incr, Woffset);
+ else if ( Pattern == PATTERN_ZEROS )
+ databingen('z', buf, grow_incr, Woffset);
+ else if ( Pattern == PATTERN_ONES )
+ databingen('o', buf, grow_incr, Woffset);
+ else
+ dataasciigen(NULL, buf, grow_incr, Woffset);
+
+ if ( Debug > 2 )
+ printf("%s: %d DEBUG3 %s/%d: attempting to write %d bytes\n",
+ Progname, Pid, __FILE__, __LINE__, grow_incr);
+
+ lkfile(fd, LOCK_EX, LKLVL0); /* get exclusive lock */
+
+/*****
+ ret=write(fd, buf, grow_incr);
+
+ tmp=tell(fd);
+
+ lkfile(fd, LOCK_UN, LKLVL0);
+
+ if ( ret != grow_incr) {
+ fprintf(stderr, "%s: %s/%d: write failed: %s\n",
+ Progname, __FILE__, __LINE__, strerror(errno));
+ return -1;
+ }
+*****/
+
+#if NEWIO
+ ret=lio_write_buffer(fd, io_type, buf, grow_incr,
+ SIGUSR1, &errmsg,0);
+#else
+ ret=write_buffer(fd, io_type, buf, grow_incr, 0, &errmsg);
+#endif
+
+ if( Mode & MODE_FIFO ){
+ /* If it is a fifo then just pretend the file
+ * offset is where we think it should be.
+ */
+ tmp = Woffset + grow_incr;
+ }
+ else{
+ if( (tmp=lseek(fd,0,SEEK_CUR)) < 0 ){ /* get offset after the write */
+ fprintf(stderr, "%s%s: %s/%d: tell(2) failed: %d %s\n",
+ Progname, TagName, __FILE__, __LINE__, errno, strerror(errno) );
+ return -1;
+ }
+#if NEWIO
+#ifdef sgi
+ /* If this is POSIX I/O and it is via aio_{read,write}
+ * or lio_listio then after completion of the I/O the
+ * value of the file offset for the file is
+ * unspecified--which means we cannot trust what
+ * tell() told us. Fudge it here.
+ */
+ if( (io_type & LIO_IO_ASYNC_TYPES) || (io_type & LIO_RANDOM) ){
+ if( tmp != Woffset + grow_incr ){
+ if( Debug > 5 ){
+ printf("%s: %d DEBUG6 %s/%d: posix fudge, forcing tmp (%d) to match Woffset+grow_incr (%d)\n",
+ Progname, Pid, __FILE__, __LINE__, tmp, Woffset+grow_incr);
+ }
+ tmp = Woffset + grow_incr;
+ }
+ }
+#endif
+#endif
+ }
+
+ lkfile(fd, LOCK_UN, LKLVL0);
+
+ if ( ret != grow_incr ) {
+ fprintf(stderr, "%s%s: %d %s/%d: %d %s\n",
+ Progname, TagName, Pid, __FILE__, __LINE__, Iter_cnt, errmsg);
+ if ( ret == -ENOSPC ) {
+ cleanup();
+ exit(2);
+ }
+ return -1;
+ }
+
+ /*
+ * Check for a condition where the file was truncated just before
+ * the write.
+ */
+ if ( tmp != Woffset + grow_incr) {
+ /*
+ * The offset after the write was not as expected.
+ * This could be caused by the following:
+ * - file truncated after the lseek and before the write.
+ * - the file was written to after fstat and before the write
+ * and the file was opened with O_APPEND.
+ *
+ * The pattern written to the file will be considered corrupted.
+ */
+ if ( Debug > 0 && lockfile ) {
+ printf("%s%s: %d DEBUG1 %s/%d: offset after write(%d) not as exp(%d+%d=%d)\n",
+ Progname, TagName, Pid, __FILE__, __LINE__, tmp, Woffset, grow_incr, Woffset+grow_incr);
+ printf("%s%s: %d DEBUG1 %s/%d: %d Assuming file changed by another process, resetting offset:%d (expect pattern mismatch)\n",
+ Progname, TagName, Pid, __FILE__, __LINE__, Iter_cnt, tmp-grow_incr);
+ }
+ if( Debug > 4 ){
+ printf("%s: %d DEBUG5 %s/%d: about to chop Woffset. tmp=%d, grow_incr=%d, Woffset was %d\n",
+ Progname, Pid, __FILE__, __LINE__, tmp, grow_incr, Woffset);
+ }
+ Woffset=tmp-grow_incr;
+ if( Woffset < 0 )
+ Woffset = 0;
+ }
+
+ } /* end of grow by write */
+
+
+ /*
+ * Woffset - holds start of grow (start of write expect in grow by lseek)
+ * Grow_incr - holds size of grow (write).
+ * fsize - holds size of file before write
+ */
+ size_grew=(Woffset + Grow_incr) - fsize;
+ if ( Debug > 1) {
+ if ( Mode & MODE_FIFO ) {
+ printf("%s: %d DEBUG2 %s/%d: file is fifo, %d wrote %d bytes\n",
+ Progname, Pid, __FILE__, __LINE__, Grow_incr, Iter_cnt);
+ }
+
+ else if ( size_grew > 0 )
+ printf("%s: %d DEBUG2 %s/%d: %d wrote %d bytes(off:%d), grew file by %d bytes\n",
+ Progname, Pid, __FILE__, __LINE__, Iter_cnt, Grow_incr, Woffset, size_grew);
+ else
+ printf("%s: %d DEBUG2 %s/%d: %d wrote %d bytes(off:%d), did not grow file\n",
+ Progname, Pid, __FILE__, __LINE__, Iter_cnt, Grow_incr, Woffset);
+ }
+
+ bytes_consumed += size_grew;
+ return 0;
+
+} /* end of growfile */
+
+/***********************************************************************
+ * shrinkfile file by trunc_incr. file can not be made smaller than
+ * size zero. Therefore, if trunc_incr is larger than file size,
+ * file will be truncated to zero.
+ * The file descriptor current offset is assumed to be the end of the
+ * file.
+ *
+ ***********************************************************************/
+int
+shrinkfile(fd, filename, trunc_incr, trunc_inter, just_trunc)
+int fd;
+char *filename;
+int trunc_incr;
+int trunc_inter; /* interval */
+int just_trunc; /* lseek has already been done for you */
+{
+ static int shrink_cnt = 0;
+ int cur_offset;
+ int new_offset;
+ int ret;
+#ifdef CRAY
+ int offset;
+#endif
+
+ shrink_cnt++;
+
+ if ( trunc_inter == 0 || (shrink_cnt % trunc_inter != 0)) {
+ if ( Debug > 3 )
+ printf("%s: %d DEBUG4 %s/%d: Not shrinking file - not time, iter=%d, cnt=%d\n",
+ Progname, Pid, __FILE__, __LINE__, trunc_inter, shrink_cnt);
+ return 0; /* not this time */
+ }
+
+ if ( Mode & MODE_FIFO ) {
+ if ( Debug > 5 )
+ printf("%s: %d DEBUG5 %s/%d: Not attempting to shrink a FIFO\n",
+ Progname, Pid, __FILE__, __LINE__);
+ return 0; /* can not truncate fifo */
+ }
+
+ lkfile(fd, LOCK_EX, LKLVL0);
+
+ if ((cur_offset=lseek(fd,0,SEEK_CUR)) == -1 ) {
+ fprintf(stderr, "%s%s: %d %s/%d: tell(%d) failed: %s\n",
+ Progname, TagName, Pid, __FILE__, __LINE__, fd, strerror(errno));
+ lkfile(fd, LOCK_UN, LKLVL0);
+ return -1;
+ }
+
+ if ( Mode & MODE_RAND_LSEEK ) {
+ if ( max_lseek <= -1 ) {
+ if ( (new_offset=file_size(fd)) == -1 ) {
+ lkfile(fd, LOCK_UN, LKLVL0);
+ return -1;
+ }
+
+ if ( new_offset < min_lseek )
+ new_offset=min_lseek;
+ else
+ new_offset=random_range(min_lseek, new_offset, 1, NULL);
+ }
+ else {
+ new_offset=random_range(min_lseek, max_lseek, 1, NULL);
+ }
+
+#ifdef CRAY
+ if ((offset=lseek(fd, new_offset, SEEK_SET)) == -1 ) {
+ fprintf(stderr, "%s%s: %d %s/%d: lseek(%d, %d, SEEK_SET) l3 failed: %s\n",
+ Progname, TagName, Pid, __FILE__, __LINE__, fd, new_offset, strerror(errno));
+ lkfile(fd, LOCK_UN, LKLVL0);
+ return -1;
+ }
+ else if ( Debug > 3 )
+ printf("%s: %d DEBUG4 %s/%d: lseeked to random offset %d\n",
+ Progname, Pid, __FILE__, __LINE__, offset);
+
+#endif
+ }
+
+ else { /* remove trunc_incr from file */
+
+ new_offset = cur_offset-trunc_incr;
+
+ if ( new_offset < 0 )
+ new_offset=0;
+
+#ifdef CRAY
+ if ( lseek(fd, new_offset, SEEK_SET) == -1 ) {
+ fprintf(stderr, "%s%s: %d %s/%d: lseek(fd, %d, SEEK_SET) l4 failed: %s\n",
+ Progname, TagName, Pid, __FILE__, __LINE__, new_offset, strerror(errno));
+ lkfile(fd, LOCK_UN, LKLVL0);
+ return -1;
+ }
+ else if ( Debug > 3 )
+ printf("%s: %d DEBUG4 %s/%d: lseeked to offset %d, %d bytes from end\n",
+ Progname, Pid, __FILE__, __LINE__, new_offset, trunc_incr);
+#endif
+ }
+
+
+#ifdef CRAY
+ ret=trunc(fd);
+#else
+ ret=ftruncate(fd, new_offset );
+ if( (ret == 0) && (Debug > 3) ){
+ printf("%s: %d DEBUG4 %s/%d: ftruncated to offset %d, %d bytes from end\n",
+ Progname, Pid, __FILE__, __LINE__, new_offset, trunc_incr);
+ }
+#endif
+
+ lkfile(fd, LOCK_UN, LKLVL0);
+
+ if ( ret == -1 ) {
+#ifdef CRAY
+ fprintf(stderr, "%s%s: %d %s/%d: trunc failed: %s\n",
+ Progname, TagName, Pid, __FILE__, __LINE__, strerror(errno));
+#else
+ fprintf(stderr, "%s%s: %d %s/%d: ftruncate failed: %s\n",
+ Progname, TagName, Pid, __FILE__, __LINE__, strerror(errno));
+#endif
+ return -1;
+ }
+
+ if ( Debug > 2 ) {
+ printf("%s: %d DEBUG2 %s/%d: trunc file by %d bytes, to size of = %d bytes\n",
+ Progname, Pid, __FILE__, __LINE__, cur_offset-new_offset, new_offset);
+ }
+
+
+ bytes_consumed -= (cur_offset - new_offset);
+ return 0;
+
+} /* end of shrinkfile */
+
+/***********************************************************************
+ *
+ ***********************************************************************/
+int
+check_write(fd, cf_inter, filename, mode)
+int fd;
+int cf_inter; /* check file interval */
+char *filename; /* needed for error messages */
+int mode; /* write mode */
+{
+ int fsize;
+ static int cf_count = 0;
+ int ret = 0;
+ int tmp;
+ char *errmsg;
+ char *ptr;
+
+ cf_count++;
+
+ if ( cf_inter == 0 || (cf_count % cf_inter != 0)) {
+ if ( Debug > 4 )
+ printf("%s: %d DEBUG5 %s/%d: no write check, not time iter=%d, cnt=%d\n",
+ Progname, Pid, __FILE__, __LINE__, cf_inter, cf_count);
+ return 0; /* no check done */
+ }
+
+ if ( Grow_incr <= 0 ) {
+ if ( Debug > 3 )
+ printf("%s: %d DEBUG4 %s/%d: No write validation, Grow_incr = %d, offset = %d\n",
+ Progname, Pid, __FILE__, __LINE__, Grow_incr, Woffset);
+ return 0; /* no check */
+ }
+
+
+
+ /*
+ * Get the shared file lock. We need to hold the lock from before
+ * we do the stat until after the read.
+ */
+ lkfile(fd, LOCK_SH, LKLVL0);
+
+ if ((fsize=file_size(fd)) == -1 ) {
+ lkfile(fd, LOCK_UN, LKLVL0);
+ return -1;
+
+ } else if ( fsize <= Woffset ) {
+ /*
+ * The file was truncated between write and now.
+ * The contents of our last write is totally gone, no check.
+ */
+ if ( Debug > 1 )
+ printf("%s%s: %d DEBUG2 %s/%d: %d File size (%d) smaller than where last wrote (%d)- no write validation\n",
+ Progname, TagName, Pid, __FILE__, __LINE__, Iter_cnt, fsize, Woffset);
+ lkfile(fd, LOCK_UN, LKLVL0);
+ return 0; /* no validation, but not an error */
+
+ } else if ( fsize < (Woffset + Grow_incr)) {
+ /*
+ * The file was truncated between write and now.
+ * Part of our last write has been truncated, adjust our Grow_incr
+ * to reflect this.
+ */
+
+ tmp=Grow_incr;
+ Grow_incr=fsize-Woffset;
+
+ if ( Debug > 1 ) {
+
+ printf("%s%s: %d DEBUG2 %s/%d: %d fsz:%d, lost(%d)of wrt(off:%d, sz:%d), adj=%d\n",
+ Progname, TagName, Pid, __FILE__, __LINE__, Iter_cnt, fsize, tmp-Grow_incr, Woffset, tmp, Grow_incr);
+ }
+
+ }
+
+ if ( Debug > 2 )
+ printf("%s: %d DEBUG3 %s/%d: about to do write validation, offset = %d, size = %d\n",
+ Progname, Pid, __FILE__, __LINE__, Woffset, Grow_incr);
+
+ if ( ! (mode & MODE_FIFO) ) {
+
+ if ( lseek(fd, Woffset, 0) == -1 ) {
+ fprintf(stderr, "%s%s: %d %s/%d: lseek(fd, %d, 0) failed: %s\n",
+ Progname, TagName, Pid, __FILE__, __LINE__, Woffset, strerror(errno));
+ }
+ if ( Debug > 3 )
+ printf("%s: %d DEBUG4 %s/%d: lseeked to offset:%d\n",
+ Progname, Pid, __FILE__, __LINE__, Woffset);
+ }
+
+ /*
+ * Read last writes data
+ */
+#if NEWIO
+ ret=lio_read_buffer(fd, io_type, Buffer, Grow_incr, SIGUSR1, &errmsg,0);
+#else
+ ret=read_buffer(fd, io_type, Buffer, Grow_incr, 0, &errmsg);
+#endif
+
+ /*
+ * report the error and debug information before releasing
+ * the file lock
+ */
+ if ( ret != Grow_incr ) {
+ fprintf(stderr, "%s%s: %d %s/%d: %d CW %s\n", Progname, TagName, Pid, __FILE__, __LINE__, Iter_cnt, errmsg);
+ {
+ struct stat stbuf;
+ fstat(fd, &stbuf);
+ if ( Debug > 2 )
+ printf("%s%s: %d DEBUG3 %s/%d: fd:%d, offset:%d, fsize:%d, openflags:%#o\n",
+ Progname, TagName, Pid, __FILE__, __LINE__, fd,
+ (int)lseek(fd,SEEK_CUR,0), /* FIXME: 64bit/LFS ? */
+ (int)stbuf.st_size,
+ Fileinfo.openflags);
+ }
+
+ lkfile(fd, LOCK_UN, LKLVL0);
+ return 1;
+ }
+
+
+ lkfile(fd, LOCK_UN, LKLVL0);
+
+ if ( Mode & MODE_GROW_BY_LSEEK ) {
+ /* check that all zeros upto last character */
+ for(ptr=Buffer; ptr < (Buffer+Grow_incr-1); ptr++) {
+ if ( *ptr != '\0' ) {
+ fprintf(stderr,
+ "%s%s: %d %s/%d: data mismatch at offset %d, exp:%#o(zerofilled), act:%#o in file %s\n",
+ Progname, TagName, Pid, __FILE__, __LINE__,
+ (int)(Woffset+(Grow_incr-(Buffer-ptr))),
+ 0, *ptr, filename);
+ fflush(stderr);
+ return 1;
+ }
+ }
+ /* check that the last char is a 'w' */
+ if ( *ptr != 'w' ) {
+ fprintf(stderr,
+ "%s%s: %d %s/%d: data mismatch at offset %d, exp:%#o(zerofilled), act:%#o in file %s\n",
+ Progname, TagName, Pid, __FILE__, __LINE__,
+ (int)(Woffset+(Grow_incr-(Buffer-ptr))), 'w',
+ *ptr, filename);
+ fflush(stderr);
+ return 1;
+ }
+ return 0; /* all is well */
+
+ }
+ else if ( Pattern == PATTERN_OFFSET )
+ ret=datapidchk(STATIC_NUM, Buffer, Grow_incr, Woffset, &errmsg);
+ else if ( Pattern == PATTERN_PID )
+ ret=datapidchk(Pid, Buffer, Grow_incr, Woffset, &errmsg);
+ else if ( Pattern == PATTERN_ASCII )
+ ret=dataasciichk(NULL, Buffer, Grow_incr, Woffset, &errmsg);
+ else if ( Pattern == PATTERN_RANDOM )
+ ; /* no check for random */
+ else if ( Pattern == PATTERN_ALT )
+ ret=databinchk('a', Buffer, Grow_incr, Woffset, &errmsg);
+ else if ( Pattern == PATTERN_CHKER )
+ ret=databinchk('c', Buffer, Grow_incr, Woffset, &errmsg);
+ else if ( Pattern == PATTERN_CNTING )
+ ret=databinchk('C', Buffer, Grow_incr, Woffset, &errmsg);
+ else if ( Pattern == PATTERN_ZEROS )
+ ret=databinchk('z', Buffer, Grow_incr, Woffset, &errmsg);
+ else if ( Pattern == PATTERN_ONES )
+ ret=databinchk('o', Buffer, Grow_incr, Woffset, &errmsg);
+ else
+ ret=dataasciichk(NULL, Buffer, Grow_incr, Woffset, &errmsg);
+
+ if ( ret >= 0 ) {
+ fprintf(stderr, "%s%s: %d %s/%d: %d CW %s in file %s\n",
+ Progname, TagName, Pid, __FILE__, __LINE__, Iter_cnt, errmsg, filename);
+
+ if ( Debug > 0 )
+ printf("%s%s: %d DEBUG1 %s/%d: **fd:%d, lk:%d, offset:%d, sz:%d open flags:%#o %s\n",
+ Progname, TagName, Pid, __FILE__, __LINE__, fd, lockfile,
+ Woffset, Grow_incr, Fileinfo.openflags, openflags2symbols(Fileinfo.openflags, ",", NULL));
+
+ fflush(stderr);
+ return 1;
+ }
+
+ if ( Debug > 6 )
+ printf("%s: %d DEBUG7 %s/%d: No corruption detected on write validation , offset = %d, size = %d\n",
+ Progname, Pid, __FILE__, __LINE__, Woffset, Grow_incr);
+
+ return 0; /* all is well */
+}
+
+
+
+/***********************************************************************
+ *
+ ***********************************************************************/
+int
+check_file(fd, cf_inter, filename, no_file_check)
+int fd;
+int cf_inter; /* check file interval */
+char *filename; /* needed for error messages */
+int no_file_check; /* if set, do not do file content check */
+{
+ int fsize;
+ static int cf_count = 0;
+ char *buf;
+ int ret;
+ int ret_val = 0;
+ int rd_cnt;
+ int rd_size;
+ char *errmsg;
+
+ cf_count++;
+
+ if ( cf_inter == 0 || (cf_count % cf_inter != 0)) {
+ if ( Debug > 4 )
+ printf("%s: %d DEBUG5 %s/%d: No file check - not time, iter=%d, cnt=%d\n",
+ Progname, Pid, __FILE__, __LINE__, cf_inter, cf_count);
+ return 0; /* no check done */
+ }
+
+ /*
+ * if we can't determine file content, don't bother checking
+ */
+ if ( no_file_check ) {
+ if ( Debug > 4 )
+ printf("%s: %d DEBUG5 %s/%d: No file check, lseek grow or random lseeks\n",
+ Progname, Pid, __FILE__, __LINE__);
+ return 0;
+ }
+
+ /*
+ * Lock the file. We need to have the file lock before
+ * the stat and until after the last read to prevent
+ * a trunc/truncate from "corrupting" our data.
+ */
+ lkfile(fd, LOCK_SH, LKLVL0);
+
+ if ((fsize=file_size(fd)) == -1 ) {
+ lkfile(fd, LOCK_UN, LKLVL0);
+ return -1;
+ }
+
+ if ( fsize == 0 ) {
+ if ( Debug > 2 )
+ printf("%s: %d DEBUG3 %s/%d: No file validation, file size == 0\n",
+ Progname, Pid, __FILE__, __LINE__);
+
+ lkfile(fd, LOCK_UN, LKLVL0);
+ return 0;
+ }
+
+ if ( Debug > 2 )
+ printf("%s: %d DEBUG3 %s/%d: about to do file validation\n",
+ Progname, Pid, __FILE__, __LINE__);
+
+ if ( fsize > MAX_FC_READ ) {
+ /*
+ * read the file in MAX_FC_READ chuncks.
+ */
+
+ if ((buf=(char *)malloc(MAX_FC_READ)) == NULL ) {
+ fprintf(stderr, "%s%s: %s/%d: malloc(%d) failed: %s\n", Progname, TagName,
+ __FILE__, __LINE__, MAX_FC_READ, strerror(errno));
+ lkfile(fd, LOCK_UN, LKLVL0);
+ return -1;
+ }
+
+ lseek(fd, 0, SEEK_SET);
+
+ lkfile(fd, LOCK_SH, LKLVL0); /* get lock on file before getting file size */
+
+ rd_cnt=0;
+ while (rd_cnt < fsize ) {
+ if ( fsize - rd_cnt > MAX_FC_READ )
+ rd_size=MAX_FC_READ;
+ else
+ rd_size=fsize - rd_cnt;
+
+#if NEWIO
+ ret=lio_read_buffer(fd, io_type, buf, rd_size,
+ SIGUSR1, &errmsg,0);
+#else
+ ret=read_buffer(fd, io_type, buf, rd_size, 0, &errmsg);
+#endif
+
+ if (ret != rd_size ) {
+ fprintf(stderr, "%s%s: %d %s/%d: %d CFa %s\n",
+ Progname, TagName, Pid, __FILE__, __LINE__, Iter_cnt, errmsg);
+ free(buf);
+ lkfile(fd, LOCK_UN, LKLVL0);
+ return -1;
+ }
+/**
+ read(fd, buf, rd_size);
+***/
+
+ if ( Pattern == PATTERN_OFFSET )
+ ret=datapidchk(STATIC_NUM, buf, rd_size, rd_cnt, &errmsg);
+ else if ( Pattern == PATTERN_PID )
+ ret=datapidchk(Pid, buf, rd_size, rd_cnt, &errmsg);
+ else if ( Pattern == PATTERN_ASCII )
+ ret=dataasciichk(NULL, buf, rd_size, rd_cnt, &errmsg);
+ else if ( Pattern == PATTERN_RANDOM )
+ ; /* no checks for random */
+ else if ( Pattern == PATTERN_ALT )
+ ret=databinchk('a', buf, rd_size, rd_cnt, &errmsg);
+ else if ( Pattern == PATTERN_CHKER )
+ ret=databinchk('c', buf, rd_size, rd_cnt, &errmsg);
+ else if ( Pattern == PATTERN_CNTING )
+ ret=databinchk('C', buf, rd_size, rd_cnt, &errmsg);
+ else if ( Pattern == PATTERN_ZEROS )
+ ret=databinchk('z', buf, rd_size, rd_cnt, &errmsg);
+ else if ( Pattern == PATTERN_ONES )
+ ret=databinchk('o', buf, rd_size, rd_cnt, &errmsg);
+ else
+ ret=dataasciichk(NULL, buf, rd_size, rd_cnt, &errmsg);
+
+
+ if ( ret >= 0 ) {
+ fprintf(stderr,
+ "%s%s: %d %s/%d: %d CFp %s in file %s\n",
+ Progname, TagName, Pid, __FILE__, __LINE__, Iter_cnt, errmsg, filename);
+ fflush(stderr);
+ ret_val=1;
+ lkfile(fd, LOCK_UN, LKLVL0);
+ break;
+ }
+ rd_cnt += rd_size;
+ }
+
+ lkfile(fd, LOCK_UN, LKLVL0);
+
+ free(buf);
+
+ }
+ else {
+ /*
+ * Read the whole file in a single read
+ */
+ if((buf=(char *)malloc(fsize)) == NULL ) {
+ fprintf(stderr, "%s%s: %s/%d: malloc(%d) failed: %s\n", Progname, TagName,
+ __FILE__, __LINE__, fsize, strerror(errno));
+ fflush(stderr);
+ return -1;
+ }
+
+ lseek(fd, 0, SEEK_SET);
+
+/****
+ read(fd, buf, fsize);
+****/
+#if NEWIO
+ ret=lio_read_buffer(fd, io_type, buf, fsize, SIGUSR1, &errmsg,0);
+#else
+ ret=read_buffer(fd, io_type, buf, fsize, 0, &errmsg);
+#endif
+
+ /* unlock the file as soon as we can */
+ lkfile(fd, LOCK_UN, LKLVL0);
+
+
+ if ( ret != fsize ) {
+ fprintf(stderr, "%s%s: %d %s/%d: %d CFw %s\n",
+ Progname, TagName, Pid, __FILE__, __LINE__, Iter_cnt, errmsg);
+ ret_val=1;
+ }
+ else {
+ if ( Pattern == PATTERN_OFFSET )
+ ret=datapidchk(STATIC_NUM, buf, fsize, 0, &errmsg);
+ else if ( Pattern == PATTERN_PID )
+ ret=datapidchk(Pid, buf, fsize, 0, &errmsg);
+ else if ( Pattern == PATTERN_ASCII )
+ ret=dataasciichk(NULL, buf, fsize, 0, &errmsg);
+ else if ( Pattern == PATTERN_RANDOM )
+ ; /* no check for random */
+ else if ( Pattern == PATTERN_ALT )
+ ret=databinchk('a', buf, fsize, 0, &errmsg);
+ else if ( Pattern == PATTERN_CHKER )
+ ret=databinchk('c', buf, fsize, 0, &errmsg);
+ else if ( Pattern == PATTERN_CNTING )
+ ret=databinchk('C', buf, fsize, 0, &errmsg);
+ else if ( Pattern == PATTERN_ZEROS )
+ ret=databinchk('z', buf, fsize, 0, &errmsg);
+ else if ( Pattern == PATTERN_ONES )
+ ret=databinchk('o', buf, fsize, 0, &errmsg);
+ else
+ ret=dataasciichk(NULL, buf, fsize, 0, &errmsg);
+
+ if ( ret >= 0 ) {
+ fprintf(stderr, "%s%s: %d %s/%d: %d CFw %s in file %s\n",
+ Progname, TagName, Pid, __FILE__, __LINE__, Iter_cnt, errmsg, filename);
+ fflush(stderr);
+ ret_val=1;
+ }
+ }
+ free(buf);
+ }
+
+ return ret_val;
+
+} /* end of check_file */
+
+/***********************************************************************
+ *
+ ***********************************************************************/
+int
+file_size(int fd)
+{
+ struct stat sb;
+
+ if (fstat(fd, &sb) < 0) {
+ fprintf(stderr, "%s%s: %d %s/%d: Unable to fstat(%d, &buf), errno:%d %s\n",
+ Progname, TagName, Pid, __FILE__, __LINE__, fd, errno, strerror(errno));
+ return -1;
+
+ }
+
+ return sb.st_size;
+}
+
+/***********************************************************************
+ * do file lock/unlock action.
+ ***********************************************************************/
+int
+lkfile(int fd, int operation, int lklevel)
+{
+ char *errmsg;
+
+
+ if ( lockfile == lklevel) {
+
+ if ( Debug > 5 ) {
+ switch (operation) {
+ case LOCK_UN:
+ printf("%s: %d DEBUG6 %s/%d: Attempting to release lock on fd %d\n",
+ Progname, Pid, __FILE__, __LINE__, fd);
+ break;
+
+ case LOCK_SH:
+ printf("%s: %d DEBUG6 %s/%d: Attempting to get read/shared lock on fd %d\n",
+ Progname, Pid, __FILE__, __LINE__, fd);
+ break;
+
+ case LOCK_EX:
+ printf("%s: %d DEBUG6 %s/%d: Attempting to get write/exclusive lock on fd %d\n",
+ Progname, Pid, __FILE__, __LINE__, fd);
+ break;
+ }
+ }
+
+ /*
+ * Attempt to get/release desired lock.
+ * file_lock will attempt to do action over and over again until
+ * either an unretryable error or the action is completed.
+ */
+
+ if ( file_lock(fd, operation, &errmsg) != 0 ) {
+ printf("%s%s: %d %s/%d: Unable to perform lock operation. %s\n",
+ Progname, TagName, Pid, __FILE__, __LINE__, errmsg);
+
+ /* do we count this as an error? handle_error(); */
+ return -1;
+ }
+
+ if ( Debug > 2 ) {
+ switch (operation) {
+ case LOCK_UN:
+ printf("%s: %d DEBUG3 %s/%d: Released lock on fd %d\n",
+ Progname, Pid, __FILE__, __LINE__, fd);
+ break;
+
+ case LOCK_SH:
+ printf("%s: %d DEBUG3 %s/%d: Got read/shared lock on fd %d\n",
+ Progname, Pid, __FILE__, __LINE__, fd);
+ break;
+
+ case LOCK_EX:
+ printf("%s: %d DEBUG3 %s/%d: Got write/exclusive lock on fd %d\n",
+ Progname, Pid, __FILE__, __LINE__, fd);
+ break;
+
+ default:
+ printf("%s: %d DEBUG3 %s/%d: Completed action %d on fd %d\n",
+ Progname, Pid, __FILE__, __LINE__, operation, fd);
+ break;
+ }
+ }
+ }
+
+ return 0;
+}
+
+#ifndef NO_XFS
+/***********************************************************************
+ *
+ ***********************************************************************/
+int
+pre_alloc(file, fd, size)
+char *file;
+int fd;
+int size;
+{
+
+#ifdef CRAY
+ long avl;
+
+ if ( ialloc(fd, size, IA_CONT, &avl) == -1 ) {
+ fprintf(stderr, "%s%s %s/%d: Unable to pre-alloc space: ialloc failed: %d %s\n",
+ Progname, TagName,
+ __FILE__, __LINE__, errno, strerror(errno));
+ return -1;
+ }
+#endif
+
+#ifndef NO_XFS
+ struct xfs_flock64 f;
+
+ f.l_whence = 0;
+ f.l_start = 0;
+ f.l_len = size;
+
+ /* non-zeroing reservation */
+ if( xfsctl( file, fd, XFS_IOC_RESVSP, &f ) == -1 ){
+ fprintf(stderr, "%s%s %s/%d: Unable to pre-alloc space: xfsctl(XFS_IOC_RESVSP) failed: %d %s\n",
+ Progname, TagName,
+ __FILE__, __LINE__, errno, strerror(errno));
+ return -1;
+ }
+
+#endif
+
+ return 0;
+}
+#endif
--- /dev/null
+/*
+ * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like. Any license provided herein, whether implied or
+ * otherwise, applies only to this software file. Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+ * Mountain View, CA 94043, or:
+ *
+ * http://www.sgi.com
+ *
+ * For further information regarding this notice, see:
+ *
+ * http://oss.sgi.com/projects/GenInfo/NoticeExplan/
+ */
+/*
+ * iogen - a tool for generating file/sds io for a doio process
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+#include <signal.h>
+#include <time.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/sysmacros.h>
+#ifdef CRAY
+#include <sys/file.h>
+#include <sys/iosw.h>
+#include <sys/listio.h>
+#endif
+#ifdef sgi
+#include <sys/statvfs.h>
+#include <sys/fs/xfs_itable.h>
+#endif
+
+#ifndef NO_XFS
+#include <xfs/libxfs.h>
+#endif
+
+#ifdef CRAY
+#include "libkern.h"
+#endif
+
+#include "doio.h"
+#include "str_to_bytes.h"
+#include "string_to_tokens.h"
+#include "open_flags.h"
+#include "random_range.h"
+
+#ifndef BSIZE
+#define BSIZE 512
+#endif
+
+#define RAW_IO(_flags_) ((_flags_) & (O_RAW | O_SSD))
+
+#define SYSERR strerror(errno)
+
+/*
+ * Structure for retaining test file information
+ */
+
+struct file_info {
+ char f_path[MAX_FNAME_LENGTH+1]; /* file name (full path) */
+ int f_length; /* length in bytes */
+ int f_iou; /* file iounit */
+ int f_riou; /* file raw iounit (for O_RAW/O_SSD) */
+ int f_dalign; /* direct I/O alignment */
+ int f_nextoff; /* offset of end of last io operation */
+ int f_type; /* file type S_IFREG, etc... */
+ int f_lastoffset; /* offset of last io operation */
+ int f_lastlength; /* length of last io operation */
+};
+
+/*
+ * Simple structure for associating strings with values - useful for converting
+ * cmdline args to internal values, as well as printing internal values in
+ * a human readable form.
+ */
+
+struct strmap {
+ char *m_string;
+ int m_value;
+ int m_flags;
+};
+
+/*
+ * Declare cmdline option flags/variables initialized in parse_cmdline()
+ */
+
+#define OPTS "a:dhf:i:L:m:op:qr:s:t:T:O:N:"
+
+int a_opt = 0; /* async io comp. types supplied */
+int o_opt = 0; /* form overlapping requests */
+int f_opt = 0; /* test flags */
+int i_opt = 0; /* iterations - 0 implies infinite */
+int L_opt = 0; /* listio min-max nstrides & nents */
+int m_opt = 0; /* offset mode */
+int O_opt = 0; /* file creation Open flags */
+int p_opt = 0; /* output pipe - default is stdout */
+int r_opt = 0; /* specify raw io multiple instead of */
+ /* getting it from the mounted on device. */
+ /* Only applies to regular files. */
+int s_opt = 0; /* syscalls */
+int t_opt = 0; /* min transfer size (bytes) */
+int T_opt = 0; /* max transfer size (bytes) */
+int q_opt = 0; /* quiet operation on startup */
+char TagName[40]; /* name of this iogen (see Monster) */
+struct strmap *Offset_Mode; /* M_SEQUENTIAL, M_RANDOM, etc. */
+int Iterations; /* # requests to generate (0 --> infinite) */
+int Time_Mode = 0; /* non-zero if Iterations is in seconds */
+ /* (ie. -i arg was suffixed with 's') */
+char *Outpipe; /* Pipe to write output to if p_opt */
+int Mintrans; /* min io transfer size */
+int Maxtrans; /* max io transfer size */
+int Rawmult; /* raw/ssd io multiple (from -r) */
+int Minstrides; /* min # of listio strides per request */
+int Maxstrides; /* max # of listio strides per request */
+int Oflags; /* open(2) flags for creating files */
+int Ocbits; /* open(2) cbits for creating files */
+int Ocblks; /* open(2) cblks for creating files */
+int Orealtime=0; /* flag set for -O REALTIME */
+int Oextsize=0; /* real-time extent size */
+int Oreserve=1; /* flag for -O [no]reserve */
+int Oallocate=0; /* flag for -O allocate */
+int Owrite=1; /* flag for -O nowrite */
+
+int Nfiles = 0; /* # files on cmdline */
+struct file_info *File_List; /* info about each file */
+int Nflags = 0; /* # flags on cmdline */
+struct strmap *Flag_List[128]; /* flags selected from cmdline */
+int Nsyscalls = 0; /* # syscalls on cmdline */
+struct strmap *Syscall_List[128]; /* syscalls selected on cmdline */
+int Fileio = 0; /* flag indicating that a file */
+ /* io syscall has been chosen. */
+int Naio_Strat_Types = 0; /* # async io completion types */
+struct strmap *Aio_Strat_List[128]; /* Async io completion types */
+
+void startup_info();
+
+/*
+ * Map async io completion modes (-a args) names to values. Macros are
+ * defined in doio.h.
+ */
+
+struct strmap Aio_Strat_Map[] = {
+#ifndef linux
+ { "poll", A_POLL },
+ { "signal", A_SIGNAL },
+#else
+ { "none", 0 },
+#endif /* !linux */
+#ifdef CRAY
+#if _UMK || RELEASE_LEVEL >= 8000
+ { "recall", A_RECALL },
+#endif
+
+#ifdef RECALL_SIZEOF
+ { "recalla", A_RECALLA },
+#endif
+ { "recalls", A_RECALLS },
+#endif /* CRAY */
+
+#ifdef sgi
+ { "suspend", A_SUSPEND },
+ { "callback", A_CALLBACK },
+#endif
+ { NULL, -1 }
+};
+
+/*
+ * Offset_Mode #defines
+ */
+
+#define M_RANDOM 1
+#define M_SEQUENTIAL 2
+#define M_REVERSE 3
+
+/*
+ * Map offset mode (-m args) names to values
+ */
+
+struct strmap Omode_Map[] = {
+ { "random", M_RANDOM },
+ { "sequential", M_SEQUENTIAL },
+ { "reverse", M_REVERSE },
+ { NULL, -1 }
+};
+
+/*
+ * Map syscall names (-s args) to values - macros are defined in doio.h.
+ */
+#define SY_ASYNC 00001
+#define SY_WRITE 00002
+#define SY_SDS 00010
+#define SY_LISTIO 00020
+#define SY_NENT 00100 /* multi entry vs multi stride >>> */
+
+struct strmap Syscall_Map[] = {
+ { "read", READ, 0 },
+ { "write", WRITE, SY_WRITE },
+#ifdef CRAY
+ { "reada", READA, SY_ASYNC },
+ { "writea", WRITEA, SY_WRITE|SY_ASYNC },
+#ifndef _CRAYMPP
+ { "ssread", SSREAD, SY_SDS },
+ { "sswrite", SSWRITE, SY_WRITE|SY_SDS },
+#endif
+ { "listio", LISTIO, SY_ASYNC },
+
+ /* listio as 4 system calls */
+ { "lread", LREAD, 0 },
+ { "lreada", LREADA, SY_ASYNC },
+ { "lwrite", LWRITE, SY_WRITE },
+ { "lwritea", LWRITEA, SY_WRITE|SY_ASYNC },
+
+ /* listio with nstrides > 1 */
+ { "lsread", LSREAD, 0 },
+ { "lsreada", LSREADA, SY_ASYNC },
+ { "lswrite", LSWRITE, SY_WRITE },
+ { "lswritea", LSWRITEA, SY_WRITE|SY_ASYNC },
+
+ /* listio with nents > 1 */
+ { "leread", LEREAD, 0|SY_NENT },
+ { "lereada", LEREADA, SY_ASYNC|SY_NENT },
+ { "lewrite", LEWRITE, SY_WRITE|SY_NENT },
+ { "lewritea", LEWRITEA, SY_WRITE|SY_ASYNC|SY_NENT },
+
+ /* listio with nents > 1 & nstrides > 1 */
+
+ /* all listio system calls under one name */
+ { "listio+", LREAD, 0 },
+ { "listio+", LREADA, SY_ASYNC },
+ { "listio+", LWRITE, SY_WRITE },
+ { "listio+", LWRITEA, SY_WRITE|SY_ASYNC },
+ { "listio+", LSREAD, 0 },
+ { "listio+", LSREADA, SY_ASYNC },
+ { "listio+", LSWRITE, SY_WRITE },
+ { "listio+", LSWRITEA, SY_WRITE|SY_ASYNC },
+ { "listio+", LEREAD, 0|SY_NENT },
+ { "listio+", LEREADA, SY_ASYNC|SY_NENT },
+ { "listio+", LEWRITE, SY_WRITE|SY_NENT },
+ { "listio+", LEWRITEA, SY_WRITE|SY_ASYNC|SY_NENT },
+#endif
+
+ { "pread", PREAD },
+ { "pwrite", PWRITE, SY_WRITE },
+#ifdef sgi
+ { "aread", AREAD, SY_ASYNC },
+ { "awrite", AWRITE, SY_WRITE|SY_ASYNC },
+#if 0
+ /* not written yet */
+ { "llread", LLREAD, 0 },
+ { "llaread", LLAREAD, SY_ASYNC },
+ { "llwrite", LLWRITE, 0 },
+ { "llawrite", LLAWRITE, SY_ASYNC },
+#endif
+ { "ffsync", DFFSYNC, SY_WRITE },
+#endif /* SGI */
+#ifndef NO_XFS
+ { "resvsp", RESVSP, SY_WRITE },
+ { "unresvsp", UNRESVSP, SY_WRITE },
+ { "reserve", RESVSP, SY_WRITE },
+ { "unreserve", UNRESVSP, SY_WRITE },
+#endif
+
+#ifndef CRAY
+ { "readv", READV },
+ { "writev", WRITEV, SY_WRITE },
+ { "mmread", MMAPR },
+ { "mmwrite", MMAPW, SY_WRITE },
+ { "fsync2", FSYNC2, SY_WRITE },
+ { "fdatasync", FDATASYNC, SY_WRITE },
+#endif
+
+ { NULL, -1 }
+};
+
+/*
+ * Map open flags (-f args) to values
+ */
+#define FLG_RAW 00001
+
+struct strmap Flag_Map[] = {
+ { "buffered", 0, 0 },
+ { "sync", O_SYNC, 0 },
+#ifdef CRAY
+ { "raw", O_RAW, FLG_RAW },
+ { "raw+wf", O_RAW | O_WELLFORMED, FLG_RAW },
+ { "raw+wf+ldraw", O_RAW | O_WELLFORMED | O_LDRAW, FLG_RAW },
+ { "raw+wf+ldraw+sync", O_RAW | O_WELLFORMED | O_LDRAW | O_SYNC, FLG_RAW },
+#ifdef O_SSD
+ { "ssd", O_SSD, FLG_RAW },
+#endif
+#ifdef O_LDRAW
+ { "ldraw", O_LDRAW, 0 },
+#endif
+#ifdef O_PARALLEL
+ { "parallel", O_PARALLEL | O_RAW | O_WELLFORMED,
+ FLG_RAW },
+ { "parallel+sync", O_PARALLEL | O_RAW | O_WELLFORMED | O_SYNC,
+ FLG_RAW },
+ { "parallel+ldraw", O_PARALLEL | O_RAW | O_WELLFORMED | O_LDRAW,
+ FLG_RAW },
+ { "parallel+ldraw+sync",
+ O_PARALLEL | O_RAW | O_WELLFORMED | O_LDRAW | O_SYNC,
+ FLG_RAW },
+#endif
+#endif /* CRAY */
+
+ { "direct", O_DIRECT, FLG_RAW },
+#ifdef sgi
+ { "dsync", O_DSYNC }, /* affects writes */
+ { "rsync", O_RSYNC }, /* affects reads */
+ { "rsync+dsync", O_RSYNC|O_DSYNC },
+#endif
+ { NULL, -1 }
+};
+
+/*
+ * Map file types to strings
+ */
+
+struct strmap Ftype_Map[] = {
+ { "regular", S_IFREG },
+ { "blk-spec", S_IFBLK },
+ { "chr-spec", S_IFCHR },
+ { NULL, 0 }
+};
+
+/*
+ * Misc declarations
+ */
+
+int Sds_Avail;
+
+char Byte_Patterns[26] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
+ 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
+ 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
+ 'Y', 'Z' };
+
+
+int form_iorequest(struct io_req *);
+int init_output();
+int parse_cmdline(int argc, char **argv, char *opts);
+int help(FILE *stream);
+int usage(FILE *stream);
+
+
+int
+main(argc, argv)
+int argc;
+char **argv;
+{
+ int rseed, outfd, infinite;
+ time_t start_time;
+ struct io_req req;
+
+ umask(0);
+
+#ifdef CRAY
+ Sds_Avail = sysconf(_SC_CRAY_SDS);
+#else
+ Sds_Avail = 0;
+#endif
+
+ TagName[0] = '\0';
+ parse_cmdline(argc, argv, OPTS);
+
+ /*
+ * Initialize output descriptor.
+ */
+ if (! p_opt) {
+ outfd = 1;
+ } else {
+ outfd = init_output();
+ }
+
+ rseed = getpid();
+ random_range_seed(rseed); /* initialize random number generator */
+
+ /*
+ * Print out startup information, unless we're running in quiet mode
+ */
+ if (!q_opt)
+ startup_info(stderr, rseed);
+
+ start_time = time(0);
+
+ /*
+ * While iterations (or forever if Iterations == 0) - compute an
+ * io request, and write the structure to the output descriptor
+ */
+
+ infinite = !Iterations;
+
+ while (infinite ||
+ (! Time_Mode && Iterations--) ||
+ (Time_Mode && time(0) - start_time <= Iterations)) {
+
+ memset(&req, 0, sizeof(struct io_req));
+ if (form_iorequest(&req) == -1) {
+ fprintf(stderr, "iogen%s: form_iorequest() failed\n", TagName);
+ continue;
+ }
+
+ req.r_magic = DOIO_MAGIC;
+ write(outfd, (char *)&req, sizeof(req));
+ }
+
+ exit(0);
+
+} /* main */
+
+void
+startup_info(FILE *stream, int seed)
+{
+ char *value_to_string(), *type;
+ int i;
+
+ fprintf(stream, "\n");
+ fprintf(stream, "iogen%s starting up with the following:\n", TagName);
+ fprintf(stream, "\n");
+
+ fprintf(stream, "Out-pipe: %s\n",
+ p_opt ? Outpipe : "stdout");
+
+ if (Iterations) {
+ fprintf(stream, "Iterations: %d", Iterations);
+ if (Time_Mode)
+ fprintf(stream, " seconds");
+
+ fprintf(stream, "\n");
+ } else {
+ fprintf(stream, "Iterations: Infinite\n");
+ }
+
+ fprintf(stream,
+ "Seed: %d\n", seed);
+
+ fprintf(stream,
+ "Offset-Mode: %s\n", Offset_Mode->m_string);
+
+ fprintf(stream, "Overlap Flag: %s\n",
+ o_opt ? "on" : "off");
+
+ fprintf(stream,
+ "Mintrans: %-11d (%d blocks)\n",
+ Mintrans, (Mintrans+BSIZE-1)/BSIZE);
+
+ fprintf(stream,
+ "Maxtrans: %-11d (%d blocks)\n",
+ Maxtrans, (Maxtrans+BSIZE-1)/BSIZE);
+
+ if (! r_opt)
+ fprintf(stream,
+ "O_RAW/O_SSD Multiple: (Determined by device)\n");
+ else
+ fprintf(stream,
+ "O_RAW/O_SSD Multiple: %-11d (%d blocks)\n",
+ Rawmult, (Rawmult+BSIZE-1)/BSIZE);
+
+ fprintf(stream, "Syscalls: ");
+ for (i = 0; i < Nsyscalls; i++)
+ fprintf(stream,
+ "%s ", Syscall_List[i]->m_string);
+ fprintf(stream, "\n");
+
+ fprintf(stream, "Aio completion types: ");
+ for (i = 0; i < Naio_Strat_Types; i++)
+ fprintf(stream,
+ "%s ", Aio_Strat_List[i]->m_string);
+ fprintf(stream, "\n");
+
+ if (Fileio) {
+ fprintf(stream, "Flags: ");
+ for (i = 0; i < Nflags; i++)
+ fprintf(stream,
+ "%s ", Flag_List[i]->m_string);
+
+ fprintf(stream, "\n");
+ fprintf(stream, "\n");
+ fprintf(stream, "Test Files: \n");
+ fprintf(stream, "\n");
+ fprintf(stream,
+ "Path Length iou raw iou file\n");
+ fprintf(stream,
+ " (bytes) (bytes) (bytes) type\n");
+ fprintf(stream,
+ "-----------------------------------------------------------------------------\n");
+
+ for (i = 0; i < Nfiles; i++) {
+ type = value_to_string(Ftype_Map, File_List[i].f_type);
+ fprintf(stream, "%-40s %12d %7d %7d %s\n",
+ File_List[i].f_path, File_List[i].f_length,
+ File_List[i].f_iou, File_List[i].f_riou, type);
+ }
+ }
+}
+
+/*
+ * Initialize output descriptor. If going to stdout, its easy,
+ * otherwise, attempt to create a FIFO on path Outpipe. Exit with an
+ * error code if this cannot be done.
+ */
+int
+init_output()
+{
+ int outfd;
+ struct stat sbuf;
+
+ if (stat(Outpipe, &sbuf) == -1) {
+ if (errno == ENOENT) {
+ if (mkfifo(Outpipe, 0666) == -1) {
+ fprintf(stderr, "iogen%s: Could not mkfifo %s: %s\n",
+ TagName, Outpipe, SYSERR);
+ exit(2);
+ }
+ } else {
+ fprintf(stderr, "iogen%s: Could not stat outpipe %s: %s\n",
+ TagName, Outpipe, SYSERR);
+ exit(2);
+ }
+ } else {
+ if (! S_ISFIFO(sbuf.st_mode)) {
+ fprintf(stderr,
+ "iogen%s: Output file %s exists, but is not a FIFO\n",
+ TagName, Outpipe);
+ exit(2);
+ }
+ }
+
+ if ((outfd = open(Outpipe, O_RDWR)) == -1) {
+ fprintf(stderr,
+ "iogen%s: Couldn't open outpipe %s with flags O_RDWR: %s\n",
+ TagName, Outpipe, SYSERR);
+ exit(2);
+ }
+
+ return(outfd);
+}
+
+
+/*
+ * Main io generation function. form_iorequest() selects a system call to
+ * do based on cmdline arguments, and proceeds to select parameters for that
+ * system call.
+ *
+ * Returns 0 if req is filled in with a complete doio request, otherwise
+ * returns -1.
+ */
+
+int
+form_iorequest(req)
+struct io_req *req;
+{
+ int mult, offset = 0, length = 0, slength;
+ int minlength, maxlength, laststart, lastend;
+ int minoffset, maxoffset;
+ int maxstride, nstrides;
+ char pattern, *errp;
+ struct strmap *flags, *sc, *aio_strat;
+ struct file_info *fptr;
+#ifdef CRAY
+ int opcode, cmd;
+#endif
+
+ /*
+ * Choose system call, flags, and file
+ */
+
+ sc = Syscall_List[random_range(0, Nsyscalls-1, 1, NULL)];
+ req->r_type = sc->m_value;
+
+#ifdef CRAY
+ if (sc->m_value == LISTIO ) {
+ opcode = random_range(0, 1, 1, NULL) ? LO_READ : LO_WRITE;
+ cmd = random_range(0, 1, 1, NULL) ? LC_START : LC_WAIT;
+ }
+#endif
+
+ if( sc->m_flags & SY_WRITE )
+ pattern = Byte_Patterns[random_range(0, sizeof(Byte_Patterns) - 1, 1, NULL)];
+ else
+ pattern = 0;
+
+#if CRAY
+ /*
+ * If sds io, simply choose a length (possibly pattern) and return
+ */
+
+ if (sc->m_flags & SY_SDS ) {
+ req->r_data.ssread.r_nbytes = random_range(Mintrans, Maxtrans, BSIZE, NULL);
+ if (sc->m_flags & SY_WRITE)
+ req->r_data.sswrite.r_pattern = pattern;
+
+ return 0;
+ }
+#endif
+
+ /*
+ * otherwise, we're doing file io. Choose starting offset, length,
+ * open flags, and possibly a pattern (for write/writea).
+ */
+
+ fptr = &File_List[random_range(0, Nfiles-1, 1, NULL)];
+ flags = Flag_List[random_range(0, Nflags-1, 1, NULL)];
+
+ /*
+ * Choose offset/length multiple. IO going to a device, or regular
+ * IO that is O_RAW or O_SSD must be aligned on the file r_iou. Otherwise
+ * it must be aligned on the regular iou (normally 1).
+ */
+
+ if ( fptr->f_type == S_IFREG && (flags->m_flags & FLG_RAW) )
+ mult = fptr->f_riou;
+ else
+ mult = fptr->f_iou;
+
+ /*
+ * Choose offset and length. Both must be a multiple of mult
+ */
+
+ /*
+ * Choose length first - it must be a multiple of mult
+ */
+
+ laststart = fptr->f_lastoffset;
+ lastend = fptr->f_lastoffset + fptr->f_lastlength - 1;
+
+ minlength = (Mintrans > mult) ? Mintrans : mult;
+
+ switch (Offset_Mode->m_value) {
+ case M_SEQUENTIAL:
+ if (o_opt && lastend > laststart)
+ offset = random_range(laststart, lastend, 1, NULL);
+ else
+ offset = lastend + 1;
+ if (offset && (offset%mult))
+ offset += mult - (offset % mult);
+
+ if (minlength > fptr->f_length - offset)
+ offset = 0;
+
+ maxlength = fptr->f_length - offset;
+ if (maxlength > Maxtrans)
+ maxlength = Maxtrans;
+
+ length = random_range(minlength, maxlength, mult, &errp);
+ if (errp != NULL) {
+ fprintf(stderr, "iogen%s: random_range(%d, %d, %d) failed\n",
+ TagName, minlength, maxlength, mult);
+ return -1;
+ }
+
+ break;
+
+ case M_REVERSE:
+ maxlength = laststart;
+
+ if (maxlength > Maxtrans)
+ maxlength = Maxtrans;
+
+ if (minlength > maxlength) {
+ laststart = fptr->f_length;
+ lastend = fptr->f_length;
+ maxlength = Maxtrans;
+ }
+
+ length = random_range(minlength, maxlength, mult, &errp);
+ if (errp != NULL) {
+ fprintf(stderr, "iogen%s: random_range(%d, %d, %d) failed\n",
+ TagName, minlength, maxlength, mult);
+ return -1;
+ }
+
+ offset = laststart - length;
+
+ if (o_opt && lastend > laststart)
+ offset += random_range(1, lastend - laststart, 1, NULL);
+
+ if (offset && (offset%mult))
+ offset -= offset % mult;
+
+ break;
+
+ case M_RANDOM:
+ length = random_range(Mintrans, Maxtrans, mult, NULL);
+
+ if (o_opt && lastend > laststart) {
+ minoffset = laststart - length + 1;
+ if (minoffset < 0) {
+ minoffset = 0;
+ }
+
+ if (lastend + length > fptr->f_length) {
+ maxoffset = fptr->f_length - length;
+ } else {
+ maxoffset = lastend;
+ }
+ } else {
+ minoffset = 0;
+ maxoffset = fptr->f_length - length;
+ }
+
+ if (minoffset < 0)
+ minoffset = 0;
+
+ offset = random_range(minoffset, maxoffset, mult, &errp);
+ if (errp != NULL) {
+ fprintf(stderr, "iogen%s: random_range(%d, %d, %d) failed\n",
+ TagName, minoffset, maxoffset, mult);
+ return -1;
+ }
+ }
+
+ fptr->f_lastoffset = offset;
+ fptr->f_lastlength = length;
+
+ /*
+ * Choose an async io completion strategy if necessary
+ */
+ if( sc->m_flags & SY_ASYNC )
+ aio_strat = Aio_Strat_List[random_range(0, Naio_Strat_Types - 1,
+ 1, NULL)];
+ else
+ aio_strat = NULL;
+
+ /*
+ * fill in specific syscall record data
+ */
+ switch (sc->m_value) {
+ case READ:
+ case READA:
+ strcpy(req->r_data.read.r_file, fptr->f_path);
+ req->r_data.read.r_oflags = O_RDONLY | flags->m_value;
+ req->r_data.read.r_offset = offset;
+ req->r_data.read.r_nbytes = length;
+ req->r_data.read.r_uflags = (flags->m_flags & FLG_RAW) ? F_WORD_ALIGNED : 0;
+ req->r_data.read.r_aio_strat = (aio_strat==NULL) ? 0 : aio_strat->m_value;
+ req->r_data.read.r_nstrides = 1;
+ req->r_data.read.r_nent = 1;
+ break;
+
+ case WRITE:
+ case WRITEA:
+ strcpy(req->r_data.write.r_file, fptr->f_path);
+ req->r_data.write.r_oflags = O_WRONLY | flags->m_value;
+ req->r_data.write.r_offset = offset;
+ req->r_data.write.r_nbytes = length;
+ req->r_data.write.r_pattern = pattern;
+ req->r_data.write.r_uflags = (flags->m_flags & FLG_RAW) ? F_WORD_ALIGNED : 0;
+ req->r_data.write.r_aio_strat = (aio_strat==NULL) ? 0 : aio_strat->m_value;
+ req->r_data.write.r_nstrides = 1;
+ req->r_data.write.r_nent = 1;
+ break;
+
+ case READV:
+ case AREAD:
+ case PREAD:
+ case WRITEV:
+ case AWRITE:
+ case PWRITE:
+
+ case LREAD:
+ case LREADA:
+ case LWRITE:
+ case LWRITEA:
+
+ case RESVSP:
+ case UNRESVSP:
+ case FSYNC2:
+ case FDATASYNC:
+
+ strcpy(req->r_data.io.r_file, fptr->f_path);
+ req->r_data.io.r_oflags = ((sc->m_flags & SY_WRITE) ? O_WRONLY : O_RDONLY) | flags->m_value;
+ req->r_data.io.r_offset = offset;
+ req->r_data.io.r_nbytes = length;
+ req->r_data.io.r_pattern = pattern;
+ req->r_data.io.r_uflags = (flags->m_flags & FLG_RAW) ? F_WORD_ALIGNED : 0;
+ req->r_data.io.r_aio_strat = (aio_strat==NULL) ? 0 : aio_strat->m_value;
+ req->r_data.io.r_nstrides = 1;
+ req->r_data.io.r_nent = 1;
+ break;
+
+ case MMAPR:
+ case MMAPW:
+ strcpy(req->r_data.io.r_file, fptr->f_path);
+ /* a subtle "feature" of mmap: a write-map requires
+ the file open read/write */
+ req->r_data.io.r_oflags = ((sc->m_flags & SY_WRITE) ? O_RDWR : O_RDONLY) | flags->m_value;
+ req->r_data.io.r_offset = offset;
+ req->r_data.io.r_nbytes = length;
+ req->r_data.io.r_pattern = pattern;
+ req->r_data.io.r_uflags = (flags->m_flags & FLG_RAW) ? F_WORD_ALIGNED : 0;
+ req->r_data.io.r_aio_strat = (aio_strat==NULL) ? 0 : aio_strat->m_value;
+ req->r_data.io.r_nstrides = 1;
+ req->r_data.io.r_nent = 1;
+ break;
+
+ case LSREAD:
+ case LSREADA:
+ case LEREAD:
+ case LEREADA:
+ case LSWRITE:
+ case LSWRITEA:
+ case LEWRITE:
+ case LEWRITEA:
+ /* multi-strided */
+ strcpy(req->r_data.io.r_file, fptr->f_path);
+ req->r_data.io.r_oflags = ((sc->m_flags & SY_WRITE) ? O_WRONLY : O_RDONLY) | flags->m_value;
+ req->r_data.io.r_offset = offset;
+ req->r_data.io.r_uflags = (flags->m_flags & FLG_RAW) ? F_WORD_ALIGNED : 0;
+ req->r_data.io.r_aio_strat = (aio_strat==NULL) ? 0 : aio_strat->m_value;
+ req->r_data.io.r_pattern = pattern;
+
+ /* multi-strided request...
+ * random number of strides (1...MaxStrides)
+ * length of stride must be > minlength
+ * length of stride must be % mult
+ *
+ * maxstrides = min(length / mult, overall.max#strides)
+ * nstrides = random #
+ * while( length / nstrides < minlength )
+ * nstrides = new random #
+ */
+ maxstride = length / mult;
+ if(maxstride > Maxstrides)
+ maxstride = Maxstrides;
+
+ if(!Minstrides)
+ Minstrides=1;
+ nstrides = random_range(Minstrides, maxstride, 1, &errp);
+ if (errp != NULL) {
+ fprintf(stderr, "iogen%s: random_range(%d, %d, %d) failed\n",
+ TagName, Minstrides, maxstride, 1);
+ return -1;
+ }
+
+ slength = length / nstrides;
+ if(slength % mult != 0) {
+ if( mult > slength) {
+ slength = mult;
+ } else {
+ slength -= slength % mult;
+ }
+ nstrides = length / slength;
+ if(nstrides > Maxstrides)
+ nstrides = Maxstrides;
+ }
+
+ req->r_data.io.r_nbytes = slength;
+ if( sc->m_flags & SY_NENT ) {
+ req->r_data.io.r_nstrides = 1;
+ req->r_data.io.r_nent = nstrides;
+ } else {
+ req->r_data.io.r_nstrides = nstrides;
+ req->r_data.io.r_nent = 1;
+ }
+ break;
+
+ case LISTIO:
+#ifdef CRAY
+ strcpy(req->r_data.listio.r_file, fptr->f_path);
+ req->r_data.listio.r_offset = offset;
+ req->r_data.listio.r_cmd = cmd;
+ req->r_data.listio.r_aio_strat = (aio_strat==NULL) ? 0 : aio_strat->m_value;
+ req->r_data.listio.r_filestride = 0;
+ req->r_data.listio.r_memstride = 0;
+ req->r_data.listio.r_opcode = opcode;
+ req->r_data.listio.r_nstrides = 1;
+ req->r_data.listio.r_nbytes = length;
+ req->r_data.listio.r_uflags = (flags->m_flags & FLG_RAW) ? F_WORD_ALIGNED : 0;
+
+ if (opcode == LO_WRITE) {
+ req->r_data.listio.r_pattern = pattern;
+ req->r_data.listio.r_oflags = O_WRONLY | flags->m_value;
+ } else {
+ req->r_data.listio.r_oflags = O_RDONLY | flags->m_value;
+ }
+#endif
+ break;
+ }
+
+ return 0;
+}
+
+/*
+ * Get information about a file that iogen uses to choose io length and
+ * offset. Information gathered is file length, iounit, and raw iounit.
+ * For regurlar files, iounit is 1, and raw iounit is the iounit of the
+ * device on which the file resides. For block/character special files
+ * the iounit and raw iounit are both the iounit of the device.
+ *
+ * Note: buffered and osync io must be iounit aligned
+ * raw and ossd io must be raw iounit aligned
+ */
+
+int
+get_file_info(rec)
+struct file_info *rec;
+{
+ struct stat sbuf;
+#ifdef CRAY
+ struct lk_device_info dinfo;
+#endif
+#ifndef NO_XFS
+ int fd;
+ struct dioattr finfo;
+#endif
+
+ /*
+ * Figure out if the files is regular, block or character special. Any
+ * other type is an error.
+ */
+
+ if (stat(rec->f_path, &sbuf) == -1) {
+ fprintf(stderr, "iogen%s: get_file_info(): Could not stat() %s: %s\n",
+ TagName, rec->f_path, SYSERR);
+ return -1;
+ }
+
+#if _CRAY2
+ if ((! S_ISREG(sbuf.st_mode)) || strncmp(rec->f_path, "/dev/", 5) == 0) {
+ fprintf(stderr, "iogen%s: device level io not supported on cray2\n", TagName);
+ return -1;
+ }
+#endif
+
+ rec->f_type = sbuf.st_mode & S_IFMT;
+
+ /*
+ * If regular, iou is 1, and we must figure out the device on
+ * which the file resides. riou is the iou (logical sector size) of
+ * this device.
+ */
+
+ if (S_ISREG(sbuf.st_mode)) {
+ rec->f_iou = 1;
+ rec->f_length = sbuf.st_size;
+
+ /*
+ * If -r used, take Rawmult as the raw/ssd io multiple. Otherwise
+ * attempt to determine it by looking at the device the file
+ * resides on.
+ */
+
+ if (r_opt) {
+ rec->f_riou = Rawmult;
+ return 0;
+ }
+
+ rec->f_riou = BSIZE;
+#ifdef CRAY
+ if (lk_rawdev(rec->f_path, dinfo.path, sizeof(dinfo.path), 0) == -1)
+ return -1;
+
+ if (lk_devinfo(&dinfo, 0) == -1) {
+ /* can't get raw I/O unit -- use stat to fudge it */
+ rec->f_riou = sbuf.st_blksize;
+ } else {
+ rec->f_riou = ctob(dinfo.iou);
+ }
+#endif
+#ifndef NO_XFS
+ if( (fd = open(rec->f_path, O_RDWR|O_DIRECT, 0)) != -1 ) {
+ if(xfsctl(rec->f_path, fd, XFS_IOC_DIOINFO, &finfo) != -1) {
+ rec->f_riou = finfo.d_miniosz;
+ } else {
+ fprintf(stderr,
+ "iogen%s: Error %s (%d) getting direct I/O info of file %s\n",
+ TagName, strerror(errno), errno, rec->f_path);
+ }
+ close(fd);
+ } else {
+ rec->f_riou = BBSIZE;
+ }
+#endif
+
+ } else {
+
+#ifdef CRAY
+ /*
+ * Otherwise, file is a device. Use lk_devinfo() to get its logical
+ * sector size. This is the iou and riou
+ */
+
+ strcpy(dinfo.path, rec->f_path);
+
+ if (lk_devinfo(&dinfo, 0) == -1) {
+ fprintf(stderr, "iogen%s: %s: %s\n", TagName, Lk_err_func, Lk_err_mesg);
+ return -1;
+ }
+
+ rec->f_iou = ctob(dinfo.iou);
+ rec->f_riou = ctob(dinfo.iou);
+ rec->f_length = ctob(dinfo.length);
+#else
+#ifdef sgi
+ rec->f_riou = BBSIZE;
+ rec->f_length = BBSIZE;
+#else
+ rec->f_riou = BSIZE;
+ rec->f_length = BSIZE;
+#endif /* sgi */
+#endif /* CRAY */
+ }
+
+ return 0;
+}
+
+/*
+ * Create file path as nbytes long. If path exists, the file will either be
+ * extended or truncated to be nbytes long. Returns final size of file,
+ * or -1 if there was a failure.
+ */
+
+int
+create_file(path, nbytes)
+char *path;
+int nbytes;
+{
+ int fd, rval;
+ char c;
+ struct stat sbuf;
+#ifndef NO_XFS
+ int nb;
+ struct xfs_flock64 f;
+ struct fsxattr xattr;
+ struct dioattr finfo;
+ char *b, *buf;
+#endif
+
+ errno = 0;
+ rval = stat(path, &sbuf);
+
+ if (rval == -1) {
+ if (errno == ENOENT) {
+ sbuf.st_size = 0;
+ } else {
+ fprintf(stderr, "iogen%s: Could not stat file %s: %s (%d)\n",
+ TagName, path, SYSERR, errno);
+ return -1;
+ }
+ } else {
+ if (! S_ISREG(sbuf.st_mode)) {
+ fprintf(stderr,
+ "iogen%s: file %s exists, but is not a regular file - cannot modify length\n",
+ TagName, path);
+ return -1;
+ }
+ }
+
+ if (sbuf.st_size == nbytes)
+ return nbytes;
+
+ Oflags |= O_CREAT | O_WRONLY;
+
+ if ((fd = open(path, Oflags, 0666, Ocbits, Ocblks)) == -1) {
+ fprintf(stderr, "iogen%s: Could not create/open file %s: %s (%d)\n",
+ TagName, path, SYSERR, errno);
+ return -1;
+ }
+
+ /*
+ * Truncate file if it is longer than nbytes, otherwise attempt to
+ * pre-allocate file blocks.
+ */
+
+ if (sbuf.st_size > nbytes) {
+ if (ftruncate(fd, nbytes) == -1) {
+ fprintf(stderr,
+ "iogen%s: Could not ftruncate() %s to %d bytes: %s (%d)\n",
+ TagName, path, nbytes, SYSERR, errno);
+ close(fd);
+ return -1;
+ }
+ } else {
+
+#ifndef NO_XFS
+ /*
+ * The file must be designated as Real-Time before any data
+ * is allocated to it.
+ *
+ */
+ if(Orealtime != 0) {
+ bzero(&xattr, sizeof(xattr));
+ xattr.fsx_xflags = XFS_XFLAG_REALTIME;
+ /*fprintf(stderr, "set: fsx_xflags = 0x%x\n", xattr.fsx_xflags);*/
+ if( xfsctl(path, fd, XFS_IOC_FSSETXATTR, &xattr) == -1 ) {
+ fprintf(stderr, "iogen%s: Error %s (%d) setting XFS XATTR->Realtime on file %s\n",
+ TagName, SYSERR, errno, path);
+ close(fd);
+ return -1;
+ }
+
+#ifdef DEBUG
+ if( xfsctl(path, fd, XFS_IOC_FSGETXATTR, &xattr) == -1 ) {
+ fprintf(stderr, "iogen%s: Error getting realtime flag %s (%d)\n",
+ TagName, SYSERR, errno);
+ close(fd);
+ return -1;
+ } else {
+ fprintf(stderr, "get: fsx_xflags = 0x%x\n",
+ xattr.fsx_xflags);
+ }
+#endif
+ }
+
+ /*
+ * Reserve space
+ *
+ * Failure is ignored since XFS_IOC_RESVSP only works on XFS and the
+ * filesystem could be on some otehr filesystem.
+ */
+ if( Oreserve ) {
+ f.l_whence = SEEK_SET;
+ f.l_start = 0;
+ f.l_len = nbytes;
+
+ /*fprintf(stderr,
+ "create_file: xfsctl(%d, RESVSP, { %d, %lld, %lld })\n",
+ fd, f.l_whence, (long long)f.l_start, (long long)f.l_len);*/
+
+ /* non-zeroing reservation */
+ if( xfsctl( path, fd, XFS_IOC_RESVSP, &f ) == -1) {
+ fprintf(stderr,
+ "iogen%s: Could not xfsctl(XFS_IOC_RESVSP) %d bytes in file %s: %s (%d)\n",
+ TagName, nbytes, path, SYSERR, errno);
+ close(fd);
+ return -1;
+ }
+ }
+
+ if( Oallocate ) {
+ /* XFS_IOC_ALLOCSP allocates from the file start to l_start */
+ f.l_whence = SEEK_SET;
+ f.l_start = nbytes;
+ f.l_len = 0;
+ /*fprintf(stderr,
+ "create_file: xfsctl(%d, XFS_IOC_ALLOCSP, { %d, %lld, %lld })\n",
+ fd, f.l_whence, (long long)f.l_start,
+ (long long)f.l_len);*/
+
+ /* zeroing reservation */
+ if( xfsctl( path, fd, XFS_IOC_ALLOCSP, &f ) == -1) {
+ fprintf(stderr,
+ "iogen%s: Could not xfsctl(XFS_IOC_ALLOCSP) %d bytes in file %s: %s (%d)\n",
+ TagName, nbytes, path, SYSERR, errno);
+ close(fd);
+ return -1;
+ }
+ }
+#endif
+
+ /*
+ * Write a byte at the end of file so that stat() sets the right
+ * file size.
+ */
+
+#ifndef NO_XFS
+ if(Owrite == 2) {
+ close(fd);
+ if( (fd = open(path, O_CREAT|O_RDWR|O_DIRECT, 0)) != -1 ) {
+ if(xfsctl(path, fd, XFS_IOC_DIOINFO, &finfo) == -1) {
+ fprintf(stderr,
+ "iogen%s: Error %s (%d) getting direct I/O info for file %s\n",
+ TagName, SYSERR, errno, path);
+ return -1;
+ } else {
+ /*fprintf(stderr, "%s: miniosz=%d\n",
+ path, finfo.d_miniosz);*/
+ }
+ } else {
+ fprintf(stderr, "iogen%s: Error %s (%d) opening file %s with flags O_CREAT|O_RDWR|O_DIRECT\n",
+ TagName, SYSERR, errno, path);
+ return -1;
+ }
+
+ /*
+ * nb is nbytes adjusted down by an even d_miniosz block
+ *
+ * Note: the first adjustment can cause iogen to print a warning
+ * about not being able to create a file of <nbytes> length,
+ * since the file will be shorter.
+ */
+ nb = nbytes-finfo.d_miniosz;
+ nb = nb-nb%finfo.d_miniosz;
+
+ /*fprintf(stderr,
+ "create_file_ow2: lseek(%d, %d {%d %d}, SEEK_SET)\n",
+ fd, nb, nbytes, finfo.d_miniosz);*/
+
+ if (lseek(fd, nb, SEEK_SET) == -1) {
+ fprintf(stderr,
+ "iogen%s: Could not lseek() to EOF of file %s: %s (%d)\n\tactual offset %d file size goal %d miniosz %lld\n",
+ TagName, path, SYSERR, errno,
+ nb, nbytes, (long long)finfo.d_miniosz);
+ close(fd);
+ return -1;
+ }
+
+ b = buf = (char *)malloc(finfo.d_miniosz+finfo.d_mem);
+
+ if( ((long)buf % finfo.d_mem != 0) ) {
+ buf += finfo.d_mem - ((long)buf % finfo.d_mem);
+ }
+
+ memset(buf, 0, finfo.d_miniosz);
+
+ if ( (rval=write(fd, buf, finfo.d_miniosz)) != finfo.d_miniosz) {
+ fprintf(stderr,
+ "iogen%s: Could not write %d byte length file %s: %s (%d)\n",
+ TagName, nb, path, SYSERR, errno);
+ fprintf(stderr,
+ "\twrite(%d, 0x%lx, %d) = %d\n",
+ fd, (long)buf, finfo.d_miniosz, rval);
+ fprintf(stderr,
+ "\toffset %d file size goal %d, miniosz=%d\n",
+ nb, nbytes, finfo.d_miniosz);
+ close(fd);
+ return -1;
+ }
+ free(b);
+ } else
+#endif
+ if(Owrite) {
+ /*fprintf(stderr,
+ "create_file_Owrite: lseek(%d, %d {%d}, SEEK_SET)\n",
+ fd, nbytes-1, nbytes);*/
+
+ if (lseek(fd, nbytes-1, SEEK_SET) == -1) {
+ fprintf(stderr,
+ "iogen%s: Could not lseek() to EOF in file %s: %s (%d)\n\toffset goal %d\n",
+ TagName, path, SYSERR, errno,
+ nbytes-1);
+ close(fd);
+ return -1;
+ }
+
+ if ( (rval=write(fd, &c, 1)) != 1) {
+ fprintf(stderr,
+ "iogen%s: Could not create a %d byte length file %s: %s (%d)\n",
+ TagName, nbytes, path, SYSERR, errno);
+ fprintf(stderr,
+ "\twrite(%d, 0x%lx, %d) = %d\n",
+ fd, (long)&c, 1, rval);
+ fprintf(stderr,
+ "\toffset %d file size goal %d\n",
+ nbytes-1, nbytes);
+ close(fd);
+ return -1;
+ }
+ }
+ }
+
+ fstat(fd, &sbuf);
+ close(fd);
+
+ return sbuf.st_size;
+}
+
+/*
+ * Function to convert a string to its corresponding value in a strmap array.
+ * If the string is not found in the array, the value corresponding to the
+ * NULL string (the last element in the array) is returned.
+ */
+
+int
+str_to_value(map, str)
+struct strmap *map;
+char *str;
+{
+ struct strmap *mp;
+
+ for (mp = map; mp->m_string != NULL; mp++)
+ if (strcmp(mp->m_string, str) == 0)
+ break;
+
+ return mp->m_value;
+}
+
+/*
+ * Function to convert a string to its corresponding entry in a strmap array.
+ * If the string is not found in the array, a NULL is returned.
+ */
+
+struct strmap *
+str_lookup(map, str)
+struct strmap *map;
+char *str;
+{
+ struct strmap *mp;
+
+ for (mp = map; mp->m_string != NULL; mp++)
+ if (strcmp(mp->m_string, str) == 0)
+ break;
+
+ return((mp->m_string == NULL) ? NULL : mp);
+}
+
+
+/*
+ * Function to convert a value to its corresponding string in a strmap array.
+ * If the value is not found in the array, NULL is returned.
+ */
+
+char *
+value_to_string(map, val)
+struct strmap *map;
+int val;
+{
+ struct strmap *mp;
+
+ for (mp = map; mp->m_string != NULL; mp++)
+ if (mp->m_value == val)
+ break;
+
+ return mp->m_string;
+}
+
+/*
+ * Interpret cmdline options/arguments. Exit with 1 if something on the
+ * cmdline isn't kosher.
+ */
+
+int
+parse_cmdline(argc, argv, opts)
+int argc;
+char **argv;
+char *opts;
+{
+ int o, len, nb, format_error;
+ struct strmap *flgs, *sc;
+ char *file, *cp, ch;
+ struct strmap *mp;
+ struct file_info *fptr;
+ int nopenargs;
+ char *openargs[5]; /* Flags, cbits, cblks */
+#ifdef CRAY
+ char *errmsg;
+ char *ranges;
+ struct strmap *type;
+#endif
+
+ while ((o = getopt(argc, argv, opts)) != EOF) {
+ switch ((char)o) {
+
+ case 'a':
+#ifndef CRAY
+ fprintf(stderr, "iogen%s: Unrecognized option -a on this platform\n", TagName);
+ exit(2);
+#else
+ cp = strtok(optarg, ",");
+ while (cp != NULL) {
+ if ((type = str_lookup(Aio_Strat_Map, cp)) == NULL) {
+ fprintf(stderr, "iogen%s: Unrecognized aio completion strategy: %s\n", TagName, cp);
+ exit(2);
+ }
+
+ Aio_Strat_List[Naio_Strat_Types++] = type;
+ cp = strtok(NULL, ",");
+ }
+ a_opt++;
+#endif
+ break;
+
+ case 'f':
+ cp = strtok(optarg, ",");
+ while (cp != NULL) {
+ if( (flgs = str_lookup(Flag_Map, cp)) == NULL ) {
+ fprintf(stderr, "iogen%s: Unrecognized flags: %s\n", TagName, cp);
+ exit(2);
+ }
+
+ cp = strtok(NULL, ",");
+
+#ifdef O_SSD
+ if (flgs->m_value & O_SSD && ! Sds_Avail) {
+ fprintf(stderr, "iogen%s: Warning - no sds available, ignoring ssd flag\n", TagName);
+ continue;
+ }
+#endif
+
+ Flag_List[Nflags++] = flgs;
+ }
+ f_opt++;
+ break;
+
+ case 'h':
+ help(stdout);
+ exit(0);
+ break;
+
+ case 'i':
+ format_error = 0;
+
+ switch (sscanf(optarg, "%i%c", &Iterations, &ch)) {
+ case 1:
+ Time_Mode = 0;
+ break;
+
+ case 2:
+ if (ch == 's')
+ Time_Mode = 1;
+ else
+ format_error = 1;
+ break;
+
+ default:
+ format_error = 1;
+ }
+
+ if (Iterations < 0)
+ format_error = 1;
+
+ if (format_error) {
+ fprintf(stderr, "iogen%s: Illegal -i arg (%s): Must be of the format: number[s]\n", TagName, optarg);
+ fprintf(stderr, " where 'number' is >= 0\n");
+ exit(1);
+ }
+
+ i_opt++;
+ break;
+
+ case 'L':
+#ifndef CRAY
+ fprintf(stderr, "iogen%s: Unrecognized option -L on this platform\n", TagName);
+ exit(2);
+#else
+ if( parse_ranges(optarg, 1, 255, 1, NULL, &ranges,
+ &errmsg ) == -1 ) {
+ fprintf(stderr, "iogen%s: error parsing listio range '%s': %s\n",
+ TagName, optarg, errmsg);
+ exit(1);
+ }
+
+ Minstrides = range_min(ranges, 0);
+ Maxstrides = range_max(ranges, 0);
+
+ free(ranges);
+ L_opt++;
+#endif
+ break;
+
+ case 'm':
+ if ((Offset_Mode = str_lookup(Omode_Map, optarg)) == NULL) {
+ fprintf(stderr, "iogen%s: Illegal -m arg (%s)\n", TagName, optarg);
+ exit(1);
+ }
+
+ m_opt++;
+ break;
+
+ case 'N':
+ sprintf( TagName, "(%.39s)", optarg );
+ break;
+
+ case 'o':
+ o_opt++;
+ break;
+
+ case 'O':
+
+ nopenargs = string_to_tokens(optarg, openargs, 4, ":/");
+
+#ifdef CRAY
+ if(nopenargs)
+ sscanf(openargs[1],"%i", &Ocbits);
+ if(nopenargs > 1)
+ sscanf(openargs[2],"%i", &Ocblks);
+
+ Oflags = parse_open_flags(openargs[0], &errmsg);
+ if(Oflags == -1) {
+ fprintf(stderr, "iogen%s: -O %s error: %s\n", TagName, optarg, errmsg);
+ exit(1);
+ }
+#endif
+#ifndef NO_XFS
+ if(!strcmp(openargs[0], "realtime")) {
+ /*
+ * -O realtime:extsize
+ */
+ Orealtime = 1;
+ if(nopenargs > 1)
+ sscanf(openargs[1],"%i", &Oextsize);
+ else
+ Oextsize=0;
+ } else if( !strcmp(openargs[0], "allocate") ||
+ !strcmp(openargs[0], "allocsp")) {
+ /*
+ * -O allocate
+ */
+ Oreserve=0;
+ Oallocate=1;
+ } else if(!strcmp(openargs[0], "reserve")) {
+ /*
+ * -O [no]reserve
+ */
+ Oallocate=0;
+ Oreserve=1;
+ } else if(!strcmp(openargs[0], "noreserve")) {
+ /* Oreserve=1 by default; this clears that default */
+ Oreserve=0;
+ } else if(!strcmp(openargs[0], "nowrite")) {
+ /* Owrite=1 by default; this clears that default */
+ Owrite=0;
+ } else if(!strcmp(openargs[0], "direct")) {
+ /* this means "use direct i/o to preallocate file" */
+ Owrite=2;
+ } else {
+ fprintf(stderr, "iogen%s: Error: -O %s error: unrecognized option\n",
+ TagName, openargs[0]);
+ exit(1);
+ }
+#else
+ Oflags = parse_open_flags(openargs[0], &errmsg);
+ if(Oflags == -1) {
+ fprintf(stderr, "iogen%s: -O %s error: %s\n", TagName, optarg, errmsg);
+ exit(1);
+ }
+#endif
+
+ O_opt++;
+ break;
+
+ case 'p':
+ Outpipe = optarg;
+ p_opt++;
+ break;
+
+ case 'r':
+ if ((Rawmult = str_to_bytes(optarg)) == -1 ||
+ Rawmult < 11 || Rawmult % BSIZE) {
+ fprintf(stderr, "iogen%s: Illegal -r arg (%s). Must be > 0 and multipe of BSIZE (%d)\n",
+ TagName, optarg, BSIZE);
+ exit(1);
+ }
+
+ r_opt++;
+ break;
+
+ case 's':
+ cp = strtok(optarg, ",");
+ while (cp != NULL) {
+ if ((sc = str_lookup(Syscall_Map, cp)) == NULL) {
+ fprintf(stderr, "iogen%s: Unrecognized syscall: %s\n", TagName, cp);
+ exit(2);
+ }
+
+ do {
+ /* >>> sc->m_flags & FLG_SDS */
+ if (sc->m_value != SSREAD && sc->m_value != SSWRITE)
+ Fileio++;
+
+ Syscall_List[Nsyscalls++] = sc;
+ } while ( (sc = str_lookup(++sc, cp)) != NULL);
+
+ cp = strtok(NULL, ",");
+ }
+ s_opt++;
+ break;
+
+ case 't':
+ if ((Mintrans = str_to_bytes(optarg)) == -1) {
+ fprintf(stderr, "iogen%s: Illegal -t arg (%s): Must have the form num[bkm]\n", TagName, optarg);
+ exit(1);
+ }
+ t_opt++;
+ break;
+
+ case 'T':
+ if ((Maxtrans = str_to_bytes(optarg)) == -1) {
+ fprintf(stderr, "iogen%s: Illegal -T arg (%s): Must have the form num[bkm]\n", TagName, optarg);
+ exit(1);
+ }
+ T_opt++;
+ break;
+
+ case 'q':
+ q_opt++;
+ break;
+
+ case '?':
+ usage(stderr);
+ exit(1);
+ }
+ }
+
+ /*
+ * Supply defaults
+ */
+
+ if( ! L_opt ) {
+ Minstrides = 1;
+ Maxstrides = 255;
+ }
+
+ if (! m_opt)
+ Offset_Mode = str_lookup(Omode_Map, "sequential");
+
+ if (! i_opt)
+ Iterations = 0;
+
+ if (! t_opt)
+ Mintrans = 1;
+
+ if (! T_opt)
+ Maxtrans = 256 * BSIZE;
+
+ if( ! O_opt)
+ Oflags = Ocbits = Ocblks = 0;
+
+ /*
+ * Supply default async io completion strategy types.
+ */
+
+ if (! a_opt) {
+ for (mp = Aio_Strat_Map; mp->m_string != NULL; mp++) {
+ Aio_Strat_List[Naio_Strat_Types++] = mp;
+ }
+ }
+
+ /*
+ * Supply default syscalls. Default is read,write,reada,writea,listio.
+ */
+
+ if (! s_opt) {
+ Nsyscalls = 0;
+ Syscall_List[Nsyscalls++] = str_lookup(Syscall_Map, "read");
+ Syscall_List[Nsyscalls++] = str_lookup(Syscall_Map, "write");
+#ifdef CRAY
+ Syscall_List[Nsyscalls++] = str_lookup(Syscall_Map, "reada");
+ Syscall_List[Nsyscalls++] = str_lookup(Syscall_Map, "writea");
+ Syscall_List[Nsyscalls++] = str_lookup(Syscall_Map, "lread");
+ Syscall_List[Nsyscalls++] = str_lookup(Syscall_Map, "lreada");
+ Syscall_List[Nsyscalls++] = str_lookup(Syscall_Map, "lwrite");
+ Syscall_List[Nsyscalls++] = str_lookup(Syscall_Map, "lwritea");
+#endif
+
+ Syscall_List[Nsyscalls++] = str_lookup(Syscall_Map, "pread");
+ Syscall_List[Nsyscalls++] = str_lookup(Syscall_Map, "pwrite");
+#ifdef sgi
+ /*Syscall_List[Nsyscalls++] = str_lookup(Syscall_Map, "aread");*/
+ /*Syscall_List[Nsyscalls++] = str_lookup(Syscall_Map, "awrite");*/
+#endif
+
+#ifndef CRAY
+ Syscall_List[Nsyscalls++] = str_lookup(Syscall_Map, "readv");
+ Syscall_List[Nsyscalls++] = str_lookup(Syscall_Map, "writev");
+ Syscall_List[Nsyscalls++] = str_lookup(Syscall_Map, "mmread");
+ Syscall_List[Nsyscalls++] = str_lookup(Syscall_Map, "mmwrite");
+#endif
+
+ Fileio = 1;
+ }
+
+ if (Fileio && (argc - optind < 1)) {
+ fprintf(stderr, "iogen%s: No files specified on the cmdline\n", TagName);
+ exit(1);
+ }
+
+ /*
+ * Supply default file io flags - defaut is 'buffered,raw,sync,ldraw'.
+ */
+
+ if (! f_opt && Fileio) {
+ Nflags = 0;
+ Flag_List[Nflags++] = str_lookup(Flag_Map, "buffered");
+ Flag_List[Nflags++] = str_lookup(Flag_Map, "sync");
+#ifdef CRAY
+ Flag_List[Nflags++] = str_lookup(Flag_Map, "raw+wf");
+ Flag_List[Nflags++] = str_lookup(Flag_Map, "ldraw");
+#endif
+
+#ifdef sgi
+ /* Warning: cannot mix direct i/o with others! */
+ Flag_List[Nflags++] = str_lookup(Flag_Map, "dsync");
+ Flag_List[Nflags++] = str_lookup(Flag_Map, "rsync");
+ /* Flag_List[Nflags++] = str_lookup(Flag_Map, "rsync+sync");*/
+ /* Flag_List[Nflags++] = str_lookup(Flag_Map, "rsync+dsync");*/
+#endif
+ }
+
+ if (Fileio) {
+ if (optind >= argc) {
+ fprintf(stderr, "iogen%s: No files listed on the cmdline\n", TagName);
+ exit(1);
+ }
+
+ /*
+ * Initialize File_List[] - only necessary if doing file io. First
+ * space for the File_List array, then fill it in.
+ */
+
+ File_List = (struct file_info *)
+ malloc((argc-optind) * sizeof(struct file_info));
+
+ if (File_List == NULL) {
+ fprintf(stderr, "iogen%s: Could not malloc space for %d file_info structures\n", TagName, argc-optind);
+ exit(2);
+ }
+
+ memset(File_List, 0, (argc-optind) * sizeof(struct file_info));
+
+ Nfiles = 0;
+ while (optind < argc) {
+ len = -1;
+
+ /*
+ * Pick off leading len: if it's there and create/extend/trunc
+ * the file to the desired length. Otherwise, just make sure
+ * the file is accessable.
+ */
+
+ if ((cp = strchr(argv[optind], ':')) != NULL) {
+ *cp = '\0';
+ if ((len = str_to_bytes(argv[optind])) == -1) {
+ fprintf(stderr,
+ "iogen%s: illegal file length (%s) for file %s\n",
+ TagName, argv[optind], cp+1);
+ exit(2);
+ }
+ *cp = ':';
+ file = cp+1;
+
+ if (strlen(file) > MAX_FNAME_LENGTH) {
+ fprintf(stderr, "iogen%s: Max fname length is %d chars - ignoring file %s\n",
+ TagName, MAX_FNAME_LENGTH, file);
+ optind++;
+ continue;
+ }
+
+ nb = create_file(file, len);
+
+ if (nb < len) {
+ fprintf(stderr,
+ "iogen%s warning: Couldn't create file %s of %d bytes\n",
+ TagName, file, len);
+
+ if (nb <= 0) {
+ optind++;
+ continue;
+ }
+ }
+ } else {
+ file = argv[optind];
+ if (access(file, R_OK | W_OK) == -1) {
+ fprintf(stderr, "iogen%s: file %s cannot be accessed for reading and/or writing: %s (%d)\n",
+ TagName, file, SYSERR, errno);
+ exit(2);
+ }
+ }
+
+ /*
+ * get per-file information
+ */
+
+ fptr = &File_List[Nfiles];
+
+ if (file[0] == '/') {
+ strcpy(fptr->f_path, file);
+ } else {
+ getcwd(fptr->f_path,
+ sizeof(fptr->f_path)-1);
+ strcat(fptr->f_path, "/");
+ strcat(fptr->f_path, file);
+ }
+
+ if (get_file_info(fptr) == -1) {
+ fprintf(stderr, "iogen%s warning: Error getting file info for %s\n", TagName, file);
+ } else {
+
+ /*
+ * If the file length is smaller than our min transfer size,
+ * ignore it.
+ */
+
+ if (fptr->f_length < Mintrans) {
+ fprintf(stderr, "iogen%s warning: Ignoring file %s\n",
+ TagName, fptr->f_path);
+ fprintf(stderr, " length (%d) is < min transfer size (%d)\n",
+ fptr->f_length, Mintrans);
+ optind++;
+ continue;
+ }
+
+ /*
+ * If the file length is smaller than our max transfer size,
+ * ignore it.
+ */
+
+ if (fptr->f_length < Maxtrans) {
+ fprintf(stderr, "iogen%s warning: Ignoring file %s\n",
+ TagName, fptr->f_path);
+ fprintf(stderr, " length (%d) is < max transfer size (%d)\n",
+ fptr->f_length, Maxtrans);
+ optind++;
+ continue;
+ }
+
+ if (fptr->f_length > 0) {
+ switch (Offset_Mode->m_value) {
+ case M_SEQUENTIAL:
+ fptr->f_lastoffset = 0;
+ fptr->f_lastlength = 0;
+ break;
+
+ case M_REVERSE:
+ fptr->f_lastoffset = fptr->f_length;
+ fptr->f_lastlength = 0;
+ break;
+
+ case M_RANDOM:
+ fptr->f_lastoffset = fptr->f_length / 2;
+ fptr->f_lastlength = 0;
+ break;
+ }
+
+ Nfiles++;
+ }
+ }
+
+ optind++;
+ }
+
+ if (Nfiles == 0) {
+ fprintf(stderr, "iogen%s: Could not create, or gather info for any test files\n", TagName);
+ exit(2);
+ }
+ }
+
+ return 0;
+}
+
+int
+help(stream)
+FILE *stream;
+{
+ usage(stream);
+ fprintf(stream, "\n");
+#ifndef linux
+ fprintf(stream, "\t-a aio_type,... Async io completion types to choose. Supported types\n");
+#ifdef CRAY
+#if _UMK || RELEASE_LEVEL >= 8000
+ fprintf(stream, "\t are: poll, signal, recall, recalla, and recalls.\n");
+#else
+ fprintf(stream, "\t are: poll, signal, recalla, and recalls.\n");
+#endif
+#else
+ fprintf(stream, "\t are: poll, signal, suspend, and callback.\n");
+#endif
+ fprintf(stream, "\t Default is all of the above.\n");
+#else /* !linux */
+ fprintf(stream, "\t-a (Not used on Linux).\n");
+#endif /* !linux */
+ fprintf(stream, "\t-f flag,... Flags to use for file IO. Supported flags are\n");
+#ifdef CRAY
+ fprintf(stream, "\t raw, ssd, buffered, ldraw, sync,\n");
+ fprintf(stream, "\t raw+wf, raw+wf+ldraw, raw+wf+ldraw+sync,\n");
+ fprintf(stream, "\t and parallel (unicos/mk on MPP only).\n");
+ fprintf(stream, "\t Default is 'raw,ldraw,sync,buffered'.\n");
+#else
+#ifndef NO_XFS
+ fprintf(stream, "\t buffered, direct, sync.\n");
+ fprintf(stream, "\t Default is 'buffered,sync'.\n");
+#else
+ fprintf(stream, "\t buffered, sync.\n");
+ fprintf(stream, "\t Default is 'buffered,sync'.\n");
+#endif /* sgi */
+#endif /* CRAY */
+ fprintf(stream, "\t-h This help.\n");
+ fprintf(stream, "\t-i iterations[s] # of requests to generate. 0 means causes iogen\n");
+ fprintf(stream, "\t to run until it's killed. If iterations is suffixed\n");
+ fprintf(stream, "\t with 's', then iterations is the number of seconds\n");
+ fprintf(stream, "\t that iogen should run for. Default is '0'.\n");
+#ifndef CRAY
+ fprintf(stream, "\t-L min:max listio nstrides / nrequests range\n");
+#else
+ fprintf(stream, "\t-L (Not used on this platform).\n");
+#endif /* !CRAY */
+ fprintf(stream, "\t-m offset-mode The mode by which iogen chooses the offset for\n");
+ fprintf(stream, "\t consectutive transfers within a given file.\n");
+ fprintf(stream, "\t Allowed values are 'random', 'sequential',\n");
+ fprintf(stream, "\t and 'reverse'.\n");
+ fprintf(stream, "\t sequential is the default.\n");
+ fprintf(stream, "\t-N tagname Tag name, for Monster.\n");
+ fprintf(stream, "\t-o Form overlapping consecutive requests.\n");
+ fprintf(stream, "\t-O Open flags for creating files\n");
+#ifdef CRAY
+ fprintf(stream, "\t {O_PLACE,O_BIG,etc}[:CBITS[:CBLKS]]\n");
+#endif
+#ifndef NO_XFS
+ fprintf(stream, "\t realtime:extsize - put file on real-time volume\n");
+ fprintf(stream, "\t allocate - allocate space with F_ALLOCSP\n");
+ fprintf(stream, "\t reserve - reserve space with F_RESVSP (default)\n");
+ fprintf(stream, "\t noreserve - do not reserve with F_RESVSP\n");
+ fprintf(stream, "\t direct - use O_DIRECT I/O to write to the file\n");
+#else
+ fprintf(stream, "\t {O_SYNC,etc}\n");
+#endif
+ fprintf(stream, "\t-p Output pipe. Default is stdout.\n");
+ fprintf(stream, "\t-q Quiet mode. Normally iogen spits out info\n");
+ fprintf(stream, "\t about test files, options, etc. before starting.\n");
+ fprintf(stream, "\t-s syscall,... Syscalls to do. Supported syscalls are\n");
+#ifdef sgi
+ fprintf(stream, "\t read, write, pread, pwrite, readv, writev\n");
+ fprintf(stream, "\t aread, awrite, resvsp, unresvsp, ffsync,\n");
+ fprintf(stream, "\t mmread, mmwrite, fsync2, fdatasync,\n");
+ fprintf(stream, "\t Default is 'read,write,pread,pwrite,readv,writev,mmread,mmwrite'.\n");
+#endif
+#ifdef CRAY
+ fprintf(stream, "\t read, write, reada, writea, listio,\n");
+ fprintf(stream, "\t ssread (PVP only), and sswrite (PVP only).\n");
+ fprintf(stream, "\t Default is 'read,write,reada,writea,listio'.\n");
+#endif
+#ifdef linux
+ fprintf(stream, "\t read, write, pread, pwrite, readv, writev,\n");
+ fprintf(stream, "\t mmread, mmwrite, fsync2, fdatasync,\n");
+ fprintf(stream, "\t Default is 'read,write,readv,writev,mmread,mmwrite'.\n");
+#endif
+ fprintf(stream, "\t-t mintrans Min transfer length\n");
+ fprintf(stream, "\t-T maxtrans Max transfer length\n");
+ fprintf(stream, "\n");
+ fprintf(stream, "\t[len:]file,... Test files to do IO against (note ssread/sswrite\n");
+ fprintf(stream, "\t don't need a test file). The len: syntax\n");
+ fprintf(stream, "\t informs iogen to first create/expand/truncate the\n");
+ fprintf(stream, "\t to the desired length.\n");
+ fprintf(stream, "\n");
+ fprintf(stream, "\tNote: The ssd flag causes sds transfers to also be done.\n");
+ fprintf(stream, "\t To totally eliminate sds transfers, you must eleminate sds\n");
+ fprintf(stream, "\t from the flags (-f) and ssread,ssrite from the syscalls (-s)\n");
+ fprintf(stream, "\tThe mintrans, maxtrans, and len: parameters are numbers of the\n");
+ fprintf(stream, "\tform [0-9]+[bkm]. The optional trailing b, k, or m multiplies\n");
+ fprintf(stream, "\tthe number by blocks, kilobytes, or megabytes. If no trailing\n");
+ fprintf(stream, "\tmultiplier is present, the number is interpreted as bytes\n");
+
+ return 0;
+}
+
+/*
+ * Obvious - usage clause
+ */
+
+int
+usage(stream)
+FILE *stream;
+{
+ fprintf(stream, "usage%s: iogen [-hoq] [-a aio_type,...] [-f flag[,flag...]] [-i iterations] [-p outpipe] [-m offset-mode] [-s syscall[,syscall...]] [-t mintrans] [-T maxtrans] [ -O file-create-flags ] [[len:]file ...]\n", TagName);
+ return 0;
+}
package_dmapidev.m4 \
package_globals.m4 \
package_ncurses.m4 \
+ package_pthread.m4 \
package_types.m4 \
package_utilies.m4 \
package_uuiddev.m4 \
|| _fail " !!! couldn't delete old dir"
_log " *** stress"
- src/fsstress -d $SCRATCH_MNT/soak_test -p $proc -n $stress $FSSTRESS_AVOID 2>&1 | \
+ ltp/fsstress -d $SCRATCH_MNT/soak_test -p $proc -n $stress $FSSTRESS_AVOID 2>&1 | \
_fix_malloc >>$FULL
_log " *** unmounting scratch device"
#
-# Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved.
+# Copyright (c) 2000-2003 Silicon Graphics, Inc. All Rights Reserved.
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of version 2 of the GNU General Public License as
include $(TOPDIR)/include/builddefs
TARGETS = alloc acl_get bstat devzero dirstress fault feature \
- fsstress fill fill2 getpagesize holes xfsctl loggen lstat64 \
+ fill fill2 getpagesize holes xfsctl loggen lstat64 \
nametest permname randholes runas truncfile usemem \
fstest mmapcat append_reader append_writer
-ifeq ($(HAVE_DB), true)
+ifeq ($(ENABLE_DBM), yes)
TARGETS += dbtest
endif
-CFILES = $(TARGETS:=.c) random.c
-HFILES = global.h
+CFILES = $(TARGETS:=.c)
LDIRT = $(TARGETS)
default: $(TARGETS)
include $(BUILDRULES)
+LINKTEST = $(LTLINK) $@.c -o $@ $(CFLAGS) $(LDFLAGS)
-install install-dev: default
+randholes: randholes.o $(LIBTEST)
+ $(LINKTEST) $(LIBTEST) $(LDLIBS)
-# binaries using non-default objects/libs need an entry below
-#
-RANDHOLES_OBJECTS = randholes.o random.o
-randholes: $(HFILES) $(RANDHOLES_OBJECTS)
- $(CCF) -o $@ $(LDFLAGS) $(RANDHOLES_OBJECTS) $(LDLIBS)
-
-TRUNCFILE_OBJECTS = truncfile.o random.o
-truncfile: $(HFILES) $(TRUNCFILE_OBJECTS)
- $(CCF) -o $@ $(LDFLAGS) $(TRUNCFILE_OBJECTS) $(LDLIBS)
-
-FSSTRESS_OBJECTS = fsstress.o random.o $(LIBATTR)
-fsstress: $(HFILES) $(FSSTRESS_OBJECTS)
- $(CCF) -o $@ $(LDFLAGS) $(FSSTRESS_OBJECTS) $(LDLIBS)
+truncfile: truncfile.o $(LIBTEST)
+ $(LINKTEST) $(LIBTEST) $(LDLIBS)
-DBTEST_OBJECTS = dbtest.o random.o
-dbtest: $(HFILES) $(DBTEST_OBJECTS)
- $(CCF) -o $@ $(LDFLAGS) $(DBTEST_OBJECTS) $(LIBGDBM) $(LDLIBS)
+dbtest: dbtest.o $(LIBTEST)
+ $(LINKTEST) $(LIBTEST) $(LIBGDBM) $(LDLIBS)
-NAMETEST_OBJECTS = nametest.o random.o
-nametest: $(HFILES) $(NAMETEST_OBJECTS)
- $(CCF) -o $@ $(LDFLAGS) $(NAMETEST_OBJECTS) $(LDLIBS)
+nametest: nametest.o $(LIBTEST)
+ $(LINKTEST) $(LIBTEST) $(LDLIBS)
-BSTAT_OBJECTS = bstat.o
-bstat: $(HFILES) $(BSTAT_OBJECTS)
- $(CCF) -o $@ $(LDFLAGS) $(BSTAT_OBJECTS) $(LIBHANDLE) $(LDLIBS)
+bstat: bstat.o $(LIBHANDLE)
+ $(LINKTEST) $(LIBHANDLE) $(LDLIBS)
-LOGGEN_OBJECTS = loggen.o $(LIBXFS)
-loggen: $(HFILES) $(LOGGEN_OBJECTS)
- $(CCF) -o $@ $(LDFLAGS) $(LOGGEN_OBJECTS) $(LDLIBS)
+loggen: loggen.o $(LIBXFS)
+ $(LINKTEST) $(LIBXFS) $(LDLIBS)
-ACLGET_OBJECTS = acl_get.o $(LIBACL) $(LIBATTR)
-acl_get: $(HFILES) $(ACLGET_OBJECTS)
- $(CCF) -o $@ $(LDFLAGS) $(ACLGET_OBJECTS) $(LDLIBS)
+acl_get: acl_get.o $(LIBACL) $(LIBATTR)
+ $(LINKTEST) $(LIBACL) $(LIBATTR) $(LDLIBS)
+++ /dev/null
-/*
- * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it would be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- *
- * Further, this software is distributed without any warranty that it is
- * free of the rightful claim of any third person regarding infringement
- * or the like. Any license provided herein, whether implied or
- * otherwise, applies only to this software file. Patent licenses, if
- * any, provided herein do not apply to combinations of this program with
- * other software, or any other product whatsoever.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write the Free Software Foundation, Inc., 59
- * Temple Place - Suite 330, Boston MA 02111-1307, USA.
- *
- * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
- * Mountain View, CA 94043, or:
- *
- * http://www.sgi.com
- *
- * For further information regarding this notice, see:
- *
- * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
- */
-
-#include "global.h"
-#include <attr/xattr.h>
-
-#define XFS_ERRTAG_MAX 17
-
-typedef enum {
- OP_ALLOCSP,
- OP_ATTR_REMOVE,
- OP_ATTR_SET,
- OP_BULKSTAT,
- OP_BULKSTAT1,
- OP_CHOWN,
- OP_CREAT,
- OP_DREAD,
- OP_DWRITE,
- OP_FDATASYNC,
- OP_FREESP,
- OP_FSYNC,
- OP_GETDENTS,
- OP_LINK,
- OP_MKDIR,
- OP_MKNOD,
- OP_READ,
- OP_READLINK,
- OP_RENAME,
- OP_RESVSP,
- OP_RMDIR,
- OP_STAT,
- OP_SYMLINK,
- OP_SYNC,
- OP_TRUNCATE,
- OP_UNLINK,
- OP_UNRESVSP,
- OP_WRITE,
- OP_LAST
-} opty_t;
-
-typedef void (*opfnc_t)(int, long);
-
-typedef struct opdesc {
- opty_t op;
- char *name;
- opfnc_t func;
- int freq;
- int iswrite;
-} opdesc_t;
-
-typedef struct fent {
- int id;
- int parent;
-} fent_t;
-
-typedef struct flist {
- int nfiles;
- int nslots;
- int tag;
- fent_t *fents;
-} flist_t;
-
-typedef struct pathname {
- int len;
- char *path;
-} pathname_t;
-
-#define FT_DIR 0
-#define FT_DIRm (1 << FT_DIR)
-#define FT_REG 1
-#define FT_REGm (1 << FT_REG)
-#define FT_SYM 2
-#define FT_SYMm (1 << FT_SYM)
-#define FT_DEV 3
-#define FT_DEVm (1 << FT_DEV)
-#define FT_RTF 4
-#define FT_RTFm (1 << FT_RTF)
-#define FT_nft 5
-#define FT_ANYm ((1 << FT_nft) - 1)
-#define FT_REGFILE (FT_REGm | FT_RTFm)
-#define FT_NOTDIR (FT_ANYm & ~FT_DIRm)
-
-#define FLIST_SLOT_INCR 16
-#define NDCACHE 64
-
-#define MAXFSIZE ((1ULL << 63) - 1ULL)
-#define MAXFSIZE32 ((1ULL << 40) - 1ULL)
-
-void allocsp_f(int, long);
-void attr_remove_f(int, long);
-void attr_set_f(int, long);
-void bulkstat_f(int, long);
-void bulkstat1_f(int, long);
-void chown_f(int, long);
-void creat_f(int, long);
-void dread_f(int, long);
-void dwrite_f(int, long);
-void fdatasync_f(int, long);
-void freesp_f(int, long);
-void fsync_f(int, long);
-void getdents_f(int, long);
-void link_f(int, long);
-void mkdir_f(int, long);
-void mknod_f(int, long);
-void read_f(int, long);
-void readlink_f(int, long);
-void rename_f(int, long);
-void resvsp_f(int, long);
-void rmdir_f(int, long);
-void stat_f(int, long);
-void symlink_f(int, long);
-void sync_f(int, long);
-void truncate_f(int, long);
-void unlink_f(int, long);
-void unresvsp_f(int, long);
-void write_f(int, long);
-
-opdesc_t ops[] = {
- { OP_ALLOCSP, "allocsp", allocsp_f, 1, 1 },
- { OP_ATTR_REMOVE, "attr_remove", attr_remove_f, /* 1 */ 0, 1 },
- { OP_ATTR_SET, "attr_set", attr_set_f, /* 2 */ 0, 1 },
- { OP_BULKSTAT, "bulkstat", bulkstat_f, 1, 0 },
- { OP_BULKSTAT1, "bulkstat1", bulkstat1_f, 1, 0 },
- { OP_CHOWN, "chown", chown_f, 3, 1 },
- { OP_CREAT, "creat", creat_f, 4, 1 },
- { OP_DREAD, "dread", dread_f, 4, 0 },
- { OP_DWRITE, "dwrite", dwrite_f, 4, 1 },
- { OP_FDATASYNC, "fdatasync", fdatasync_f, 1, 1 },
- { OP_FREESP, "freesp", freesp_f, 1, 1 },
- { OP_FSYNC, "fsync", fsync_f, 1, 1 },
- { OP_GETDENTS, "getdents", getdents_f, 1, 0 },
- { OP_LINK, "link", link_f, 1, 1 },
- { OP_MKDIR, "mkdir", mkdir_f, 2, 1 },
- { OP_MKNOD, "mknod", mknod_f, 2, 1 },
- { OP_READ, "read", read_f, 1, 0 },
- { OP_READLINK, "readlink", readlink_f, 1, 0 },
- { OP_RENAME, "rename", rename_f, 2, 1 },
- { OP_RESVSP, "resvsp", resvsp_f, 1, 1 },
- { OP_RMDIR, "rmdir", rmdir_f, 1, 1 },
- { OP_STAT, "stat", stat_f, 1, 0 },
- { OP_SYMLINK, "symlink", symlink_f, 2, 1 },
- { OP_SYNC, "sync", sync_f, 1, 0 },
- { OP_TRUNCATE, "truncate", truncate_f, 2, 1 },
- { OP_UNLINK, "unlink", unlink_f, 1, 1 },
- { OP_UNRESVSP, "unresvsp", unresvsp_f, 1, 1 },
- { OP_WRITE, "write", write_f, 4, 1 },
-}, *ops_end;
-
-flist_t flist[FT_nft] = {
- { 0, 0, 'd', NULL },
- { 0, 0, 'f', NULL },
- { 0, 0, 'l', NULL },
- { 0, 0, 'c', NULL },
- { 0, 0, 'r', NULL },
-};
-
-int dcache[NDCACHE];
-int errrange;
-int errtag;
-opty_t *freq_table;
-int freq_table_size;
-xfs_fsop_geom_t geom;
-char *homedir;
-int *ilist;
-int ilistlen;
-off64_t maxfsize;
-char *myprog;
-int namerand;
-int nameseq;
-int nops;
-int nproc = 1;
-int operations = 1;
-int procid;
-int rtpct;
-unsigned long seed = 0;
-ino_t top_ino;
-int verbose = 0;
-
-void add_to_flist(int, int, int);
-void append_pathname(pathname_t *, char *);
-int attr_list_path(pathname_t *, char *, const int, int);
-int attr_remove_path(pathname_t *, const char *, int);
-int attr_set_path(pathname_t *, const char *, const char *, const int, int);
-void check_cwd(void);
-int creat_path(pathname_t *, mode_t);
-void dcache_enter(int, int);
-void dcache_init(void);
-fent_t *dcache_lookup(int);
-void dcache_purge(int);
-void del_from_flist(int, int);
-int dirid_to_name(char *, int);
-void doproc(void);
-void fent_to_name(pathname_t *, flist_t *, fent_t *);
-void fix_parent(int, int);
-void free_pathname(pathname_t *);
-int generate_fname(fent_t *, int, pathname_t *, int *, int *);
-int get_fname(int, long, pathname_t *, flist_t **, fent_t **, int *);
-void init_pathname(pathname_t *);
-int lchown_path(pathname_t *, uid_t, gid_t);
-int link_path(pathname_t *, pathname_t *);
-int lstat64_path(pathname_t *, struct stat64 *);
-void make_freq_table(void);
-int mkdir_path(pathname_t *, mode_t);
-int mknod_path(pathname_t *, mode_t, dev_t);
-void namerandpad(int, char *, int);
-int open_path(pathname_t *, int);
-DIR *opendir_path(pathname_t *);
-void process_freq(char *);
-int readlink_path(pathname_t *, char *, size_t);
-int rename_path(pathname_t *, pathname_t *);
-int rmdir_path(pathname_t *);
-void separate_pathname(pathname_t *, char *, pathname_t *);
-void show_ops(int, char *);
-int stat64_path(pathname_t *, struct stat64 *);
-int symlink_path(const char *, pathname_t *);
-int truncate64_path(pathname_t *, off64_t);
-int unlink_path(pathname_t *);
-void usage(void);
-void write_freq(void);
-void zero_freq(void);
-
-int main(int argc, char **argv)
-{
- char buf[10];
- int c;
- char *dirname = NULL;
- int fd;
- int i;
- int j;
- char *p;
- int stat;
- struct timeval t;
- ptrdiff_t srval;
- int nousage=0;
- xfs_error_injection_t err_inj;
-
- errrange = errtag = 0;
- umask(0);
- nops = sizeof(ops) / sizeof(ops[0]);
- ops_end = &ops[nops];
- myprog = argv[0];
- while ((c = getopt(argc, argv, "d:e:f:i:n:p:rs:vwzHS")) != -1) {
- switch (c) {
- case 'd':
- dirname = optarg;
- break;
- case 'e':
- sscanf(optarg, "%d", &errtag);
- if (errtag < 0) {
- errtag = -errtag;
- errrange = 1;
- } else if (errtag == 0)
- errtag = -1;
- if (errtag >= XFS_ERRTAG_MAX) {
- fprintf(stderr,
- "error tag %d too large (max %d)\n",
- errtag, XFS_ERRTAG_MAX - 1);
- exit(1);
- }
- break;
- case 'f':
- process_freq(optarg);
- break;
- case 'i':
- ilist = realloc(ilist, ++ilistlen * sizeof(*ilist));
- ilist[ilistlen - 1] = strtol(optarg, &p, 16);
- break;
- case 'n':
- operations = atoi(optarg);
- break;
- case 'p':
- nproc = atoi(optarg);
- break;
- case 'r':
- namerand = 1;
- break;
- case 's':
- seed = strtoul(optarg, NULL, 0);
- break;
- case 'v':
- verbose = 1;
- break;
- case 'w':
- write_freq();
- break;
- case 'z':
- zero_freq();
- break;
- case 'S':
- show_ops(0, NULL);
- printf("\n");
- nousage=1;
- break;
- case '?':
- fprintf(stderr, "%s - invalid parameters\n",
- myprog);
- /* fall through */
- case 'H':
- usage();
- exit(1);
- }
- }
-
- if (!dirname) {
- /* no directory specified */
- if (!nousage) usage();
- exit(1);
- }
-
- (void)mkdir(dirname, 0777);
- if (chdir(dirname) < 0) {
- perror(dirname);
- exit(1);
- }
- sprintf(buf, "fss%x", getpid());
- fd = creat(buf, 0666);
- if (lseek64(fd, (off64_t)(MAXFSIZE32 + 1ULL), SEEK_SET) < 0)
- maxfsize = (off64_t)MAXFSIZE32;
- else
- maxfsize = (off64_t)MAXFSIZE;
- make_freq_table();
- dcache_init();
- setlinebuf(stdout);
- if (!seed) {
- gettimeofday(&t, (void *)NULL);
- seed = (int)t.tv_sec ^ (int)t.tv_usec;
- printf("seed = %ld\n", seed);
- }
- i = ioctl(fd, XFS_IOC_FSGEOMETRY, &geom);
- if (i >= 0 && geom.rtblocks)
- rtpct = MIN(MAX(geom.rtblocks * 100 /
- (geom.rtblocks + geom.datablocks), 1), 99);
- else
- rtpct = 0;
- if (errtag != 0) {
- if (errrange == 0) {
- if (errtag <= 0) {
- srandom(seed);
- j = random() % 100;
-
- for (i = 0; i < j; i++)
- (void) random();
-
- errtag = (random() % (XFS_ERRTAG_MAX-1)) + 1;
- }
- } else {
- srandom(seed);
- j = random() % 100;
-
- for (i = 0; i < j; i++)
- (void) random();
-
- errtag += (random() % (XFS_ERRTAG_MAX - errtag));
- }
- printf("Injecting failure on tag #%d\n", errtag);
- err_inj.errtag = errtag;
- err_inj.fd = fd;
- srval = ioctl(fd, XFS_IOC_ERROR_INJECTION, &err_inj);
- if (srval < -1) {
- perror("fsstress - XFS_SYSSGI error injection call");
- close(fd);
- unlink(buf);
- exit(1);
- }
- } else
- close(fd);
- unlink(buf);
- for (i = 0; i < nproc; i++) {
- if (fork() == 0) {
- procid = i;
- doproc();
- return 0;
- }
- }
- while (wait(&stat) > 0)
- continue;
- if (errtag != 0) {
- err_inj.errtag = 0;
- err_inj.fd = fd;
- if((srval = ioctl(fd, XFS_IOC_ERROR_CLEARALL, &err_inj)) != 0) {
- fprintf(stderr, "Bad ej clear on %d (%d).\n", fd, errno);
- perror("fsstress - XFS_SYSSGI clear error injection call");
- close(fd);
- exit(1);
- }
- close(fd);
- }
-
- return 0;
-}
-
-void
-add_to_flist(int ft, int id, int parent)
-{
- fent_t *fep;
- flist_t *ftp;
-
- ftp = &flist[ft];
- if (ftp->nfiles == ftp->nslots) {
- ftp->nslots += FLIST_SLOT_INCR;
- ftp->fents = realloc(ftp->fents, ftp->nslots * sizeof(fent_t));
- }
- fep = &ftp->fents[ftp->nfiles++];
- fep->id = id;
- fep->parent = parent;
-}
-
-void
-append_pathname(pathname_t *name, char *str)
-{
- int len;
-
- len = strlen(str);
-#ifdef DEBUG
- if (len && *str == '/' && name->len == 0) {
- fprintf(stderr, "fsstress: append_pathname failure\n");
- chdir(homedir);
- abort();
- /* NOTREACHED */
- }
-#endif
- name->path = realloc(name->path, name->len + 1 + len);
- strcpy(&name->path[name->len], str);
- name->len += len;
-}
-
-int
-attr_list_path(pathname_t *name, char *buffer, const int buffersize, int flags)
-{
- char buf[MAXNAMELEN];
- pathname_t newname;
- int rval;
-
- if (flags != ATTR_DONTFOLLOW) {
- errno = EINVAL;
- return -1;
- }
- rval = llistxattr(name->path, buffer, buffersize);
- if (rval >= 0 || errno != ENAMETOOLONG)
- return rval;
- separate_pathname(name, buf, &newname);
- if (chdir(buf) == 0) {
- rval = attr_list_path(&newname, buffer, buffersize, flags);
- chdir("..");
- }
- free_pathname(&newname);
- return rval;
-}
-
-int
-attr_remove_path(pathname_t *name, const char *attrname, int flags)
-{
- char buf[MAXNAMELEN];
- pathname_t newname;
- int rval;
-
- rval = attr_remove(name->path, attrname, flags);
- if (rval >= 0 || errno != ENAMETOOLONG)
- return rval;
- separate_pathname(name, buf, &newname);
- if (chdir(buf) == 0) {
- rval = attr_remove_path(&newname, attrname, flags);
- chdir("..");
- }
- free_pathname(&newname);
- return rval;
-}
-
-int
-attr_set_path(pathname_t *name, const char *attrname, const char *attrvalue,
- const int valuelength, int flags)
-{
- char buf[MAXNAMELEN];
- pathname_t newname;
- int rval;
-
- rval = attr_set(name->path, attrname, attrvalue, valuelength, flags);
- if (rval >= 0 || errno != ENAMETOOLONG)
- return rval;
- separate_pathname(name, buf, &newname);
- if (chdir(buf) == 0) {
- rval = attr_set_path(&newname, attrname, attrvalue, valuelength,
- flags);
- chdir("..");
- }
- free_pathname(&newname);
- return rval;
-}
-
-void
-check_cwd(void)
-{
-#ifdef DEBUG
- struct stat64 statbuf;
-
- if (stat64(".", &statbuf) == 0 && statbuf.st_ino == top_ino)
- return;
- chdir(homedir);
- fprintf(stderr, "fsstress: check_cwd failure\n");
- abort();
- /* NOTREACHED */
-#endif
-}
-
-int
-creat_path(pathname_t *name, mode_t mode)
-{
- char buf[MAXNAMELEN];
- pathname_t newname;
- int rval;
-
- rval = creat(name->path, mode);
- if (rval >= 0 || errno != ENAMETOOLONG)
- return rval;
- separate_pathname(name, buf, &newname);
- if (chdir(buf) == 0) {
- rval = creat_path(&newname, mode);
- chdir("..");
- }
- free_pathname(&newname);
- return rval;
-}
-
-void
-dcache_enter(int dirid, int slot)
-{
- dcache[dirid % NDCACHE] = slot;
-}
-
-void
-dcache_init(void)
-{
- int i;
-
- for (i = 0; i < NDCACHE; i++)
- dcache[i] = -1;
-}
-
-fent_t *
-dcache_lookup(int dirid)
-{
- fent_t *fep;
- int i;
-
- i = dcache[dirid % NDCACHE];
- if (i >= 0 && (fep = &flist[FT_DIR].fents[i])->id == dirid)
- return fep;
- return NULL;
-}
-
-void
-dcache_purge(int dirid)
-{
- int *dcp;
-
- dcp = &dcache[dirid % NDCACHE];
- if (*dcp >= 0 && flist[FT_DIR].fents[*dcp].id == dirid)
- *dcp = -1;
-}
-
-void
-del_from_flist(int ft, int slot)
-{
- flist_t *ftp;
-
- ftp = &flist[ft];
- if (ft == FT_DIR)
- dcache_purge(ftp->fents[slot].id);
- if (slot != ftp->nfiles - 1) {
- if (ft == FT_DIR)
- dcache_purge(ftp->fents[ftp->nfiles - 1].id);
- ftp->fents[slot] = ftp->fents[--ftp->nfiles];
- } else
- ftp->nfiles--;
-}
-
-fent_t *
-dirid_to_fent(int dirid)
-{
- fent_t *efep;
- fent_t *fep;
- flist_t *flp;
-
- if ((fep = dcache_lookup(dirid)))
- return fep;
- flp = &flist[FT_DIR];
- for (fep = flp->fents, efep = &fep[flp->nfiles]; fep < efep; fep++) {
- if (fep->id == dirid) {
- dcache_enter(dirid, fep - flp->fents);
- return fep;
- }
- }
- return NULL;
-}
-
-void
-doproc(void)
-{
- struct stat64 statbuf;
- char buf[10];
- int opno;
- int rval;
- opdesc_t *p;
-
- sprintf(buf, "p%x", procid);
- (void)mkdir(buf, 0777);
- if (chdir(buf) < 0 || stat64(".", &statbuf) < 0) {
- perror(buf);
- _exit(1);
- }
- top_ino = statbuf.st_ino;
- homedir = getcwd(NULL, -1);
- seed += procid;
- srandom(seed);
- if (namerand)
- namerand = random();
- for (opno = 0; opno < operations; opno++) {
- p = &ops[freq_table[random() % freq_table_size]];
- p->func(opno, random());
- /*
- * test for forced shutdown by stat'ing the test
- * directory. If this stat returns EIO, assume
- * the forced shutdown happened.
- */
- if (errtag != 0 && opno % 100 == 0) {
- rval = stat64(".", &statbuf);
- if (rval == EIO) {
- fprintf(stderr, "Detected EIO\n");
- return;
- }
- }
- }
-}
-
-void
-fent_to_name(pathname_t *name, flist_t *flp, fent_t *fep)
-{
- char buf[MAXNAMELEN];
- int i;
- fent_t *pfep;
-
- if (fep == NULL)
- return;
- if (fep->parent != -1) {
- pfep = dirid_to_fent(fep->parent);
- fent_to_name(name, &flist[FT_DIR], pfep);
- append_pathname(name, "/");
- }
- i = sprintf(buf, "%c%x", flp->tag, fep->id);
- namerandpad(fep->id, buf, i);
- append_pathname(name, buf);
-}
-
-void
-fix_parent(int oldid, int newid)
-{
- fent_t *fep;
- flist_t *flp;
- int i;
- int j;
-
- for (i = 0, flp = flist; i < FT_nft; i++, flp++) {
- for (j = 0, fep = flp->fents; j < flp->nfiles; j++, fep++) {
- if (fep->parent == oldid)
- fep->parent = newid;
- }
- }
-}
-
-void
-free_pathname(pathname_t *name)
-{
- if (name->path) {
- free(name->path);
- name->path = NULL;
- name->len = 0;
- }
-}
-
-int
-generate_fname(fent_t *fep, int ft, pathname_t *name, int *idp, int *v)
-{
- char buf[MAXNAMELEN];
- flist_t *flp;
- int id;
- int j;
- int len;
-
- flp = &flist[ft];
- len = sprintf(buf, "%c%x", flp->tag, id = nameseq++);
- namerandpad(id, buf, len);
- if (fep) {
- fent_to_name(name, &flist[FT_DIR], fep);
- append_pathname(name, "/");
- }
- append_pathname(name, buf);
- *idp = id;
- *v = verbose;
- for (j = 0; !*v && j < ilistlen; j++) {
- if (ilist[j] == id) {
- *v = 1;
- break;
- }
- }
- return 1;
-}
-
-int
-get_fname(int which, long r, pathname_t *name, flist_t **flpp, fent_t **fepp,
- int *v)
-{
- int c;
- fent_t *fep;
- flist_t *flp;
- int i;
- int j;
- int x;
-
- for (i = 0, c = 0, flp = flist; i < FT_nft; i++, flp++) {
- if (which & (1 << i))
- c += flp->nfiles;
- }
- if (c == 0) {
- if (flpp)
- *flpp = NULL;
- if (fepp)
- *fepp = NULL;
- *v = verbose;
- return 0;
- }
- x = (int)(r % c);
- for (i = 0, c = 0, flp = flist; i < FT_nft; i++, flp++) {
- if (which & (1 << i)) {
- if (x < c + flp->nfiles) {
- fep = &flp->fents[x - c];
- if (name)
- fent_to_name(name, flp, fep);
- if (flpp)
- *flpp = flp;
- if (fepp)
- *fepp = fep;
- *v = verbose;
- for (j = 0; !*v && j < ilistlen; j++) {
- if (ilist[j] == fep->id) {
- *v = 1;
- break;
- }
- }
- return 1;
- }
- c += flp->nfiles;
- }
- }
-#ifdef DEBUG
- fprintf(stderr, "fsstress: get_fname failure\n");
- abort();
-#endif
- return -1;
- /* NOTREACHED */
-}
-
-void
-init_pathname(pathname_t *name)
-{
- name->len = 0;
- name->path = NULL;
-}
-
-int
-lchown_path(pathname_t *name, uid_t owner, gid_t group)
-{
- char buf[MAXNAMELEN];
- pathname_t newname;
- int rval;
-
- rval = lchown(name->path, owner, group);
- if (rval >= 0 || errno != ENAMETOOLONG)
- return rval;
- separate_pathname(name, buf, &newname);
- if (chdir(buf) == 0) {
- rval = lchown_path(&newname, owner, group);
- chdir("..");
- }
- free_pathname(&newname);
- return rval;
-}
-
-int
-link_path(pathname_t *name1, pathname_t *name2)
-{
- char buf1[MAXNAMELEN];
- char buf2[MAXNAMELEN];
- int down1;
- pathname_t newname1;
- pathname_t newname2;
- int rval;
-
- rval = link(name1->path, name2->path);
- if (rval >= 0 || errno != ENAMETOOLONG)
- return rval;
- separate_pathname(name1, buf1, &newname1);
- separate_pathname(name2, buf2, &newname2);
- if (strcmp(buf1, buf2) == 0) {
- if (chdir(buf1) == 0) {
- rval = link_path(&newname1, &newname2);
- chdir("..");
- }
- } else {
- if (strcmp(buf1, "..") == 0)
- down1 = 0;
- else if (strcmp(buf2, "..") == 0)
- down1 = 1;
- else if (strlen(buf1) == 0)
- down1 = 0;
- else if (strlen(buf2) == 0)
- down1 = 1;
- else
- down1 = MAX(newname1.len, 3 + name2->len) <=
- MAX(3 + name1->len, newname2.len);
- if (down1) {
- free_pathname(&newname2);
- append_pathname(&newname2, "../");
- append_pathname(&newname2, name2->path);
- if (chdir(buf1) == 0) {
- rval = link_path(&newname1, &newname2);
- chdir("..");
- }
- } else {
- free_pathname(&newname1);
- append_pathname(&newname1, "../");
- append_pathname(&newname1, name1->path);
- if (chdir(buf2) == 0) {
- rval = link_path(&newname1, &newname2);
- chdir("..");
- }
- }
- }
- free_pathname(&newname1);
- free_pathname(&newname2);
- return rval;
-}
-
-int
-lstat64_path(pathname_t *name, struct stat64 *sbuf)
-{
- char buf[MAXNAMELEN];
- pathname_t newname;
- int rval;
-
- rval = lstat64(name->path, sbuf);
- if (rval >= 0 || errno != ENAMETOOLONG)
- return rval;
- separate_pathname(name, buf, &newname);
- if (chdir(buf) == 0) {
- rval = lstat64_path(&newname, sbuf);
- chdir("..");
- }
- free_pathname(&newname);
- return rval;
-}
-
-void
-make_freq_table(void)
-{
- int f;
- int i;
- opdesc_t *p;
-
- for (p = ops, f = 0; p < ops_end; p++)
- f += p->freq;
- freq_table = malloc(f * sizeof(*freq_table));
- freq_table_size = f;
- for (p = ops, i = 0; p < ops_end; p++) {
- for (f = 0; f < p->freq; f++, i++)
- freq_table[i] = p->op;
- }
-}
-
-int
-mkdir_path(pathname_t *name, mode_t mode)
-{
- char buf[MAXNAMELEN];
- pathname_t newname;
- int rval;
-
- rval = mkdir(name->path, mode);
- if (rval >= 0 || errno != ENAMETOOLONG)
- return rval;
- separate_pathname(name, buf, &newname);
- if (chdir(buf) == 0) {
- rval = mkdir_path(&newname, mode);
- chdir("..");
- }
- free_pathname(&newname);
- return rval;
-}
-
-int
-mknod_path(pathname_t *name, mode_t mode, dev_t dev)
-{
- char buf[MAXNAMELEN];
- pathname_t newname;
- int rval;
-
- rval = mknod(name->path, mode, dev);
- if (rval >= 0 || errno != ENAMETOOLONG)
- return rval;
- separate_pathname(name, buf, &newname);
- if (chdir(buf) == 0) {
- rval = mknod_path(&newname, mode, dev);
- chdir("..");
- }
- free_pathname(&newname);
- return rval;
-}
-
-void
-namerandpad(int id, char *buf, int i)
-{
- int bucket;
- static int buckets[] =
- { 2, 4, 8, 16, 32, 64, 128, MAXNAMELEN - 1 };
- int padlen;
- int padmod;
-
- if (namerand == 0)
- return;
- bucket = (id ^ namerand) % (sizeof(buckets) / sizeof(buckets[0]));
- padmod = buckets[bucket] + 1 - i;
- if (padmod <= 0)
- return;
- padlen = (id ^ namerand) % padmod;
- if (padlen) {
- memset(&buf[i], 'X', padlen);
- buf[i + padlen] = '\0';
- }
-}
-
-int
-open_path(pathname_t *name, int oflag)
-{
- char buf[MAXNAMELEN];
- pathname_t newname;
- int rval;
-
- rval = open(name->path, oflag);
- if (rval >= 0 || errno != ENAMETOOLONG)
- return rval;
- separate_pathname(name, buf, &newname);
- if (chdir(buf) == 0) {
- rval = open_path(&newname, oflag);
- chdir("..");
- }
- free_pathname(&newname);
- return rval;
-}
-
-DIR *
-opendir_path(pathname_t *name)
-{
- char buf[MAXNAMELEN];
- pathname_t newname;
- DIR *rval;
-
- rval = opendir(name->path);
- if (rval || errno != ENAMETOOLONG)
- return rval;
- separate_pathname(name, buf, &newname);
- if (chdir(buf) == 0) {
- rval = opendir_path(&newname);
- chdir("..");
- }
- free_pathname(&newname);
- return rval;
-}
-
-void
-process_freq(char *arg)
-{
- opdesc_t *p;
- char *s;
-
- s = strchr(arg, '=');
- if (s == NULL) {
- fprintf(stderr, "bad argument '%s'\n", arg);
- exit(1);
- }
- *s++ = '\0';
- for (p = ops; p < ops_end; p++) {
- if (strcmp(arg, p->name) == 0) {
- p->freq = atoi(s);
- return;
- }
- }
- fprintf(stderr, "can't find op type %s for -f\n", arg);
- exit(1);
-}
-
-int
-readlink_path(pathname_t *name, char *lbuf, size_t lbufsiz)
-{
- char buf[MAXNAMELEN];
- pathname_t newname;
- int rval;
-
- rval = readlink(name->path, lbuf, lbufsiz);
- if (rval >= 0 || errno != ENAMETOOLONG)
- return rval;
- separate_pathname(name, buf, &newname);
- if (chdir(buf) == 0) {
- rval = readlink_path(&newname, lbuf, lbufsiz);
- chdir("..");
- }
- free_pathname(&newname);
- return rval;
-}
-
-int
-rename_path(pathname_t *name1, pathname_t *name2)
-{
- char buf1[MAXNAMELEN];
- char buf2[MAXNAMELEN];
- int down1;
- pathname_t newname1;
- pathname_t newname2;
- int rval;
-
- rval = rename(name1->path, name2->path);
- if (rval >= 0 || errno != ENAMETOOLONG)
- return rval;
- separate_pathname(name1, buf1, &newname1);
- separate_pathname(name2, buf2, &newname2);
- if (strcmp(buf1, buf2) == 0) {
- if (chdir(buf1) == 0) {
- rval = rename_path(&newname1, &newname2);
- chdir("..");
- }
- } else {
- if (strcmp(buf1, "..") == 0)
- down1 = 0;
- else if (strcmp(buf2, "..") == 0)
- down1 = 1;
- else if (strlen(buf1) == 0)
- down1 = 0;
- else if (strlen(buf2) == 0)
- down1 = 1;
- else
- down1 = MAX(newname1.len, 3 + name2->len) <=
- MAX(3 + name1->len, newname2.len);
- if (down1) {
- free_pathname(&newname2);
- append_pathname(&newname2, "../");
- append_pathname(&newname2, name2->path);
- if (chdir(buf1) == 0) {
- rval = rename_path(&newname1, &newname2);
- chdir("..");
- }
- } else {
- free_pathname(&newname1);
- append_pathname(&newname1, "../");
- append_pathname(&newname1, name1->path);
- if (chdir(buf2) == 0) {
- rval = rename_path(&newname1, &newname2);
- chdir("..");
- }
- }
- }
- free_pathname(&newname1);
- free_pathname(&newname2);
- return rval;
-}
-
-int
-rmdir_path(pathname_t *name)
-{
- char buf[MAXNAMELEN];
- pathname_t newname;
- int rval;
-
- rval = rmdir(name->path);
- if (rval >= 0 || errno != ENAMETOOLONG)
- return rval;
- separate_pathname(name, buf, &newname);
- if (chdir(buf) == 0) {
- rval = rmdir_path(&newname);
- chdir("..");
- }
- free_pathname(&newname);
- return rval;
-}
-
-void
-separate_pathname(pathname_t *name, char *buf, pathname_t *newname)
-{
- char *slash;
-
- init_pathname(newname);
- slash = strchr(name->path, '/');
- if (slash == NULL) {
- buf[0] = '\0';
- return;
- }
- *slash = '\0';
- strcpy(buf, name->path);
- *slash = '/';
- append_pathname(newname, slash + 1);
-}
-
-#define WIDTH 80
-
-void
-show_ops(int flag, char *lead_str)
-{
- opdesc_t *p;
-
- if (flag<0) {
- /* print in list form */
- int x = WIDTH;
-
- for (p = ops; p < ops_end; p++) {
- if (lead_str != NULL && x+strlen(p->name)>=WIDTH-5)
- x=printf("%s%s", (p==ops)?"":"\n", lead_str);
- x+=printf("%s ", p->name);
- }
- printf("\n");
- } else {
- int f;
- for (f = 0, p = ops; p < ops_end; p++)
- f += p->freq;
-
- if (f == 0)
- flag = 1;
-
- for (p = ops; p < ops_end; p++) {
- if (flag != 0 || p->freq > 0) {
- if (lead_str != NULL)
- printf("%s", lead_str);
- printf("%20s %d/%d %s\n",
- p->name, p->freq, f,
- (p->iswrite == 0) ? " " : "write op");
- }
- }
- }
-}
-
-int
-stat64_path(pathname_t *name, struct stat64 *sbuf)
-{
- char buf[MAXNAMELEN];
- pathname_t newname;
- int rval;
-
- rval = stat64(name->path, sbuf);
- if (rval >= 0 || errno != ENAMETOOLONG)
- return rval;
- separate_pathname(name, buf, &newname);
- if (chdir(buf) == 0) {
- rval = stat64_path(&newname, sbuf);
- chdir("..");
- }
- free_pathname(&newname);
- return rval;
-}
-
-int
-symlink_path(const char *name1, pathname_t *name)
-{
- char buf[MAXNAMELEN];
- pathname_t newname;
- int rval;
-
- if (!strcmp(name1, name->path)) {
- printf("yikes! %s %s\n", name1, name->path);
- return 0;
- }
-
- rval = symlink(name1, name->path);
- if (rval >= 0 || errno != ENAMETOOLONG)
- return rval;
- separate_pathname(name, buf, &newname);
- if (chdir(buf) == 0) {
- rval = symlink_path(name1, &newname);
- chdir("..");
- }
- free_pathname(&newname);
- return rval;
-}
-
-int
-truncate64_path(pathname_t *name, off64_t length)
-{
- char buf[MAXNAMELEN];
- pathname_t newname;
- int rval;
-
- rval = truncate64(name->path, length);
- if (rval >= 0 || errno != ENAMETOOLONG)
- return rval;
- separate_pathname(name, buf, &newname);
- if (chdir(buf) == 0) {
- rval = truncate64_path(&newname, length);
- chdir("..");
- }
- free_pathname(&newname);
- return rval;
-}
-
-int
-unlink_path(pathname_t *name)
-{
- char buf[MAXNAMELEN];
- pathname_t newname;
- int rval;
-
- rval = unlink(name->path);
- if (rval >= 0 || errno != ENAMETOOLONG)
- return rval;
- separate_pathname(name, buf, &newname);
- if (chdir(buf) == 0) {
- rval = unlink_path(&newname);
- chdir("..");
- }
- free_pathname(&newname);
- return rval;
-}
-
-void
-usage(void)
-{
- printf("Usage: %s -H or\n", myprog);
- printf(" %s [-d dir][-e errtg][-f op_name=freq][-n nops]\n",
- myprog);
- printf(" [-p nproc][-r len][-s seed][-v][-w][-z][-S]\n");
- printf("where\n");
- printf(" -d dir specifies the base directory for operations\n");
- printf(" -e errtg specifies error injection stuff\n");
- printf(" -f op_name=freq changes the frequency of option name to freq\n");
- printf(" the valid operation names are:\n");
- show_ops(-1, " ");
- printf(" -n nops specifies the no. of operations per process (default 1)\n");
- printf(" -p nproc specifies the no. of processes (default 1)\n");
- printf(" -r specifies random name padding\n");
- printf(" -s seed specifies the seed for the random generator (default random)\n");
- printf(" -v specifies verbose mode\n");
- printf(" -w zeros frequencies of non-write operations\n");
- printf(" -z zeros frequencies of all operations\n");
- printf(" -S prints the table of operations (omitting zero frequency)\n");
- printf(" -H prints usage and exits\n");
-}
-
-void
-write_freq(void)
-{
- opdesc_t *p;
-
- for (p = ops; p < ops_end; p++) {
- if (!p->iswrite)
- p->freq = 0;
- }
-}
-
-void
-zero_freq(void)
-{
- opdesc_t *p;
-
- for (p = ops; p < ops_end; p++)
- p->freq = 0;
-}
-
-void
-allocsp_f(int opno, long r)
-{
- int e;
- pathname_t f;
- int fd;
- struct flock64 fl;
- __int64_t lr;
- off64_t off;
- struct stat64 stb;
- int v;
-
- init_pathname(&f);
- if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) {
- if (v)
- printf("%d/%d: allocsp - no filename\n", procid, opno);
- free_pathname(&f);
- return;
- }
- fd = open_path(&f, O_RDWR);
- e = fd < 0 ? errno : 0;
- check_cwd();
- if (fd < 0) {
- if (v)
- printf("%d/%d: allocsp - open %s failed %d\n",
- procid, opno, f.path, e);
- free_pathname(&f);
- return;
- }
- if (fstat64(fd, &stb) < 0) {
- if (v)
- printf("%d/%d: allocsp - fstat64 %s failed %d\n",
- procid, opno, f.path, errno);
- free_pathname(&f);
- close(fd);
- return;
- }
- lr = ((__int64_t)random() << 32) + random();
- off = (off64_t)(lr % MIN(stb.st_size + (1024 * 1024), MAXFSIZE));
- off %= maxfsize;
- fl.l_whence = SEEK_SET;
- fl.l_start = off;
- fl.l_len = 0;
- e = ioctl(fd, XFS_IOC_ALLOCSP64, &fl) < 0 ? errno : 0;
- if (v)
- printf("%d/%d: ioctl(XFS_IOC_ALLOCSP64) %s %lld 0 %d\n",
- procid, opno, f.path, off, e);
- free_pathname(&f);
- close(fd);
-}
-
-void
-attr_remove_f(int opno, long r)
-{
- char *aname, *l;
- char buf[4096];
- int e;
- int ent;
- pathname_t f;
- int total;
- int v;
- int which;
-
- init_pathname(&f);
- if (!get_fname(FT_ANYm, r, &f, NULL, NULL, &v))
- append_pathname(&f, ".");
- total = 0;
- e = attr_list_path(&f, buf, sizeof(buf), ATTR_DONTFOLLOW);
- check_cwd();
- if (e > 0) {
- for (l = buf; l - buf <= e; l += strlen(l)+1)
- if (strncmp(l, "user.",5) == 0)
- total++;
- }
- if (total == 0) {
- if (v)
- printf("%d/%d: attr_remove - no attrs for %s\n",
- procid, opno, f.path);
- free_pathname(&f);
- return;
- }
- which = (int)(random() % total);
- ent = 0;
- aname = NULL;
- e = attr_list_path(&f, buf, sizeof(buf), ATTR_DONTFOLLOW);
- check_cwd();
- if (e <= 0)
- return;
- for (l = buf; l - buf <= e; l += strlen(l)+1) {
- if (strncmp(l, "user.",5) == 0) {
- if (++ent == which) {
- aname = l;
- break;
- }
- }
- }
- if (aname == NULL) {
- if (v)
- printf(
- "%d/%d: attr_remove - name %d not found at %s\n",
- procid, opno, which, f.path);
- free_pathname(&f);
- return;
- }
- e = attr_remove_path(&f, aname, ATTR_DONTFOLLOW) < 0 ? errno : 0;
- check_cwd();
- if (v)
- printf("%d/%d: attr_remove %s %s %d\n",
- procid, opno, f.path, aname, e);
- free_pathname(&f);
-}
-
-void
-attr_set_f(int opno, long r)
-{
- char aname[10];
- char *aval;
- int e;
- pathname_t f;
- int len;
- static int lengths[] = { 10, 100, 1000, 10000 };
- int li;
- int v;
-
- init_pathname(&f);
- if (!get_fname(FT_ANYm, r, &f, NULL, NULL, &v))
- append_pathname(&f, ".");
- sprintf(aname, "a%x", nameseq++);
- li = (int)(random() % (sizeof(lengths) / sizeof(lengths[0])));
- len = (int)(random() % lengths[li]);
- if (len == 0)
- len = 1;
- aval = malloc(len);
- memset(aval, nameseq & 0xff, len);
- e = attr_set_path(&f, aname, aval, len, ATTR_DONTFOLLOW) < 0 ?
- errno : 0;
- check_cwd();
- free(aval);
- if (v)
- printf("%d/%d: attr_set %s %s %d\n", procid, opno, f.path,
- aname, e);
- free_pathname(&f);
-}
-
-void
-bulkstat_f(int opno, long r)
-{
- int count;
- int fd;
- __uint64_t last;
- int nent;
- xfs_bstat_t *t;
- __int64_t total;
- xfs_fsop_bulkreq_t bsr;
-
- last = 0;
- nent = (r % 999) + 2;
- t = malloc(nent * sizeof(*t));
- fd = open(".", O_RDONLY);
- total = 0;
-
- bsr.lastip=&last;
- bsr.icount=nent;
- bsr.ubuffer=t;
- bsr.ocount=&count;
-
- while (ioctl(fd, XFS_IOC_FSBULKSTAT, &bsr) == 0 && count > 0)
- total += count;
- free(t);
- if (verbose)
- printf("%d/%d: bulkstat nent %d total %lld\n",
- procid, opno, nent, total);
- close(fd);
-}
-
-void
-bulkstat1_f(int opno, long r)
-{
- int e;
- pathname_t f;
- int fd;
- int good;
- __uint64_t ino;
- struct stat64 s;
- xfs_bstat_t t;
- int v;
- xfs_fsop_bulkreq_t bsr;
-
-
- good = random() & 1;
- if (good) {
- /* use an inode we know exists */
- init_pathname(&f);
- if (!get_fname(FT_ANYm, r, &f, NULL, NULL, &v))
- append_pathname(&f, ".");
- ino = stat64_path(&f, &s) < 0 ? (ino64_t)r : s.st_ino;
- check_cwd();
- free_pathname(&f);
- } else {
- /*
- * pick a random inode
- *
- * note this can generate kernel warning messages
- * since bulkstat_one will read the disk block that
- * would contain a given inode even if that disk
- * block doesn't contain inodes.
- *
- * this is detected later, but not until after the
- * warning is displayed.
- *
- * "XFS: device 0x825- bad inode magic/vsn daddr 0x0 #0"
- *
- */
- ino = (ino64_t)r;
- v = verbose;
- }
- fd = open(".", O_RDONLY);
-
- bsr.lastip=&ino;
- bsr.icount=1;
- bsr.ubuffer=&t;
- bsr.ocount=NULL;
-
- e = ioctl(fd, XFS_IOC_FSBULKSTAT_SINGLE, &bsr) < 0 ? errno : 0;
- if (v)
- printf("%d/%d: bulkstat1 %s ino %lld %d\n",
- procid, opno, good?"real":"random", (int64_t)ino, e);
- close(fd);
-}
-
-void
-chown_f(int opno, long r)
-{
- int e;
- pathname_t f;
- int nbits;
- uid_t u;
- int v;
-
- init_pathname(&f);
- if (!get_fname(FT_ANYm, r, &f, NULL, NULL, &v))
- append_pathname(&f, ".");
- u = (uid_t)random();
- nbits = (int)(random() % 32);
- u &= (1 << nbits) - 1;
- e = lchown_path(&f, u, -1) < 0 ? errno : 0;
- check_cwd();
- if (v)
- printf("%d/%d: chown %s %d %d\n", procid, opno, f.path, u, e);
- free_pathname(&f);
-}
-
-void
-creat_f(int opno, long r)
-{
- struct fsxattr a;
- int e;
- int e1;
- int extsize;
- pathname_t f;
- int fd;
- fent_t *fep;
- int id;
- int parid;
- int type;
- int v;
- int v1;
-
- if (!get_fname(FT_DIRm, r, NULL, NULL, &fep, &v1))
- parid = -1;
- else
- parid = fep->id;
- init_pathname(&f);
- type = rtpct ? ((random() % 100) > rtpct ? FT_REG : FT_RTF) : FT_REG;
- if (type == FT_RTF)
- extsize = (random() % 10) + 1;
- else
- extsize = 0;
- e = generate_fname(fep, type, &f, &id, &v);
- v |= v1;
- if (!e) {
- if (v) {
- fent_to_name(&f, &flist[FT_DIR], fep);
- printf("%d/%d: creat - no filename from %s\n",
- procid, opno, f.path);
- }
- free_pathname(&f);
- return;
- }
- fd = creat_path(&f, 0666);
- e = fd < 0 ? errno : 0;
- e1 = 0;
- check_cwd();
- if (fd >= 0) {
- if (extsize && ioctl(fd, XFS_IOC_FSGETXATTR, &a) >= 0) {
- a.fsx_xflags |= XFS_XFLAG_REALTIME;
- a.fsx_extsize =
- geom.rtextsize * geom.blocksize * extsize;
- if (ioctl(fd, XFS_IOC_FSSETXATTR, &a) < 0)
- e1 = errno;
- }
- add_to_flist(type, id, parid);
- close(fd);
- }
- if (v)
- printf("%d/%d: creat %s x:%d %d %d\n", procid, opno, f.path,
- extsize ? a.fsx_extsize : 0, e, e1);
- free_pathname(&f);
-}
-
-void
-dread_f(int opno, long r)
-{
- __int64_t align;
- char *buf;
- struct dioattr diob;
- int e;
- pathname_t f;
- int fd;
- size_t len;
- __int64_t lr;
- off64_t off;
- struct stat64 stb;
- int v;
-
- init_pathname(&f);
- if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) {
- if (v)
- printf("%d/%d: dread - no filename\n", procid, opno);
- free_pathname(&f);
- return;
- }
- fd = open_path(&f, O_RDONLY|O_DIRECT);
- e = fd < 0 ? errno : 0;
- check_cwd();
- if (fd < 0) {
- if (v)
- printf("%d/%d: dread - open %s failed %d\n",
- procid, opno, f.path, e);
- free_pathname(&f);
- return;
- }
- if (fstat64(fd, &stb) < 0) {
- if (v)
- printf("%d/%d: dread - fstat64 %s failed %d\n",
- procid, opno, f.path, errno);
- free_pathname(&f);
- close(fd);
- return;
- }
- if (stb.st_size == 0) {
- if (v)
- printf("%d/%d: dread - %s zero size\n", procid, opno,
- f.path);
- free_pathname(&f);
- close(fd);
- return;
- }
- if (ioctl(fd, XFS_IOC_DIOINFO, &diob) < 0) {
- if (v)
- printf(
- "%d/%d: dread - ioctl(fd, XFS_IOC_DIOINFO) %s failed %d\n",
- procid, opno, f.path, errno);
- free_pathname(&f);
- close(fd);
- return;
- }
- align = (__int64_t)diob.d_miniosz;
- lr = ((__int64_t)random() << 32) + random();
- off = (off64_t)(lr % stb.st_size);
- off -= (off % align);
- lseek64(fd, off, SEEK_SET);
- len = (random() % (getpagesize() * 32)) + 1;
- len -= (len % align);
- if (len <= 0)
- len = align;
- else if (len > diob.d_maxiosz)
- len = diob.d_maxiosz;
- buf = memalign(diob.d_mem, len);
- e = read(fd, buf, len) < 0 ? errno : 0;
- free(buf);
- if (v)
- printf("%d/%d: dread %s [%lld,%d] %d\n",
- procid, opno, f.path, off, len, e);
- free_pathname(&f);
- close(fd);
-}
-
-void
-dwrite_f(int opno, long r)
-{
- __int64_t align;
- char *buf;
- struct dioattr diob;
- int e;
- pathname_t f;
- int fd;
- size_t len;
- __int64_t lr;
- off64_t off;
- struct stat64 stb;
- int v;
-
- init_pathname(&f);
- if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) {
- if (v)
- printf("%d/%d: dwrite - no filename\n", procid, opno);
- free_pathname(&f);
- return;
- }
- fd = open_path(&f, O_WRONLY|O_DIRECT);
- e = fd < 0 ? errno : 0;
- check_cwd();
- if (fd < 0) {
- if (v)
- printf("%d/%d: dwrite - open %s failed %d\n",
- procid, opno, f.path, e);
- free_pathname(&f);
- return;
- }
- if (fstat64(fd, &stb) < 0) {
- if (v)
- printf("%d/%d: dwrite - fstat64 %s failed %d\n",
- procid, opno, f.path, errno);
- free_pathname(&f);
- close(fd);
- return;
- }
- if (ioctl(fd, XFS_IOC_DIOINFO, &diob) < 0) {
- if (v)
- printf(
- "%d/%d: dwrite - ioctl(fd, XFS_IOC_DIOINFO) %s failed %d\n",
- procid, opno, f.path, errno);
- free_pathname(&f);
- close(fd);
- return;
- }
- align = (__int64_t)diob.d_miniosz;
- lr = ((__int64_t)random() << 32) + random();
- off = (off64_t)(lr % MIN(stb.st_size + (1024 * 1024), MAXFSIZE));
- off -= (off % align);
- lseek64(fd, off, SEEK_SET);
- len = (random() % (getpagesize() * 32)) + 1;
- len -= (len % align);
- if (len <= 0)
- len = align;
- else if (len > diob.d_maxiosz)
- len = diob.d_maxiosz;
- buf = memalign(diob.d_mem, len);
- off %= maxfsize;
- lseek64(fd, off, SEEK_SET);
- memset(buf, nameseq & 0xff, len);
- e = write(fd, buf, len) < 0 ? errno : 0;
- free(buf);
- if (v)
- printf("%d/%d: dwrite %s [%lld,%d] %d\n",
- procid, opno, f.path, off, len, e);
- free_pathname(&f);
- close(fd);
-}
-
-void
-fdatasync_f(int opno, long r)
-{
- int e;
- pathname_t f;
- int fd;
- int v;
-
- init_pathname(&f);
- if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) {
- if (v)
- printf("%d/%d: fdatasync - no filename\n",
- procid, opno);
- free_pathname(&f);
- return;
- }
- fd = open_path(&f, O_WRONLY);
- e = fd < 0 ? errno : 0;
- check_cwd();
- if (fd < 0) {
- if (v)
- printf("%d/%d: fdatasync - open %s failed %d\n",
- procid, opno, f.path, e);
- free_pathname(&f);
- return;
- }
- e = fdatasync(fd) < 0 ? errno : 0;
- if (v)
- printf("%d/%d: fdatasync %s %d\n", procid, opno, f.path, e);
- free_pathname(&f);
- close(fd);
-}
-
-void
-freesp_f(int opno, long r)
-{
- int e;
- pathname_t f;
- int fd;
- struct flock64 fl;
- __int64_t lr;
- off64_t off;
- struct stat64 stb;
- int v;
-
- init_pathname(&f);
- if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) {
- if (v)
- printf("%d/%d: freesp - no filename\n", procid, opno);
- free_pathname(&f);
- return;
- }
- fd = open_path(&f, O_RDWR);
- e = fd < 0 ? errno : 0;
- check_cwd();
- if (fd < 0) {
- if (v)
- printf("%d/%d: freesp - open %s failed %d\n",
- procid, opno, f.path, e);
- free_pathname(&f);
- return;
- }
- if (fstat64(fd, &stb) < 0) {
- if (v)
- printf("%d/%d: freesp - fstat64 %s failed %d\n",
- procid, opno, f.path, errno);
- free_pathname(&f);
- close(fd);
- return;
- }
- lr = ((__int64_t)random() << 32) + random();
- off = (off64_t)(lr % MIN(stb.st_size + (1024 * 1024), MAXFSIZE));
- off %= maxfsize;
- fl.l_whence = SEEK_SET;
- fl.l_start = off;
- fl.l_len = 0;
- e = ioctl(fd, XFS_IOC_FREESP64, &fl) < 0 ? errno : 0;
- if (v)
- printf("%d/%d: ioctl(XFS_IOC_FREESP64) %s %lld 0 %d\n",
- procid, opno, f.path, off, e);
- free_pathname(&f);
- close(fd);
-}
-
-void
-fsync_f(int opno, long r)
-{
- int e;
- pathname_t f;
- int fd;
- int v;
-
- init_pathname(&f);
- if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) {
- if (v)
- printf("%d/%d: fsync - no filename\n", procid, opno);
- free_pathname(&f);
- return;
- }
- fd = open_path(&f, O_WRONLY);
- e = fd < 0 ? errno : 0;
- check_cwd();
- if (fd < 0) {
- if (v)
- printf("%d/%d: fsync - open %s failed %d\n",
- procid, opno, f.path, e);
- free_pathname(&f);
- return;
- }
- e = fsync(fd) < 0 ? errno : 0;
- if (v)
- printf("%d/%d: fsync %s %d\n", procid, opno, f.path, e);
- free_pathname(&f);
- close(fd);
-}
-
-void
-getdents_f(int opno, long r)
-{
- DIR *dir;
- pathname_t f;
- int v;
-
- init_pathname(&f);
- if (!get_fname(FT_DIRm, r, &f, NULL, NULL, &v))
- append_pathname(&f, ".");
- dir = opendir_path(&f);
- check_cwd();
- if (dir == NULL) {
- if (v)
- printf("%d/%d: getdents - can't open %s\n",
- procid, opno, f.path);
- free_pathname(&f);
- return;
- }
- while (readdir64(dir) != NULL)
- continue;
- if (v)
- printf("%d/%d: getdents %s 0\n", procid, opno, f.path);
- free_pathname(&f);
- closedir(dir);
-}
-
-void
-link_f(int opno, long r)
-{
- int e;
- pathname_t f;
- fent_t *fep;
- flist_t *flp;
- int id;
- pathname_t l;
- int parid;
- int v;
- int v1;
-
- init_pathname(&f);
- if (!get_fname(FT_NOTDIR, r, &f, &flp, NULL, &v1)) {
- if (v1)
- printf("%d/%d: link - no file\n", procid, opno);
- free_pathname(&f);
- return;
- }
- if (!get_fname(FT_DIRm, random(), NULL, NULL, &fep, &v))
- parid = -1;
- else
- parid = fep->id;
- v |= v1;
- init_pathname(&l);
- e = generate_fname(fep, flp - flist, &l, &id, &v1);
- v |= v1;
- if (!e) {
- if (v) {
- fent_to_name(&l, &flist[FT_DIR], fep);
- printf("%d/%d: link - no filename from %s\n",
- procid, opno, l.path);
- }
- free_pathname(&l);
- free_pathname(&f);
- return;
- }
- e = link_path(&f, &l) < 0 ? errno : 0;
- check_cwd();
- if (e == 0)
- add_to_flist(flp - flist, id, parid);
- if (v)
- printf("%d/%d: link %s %s %d\n", procid, opno, f.path, l.path,
- e);
- free_pathname(&l);
- free_pathname(&f);
-}
-
-void
-mkdir_f(int opno, long r)
-{
- int e;
- pathname_t f;
- fent_t *fep;
- int id;
- int parid;
- int v;
- int v1;
-
- if (!get_fname(FT_DIRm, r, NULL, NULL, &fep, &v))
- parid = -1;
- else
- parid = fep->id;
- init_pathname(&f);
- e = generate_fname(fep, FT_DIR, &f, &id, &v1);
- v |= v1;
- if (!e) {
- if (v) {
- fent_to_name(&f, &flist[FT_DIR], fep);
- printf("%d/%d: mkdir - no filename from %s\n",
- procid, opno, f.path);
- }
- free_pathname(&f);
- return;
- }
- e = mkdir_path(&f, 0777) < 0 ? errno : 0;
- check_cwd();
- if (e == 0)
- add_to_flist(FT_DIR, id, parid);
- if (v)
- printf("%d/%d: mkdir %s %d\n", procid, opno, f.path, e);
- free_pathname(&f);
-}
-
-void
-mknod_f(int opno, long r)
-{
- int e;
- pathname_t f;
- fent_t *fep;
- int id;
- int parid;
- int v;
- int v1;
-
- if (!get_fname(FT_DIRm, r, NULL, NULL, &fep, &v))
- parid = -1;
- else
- parid = fep->id;
- init_pathname(&f);
- e = generate_fname(fep, FT_DEV, &f, &id, &v1);
- v |= v1;
- if (!e) {
- if (v) {
- fent_to_name(&f, &flist[FT_DIR], fep);
- printf("%d/%d: mknod - no filename from %s\n",
- procid, opno, f.path);
- }
- free_pathname(&f);
- return;
- }
- e = mknod_path(&f, S_IFCHR|0444, 0) < 0 ? errno : 0;
- check_cwd();
- if (e == 0)
- add_to_flist(FT_DEV, id, parid);
- if (v)
- printf("%d/%d: mknod %s %d\n", procid, opno, f.path, e);
- free_pathname(&f);
-}
-
-void
-read_f(int opno, long r)
-{
- char *buf;
- int e;
- pathname_t f;
- int fd;
- size_t len;
- __int64_t lr;
- off64_t off;
- struct stat64 stb;
- int v;
-
- init_pathname(&f);
- if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) {
- if (v)
- printf("%d/%d: read - no filename\n", procid, opno);
- free_pathname(&f);
- return;
- }
- fd = open_path(&f, O_RDONLY);
- e = fd < 0 ? errno : 0;
- check_cwd();
- if (fd < 0) {
- if (v)
- printf("%d/%d: read - open %s failed %d\n",
- procid, opno, f.path, e);
- free_pathname(&f);
- return;
- }
- if (fstat64(fd, &stb) < 0) {
- if (v)
- printf("%d/%d: read - fstat64 %s failed %d\n",
- procid, opno, f.path, errno);
- free_pathname(&f);
- close(fd);
- return;
- }
- if (stb.st_size == 0) {
- if (v)
- printf("%d/%d: read - %s zero size\n", procid, opno,
- f.path);
- free_pathname(&f);
- close(fd);
- return;
- }
- lr = ((__int64_t)random() << 32) + random();
- off = (off64_t)(lr % stb.st_size);
- lseek64(fd, off, SEEK_SET);
- len = (random() % (getpagesize() * 32)) + 1;
- buf = malloc(len);
- e = read(fd, buf, len) < 0 ? errno : 0;
- free(buf);
- if (v)
- printf("%d/%d: read %s [%lld,%d] %d\n",
- procid, opno, f.path, off, len, e);
- free_pathname(&f);
- close(fd);
-}
-
-void
-readlink_f(int opno, long r)
-{
- char buf[PATH_MAX];
- int e;
- pathname_t f;
- int v;
-
- init_pathname(&f);
- if (!get_fname(FT_SYMm, r, &f, NULL, NULL, &v)) {
- if (v)
- printf("%d/%d: readlink - no filename\n", procid, opno);
- free_pathname(&f);
- return;
- }
- e = readlink_path(&f, buf, PATH_MAX) < 0 ? errno : 0;
- check_cwd();
- if (v)
- printf("%d/%d: readlink %s %d\n", procid, opno, f.path, e);
- free_pathname(&f);
-}
-
-void
-rename_f(int opno, long r)
-{
- fent_t *dfep;
- int e;
- pathname_t f;
- fent_t *fep;
- flist_t *flp;
- int id;
- pathname_t newf;
- int oldid;
- int parid;
- int v;
- int v1;
-
- init_pathname(&f);
- if (!get_fname(FT_ANYm, r, &f, &flp, &fep, &v1)) {
- if (v1)
- printf("%d/%d: rename - no filename\n", procid, opno);
- free_pathname(&f);
- return;
- }
- if (!get_fname(FT_DIRm, random(), NULL, NULL, &dfep, &v))
- parid = -1;
- else
- parid = dfep->id;
- v |= v1;
- init_pathname(&newf);
- e = generate_fname(dfep, flp - flist, &newf, &id, &v1);
- v |= v1;
- if (!e) {
- if (v) {
- fent_to_name(&f, &flist[FT_DIR], dfep);
- printf("%d/%d: rename - no filename from %s\n",
- procid, opno, f.path);
- }
- free_pathname(&newf);
- free_pathname(&f);
- return;
- }
- e = rename_path(&f, &newf) < 0 ? errno : 0;
- check_cwd();
- if (e == 0) {
- if (flp - flist == FT_DIR) {
- oldid = fep->id;
- fix_parent(oldid, id);
- }
- del_from_flist(flp - flist, fep - flp->fents);
- add_to_flist(flp - flist, id, parid);
- }
- if (v)
- printf("%d/%d: rename %s to %s %d\n", procid, opno, f.path,
- newf.path, e);
- free_pathname(&newf);
- free_pathname(&f);
-}
-
-void
-resvsp_f(int opno, long r)
-{
- int e;
- pathname_t f;
- int fd;
- struct flock64 fl;
- __int64_t lr;
- off64_t off;
- struct stat64 stb;
- int v;
-
- init_pathname(&f);
- if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) {
- if (v)
- printf("%d/%d: resvsp - no filename\n", procid, opno);
- free_pathname(&f);
- return;
- }
- fd = open_path(&f, O_RDWR);
- e = fd < 0 ? errno : 0;
- check_cwd();
- if (fd < 0) {
- if (v)
- printf("%d/%d: resvsp - open %s failed %d\n",
- procid, opno, f.path, e);
- free_pathname(&f);
- return;
- }
- if (fstat64(fd, &stb) < 0) {
- if (v)
- printf("%d/%d: resvsp - fstat64 %s failed %d\n",
- procid, opno, f.path, errno);
- free_pathname(&f);
- close(fd);
- return;
- }
- lr = ((__int64_t)random() << 32) + random();
- off = (off64_t)(lr % MIN(stb.st_size + (1024 * 1024), MAXFSIZE));
- off %= maxfsize;
- fl.l_whence = SEEK_SET;
- fl.l_start = off;
- fl.l_len = (off64_t)(random() % (1024 * 1024));
- e = ioctl(fd, XFS_IOC_RESVSP64, &fl) < 0 ? errno : 0;
- if (v)
- printf("%d/%d: ioctl(XFS_IOC_RESVSP64) %s %lld %lld %d\n",
- procid, opno, f.path, off, fl.l_len, e);
- free_pathname(&f);
- close(fd);
-}
-
-void
-rmdir_f(int opno, long r)
-{
- int e;
- pathname_t f;
- fent_t *fep;
- int v;
-
- init_pathname(&f);
- if (!get_fname(FT_DIRm, r, &f, NULL, &fep, &v)) {
- if (v)
- printf("%d/%d: rmdir - no directory\n", procid, opno);
- free_pathname(&f);
- return;
- }
- e = rmdir_path(&f) < 0 ? errno : 0;
- check_cwd();
- if (e == 0)
- del_from_flist(FT_DIR, fep - flist[FT_DIR].fents);
- if (v)
- printf("%d/%d: rmdir %s %d\n", procid, opno, f.path, e);
- free_pathname(&f);
-}
-
-void
-stat_f(int opno, long r)
-{
- int e;
- pathname_t f;
- struct stat64 stb;
- int v;
-
- init_pathname(&f);
- if (!get_fname(FT_ANYm, r, &f, NULL, NULL, &v)) {
- if (v)
- printf("%d/%d: stat - no entries\n", procid, opno);
- free_pathname(&f);
- return;
- }
- e = lstat64_path(&f, &stb) < 0 ? errno : 0;
- check_cwd();
- if (v)
- printf("%d/%d: stat %s %d\n", procid, opno, f.path, e);
- free_pathname(&f);
-}
-
-void
-symlink_f(int opno, long r)
-{
- int e;
- pathname_t f;
- fent_t *fep;
- int i;
- int id;
- int len;
- int parid;
- int v;
- int v1;
- char *val;
-
- if (!get_fname(FT_DIRm, r, NULL, NULL, &fep, &v))
- parid = -1;
- else
- parid = fep->id;
- init_pathname(&f);
- e = generate_fname(fep, FT_SYM, &f, &id, &v1);
- v |= v1;
- if (!e) {
- if (v) {
- fent_to_name(&f, &flist[FT_DIR], fep);
- printf("%d/%d: symlink - no filename from %s\n",
- procid, opno, f.path);
- }
- free_pathname(&f);
- return;
- }
- len = (int)(random() % PATH_MAX);
- val = malloc(len + 1);
- if (len)
- memset(val, 'x', len);
- val[len] = '\0';
- for (i = 10; i < len - 1; i += 10)
- val[i] = '/';
- e = symlink_path(val, &f) < 0 ? errno : 0;
- check_cwd();
- if (e == 0)
- add_to_flist(FT_SYM, id, parid);
- free(val);
- if (v)
- printf("%d/%d: symlink %s %d\n", procid, opno, f.path, e);
- free_pathname(&f);
-}
-
-/* ARGSUSED */
-void
-sync_f(int opno, long r)
-{
- sync();
- if (verbose)
- printf("%d/%d: sync\n", procid, opno);
-}
-
-void
-truncate_f(int opno, long r)
-{
- int e;
- pathname_t f;
- __int64_t lr;
- off64_t off;
- struct stat64 stb;
- int v;
-
- init_pathname(&f);
- if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) {
- if (v)
- printf("%d/%d: truncate - no filename\n", procid, opno);
- free_pathname(&f);
- return;
- }
- e = stat64_path(&f, &stb) < 0 ? errno : 0;
- check_cwd();
- if (e > 0) {
- if (v)
- printf("%d/%d: truncate - stat64 %s failed %d\n",
- procid, opno, f.path, e);
- free_pathname(&f);
- return;
- }
- lr = ((__int64_t)random() << 32) + random();
- off = (off64_t)(lr % MIN(stb.st_size + (1024 * 1024), MAXFSIZE));
- off %= maxfsize;
- e = truncate64_path(&f, off) < 0 ? errno : 0;
- check_cwd();
- if (v)
- printf("%d/%d: truncate %s %lld %d\n", procid, opno, f.path,
- off, e);
- free_pathname(&f);
-}
-
-void
-unlink_f(int opno, long r)
-{
- int e;
- pathname_t f;
- fent_t *fep;
- flist_t *flp;
- int v;
-
- init_pathname(&f);
- if (!get_fname(FT_NOTDIR, r, &f, &flp, &fep, &v)) {
- if (v)
- printf("%d/%d: unlink - no file\n", procid, opno);
- free_pathname(&f);
- return;
- }
- e = unlink_path(&f) < 0 ? errno : 0;
- check_cwd();
- if (e == 0)
- del_from_flist(flp - flist, fep - flp->fents);
- if (v)
- printf("%d/%d: unlink %s %d\n", procid, opno, f.path, e);
- free_pathname(&f);
-}
-
-void
-unresvsp_f(int opno, long r)
-{
- int e;
- pathname_t f;
- int fd;
- struct flock64 fl;
- __int64_t lr;
- off64_t off;
- struct stat64 stb;
- int v;
-
- init_pathname(&f);
- if (!get_fname(FT_REGFILE, r, &f, NULL, NULL, &v)) {
- if (v)
- printf("%d/%d: unresvsp - no filename\n", procid, opno);
- free_pathname(&f);
- return;
- }
- fd = open_path(&f, O_RDWR);
- e = fd < 0 ? errno : 0;
- check_cwd();
- if (fd < 0) {
- if (v)
- printf("%d/%d: unresvsp - open %s failed %d\n",
- procid, opno, f.path, e);
- free_pathname(&f);
- return;
- }
- if (fstat64(fd, &stb) < 0) {
- if (v)
- printf("%d/%d: unresvsp - fstat64 %s failed %d\n",
- procid, opno, f.path, errno);
- free_pathname(&f);
- close(fd);
- return;
- }
- lr = ((__int64_t)random() << 32) + random();
- off = (off64_t)(lr % MIN(stb.st_size + (1024 * 1024), MAXFSIZE));
- off %= maxfsize;
- fl.l_whence = SEEK_SET;
- fl.l_start = off;
- fl.l_len = (off64_t)(random() % (1 << 20));
- e = ioctl(fd, XFS_IOC_UNRESVSP64, &fl) < 0 ? errno : 0;
- if (v)
- printf("%d/%d: ioctl(XFS_IOC_UNRESVSP64) %s %lld %lld %d\n",
- procid, opno, f.path, off, fl.l_len, e);
- free_pathname(&f);
- close(fd);
-}
-
-void
-write_f(int opno, long r)
-{
- char *buf;
- int e;
- pathname_t f;
- int fd;
- size_t len;
- __int64_t lr;
- off64_t off;
- struct stat64 stb;
- int v;
-
- init_pathname(&f);
- if (!get_fname(FT_REGm, r, &f, NULL, NULL, &v)) {
- if (v)
- printf("%d/%d: write - no filename\n", procid, opno);
- free_pathname(&f);
- return;
- }
- fd = open_path(&f, O_WRONLY);
- e = fd < 0 ? errno : 0;
- check_cwd();
- if (fd < 0) {
- if (v)
- printf("%d/%d: write - open %s failed %d\n",
- procid, opno, f.path, e);
- free_pathname(&f);
- return;
- }
- if (fstat64(fd, &stb) < 0) {
- if (v)
- printf("%d/%d: write - fstat64 %s failed %d\n",
- procid, opno, f.path, errno);
- free_pathname(&f);
- close(fd);
- return;
- }
- lr = ((__int64_t)random() << 32) + random();
- off = (off64_t)(lr % MIN(stb.st_size + (1024 * 1024), MAXFSIZE));
- off %= maxfsize;
- lseek64(fd, off, SEEK_SET);
- len = (random() % (getpagesize() * 32)) + 1;
- buf = malloc(len);
- memset(buf, nameseq & 0xff, len);
- e = write(fd, buf, len) < 0 ? errno : 0;
- free(buf);
- if (v)
- printf("%d/%d: write %s [%lld,%d] %d\n",
- procid, opno, f.path, off, len, e);
- free_pathname(&f);
- close(fd);
-}
+++ /dev/null
-/**************************************************************************
- *
- * random.c -- pseudo random number generator
- * Copyright (C) 1994 Chris Wallace (csw@bruce.cs.monash.edu.au)
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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 for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- *
- **************************************************************************/
-
-#include <sys/types.h>
-
-/*
- * modified by dxm@sgi.com so that this file acts as a drop in replacement
- * for srandom and random.
- */
-
-/*
- * A random number generator called as a function by
- * random (iseed) or irandm (iseed)
- * The parameter should be a pointer to a 2-element int32_t vector.
- * The first function returns a double uniform in 0 .. 1.
- * The second returns a int32_t integer uniform in 0 .. 2**31-1
- * Both update iseed[] in exactly the same way.
- * iseed[] must be a 2-element integer vector.
- * The initial value of the second element may be anything.
- *
- * The period of the random sequence is 2**32 * (2**32-1)
- * The table mt[0:127] is defined by mt[i] = 69069 ** (128-i)
- */
-
-#define MASK ((int32_t) 593970775)
-/* or in hex, 23674657 */
-
-#define SCALE ((double) 1.0 / (1024.0 * 1024.0 * 1024.0 * 2.0))
-/* i.e. 2 to power -31 */
-
-static int32_t mt [128] = {
- 902906369,
- 2030498053,
- -473499623,
- 1640834941,
- 723406961,
- 1993558325,
- -257162999,
- -1627724755,
- 913952737,
- 278845029,
- 1327502073,
- -1261253155,
- 981676113,
- -1785280363,
- 1700077033,
- 366908557,
- -1514479167,
- -682799163,
- 141955545,
- -830150595,
- 317871153,
- 1542036469,
- -946413879,
- -1950779155,
- 985397153,
- 626515237,
- 530871481,
- 783087261,
- -1512358895,
- 1031357269,
- -2007710807,
- -1652747955,
- -1867214463,
- 928251525,
- 1243003801,
- -2132510467,
- 1874683889,
- -717013323,
- 218254473,
- -1628774995,
- -2064896159,
- 69678053,
- 281568889,
- -2104168611,
- -165128239,
- 1536495125,
- -39650967,
- 546594317,
- -725987007,
- 1392966981,
- 1044706649,
- 687331773,
- -2051306575,
- 1544302965,
- -758494647,
- -1243934099,
- -75073759,
- 293132965,
- -1935153095,
- 118929437,
- 807830417,
- -1416222507,
- -1550074071,
- -84903219,
- 1355292929,
- -380482555,
- -1818444007,
- -204797315,
- 170442609,
- -1636797387,
- 868931593,
- -623503571,
- 1711722209,
- 381210981,
- -161547783,
- -272740131,
- -1450066095,
- 2116588437,
- 1100682473,
- 358442893,
- -1529216831,
- 2116152005,
- -776333095,
- 1265240893,
- -482278607,
- 1067190005,
- 333444553,
- 86502381,
- 753481377,
- 39000101,
- 1779014585,
- 219658653,
- -920253679,
- 2029538901,
- 1207761577,
- -1515772851,
- -236195711,
- 442620293,
- 423166617,
- -1763648515,
- -398436623,
- -1749358155,
- -538598519,
- -652439379,
- 430550625,
- -1481396507,
- 2093206905,
- -1934691747,
- -962631983,
- 1454463253,
- -1877118871,
- -291917555,
- -1711673279,
- 201201733,
- -474645415,
- -96764739,
- -1587365199,
- 1945705589,
- 1303896393,
- 1744831853,
- 381957665,
- 2135332261,
- -55996615,
- -1190135011,
- 1790562961,
- -1493191723,
- 475559465,
- 69069
- };
-
-double
-_random (int32_t is [2])
-{
- int32_t it, leh, nit;
-
- it = is [0];
- leh = is [1];
- if (it <= 0)
- it = (it + it) ^ MASK;
- else
- it = it + it;
- nit = it - 1;
-/* to ensure all-ones pattern omitted */
- leh = leh * mt[nit & 127] + nit;
- is [0] = it; is [1] = leh;
- if (leh < 0) leh = ~leh;
- return (SCALE * ((int32_t) (leh | 1)));
-}
-
-
-
-int32_t
-_irandm (int32_t is [2])
-{
- int32_t it, leh, nit;
-
- it = is [0];
- leh = is [1];
- if (it <= 0)
- it = (it + it) ^ MASK;
- else
- it = it + it;
- nit = it - 1;
-/* to ensure all-ones pattern omitted */
- leh = leh * mt[nit & 127] + nit;
- is [0] = it; is [1] = leh;
- if (leh < 0) leh = ~leh;
- return (leh);
-}
-
-/*
- * make this a drop in replacement for random and srandom
- *
- * XXX not thread safe I guess.
- */
-
-static int32_t saved_seed[2];
-
-long random(void)
-{
- return _irandm(saved_seed);
-}
-
-void srandom(unsigned seed)
-{
- saved_seed[0]=seed;
- saved_seed[1]=0;
- _irandm(saved_seed);
-}
-
exit 1;
}
-my @pkglist = qw( attr acl dmapi xfsdump xfsprogs );
+my @pkglist = qw( xfstests attr acl dmapi xfsdump xfsprogs );
my @difflist = qw(
xfs_ag.h xfs_alloc.h xfs_alloc_btree.h xfs_arch.h
xfs_attr_leaf.h xfs_attr_sf.h xfs_bit.h xfs_bmap.h