mirror of
https://git.proxmox.com/git/mirror_zfs.git
synced 2024-12-25 18:59:33 +03:00
Add the ZFS Test Suite
Add the ZFS Test Suite and test-runner framework from illumos. This is a continuation of the work done by Turbo Fredriksson to port the ZFS Test Suite to Linux. While this work was originally conceived as a stand alone project integrating it directly with the ZoL source tree has several advantages: * Allows the ZFS Test Suite to be packaged in zfs-test package. * Facilitates easy integration with the CI testing. * Users can locally run the ZFS Test Suite to validate ZFS. This testing should ONLY be done on a dedicated test system because the ZFS Test Suite in its current form is destructive. * Allows the ZFS Test Suite to be run directly in the ZoL source tree enabled developers to iterate quickly during development. * Developers can easily add/modify tests in the framework as features are added or functionality is changed. The tests will then always be in sync with the implementation. Full documentation for how to run the ZFS Test Suite is available in the tests/README.md file. Warning: This test suite is designed to be run on a dedicated test system. It will make modifications to the system including, but not limited to, the following. * Adding new users * Adding new groups * Modifying the following /proc files: * /proc/sys/kernel/core_pattern * /proc/sys/kernel/core_uses_pid * Creating directories under / Notes: * Not all of the test cases are expected to pass and by default these test cases are disabled. The failures are primarily due to assumption made for illumos which are invalid under Linux. * When updating these test cases it should be done in as generic a way as possible so the patch can be submitted back upstream. Most existing library functions have been updated to be Linux aware, and the following functions and variables have been added. * Functions: * is_linux - Used to wrap a Linux specific section. * block_device_wait - Waits for block devices to be added to /dev/. * Variables: Linux Illumos * ZVOL_DEVDIR "/dev/zvol" "/dev/zvol/dsk" * ZVOL_RDEVDIR "/dev/zvol" "/dev/zvol/rdsk" * DEV_DSKDIR "/dev" "/dev/dsk" * DEV_RDSKDIR "/dev" "/dev/rdsk" * NEWFS_DEFAULT_FS "ext2" "ufs" * Many of the disabled test cases fail because 'zfs/zpool destroy' returns EBUSY. This is largely causes by the asynchronous nature of device handling on Linux and is expected, the impacted test cases will need to be updated to handle this. * There are several test cases which have been disabled because they can trigger a deadlock. A primary example of this is to recursively create zpools within zpools. These tests have been disabled until the root issue can be addressed. * Illumos specific utilities such as (mkfile) should be added to the tests/zfs-tests/cmd/ directory. Custom programs required by the test scripts can also be added here. * SELinux should be either is permissive mode or disabled when running the tests. The test cases should be updated to conform to a standard policy. * Redundant test functionality has been removed (zfault.sh). * Existing test scripts (zconfig.sh) should be migrated to use the framework for consistency and ease of testing. * The DISKS environment variable currently only supports loopback devices because of how the ZFS Test Suite expects partitions to be named (p1, p2, etc). Support must be added to generate the correct partition name based on the device location and name. * The ZFS Test Suite is part of the illumos code base at: https://github.com/illumos/illumos-gate/tree/master/usr/src/test Original-patch-by: Turbo Fredriksson <turbo@bayour.com> Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov> Signed-off-by: Olaf Faaland <faaland1@llnl.gov> Closes #6 Closes #1534
This commit is contained in:
parent
887d1e60ef
commit
6bb24f4dc7
@ -6,7 +6,7 @@ include config/tgz.am
|
|||||||
|
|
||||||
SUBDIRS = include rpm
|
SUBDIRS = include rpm
|
||||||
if CONFIG_USER
|
if CONFIG_USER
|
||||||
SUBDIRS += udev etc man scripts lib cmd contrib
|
SUBDIRS += udev etc man scripts tests lib cmd contrib
|
||||||
endif
|
endif
|
||||||
if CONFIG_KERNEL
|
if CONFIG_KERNEL
|
||||||
SUBDIRS += module
|
SUBDIRS += module
|
||||||
|
6
TEST
6
TEST
@ -37,6 +37,12 @@ TEST_ZCONFIG_OPTIONS="-c -s10"
|
|||||||
#TEST_XFSTESTS_VDEV="/var/tmp/vdev"
|
#TEST_XFSTESTS_VDEV="/var/tmp/vdev"
|
||||||
#TEST_XFSTESTS_OPTIONS=""
|
#TEST_XFSTESTS_OPTIONS=""
|
||||||
|
|
||||||
|
### zfs-tests.sh
|
||||||
|
#TEST_ZFSTESTS_SKIP="yes"
|
||||||
|
#TEST_ZFSTESTS_DISKS="vdb vdc vdd"
|
||||||
|
#TEST_ZFSTESTS_DISKSIZE="8G"
|
||||||
|
#TEST_ZFSTESTS_RUNFILE="linux.run"
|
||||||
|
|
||||||
### filebench
|
### filebench
|
||||||
#TEST_FILEBENCH_SKIP="yes"
|
#TEST_FILEBENCH_SKIP="yes"
|
||||||
#TEST_FILEBENCH_URL="http://build.zfsonlinux.org/"
|
#TEST_FILEBENCH_URL="http://build.zfsonlinux.org/"
|
||||||
|
171
config/user-commands.m4
Normal file
171
config/user-commands.m4
Normal file
@ -0,0 +1,171 @@
|
|||||||
|
dnl #
|
||||||
|
dnl # Commands common to multiple platforms. They generally behave
|
||||||
|
dnl # in the same way and take similar options.
|
||||||
|
dnl #
|
||||||
|
AC_DEFUN([ZFS_AC_CONFIG_USER_COMMANDS_COMMON], [
|
||||||
|
AC_PATH_TOOL(AWK, awk, "")
|
||||||
|
AC_PATH_TOOL(BASENAME, basename, "")
|
||||||
|
AC_PATH_TOOL(BC, bc, "")
|
||||||
|
AC_PATH_TOOL(BUNZIP2, bunzip2, "")
|
||||||
|
AC_PATH_TOOL(BZCAT, bzcat, "")
|
||||||
|
AC_PATH_TOOL(CAT, cat, "")
|
||||||
|
AC_PATH_TOOL(CD, cd, "cd") dnl # Builtin in bash
|
||||||
|
AC_PATH_TOOL(CHGRP, chgrp, "")
|
||||||
|
AC_PATH_TOOL(CHMOD, chmod, "")
|
||||||
|
AC_PATH_TOOL(CHOWN, chown, "")
|
||||||
|
AC_PATH_TOOL(CKSUM, cksum, "")
|
||||||
|
AC_PATH_TOOL(CMP, cmp, "")
|
||||||
|
AC_PATH_TOOL(CP, cp, "")
|
||||||
|
AC_PATH_TOOL(CPIO, cpio, "")
|
||||||
|
AC_PATH_TOOL(CUT, cut, "")
|
||||||
|
AC_PATH_TOOL(DATE, date, "")
|
||||||
|
AC_PATH_TOOL(DD, dd, "")
|
||||||
|
AC_PATH_TOOL(DF, df, "")
|
||||||
|
AC_PATH_TOOL(DIFF, diff, "")
|
||||||
|
AC_PATH_TOOL(DIRNAME, dirname, "")
|
||||||
|
AC_PATH_TOOL(DU, du, "")
|
||||||
|
AC_PATH_TOOL(ECHO, echo, "")
|
||||||
|
AC_PATH_TOOL(EGREP, egrep, "")
|
||||||
|
AC_PATH_TOOL(FDISK, fdisk, "")
|
||||||
|
AC_PATH_TOOL(FGREP, fgrep, "")
|
||||||
|
AC_PATH_TOOL(FILE, file, "")
|
||||||
|
AC_PATH_TOOL(FIND, find, "")
|
||||||
|
AC_PATH_TOOL(FSCK, fsck, "")
|
||||||
|
AC_PATH_TOOL(GNUDD, dd, "")
|
||||||
|
AC_PATH_TOOL(GETCONF, getconf, "")
|
||||||
|
AC_PATH_TOOL(GETENT, getent, "")
|
||||||
|
AC_PATH_TOOL(GREP, grep, "")
|
||||||
|
dnl # Due to permissions unpriviledged users may not detect group*.
|
||||||
|
AC_PATH_TOOL(GROUPADD, groupadd, "/usr/sbin/groupadd")
|
||||||
|
AC_PATH_TOOL(GROUPDEL, groupdel, "/usr/sbin/groupdel")
|
||||||
|
AC_PATH_TOOL(GROUPMOD, groupmod, "/usr/sbin/groupmod")
|
||||||
|
AC_PATH_TOOL(HEAD, head, "")
|
||||||
|
AC_PATH_TOOL(HOSTNAME, hostname, "")
|
||||||
|
AC_PATH_TOOL(ID, id, "")
|
||||||
|
AC_PATH_TOOL(KILL, kill, "")
|
||||||
|
AC_PATH_TOOL(KSH, ksh, "")
|
||||||
|
AC_PATH_TOOL(LOGNAME, logname, "")
|
||||||
|
AC_PATH_TOOL(LS, ls, "")
|
||||||
|
AC_PATH_TOOL(MD5SUM, md5sum, "")
|
||||||
|
AC_PATH_TOOL(MKDIR, mkdir, "")
|
||||||
|
AC_PATH_TOOL(MKNOD, mknod, "")
|
||||||
|
AC_PATH_TOOL(MKTEMP, mktemp, "")
|
||||||
|
AC_PATH_TOOL(MODINFO, modinfo, "")
|
||||||
|
AC_PATH_TOOL(MOUNT, mount, "")
|
||||||
|
AC_PATH_TOOL(MV, mv, "")
|
||||||
|
AC_PATH_TOOL(NAWK, nawk, "")
|
||||||
|
AC_PATH_TOOL(PGREP, pgrep, "")
|
||||||
|
AC_PATH_TOOL(PING, ping, "")
|
||||||
|
AC_PATH_TOOL(PKILL, pkill, "")
|
||||||
|
AC_PATH_TOOL(PRINTF, printf, "")
|
||||||
|
AC_PATH_TOOL(PS, ps, "")
|
||||||
|
AC_PATH_TOOL(PYTHON, python, "")
|
||||||
|
AC_PATH_TOOL(REBOOT, reboot, "")
|
||||||
|
AC_PATH_TOOL(RMDIR, rmdir, "")
|
||||||
|
AC_PATH_TOOL(RSH, rsh, "")
|
||||||
|
AC_PATH_TOOL(SED, sed, "")
|
||||||
|
AC_PATH_TOOL(SHUF, shuf, "")
|
||||||
|
AC_PATH_TOOL(SLEEP, sleep, "")
|
||||||
|
AC_PATH_TOOL(SORT, sort, "")
|
||||||
|
AC_PATH_TOOL(STRINGS, strings, "")
|
||||||
|
AC_PATH_TOOL(SU, su, "")
|
||||||
|
AC_PATH_TOOL(SUM, sum, "")
|
||||||
|
AC_PATH_TOOL(SYNC, sync, "")
|
||||||
|
AC_PATH_TOOL(TAIL, tail, "")
|
||||||
|
AC_PATH_TOOL(TAR, tar, "")
|
||||||
|
AC_PATH_TOOL(TOUCH, touch, "")
|
||||||
|
AC_PATH_TOOL(TR, tr, "")
|
||||||
|
AC_PATH_TOOL(TRUE, true, "")
|
||||||
|
AC_PATH_TOOL(UMASK, umask, "")
|
||||||
|
AC_PATH_TOOL(UMOUNT, umount, "")
|
||||||
|
AC_PATH_TOOL(UNAME, uname, "")
|
||||||
|
AC_PATH_TOOL(UNIQ, uniq, "")
|
||||||
|
dnl # Due to permissions unpriviledged users may not detect user*.
|
||||||
|
AC_PATH_TOOL(USERADD, useradd, "/usr/sbin/useradd")
|
||||||
|
AC_PATH_TOOL(USERDEL, userdel, "/usr/sbin/userdel")
|
||||||
|
AC_PATH_TOOL(USERMOD, usermod, "/usr/sbin/usermod")
|
||||||
|
AC_PATH_TOOL(WAIT, wait, "wait") dnl # Builtin in bash
|
||||||
|
AC_PATH_TOOL(WC, wc, "")
|
||||||
|
])
|
||||||
|
|
||||||
|
dnl #
|
||||||
|
dnl # Linux commands, used withing 'is_linux' blocks of test scripts.
|
||||||
|
dnl # These commands may take different command line arguments.
|
||||||
|
dnl #
|
||||||
|
AC_DEFUN([ZFS_AC_CONFIG_USER_COMMANDS_LINUX], [
|
||||||
|
AC_PATH_TOOL(BLOCKDEV, blockdev, "")
|
||||||
|
AC_PATH_TOOL(COMPRESS, gzip, "")
|
||||||
|
AC_PATH_TOOL(FORMAT, parted, "")
|
||||||
|
AC_PATH_TOOL(LOCKFS, lsof, "")
|
||||||
|
AC_PATH_TOOL(MODUNLOAD, rmmod, "")
|
||||||
|
AC_PATH_TOOL(NEWFS, mke2fs, "")
|
||||||
|
AC_PATH_TOOL(PFEXEC, sudo, "")
|
||||||
|
AC_PATH_TOOL(SHARE, exportfs, "")
|
||||||
|
AC_PATH_TOOL(SWAP, swapon, "")
|
||||||
|
AC_PATH_TOOL(SWAPADD, swapon, "")
|
||||||
|
AC_PATH_TOOL(TRUNCATE, truncate, "")
|
||||||
|
AC_PATH_TOOL(UDEVADM, udevadm, "")
|
||||||
|
AC_PATH_TOOL(UFSDUMP, dump, "")
|
||||||
|
AC_PATH_TOOL(UFSRESTORE, restore, "")
|
||||||
|
AC_PATH_TOOL(UNCOMPRESS, gunzip, "")
|
||||||
|
AC_PATH_TOOL(UNSHARE, exportfs, "")
|
||||||
|
AC_PATH_TOOL(GETFACL, getfacl, "")
|
||||||
|
AC_PATH_TOOL(SETFACL, setfacl, "")
|
||||||
|
AC_PATH_TOOL(CHACL, chacl, "")
|
||||||
|
AC_PATH_TOOL(NPROC, nproc, "")
|
||||||
|
|
||||||
|
PAGESIZE=$($GETCONF PAGESIZE)
|
||||||
|
AC_SUBST(PAGESIZE)
|
||||||
|
|
||||||
|
MNTTAB=/etc/mtab
|
||||||
|
AC_SUBST(MNTTAB)
|
||||||
|
])
|
||||||
|
|
||||||
|
dnl #
|
||||||
|
dnl # BSD style commands, these have been kept in case at some point
|
||||||
|
dnl # we want to build these packages on a BSD style systems. Otherwise
|
||||||
|
dnl # they are unused and should be treated as such.
|
||||||
|
dnl #
|
||||||
|
AC_DEFUN([ZFS_AC_CONFIG_USER_COMMANDS_BSD], [
|
||||||
|
AC_PATH_TOOL(COMPRESS, compress, "")
|
||||||
|
AC_PATH_TOOL(COREADM, coreadm, "")
|
||||||
|
AC_PATH_TOOL(DIRCMP, dircmp, "")
|
||||||
|
AC_PATH_TOOL(DUMPADM, dumpadm, "")
|
||||||
|
AC_PATH_TOOL(FORMAT, format, "")
|
||||||
|
AC_PATH_TOOL(GETMAJOR, getmajor, "")
|
||||||
|
AC_PATH_TOOL(ISAINFO, isainfo, "")
|
||||||
|
AC_PATH_TOOL(KSTAT, kstat, "")
|
||||||
|
AC_PATH_TOOL(LOCKFS, lockfs, "")
|
||||||
|
AC_PATH_TOOL(LOFIADM, lofiadm, "")
|
||||||
|
AC_PATH_TOOL(MODUNLOAD, modunload, "")
|
||||||
|
AC_PATH_TOOL(NEWFS, newfs, "")
|
||||||
|
AC_PATH_TOOL(PAGESIZE, pagesize, "")
|
||||||
|
AC_PATH_TOOL(PFEXEC, pfexec, "")
|
||||||
|
AC_PATH_TOOL(PKGINFO, pkginfo, "")
|
||||||
|
AC_PATH_TOOL(PRTVTOC, prtvtoc, "")
|
||||||
|
AC_PATH_TOOL(PSRINFO, psrinfo, "")
|
||||||
|
AC_PATH_TOOL(SHARE, share, "")
|
||||||
|
AC_PATH_TOOL(SVCADM, svcadm, "")
|
||||||
|
AC_PATH_TOOL(SVCS, svcs, "")
|
||||||
|
AC_PATH_TOOL(SWAP, swap, "")
|
||||||
|
AC_PATH_TOOL(SWAPADD, swapadd, "")
|
||||||
|
AC_PATH_TOOL(UFSDUMP, ufsdump, "")
|
||||||
|
AC_PATH_TOOL(UFSRESTORE, ufsrestore, "")
|
||||||
|
AC_PATH_TOOL(UMOUNTALL, umountall, "")
|
||||||
|
AC_PATH_TOOL(UNCOMPRESS, uncompress, "")
|
||||||
|
AC_PATH_TOOL(UNSHARE, unshare, "")
|
||||||
|
AC_PATH_TOOL(ZONEADM, zoneadm, "")
|
||||||
|
AC_PATH_TOOL(ZONECFG, zonecfg, "")
|
||||||
|
AC_PATH_TOOL(ZONENAME, zonename, "")
|
||||||
|
])
|
||||||
|
|
||||||
|
AC_DEFUN([ZFS_AC_CONFIG_USER_COMMANDS], [
|
||||||
|
ZFS_AC_CONFIG_USER_COMMANDS_COMMON
|
||||||
|
|
||||||
|
OS=$($UNAME -o)
|
||||||
|
AS_IF([test "$OS" == "GNU/Linux"], [
|
||||||
|
ZFS_AC_CONFIG_USER_COMMANDS_LINUX
|
||||||
|
], [
|
||||||
|
ZFS_AC_CONFIG_USER_COMMANDS_BSD
|
||||||
|
])
|
||||||
|
])
|
12
config/user-libattr.m4
Normal file
12
config/user-libattr.m4
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
dnl #
|
||||||
|
dnl # Check for libattr
|
||||||
|
dnl #
|
||||||
|
AC_DEFUN([ZFS_AC_CONFIG_USER_LIBATTR], [
|
||||||
|
LIBATTR=
|
||||||
|
|
||||||
|
AC_CHECK_HEADER([attr/xattr.h], [], [AC_MSG_FAILURE([
|
||||||
|
*** attr/xattr.h missing, libattr-devel package required])])
|
||||||
|
|
||||||
|
AC_SUBST([LIBATTR], ["-lattr"])
|
||||||
|
AC_DEFINE([HAVE_LIBATTR], 1, [Define if you have libattr])
|
||||||
|
])
|
@ -11,9 +11,24 @@ AC_DEFUN([ZFS_AC_CONFIG_USER], [
|
|||||||
ZFS_AC_CONFIG_USER_ZLIB
|
ZFS_AC_CONFIG_USER_ZLIB
|
||||||
ZFS_AC_CONFIG_USER_LIBUUID
|
ZFS_AC_CONFIG_USER_LIBUUID
|
||||||
ZFS_AC_CONFIG_USER_LIBBLKID
|
ZFS_AC_CONFIG_USER_LIBBLKID
|
||||||
|
ZFS_AC_CONFIG_USER_LIBATTR
|
||||||
ZFS_AC_CONFIG_USER_FRAME_LARGER_THAN
|
ZFS_AC_CONFIG_USER_FRAME_LARGER_THAN
|
||||||
ZFS_AC_CONFIG_USER_RUNSTATEDIR
|
ZFS_AC_CONFIG_USER_RUNSTATEDIR
|
||||||
dnl #
|
|
||||||
dnl # Checks for library functions
|
ZFS_AC_CONFIG_USER_COMMANDS
|
||||||
|
ZFS_AC_TEST_FRAMEWORK
|
||||||
|
|
||||||
AC_CHECK_FUNCS([mlockall])
|
AC_CHECK_FUNCS([mlockall])
|
||||||
])
|
])
|
||||||
|
|
||||||
|
dnl #
|
||||||
|
dnl # Setup the environment for the ZFS Test Suite. Currently only
|
||||||
|
dnl # Linux sytle systems are supported but this infrastructure can
|
||||||
|
dnl # be extended to support other platforms if needed.
|
||||||
|
dnl #
|
||||||
|
AC_DEFUN([ZFS_AC_TEST_FRAMEWORK], [
|
||||||
|
ZONENAME="echo global"
|
||||||
|
AC_SUBST(ZONENAME)
|
||||||
|
|
||||||
|
AC_SUBST(RM)
|
||||||
|
])
|
||||||
|
@ -89,8 +89,8 @@ AC_DEFUN([ZFS_AC_CONFIG], [
|
|||||||
case "$ZFS_CONFIG" in
|
case "$ZFS_CONFIG" in
|
||||||
kernel) ZFS_AC_CONFIG_KERNEL ;;
|
kernel) ZFS_AC_CONFIG_KERNEL ;;
|
||||||
user) ZFS_AC_CONFIG_USER ;;
|
user) ZFS_AC_CONFIG_USER ;;
|
||||||
all) ZFS_AC_CONFIG_KERNEL
|
all) ZFS_AC_CONFIG_USER
|
||||||
ZFS_AC_CONFIG_USER ;;
|
ZFS_AC_CONFIG_KERNEL ;;
|
||||||
srpm) ;;
|
srpm) ;;
|
||||||
*)
|
*)
|
||||||
AC_MSG_RESULT([Error!])
|
AC_MSG_RESULT([Error!])
|
||||||
|
139
configure.ac
139
configure.ac
@ -134,6 +134,145 @@ AC_CONFIG_FILES([
|
|||||||
scripts/zpios-test/Makefile
|
scripts/zpios-test/Makefile
|
||||||
scripts/zpool-config/Makefile
|
scripts/zpool-config/Makefile
|
||||||
scripts/common.sh
|
scripts/common.sh
|
||||||
|
tests/Makefile
|
||||||
|
tests/test-runner/Makefile
|
||||||
|
tests/test-runner/cmd/Makefile
|
||||||
|
tests/test-runner/include/Makefile
|
||||||
|
tests/test-runner/man/Makefile
|
||||||
|
tests/runfiles/Makefile
|
||||||
|
tests/zfs-tests/Makefile
|
||||||
|
tests/zfs-tests/cmd/Makefile
|
||||||
|
tests/zfs-tests/cmd/chg_usr_exec/Makefile
|
||||||
|
tests/zfs-tests/cmd/devname2devid/Makefile
|
||||||
|
tests/zfs-tests/cmd/dir_rd_update/Makefile
|
||||||
|
tests/zfs-tests/cmd/file_check/Makefile
|
||||||
|
tests/zfs-tests/cmd/file_trunc/Makefile
|
||||||
|
tests/zfs-tests/cmd/file_write/Makefile
|
||||||
|
tests/zfs-tests/cmd/largest_file/Makefile
|
||||||
|
tests/zfs-tests/cmd/mkbusy/Makefile
|
||||||
|
tests/zfs-tests/cmd/mkfile/Makefile
|
||||||
|
tests/zfs-tests/cmd/mkfiles/Makefile
|
||||||
|
tests/zfs-tests/cmd/mktree/Makefile
|
||||||
|
tests/zfs-tests/cmd/mmap_exec/Makefile
|
||||||
|
tests/zfs-tests/cmd/mmapwrite/Makefile
|
||||||
|
tests/zfs-tests/cmd/randfree_file/Makefile
|
||||||
|
tests/zfs-tests/cmd/readmmap/Makefile
|
||||||
|
tests/zfs-tests/cmd/rename_dir/Makefile
|
||||||
|
tests/zfs-tests/cmd/rm_lnkcnt_zero_file/Makefile
|
||||||
|
tests/zfs-tests/cmd/threadsappend/Makefile
|
||||||
|
tests/zfs-tests/cmd/xattrtest/Makefile
|
||||||
|
tests/zfs-tests/include/Makefile
|
||||||
|
tests/zfs-tests/include/commands.cfg
|
||||||
|
tests/zfs-tests/include/default.cfg
|
||||||
|
tests/zfs-tests/tests/Makefile
|
||||||
|
tests/zfs-tests/tests/functional/Makefile
|
||||||
|
tests/zfs-tests/tests/functional/acl/Makefile
|
||||||
|
tests/zfs-tests/tests/functional/acl/posix/Makefile
|
||||||
|
tests/zfs-tests/tests/functional/atime/Makefile
|
||||||
|
tests/zfs-tests/tests/functional/bootfs/Makefile
|
||||||
|
tests/zfs-tests/tests/functional/cache/Makefile
|
||||||
|
tests/zfs-tests/tests/functional/cachefile/Makefile
|
||||||
|
tests/zfs-tests/tests/functional/casenorm/Makefile
|
||||||
|
tests/zfs-tests/tests/functional/clean_mirror/Makefile
|
||||||
|
tests/zfs-tests/tests/functional/cli_root/Makefile
|
||||||
|
tests/zfs-tests/tests/functional/cli_root/zdb/Makefile
|
||||||
|
tests/zfs-tests/tests/functional/cli_root/zfs_clone/Makefile
|
||||||
|
tests/zfs-tests/tests/functional/cli_root/zfs_copies/Makefile
|
||||||
|
tests/zfs-tests/tests/functional/cli_root/zfs_create/Makefile
|
||||||
|
tests/zfs-tests/tests/functional/cli_root/zfs_destroy/Makefile
|
||||||
|
tests/zfs-tests/tests/functional/cli_root/zfs_get/Makefile
|
||||||
|
tests/zfs-tests/tests/functional/cli_root/zfs_inherit/Makefile
|
||||||
|
tests/zfs-tests/tests/functional/cli_root/zfs/Makefile
|
||||||
|
tests/zfs-tests/tests/functional/cli_root/zfs_mount/Makefile
|
||||||
|
tests/zfs-tests/tests/functional/cli_root/zfs_promote/Makefile
|
||||||
|
tests/zfs-tests/tests/functional/cli_root/zfs_property/Makefile
|
||||||
|
tests/zfs-tests/tests/functional/cli_root/zfs_receive/Makefile
|
||||||
|
tests/zfs-tests/tests/functional/cli_root/zfs_rename/Makefile
|
||||||
|
tests/zfs-tests/tests/functional/cli_root/zfs_reservation/Makefile
|
||||||
|
tests/zfs-tests/tests/functional/cli_root/zfs_rollback/Makefile
|
||||||
|
tests/zfs-tests/tests/functional/cli_root/zfs_send/Makefile
|
||||||
|
tests/zfs-tests/tests/functional/cli_root/zfs_set/Makefile
|
||||||
|
tests/zfs-tests/tests/functional/cli_root/zfs_share/Makefile
|
||||||
|
tests/zfs-tests/tests/functional/cli_root/zfs_snapshot/Makefile
|
||||||
|
tests/zfs-tests/tests/functional/cli_root/zfs_unmount/Makefile
|
||||||
|
tests/zfs-tests/tests/functional/cli_root/zfs_unshare/Makefile
|
||||||
|
tests/zfs-tests/tests/functional/cli_root/zfs_upgrade/Makefile
|
||||||
|
tests/zfs-tests/tests/functional/cli_root/zpool_add/Makefile
|
||||||
|
tests/zfs-tests/tests/functional/cli_root/zpool_attach/Makefile
|
||||||
|
tests/zfs-tests/tests/functional/cli_root/zpool_clear/Makefile
|
||||||
|
tests/zfs-tests/tests/functional/cli_root/zpool_create/Makefile
|
||||||
|
tests/zfs-tests/tests/functional/cli_root/zpool_destroy/Makefile
|
||||||
|
tests/zfs-tests/tests/functional/cli_root/zpool_detach/Makefile
|
||||||
|
tests/zfs-tests/tests/functional/cli_root/zpool_expand/Makefile
|
||||||
|
tests/zfs-tests/tests/functional/cli_root/zpool_export/Makefile
|
||||||
|
tests/zfs-tests/tests/functional/cli_root/zpool_get/Makefile
|
||||||
|
tests/zfs-tests/tests/functional/cli_root/zpool_history/Makefile
|
||||||
|
tests/zfs-tests/tests/functional/cli_root/zpool_import/Makefile
|
||||||
|
tests/zfs-tests/tests/functional/cli_root/zpool/Makefile
|
||||||
|
tests/zfs-tests/tests/functional/cli_root/zpool_offline/Makefile
|
||||||
|
tests/zfs-tests/tests/functional/cli_root/zpool_online/Makefile
|
||||||
|
tests/zfs-tests/tests/functional/cli_root/zpool_remove/Makefile
|
||||||
|
tests/zfs-tests/tests/functional/cli_root/zpool_replace/Makefile
|
||||||
|
tests/zfs-tests/tests/functional/cli_root/zpool_scrub/Makefile
|
||||||
|
tests/zfs-tests/tests/functional/cli_root/zpool_set/Makefile
|
||||||
|
tests/zfs-tests/tests/functional/cli_root/zpool_status/Makefile
|
||||||
|
tests/zfs-tests/tests/functional/cli_root/zpool_upgrade/Makefile
|
||||||
|
tests/zfs-tests/tests/functional/cli_user/Makefile
|
||||||
|
tests/zfs-tests/tests/functional/cli_user/misc/Makefile
|
||||||
|
tests/zfs-tests/tests/functional/cli_user/zfs_list/Makefile
|
||||||
|
tests/zfs-tests/tests/functional/cli_user/zpool_iostat/Makefile
|
||||||
|
tests/zfs-tests/tests/functional/cli_user/zpool_list/Makefile
|
||||||
|
tests/zfs-tests/tests/functional/compression/Makefile
|
||||||
|
tests/zfs-tests/tests/functional/ctime/Makefile
|
||||||
|
tests/zfs-tests/tests/functional/delegate/Makefile
|
||||||
|
tests/zfs-tests/tests/functional/devices/Makefile
|
||||||
|
tests/zfs-tests/tests/functional/exec/Makefile
|
||||||
|
tests/zfs-tests/tests/functional/features/async_destroy/Makefile
|
||||||
|
tests/zfs-tests/tests/functional/features/Makefile
|
||||||
|
tests/zfs-tests/tests/functional/grow_pool/Makefile
|
||||||
|
tests/zfs-tests/tests/functional/grow_replicas/Makefile
|
||||||
|
tests/zfs-tests/tests/functional/history/Makefile
|
||||||
|
tests/zfs-tests/tests/functional/inheritance/Makefile
|
||||||
|
tests/zfs-tests/tests/functional/inuse/Makefile
|
||||||
|
tests/zfs-tests/tests/functional/large_files/Makefile
|
||||||
|
tests/zfs-tests/tests/functional/largest_pool/Makefile
|
||||||
|
tests/zfs-tests/tests/functional/link_count/Makefile
|
||||||
|
tests/zfs-tests/tests/functional/migration/Makefile
|
||||||
|
tests/zfs-tests/tests/functional/mmap/Makefile
|
||||||
|
tests/zfs-tests/tests/functional/mount/Makefile
|
||||||
|
tests/zfs-tests/tests/functional/mv_files/Makefile
|
||||||
|
tests/zfs-tests/tests/functional/nestedfs/Makefile
|
||||||
|
tests/zfs-tests/tests/functional/no_space/Makefile
|
||||||
|
tests/zfs-tests/tests/functional/nopwrite/Makefile
|
||||||
|
tests/zfs-tests/tests/functional/online_offline/Makefile
|
||||||
|
tests/zfs-tests/tests/functional/pool_names/Makefile
|
||||||
|
tests/zfs-tests/tests/functional/poolversion/Makefile
|
||||||
|
tests/zfs-tests/tests/functional/privilege/Makefile
|
||||||
|
tests/zfs-tests/tests/functional/quota/Makefile
|
||||||
|
tests/zfs-tests/tests/functional/redundancy/Makefile
|
||||||
|
tests/zfs-tests/tests/functional/refquota/Makefile
|
||||||
|
tests/zfs-tests/tests/functional/refreserv/Makefile
|
||||||
|
tests/zfs-tests/tests/functional/rename_dirs/Makefile
|
||||||
|
tests/zfs-tests/tests/functional/replacement/Makefile
|
||||||
|
tests/zfs-tests/tests/functional/reservation/Makefile
|
||||||
|
tests/zfs-tests/tests/functional/rootpool/Makefile
|
||||||
|
tests/zfs-tests/tests/functional/rsend/Makefile
|
||||||
|
tests/zfs-tests/tests/functional/scrub_mirror/Makefile
|
||||||
|
tests/zfs-tests/tests/functional/slog/Makefile
|
||||||
|
tests/zfs-tests/tests/functional/snapshot/Makefile
|
||||||
|
tests/zfs-tests/tests/functional/snapused/Makefile
|
||||||
|
tests/zfs-tests/tests/functional/sparse/Makefile
|
||||||
|
tests/zfs-tests/tests/functional/threadsappend/Makefile
|
||||||
|
tests/zfs-tests/tests/functional/truncate/Makefile
|
||||||
|
tests/zfs-tests/tests/functional/userquota/Makefile
|
||||||
|
tests/zfs-tests/tests/functional/write_dirs/Makefile
|
||||||
|
tests/zfs-tests/tests/functional/xattr/Makefile
|
||||||
|
tests/zfs-tests/tests/functional/zvol/Makefile
|
||||||
|
tests/zfs-tests/tests/functional/zvol/zvol_cli/Makefile
|
||||||
|
tests/zfs-tests/tests/functional/zvol/zvol_ENOSPC/Makefile
|
||||||
|
tests/zfs-tests/tests/functional/zvol/zvol_misc/Makefile
|
||||||
|
tests/zfs-tests/tests/functional/zvol/zvol_swap/Makefile
|
||||||
|
tests/zfs-tests/tests/stress/Makefile
|
||||||
rpm/Makefile
|
rpm/Makefile
|
||||||
rpm/redhat/Makefile
|
rpm/redhat/Makefile
|
||||||
rpm/redhat/zfs.spec
|
rpm/redhat/zfs.spec
|
||||||
|
@ -58,6 +58,7 @@ extern "C" {
|
|||||||
*/
|
*/
|
||||||
#define DISK_ROOT "/dev"
|
#define DISK_ROOT "/dev"
|
||||||
#define UDISK_ROOT "/dev/disk"
|
#define UDISK_ROOT "/dev/disk"
|
||||||
|
#define ZVOL_ROOT "/dev/zvol"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Default wait time for a device name to be created.
|
* Default wait time for a device name to be created.
|
||||||
|
@ -908,7 +908,8 @@ zfs_append_partition(char *path, size_t max_len)
|
|||||||
{
|
{
|
||||||
int len = strlen(path);
|
int len = strlen(path);
|
||||||
|
|
||||||
if (strncmp(path, UDISK_ROOT, strlen(UDISK_ROOT)) == 0) {
|
if ((strncmp(path, UDISK_ROOT, strlen(UDISK_ROOT)) == 0) ||
|
||||||
|
(strncmp(path, ZVOL_ROOT, strlen(ZVOL_ROOT)) == 0)) {
|
||||||
if (len + 6 >= max_len)
|
if (len + 6 >= max_len)
|
||||||
return (-1);
|
return (-1);
|
||||||
|
|
||||||
|
@ -171,6 +171,7 @@ Requires: parted
|
|||||||
Requires: lsscsi
|
Requires: lsscsi
|
||||||
Requires: mdadm
|
Requires: mdadm
|
||||||
Requires: bc
|
Requires: bc
|
||||||
|
Requires: ksh
|
||||||
|
|
||||||
%description test
|
%description test
|
||||||
This package contains test infrastructure and support scripts for
|
This package contains test infrastructure and support scripts for
|
||||||
|
@ -6,52 +6,12 @@ pkgdatadir = $(datadir)/@PACKAGE@
|
|||||||
dist_pkgdata_SCRIPTS = \
|
dist_pkgdata_SCRIPTS = \
|
||||||
$(top_builddir)/scripts/common.sh \
|
$(top_builddir)/scripts/common.sh \
|
||||||
$(top_srcdir)/scripts/zconfig.sh \
|
$(top_srcdir)/scripts/zconfig.sh \
|
||||||
$(top_srcdir)/scripts/zfault.sh \
|
|
||||||
$(top_srcdir)/scripts/ziltest.sh \
|
$(top_srcdir)/scripts/ziltest.sh \
|
||||||
$(top_srcdir)/scripts/zimport.sh \
|
$(top_srcdir)/scripts/zimport.sh \
|
||||||
$(top_srcdir)/scripts/zfs.sh \
|
$(top_srcdir)/scripts/zfs.sh \
|
||||||
|
$(top_srcdir)/scripts/zfs-tests.sh \
|
||||||
$(top_srcdir)/scripts/zpool-create.sh \
|
$(top_srcdir)/scripts/zpool-create.sh \
|
||||||
$(top_srcdir)/scripts/zpios.sh \
|
$(top_srcdir)/scripts/zpios.sh \
|
||||||
$(top_srcdir)/scripts/zpios-sanity.sh \
|
$(top_srcdir)/scripts/zpios-sanity.sh \
|
||||||
$(top_srcdir)/scripts/zpios-survey.sh \
|
$(top_srcdir)/scripts/zpios-survey.sh \
|
||||||
$(top_srcdir)/scripts/smb.sh
|
$(top_srcdir)/scripts/smb.sh
|
||||||
|
|
||||||
ZFS=$(top_builddir)/scripts/zfs.sh
|
|
||||||
ZCONFIG=$(top_builddir)/scripts/zconfig.sh
|
|
||||||
ZFAULT=$(top_builddir)/scripts/zfault.sh
|
|
||||||
ZIMPORT=$(top_builddir)/scripts/zimport.sh
|
|
||||||
ZTEST=$(top_builddir)/cmd/ztest/ztest
|
|
||||||
ZPIOS_SANITY=$(top_builddir)/scripts/zpios-sanity.sh
|
|
||||||
|
|
||||||
check:
|
|
||||||
@$(ZFS) -u
|
|
||||||
@echo
|
|
||||||
@echo -n "===================================="
|
|
||||||
@echo -n " ZTEST "
|
|
||||||
@echo "===================================="
|
|
||||||
@echo
|
|
||||||
@$(ZFS)
|
|
||||||
@$(ZTEST) -V
|
|
||||||
@$(ZFS) -u
|
|
||||||
@echo
|
|
||||||
@echo
|
|
||||||
@echo -n "==================================="
|
|
||||||
@echo -n " ZCONFIG "
|
|
||||||
@echo "==================================="
|
|
||||||
@echo
|
|
||||||
@$(ZCONFIG) -c
|
|
||||||
@echo
|
|
||||||
@echo -n "==================================="
|
|
||||||
@echo -n " ZFAULT "
|
|
||||||
@echo "==================================="
|
|
||||||
@echo
|
|
||||||
@$(ZFAULT) -c
|
|
||||||
@echo
|
|
||||||
@echo -n "===================================="
|
|
||||||
@echo -n " ZPIOS "
|
|
||||||
@echo "===================================="
|
|
||||||
@echo
|
|
||||||
@$(ZFS)
|
|
||||||
@$(ZPIOS_SANITY)
|
|
||||||
@$(ZFS) -u
|
|
||||||
@echo
|
|
||||||
|
@ -45,10 +45,13 @@ DEVDIR=${DEVDIR:-/dev/disk/by-vdev}
|
|||||||
ZPOOLDIR=${ZPOOLDIR:-${pkgdatadir}/zpool-config}
|
ZPOOLDIR=${ZPOOLDIR:-${pkgdatadir}/zpool-config}
|
||||||
ZPIOSDIR=${ZPIOSDIR:-${pkgdatadir}/zpios-test}
|
ZPIOSDIR=${ZPIOSDIR:-${pkgdatadir}/zpios-test}
|
||||||
ZPIOSPROFILEDIR=${ZPIOSPROFILEDIR:-${pkgdatadir}/zpios-profile}
|
ZPIOSPROFILEDIR=${ZPIOSPROFILEDIR:-${pkgdatadir}/zpios-profile}
|
||||||
|
TESTSDIR=${TESTSDIR:-${pkgdatadir}/zfs-tests}
|
||||||
|
RUNFILEDIR=${RUNFILEDIR:-${pkgdatadir}/runfiles}
|
||||||
|
|
||||||
ZDB=${ZDB:-${sbindir}/zdb}
|
ZDB=${ZDB:-${sbindir}/zdb}
|
||||||
ZFS=${ZFS:-${sbindir}/zfs}
|
ZFS=${ZFS:-${sbindir}/zfs}
|
||||||
ZINJECT=${ZINJECT:-${sbindir}/zinject}
|
ZINJECT=${ZINJECT:-${sbindir}/zinject}
|
||||||
|
ZHACK=${ZHACK:-${sbindir}/zhack}
|
||||||
ZPOOL=${ZPOOL:-${sbindir}/zpool}
|
ZPOOL=${ZPOOL:-${sbindir}/zpool}
|
||||||
ZTEST=${ZTEST:-${sbindir}/ztest}
|
ZTEST=${ZTEST:-${sbindir}/ztest}
|
||||||
ZPIOS=${ZPIOS:-${sbindir}/zpios}
|
ZPIOS=${ZPIOS:-${sbindir}/zpios}
|
||||||
@ -58,6 +61,9 @@ ZFS_SH=${ZFS_SH:-${pkgdatadir}/zfs.sh}
|
|||||||
ZPOOL_CREATE_SH=${ZPOOL_CREATE_SH:-${pkgdatadir}/zpool-create.sh}
|
ZPOOL_CREATE_SH=${ZPOOL_CREATE_SH:-${pkgdatadir}/zpool-create.sh}
|
||||||
ZPIOS_SH=${ZPIOS_SH:-${pkgdatadir}/zpios.sh}
|
ZPIOS_SH=${ZPIOS_SH:-${pkgdatadir}/zpios.sh}
|
||||||
ZPIOS_SURVEY_SH=${ZPIOS_SURVEY_SH:-${pkgdatadir}/zpios-survey.sh}
|
ZPIOS_SURVEY_SH=${ZPIOS_SURVEY_SH:-${pkgdatadir}/zpios-survey.sh}
|
||||||
|
TEST_RUNNER=${TEST_RUNNER:-${pkgdatadir}/test-runner/bin/test-runner.py}
|
||||||
|
STF_TOOLS=${STF_TOOLS:-${pkgdatadir}/test-runner}
|
||||||
|
STF_SUITE=${STF_SUITE:-${pkgdatadir}/zfs-tests}
|
||||||
|
|
||||||
LDMOD=${LDMOD:-/sbin/modprobe}
|
LDMOD=${LDMOD:-/sbin/modprobe}
|
||||||
LSMOD=${LSMOD:-/sbin/lsmod}
|
LSMOD=${LSMOD:-/sbin/lsmod}
|
||||||
@ -65,6 +71,7 @@ RMMOD=${RMMOD:-/sbin/rmmod}
|
|||||||
INFOMOD=${INFOMOD:-/sbin/modinfo}
|
INFOMOD=${INFOMOD:-/sbin/modinfo}
|
||||||
LOSETUP=${LOSETUP:-/sbin/losetup}
|
LOSETUP=${LOSETUP:-/sbin/losetup}
|
||||||
MDADM=${MDADM:-/sbin/mdadm}
|
MDADM=${MDADM:-/sbin/mdadm}
|
||||||
|
DMSETUP=${DMSETUP:-/sbin/dmsetup}
|
||||||
PARTED=${PARTED:-/sbin/parted}
|
PARTED=${PARTED:-/sbin/parted}
|
||||||
BLOCKDEV=${BLOCKDEV:-/sbin/blockdev}
|
BLOCKDEV=${BLOCKDEV:-/sbin/blockdev}
|
||||||
LSSCSI=${LSSCSI:-/usr/bin/lsscsi}
|
LSSCSI=${LSSCSI:-/usr/bin/lsscsi}
|
||||||
@ -297,7 +304,7 @@ check_loop_utils() {
|
|||||||
# the minor as long as it's less than /sys/module/loop/parameters/max_loop.
|
# the minor as long as it's less than /sys/module/loop/parameters/max_loop.
|
||||||
#
|
#
|
||||||
unused_loop_device() {
|
unused_loop_device() {
|
||||||
local DEVICE=`${LOSETUP} -f`
|
local DEVICE=$(${LOSETUP} -f)
|
||||||
local MAX_LOOP_PATH="/sys/module/loop/parameters/max_loop"
|
local MAX_LOOP_PATH="/sys/module/loop/parameters/max_loop"
|
||||||
local MAX_LOOP;
|
local MAX_LOOP;
|
||||||
|
|
||||||
@ -359,7 +366,7 @@ destroy_loop_devices() {
|
|||||||
local LODEVICES="$1"
|
local LODEVICES="$1"
|
||||||
|
|
||||||
msg "Destroying ${LODEVICES}"
|
msg "Destroying ${LODEVICES}"
|
||||||
${LOSETUP} -d ${LODEVICES} || \
|
${LOSETUP} -d ${LODEVICES} || \
|
||||||
die "Error $? destroying ${FILE} -> ${DEVICE} loopback"
|
die "Error $? destroying ${FILE} -> ${DEVICE} loopback"
|
||||||
|
|
||||||
rm -f ${FILES}
|
rm -f ${FILES}
|
||||||
|
@ -1,955 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
#
|
|
||||||
# ZPOOL fault verification test script.
|
|
||||||
#
|
|
||||||
# The current suite of fault tests should not be thought of an exhaustive
|
|
||||||
# list of failure modes. Rather it is simply an starting point which trys
|
|
||||||
# to cover the bulk the of the 'easy' and hopefully common, failure modes.
|
|
||||||
#
|
|
||||||
# Additional tests should be added but the current suite as new interesting
|
|
||||||
# failures modes are observed. Additional failure modes I'd like to see
|
|
||||||
# tests for include, but are not limited too:
|
|
||||||
#
|
|
||||||
# * Slow but successful IO.
|
|
||||||
# * SCSI sense codes generated as zevents.
|
|
||||||
# * 4k sectors
|
|
||||||
# * noise
|
|
||||||
# * medium error
|
|
||||||
# * recovered error
|
|
||||||
#
|
|
||||||
# The current infrastructure using the 'mdadm' faulty device and the
|
|
||||||
# 'scsi_debug' simulated scsi devices. The idea is to inject the error
|
|
||||||
# below the zfs stack to validate all the error paths. More targeted
|
|
||||||
# failure testing should be added using the 'zinject' command line util.
|
|
||||||
#
|
|
||||||
# Requires the following packages:
|
|
||||||
# * mdadm
|
|
||||||
# * lsscsi
|
|
||||||
# * sg3-utils
|
|
||||||
#
|
|
||||||
|
|
||||||
basedir="$(dirname $0)"
|
|
||||||
|
|
||||||
SCRIPT_COMMON=common.sh
|
|
||||||
if [ -f "${basedir}/${SCRIPT_COMMON}" ]; then
|
|
||||||
. "${basedir}/${SCRIPT_COMMON}"
|
|
||||||
else
|
|
||||||
echo "Missing helper script ${SCRIPT_COMMON}" && exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
PROG=zfault.sh
|
|
||||||
|
|
||||||
usage() {
|
|
||||||
cat << EOF
|
|
||||||
USAGE:
|
|
||||||
$0 [hvcts]
|
|
||||||
|
|
||||||
DESCRIPTION:
|
|
||||||
ZPOOL fault verification tests
|
|
||||||
|
|
||||||
OPTIONS:
|
|
||||||
-h Show this message
|
|
||||||
-v Verbose
|
|
||||||
-c Cleanup md+lo+file devices at start
|
|
||||||
-t <#> Run listed tests
|
|
||||||
-s <#> Skip listed tests
|
|
||||||
|
|
||||||
EOF
|
|
||||||
}
|
|
||||||
|
|
||||||
while getopts 'hvct:s:?' OPTION; do
|
|
||||||
case $OPTION in
|
|
||||||
h)
|
|
||||||
usage
|
|
||||||
exit 1
|
|
||||||
;;
|
|
||||||
v)
|
|
||||||
VERBOSE=1
|
|
||||||
;;
|
|
||||||
c)
|
|
||||||
CLEANUP=1
|
|
||||||
;;
|
|
||||||
t)
|
|
||||||
TESTS_RUN=($OPTARG)
|
|
||||||
;;
|
|
||||||
s)
|
|
||||||
TESTS_SKIP=($OPTARG)
|
|
||||||
;;
|
|
||||||
?)
|
|
||||||
usage
|
|
||||||
exit
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
|
|
||||||
if [ $(id -u) != 0 ]; then
|
|
||||||
die "Must run as root"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Initialize the test suite
|
|
||||||
init
|
|
||||||
|
|
||||||
# Perform pre-cleanup is requested
|
|
||||||
if [ ${CLEANUP} ]; then
|
|
||||||
${ZFS_SH} -u
|
|
||||||
cleanup_md_devices
|
|
||||||
cleanup_loop_devices
|
|
||||||
rm -f /tmp/zpool.cache.*
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Check if we need to skip all md based tests.
|
|
||||||
MD_PARTITIONABLE=0
|
|
||||||
check_md_partitionable && MD_PARTITIONABLE=1
|
|
||||||
if [ ${MD_PARTITIONABLE} -eq 0 ]; then
|
|
||||||
echo "Skipping tests 1-7 which require partitionable md devices"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Check if we need to skip all the scsi_debug tests.
|
|
||||||
SCSI_DEBUG=0
|
|
||||||
${INFOMOD} scsi_debug &>/dev/null && SCSI_DEBUG=1
|
|
||||||
if [ ${SCSI_DEBUG} -eq 0 ]; then
|
|
||||||
echo "Skipping tests 8-9 which require the scsi_debug module"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ ${MD_PARTITIONABLE} -eq 0 ] || [ ${SCSI_DEBUG} -eq 0 ]; then
|
|
||||||
echo
|
|
||||||
fi
|
|
||||||
|
|
||||||
printf "%40s%s\t%s\t%s\t%s\t%s\n" "" "raid0" "raid10" "raidz" "raidz2" "raidz3"
|
|
||||||
|
|
||||||
pass_nonewline() {
|
|
||||||
echo -n -e "${COLOR_GREEN}Pass${COLOR_RESET}\t"
|
|
||||||
}
|
|
||||||
|
|
||||||
skip_nonewline() {
|
|
||||||
echo -n -e "${COLOR_BROWN}Skip${COLOR_RESET}\t"
|
|
||||||
}
|
|
||||||
|
|
||||||
nth_zpool_vdev() {
|
|
||||||
local POOL_NAME=$1
|
|
||||||
local DEVICE_TYPE=$2
|
|
||||||
local DEVICE_NTH=$3
|
|
||||||
|
|
||||||
${ZPOOL} status ${POOL_NAME} | grep ${DEVICE_TYPE} ${TMP_STATUS} | \
|
|
||||||
head -n${DEVICE_NTH} | tail -n1 | ${AWK} "{ print \$1 }"
|
|
||||||
}
|
|
||||||
|
|
||||||
vdev_status() {
|
|
||||||
local POOL_NAME=$1
|
|
||||||
local VDEV_NAME=$2
|
|
||||||
|
|
||||||
${ZPOOL} status ${POOL_NAME} | ${AWK} "/${VDEV_NAME}/ { print \$2 }"
|
|
||||||
}
|
|
||||||
|
|
||||||
# Required format is x.yz[KMGTP]
|
|
||||||
expand_numeric_suffix() {
|
|
||||||
local VALUE=$1
|
|
||||||
|
|
||||||
VALUE=`echo "${VALUE/%K/*1000}"`
|
|
||||||
VALUE=`echo "${VALUE/%M/*1000000}"`
|
|
||||||
VALUE=`echo "${VALUE/%G/*1000000000}"`
|
|
||||||
VALUE=`echo "${VALUE/%T/*1000000000000}"`
|
|
||||||
VALUE=`echo "${VALUE/%P/*1000000000000000}"`
|
|
||||||
VALUE=`echo "${VALUE}" | bc | cut -d'.' -f1`
|
|
||||||
|
|
||||||
echo "${VALUE}"
|
|
||||||
}
|
|
||||||
|
|
||||||
vdev_read_errors() {
|
|
||||||
local POOL_NAME=$1
|
|
||||||
local VDEV_NAME=$2
|
|
||||||
local VDEV_ERRORS=`${ZPOOL} status ${POOL_NAME} |
|
|
||||||
${AWK} "/${VDEV_NAME}/ { print \\$3 }"`
|
|
||||||
|
|
||||||
expand_numeric_suffix ${VDEV_ERRORS}
|
|
||||||
}
|
|
||||||
|
|
||||||
vdev_write_errors() {
|
|
||||||
local POOL_NAME=$1
|
|
||||||
local VDEV_NAME=$2
|
|
||||||
local VDEV_ERRORS=`${ZPOOL} status ${POOL_NAME} |
|
|
||||||
${AWK} "/${VDEV_NAME}/ { print \\$4 }"`
|
|
||||||
|
|
||||||
expand_numeric_suffix ${VDEV_ERRORS}
|
|
||||||
}
|
|
||||||
|
|
||||||
vdev_cksum_errors() {
|
|
||||||
local POOL_NAME=$1
|
|
||||||
local VDEV_NAME=$2
|
|
||||||
local VDEV_ERRORS=`${ZPOOL} status ${POOL_NAME} |
|
|
||||||
${AWK} "/${VDEV_NAME}/ { print \\$5 }"`
|
|
||||||
|
|
||||||
expand_numeric_suffix ${VDEV_ERRORS}
|
|
||||||
}
|
|
||||||
|
|
||||||
zpool_state() {
|
|
||||||
local POOL_NAME=$1
|
|
||||||
|
|
||||||
${ZPOOL} status ${POOL_NAME} | ${AWK} "/state/ { print \$2; exit }"
|
|
||||||
}
|
|
||||||
|
|
||||||
zpool_event() {
|
|
||||||
local EVENT_NAME=$1
|
|
||||||
local EVENT_KEY=$2
|
|
||||||
|
|
||||||
SCRIPT1="BEGIN {RS=\"\"; FS=\"\n\"} /${EVENT_NAME}/ { print \$0; exit }"
|
|
||||||
SCRIPT2="BEGIN {FS=\"=\"} /${EVENT_KEY}/ { print \$2; exit }"
|
|
||||||
|
|
||||||
${ZPOOL} events -vH | ${AWK} "${SCRIPT1}" | ${AWK} "${SCRIPT2}"
|
|
||||||
}
|
|
||||||
|
|
||||||
zpool_scan_errors() {
|
|
||||||
local POOL_NAME=$1
|
|
||||||
|
|
||||||
${ZPOOL} status ${POOL_NAME} | ${AWK} "/scan: scrub/ { print \$8 }"
|
|
||||||
${ZPOOL} status ${POOL_NAME} | ${AWK} "/scan: resilver/ { print \$7 }"
|
|
||||||
}
|
|
||||||
|
|
||||||
pattern_create() {
|
|
||||||
local PATTERN_BLOCK_SIZE=$1
|
|
||||||
local PATTERN_BLOCK_COUNT=$2
|
|
||||||
local PATTERN_NAME=`mktemp -p /tmp zpool.pattern.XXXXXXXX`
|
|
||||||
|
|
||||||
echo ${PATTERN_NAME}
|
|
||||||
dd if=/dev/urandom of=${PATTERN_NAME} bs=${PATTERN_BLOCK_SIZE} \
|
|
||||||
count=${PATTERN_BLOCK_COUNT} &>/dev/null
|
|
||||||
return $?
|
|
||||||
}
|
|
||||||
|
|
||||||
pattern_write() {
|
|
||||||
local PATTERN_NAME=$1
|
|
||||||
local PATTERN_BLOCK_SIZE=$2
|
|
||||||
local PATTERN_BLOCK_COUNT=$3
|
|
||||||
local DEVICE_NAME=$4
|
|
||||||
|
|
||||||
dd if=${PATTERN_NAME} of=${DEVICE_NAME} bs=${PATTERN_BLOCK_SIZE} \
|
|
||||||
count=${PATTERN_BLOCK_COUNT} oflag=direct &>/dev/null
|
|
||||||
return $?
|
|
||||||
}
|
|
||||||
|
|
||||||
pattern_write_bg() {
|
|
||||||
local PATTERN_NAME=$1
|
|
||||||
local PATTERN_BLOCK_SIZE=$2
|
|
||||||
local PATTERN_BLOCK_COUNT=$3
|
|
||||||
local DEVICE_NAME=$4
|
|
||||||
|
|
||||||
dd if=${PATTERN_NAME} of=${DEVICE_NAME} bs=${PATTERN_BLOCK_SIZE} \
|
|
||||||
count=${PATTERN_BLOCK_COUNT} oflag=direct &>/dev/null &
|
|
||||||
return $?
|
|
||||||
}
|
|
||||||
|
|
||||||
pattern_verify() {
|
|
||||||
local PATTERN_NAME=$1
|
|
||||||
local PATTERN_BLOCK_SIZE=$2
|
|
||||||
local PATTERN_BLOCK_COUNT=$3
|
|
||||||
local DEVICE_NAME=$4
|
|
||||||
local DEVICE_FILE=`mktemp -p /tmp zpool.pattern.XXXXXXXX`
|
|
||||||
|
|
||||||
dd if=${DEVICE_NAME} of=${DEVICE_FILE} bs=${PATTERN_BLOCK_SIZE} \
|
|
||||||
count=${PATTERN_BLOCK_COUNT} iflag=direct &>/dev/null
|
|
||||||
cmp -s ${PATTERN_NAME} ${DEVICE_FILE}
|
|
||||||
RC=$?
|
|
||||||
rm -f ${DEVICE_FILE}
|
|
||||||
|
|
||||||
return ${RC}
|
|
||||||
}
|
|
||||||
|
|
||||||
pattern_remove() {
|
|
||||||
local PATTERN_NAME=$1
|
|
||||||
|
|
||||||
rm -f ${PATTERN_NAME}
|
|
||||||
return $?
|
|
||||||
}
|
|
||||||
|
|
||||||
fault_set_md() {
|
|
||||||
local VDEV_FAULTY=$1
|
|
||||||
local FAULT_TYPE=$2
|
|
||||||
|
|
||||||
${MDADM} /dev/${VDEV_FAULTY} --grow --level=faulty \
|
|
||||||
--layout=${FAULT_TYPE} >/dev/null
|
|
||||||
return $?
|
|
||||||
}
|
|
||||||
|
|
||||||
fault_clear_md() {
|
|
||||||
local VDEV_FAULTY=$1
|
|
||||||
|
|
||||||
# Clear all failure injection.
|
|
||||||
${MDADM} /dev/${VDEV_FAULTY} --grow --level=faulty \
|
|
||||||
--layout=clear >/dev/null || return $?
|
|
||||||
${MDADM} /dev/${VDEV_FAULTY} --grow --level=faulty \
|
|
||||||
--layout=flush >/dev/null || return $?
|
|
||||||
return $?
|
|
||||||
}
|
|
||||||
|
|
||||||
fault_set_sd() {
|
|
||||||
local OPTS=$1
|
|
||||||
local NTH=$2
|
|
||||||
|
|
||||||
echo ${OPTS} >/sys/bus/pseudo/drivers/scsi_debug/opts
|
|
||||||
echo ${NTH} >/sys/bus/pseudo/drivers/scsi_debug/every_nth
|
|
||||||
}
|
|
||||||
|
|
||||||
fault_clear_sd() {
|
|
||||||
echo 0 >/sys/bus/pseudo/drivers/scsi_debug/every_nth
|
|
||||||
echo 0 >/sys/bus/pseudo/drivers/scsi_debug/opts
|
|
||||||
}
|
|
||||||
|
|
||||||
test_setup() {
|
|
||||||
local POOL_NAME=$1
|
|
||||||
local POOL_CONFIG=$2
|
|
||||||
local ZVOL_NAME=$3
|
|
||||||
local TMP_CACHE=$4
|
|
||||||
|
|
||||||
${ZFS_SH} zfs="spa_config_path=${TMP_CACHE}" || fail 1
|
|
||||||
${ZPOOL_CREATE_SH} -p ${POOL_NAME} -c ${POOL_CONFIG} || fail 2
|
|
||||||
${ZFS} create -V 64M ${POOL_NAME}/${ZVOL_NAME} || fail 3
|
|
||||||
|
|
||||||
# Trigger udev and re-read the partition table to ensure all of
|
|
||||||
# this IO is out of the way before we begin injecting failures.
|
|
||||||
udev_trigger || fail 4
|
|
||||||
${BLOCKDEV} --rereadpt /dev/${POOL_NAME}/${ZVOL_NAME} || fail 5
|
|
||||||
}
|
|
||||||
|
|
||||||
test_cleanup() {
|
|
||||||
local POOL_NAME=$1
|
|
||||||
local POOL_CONFIG=$2
|
|
||||||
local ZVOL_NAME=$3
|
|
||||||
local TMP_CACHE=$4
|
|
||||||
|
|
||||||
${ZFS} destroy ${POOL_NAME}/${ZVOL_NAME} || fail 101
|
|
||||||
${ZPOOL_CREATE_SH} -p ${POOL_NAME} -c ${POOL_CONFIG} -d || fail 102
|
|
||||||
${ZFS_SH} -u || fail 103
|
|
||||||
rm -f ${TMP_CACHE} || fail 104
|
|
||||||
}
|
|
||||||
|
|
||||||
test_write_soft() {
|
|
||||||
local POOL_NAME=$1
|
|
||||||
local POOL_CONFIG=$2
|
|
||||||
local POOL_REDUNDANT=$3
|
|
||||||
local ZVOL_NAME="zvol"
|
|
||||||
local ZVOL_DEVICE="/dev/${POOL_NAME}/${ZVOL_NAME}"
|
|
||||||
|
|
||||||
if [ ${MD_PARTITIONABLE} -eq 0 ]; then
|
|
||||||
skip_nonewline
|
|
||||||
return
|
|
||||||
fi
|
|
||||||
|
|
||||||
local TMP_CACHE=`mktemp -p /tmp zpool.cache.XXXXXXXX`
|
|
||||||
test_setup ${POOL_NAME} ${POOL_CONFIG} ${ZVOL_NAME} ${TMP_CACHE}
|
|
||||||
|
|
||||||
# Set soft write failure for first vdev device.
|
|
||||||
local VDEV_FAULTY=`nth_zpool_vdev ${POOL_NAME} md 1`
|
|
||||||
fault_set_md ${VDEV_FAULTY} write-transient
|
|
||||||
|
|
||||||
# The application must not observe an error.
|
|
||||||
local TMP_PATTERN=`pattern_create 1M 8` || fail 11
|
|
||||||
pattern_write ${TMP_PATTERN} 1M 8 ${ZVOL_DEVICE} || fail 12
|
|
||||||
fault_clear_md ${VDEV_FAULTY}
|
|
||||||
|
|
||||||
# Soft errors will not be logged to 'zpool status'
|
|
||||||
local WRITE_ERRORS=`vdev_write_errors ${POOL_NAME} ${VDEV_FAULTY}`
|
|
||||||
test ${WRITE_ERRORS} -eq 0 || fail 13
|
|
||||||
|
|
||||||
# Soft errors will still generate an EIO (5) event.
|
|
||||||
test `zpool_event "zfs.io" "zio_err"` = "0x5" || fail 14
|
|
||||||
|
|
||||||
# Verify the known pattern.
|
|
||||||
pattern_verify ${TMP_PATTERN} 1M 8 ${ZVOL_DEVICE} || fail 15
|
|
||||||
pattern_remove ${TMP_PATTERN} || fail 16
|
|
||||||
|
|
||||||
test_cleanup ${POOL_NAME} ${POOL_CONFIG} ${ZVOL_NAME} ${TMP_CACHE}
|
|
||||||
pass_nonewline
|
|
||||||
}
|
|
||||||
|
|
||||||
# Soft write error.
|
|
||||||
test_1() {
|
|
||||||
test_write_soft tank lo-faulty-raid0 0
|
|
||||||
test_write_soft tank lo-faulty-raid10 1
|
|
||||||
test_write_soft tank lo-faulty-raidz 1
|
|
||||||
test_write_soft tank lo-faulty-raidz2 1
|
|
||||||
test_write_soft tank lo-faulty-raidz3 1
|
|
||||||
echo
|
|
||||||
}
|
|
||||||
run_test 1 "soft write error"
|
|
||||||
|
|
||||||
test_write_hard() {
|
|
||||||
local POOL_NAME=$1
|
|
||||||
local POOL_CONFIG=$2
|
|
||||||
local POOL_REDUNDANT=$3
|
|
||||||
local ZVOL_NAME="zvol"
|
|
||||||
local ZVOL_DEVICE="/dev/${POOL_NAME}/${ZVOL_NAME}"
|
|
||||||
|
|
||||||
if [ ${MD_PARTITIONABLE} -eq 0 ]; then
|
|
||||||
skip_nonewline
|
|
||||||
return
|
|
||||||
fi
|
|
||||||
|
|
||||||
local TMP_CACHE=`mktemp -p /tmp zpool.cache.XXXXXXXX`
|
|
||||||
test_setup ${POOL_NAME} ${POOL_CONFIG} ${ZVOL_NAME} ${TMP_CACHE}
|
|
||||||
|
|
||||||
# Set hard write failure for first vdev device.
|
|
||||||
local VDEV_FAULTY=`nth_zpool_vdev ${POOL_NAME} md 1`
|
|
||||||
fault_set_md ${VDEV_FAULTY} write-persistent
|
|
||||||
|
|
||||||
# The application must not observe an error.
|
|
||||||
local TMP_PATTERN=`pattern_create 1M 8` || fail 11
|
|
||||||
pattern_write ${TMP_PATTERN} 1M 8 ${ZVOL_DEVICE} || fail 12
|
|
||||||
fault_clear_md ${VDEV_FAULTY}
|
|
||||||
|
|
||||||
local WRITE_ERRORS=`vdev_write_errors ${POOL_NAME} ${VDEV_FAULTY}`
|
|
||||||
if [ ${POOL_REDUNDANT} -eq 1 ]; then
|
|
||||||
# For redundant configurations hard errors will not be
|
|
||||||
# logged to 'zpool status' but will generate EIO events.
|
|
||||||
test ${WRITE_ERRORS} -eq 0 || fail 21
|
|
||||||
test `zpool_event "zfs.io" "zio_err"` = "0x5" || fail 22
|
|
||||||
else
|
|
||||||
# For non-redundant configurations hard errors will be
|
|
||||||
# logged to 'zpool status' and generate EIO events. They
|
|
||||||
# will also trigger a scrub of the impacted sectors.
|
|
||||||
sleep 10
|
|
||||||
test ${WRITE_ERRORS} -gt 0 || fail 31
|
|
||||||
test `zpool_event "zfs.io" "zio_err"` = "0x5" || fail 32
|
|
||||||
test `zpool_event "zfs.resilver.start" "ena"` != "" || fail 33
|
|
||||||
test `zpool_event "zfs.resilver.finish" "ena"` != "" || fail 34
|
|
||||||
test `zpool_scan_errors ${POOL_NAME}` -eq 0 || fail 35
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Verify the known pattern.
|
|
||||||
pattern_verify ${TMP_PATTERN} 1M 8 ${ZVOL_DEVICE} || fail 41
|
|
||||||
pattern_remove ${TMP_PATTERN} || fail 42
|
|
||||||
|
|
||||||
test_cleanup ${POOL_NAME} ${POOL_CONFIG} ${ZVOL_NAME} ${TMP_CACHE}
|
|
||||||
pass_nonewline
|
|
||||||
}
|
|
||||||
|
|
||||||
# Hard write error.
|
|
||||||
test_2() {
|
|
||||||
test_write_hard tank lo-faulty-raid0 0
|
|
||||||
test_write_hard tank lo-faulty-raid10 1
|
|
||||||
test_write_hard tank lo-faulty-raidz 1
|
|
||||||
test_write_hard tank lo-faulty-raidz2 1
|
|
||||||
test_write_hard tank lo-faulty-raidz3 1
|
|
||||||
echo
|
|
||||||
}
|
|
||||||
run_test 2 "hard write error"
|
|
||||||
|
|
||||||
test_write_all() {
|
|
||||||
local POOL_NAME=$1
|
|
||||||
local POOL_CONFIG=$2
|
|
||||||
local POOL_REDUNDANT=$3
|
|
||||||
local ZVOL_NAME="zvol"
|
|
||||||
local ZVOL_DEVICE="/dev/${POOL_NAME}/${ZVOL_NAME}"
|
|
||||||
|
|
||||||
if [ ${MD_PARTITIONABLE} -eq 0 ]; then
|
|
||||||
skip_nonewline
|
|
||||||
return
|
|
||||||
fi
|
|
||||||
|
|
||||||
local TMP_CACHE=`mktemp -p /tmp zpool.cache.XXXXXXXX`
|
|
||||||
test_setup ${POOL_NAME} ${POOL_CONFIG} ${ZVOL_NAME} ${TMP_CACHE}
|
|
||||||
|
|
||||||
# Set all write failures for first vdev device.
|
|
||||||
local VDEV_FAULTY=`nth_zpool_vdev ${POOL_NAME} md 1`
|
|
||||||
fault_set_md ${VDEV_FAULTY} write-all
|
|
||||||
|
|
||||||
local TMP_PATTERN=`pattern_create 1M 8` || fail 11
|
|
||||||
if [ ${POOL_REDUNDANT} -eq 1 ]; then
|
|
||||||
# The application must not observe an error.
|
|
||||||
pattern_write ${TMP_PATTERN} 1M 8 ${ZVOL_DEVICE} || fail 12
|
|
||||||
else
|
|
||||||
# The application is expected to hang in the background until
|
|
||||||
# the faulty device is repaired and 'zpool clear' is run.
|
|
||||||
pattern_write_bg ${TMP_PATTERN} 1M 8 ${ZVOL_DEVICE} || fail 13
|
|
||||||
sleep 10
|
|
||||||
fi
|
|
||||||
fault_clear_md ${VDEV_FAULTY}
|
|
||||||
|
|
||||||
local WRITE_ERRORS=`vdev_write_errors ${POOL_NAME} ${VDEV_FAULTY}`
|
|
||||||
local VDEV_STATUS=`vdev_status ${POOL_NAME} ${VDEV_FAULTY}`
|
|
||||||
local POOL_STATE=`zpool_state ${POOL_NAME}`
|
|
||||||
# For all configurations write errors are logged to 'zpool status',
|
|
||||||
# and EIO events are generated. However, only a redundant config
|
|
||||||
# will cause the vdev to be FAULTED and pool DEGRADED. In a non-
|
|
||||||
# redundant config the IO will hang until 'zpool clear' is run.
|
|
||||||
test ${WRITE_ERRORS} -gt 0 || fail 14
|
|
||||||
test `zpool_event "zfs.io" "zio_err"` = "0x5" || fail 15
|
|
||||||
|
|
||||||
if [ ${POOL_REDUNDANT} -eq 1 ]; then
|
|
||||||
test "${VDEV_STATUS}" = "FAULTED" || fail 21
|
|
||||||
test "${POOL_STATE}" = "DEGRADED" || fail 22
|
|
||||||
else
|
|
||||||
BLOCKED=`ps a | grep "${ZVOL_DEVICE}" | grep -c -v "grep"`
|
|
||||||
${ZPOOL} clear ${POOL_NAME} || fail 31
|
|
||||||
test ${BLOCKED} -eq 1 || fail 32
|
|
||||||
wait
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Verify the known pattern.
|
|
||||||
pattern_verify ${TMP_PATTERN} 1M 8 ${ZVOL_DEVICE} || fail 41
|
|
||||||
pattern_remove ${TMP_PATTERN} || fail 42
|
|
||||||
|
|
||||||
test_cleanup ${POOL_NAME} ${POOL_CONFIG} ${ZVOL_NAME} ${TMP_CACHE}
|
|
||||||
pass_nonewline
|
|
||||||
}
|
|
||||||
|
|
||||||
# All write errors.
|
|
||||||
test_3() {
|
|
||||||
test_write_all tank lo-faulty-raid0 0
|
|
||||||
test_write_all tank lo-faulty-raid10 1
|
|
||||||
test_write_all tank lo-faulty-raidz 1
|
|
||||||
test_write_all tank lo-faulty-raidz2 1
|
|
||||||
test_write_all tank lo-faulty-raidz3 1
|
|
||||||
echo
|
|
||||||
}
|
|
||||||
run_test 3 "all write errors"
|
|
||||||
|
|
||||||
test_read_soft() {
|
|
||||||
local POOL_NAME=$1
|
|
||||||
local POOL_CONFIG=$2
|
|
||||||
local POOL_REDUNDANT=$3
|
|
||||||
local ZVOL_NAME="zvol"
|
|
||||||
local ZVOL_DEVICE="/dev/${POOL_NAME}/${ZVOL_NAME}"
|
|
||||||
local READ_ERRORS=0
|
|
||||||
|
|
||||||
if [ ${MD_PARTITIONABLE} -eq 0 ]; then
|
|
||||||
skip_nonewline
|
|
||||||
return
|
|
||||||
fi
|
|
||||||
|
|
||||||
local TMP_CACHE=`mktemp -p /tmp zpool.cache.XXXXXXXX`
|
|
||||||
test_setup ${POOL_NAME} ${POOL_CONFIG} ${ZVOL_NAME} ${TMP_CACHE}
|
|
||||||
|
|
||||||
# Create a pattern to be verified during a read error.
|
|
||||||
local TMP_PATTERN=`pattern_create 1M 8` || fail 11
|
|
||||||
pattern_write ${TMP_PATTERN} 1M 8 ${ZVOL_DEVICE} || fail 12
|
|
||||||
|
|
||||||
# Set soft read failure for all the vdevs to ensure we hit it.
|
|
||||||
for (( i=1; i<=4; i++ )); do
|
|
||||||
fault_set_md `nth_zpool_vdev ${POOL_NAME} md $i` read-transient
|
|
||||||
done
|
|
||||||
|
|
||||||
pattern_verify ${TMP_PATTERN} 1M 8 ${ZVOL_DEVICE} || fail 13
|
|
||||||
pattern_remove ${TMP_PATTERN} || fail 14
|
|
||||||
|
|
||||||
# Clear all failure injection and sum read errors.
|
|
||||||
for (( i=1; i<=4; i++ )); do
|
|
||||||
local VDEV_FAULTY=`nth_zpool_vdev ${POOL_NAME} md $i`
|
|
||||||
local VDEV_ERRORS=`vdev_read_errors ${POOL_NAME} ${VDEV_FAULTY}`
|
|
||||||
let READ_ERRORS=${READ_ERRORS}+${VDEV_ERRORS}
|
|
||||||
fault_clear_md ${VDEV_FAULTY}
|
|
||||||
done
|
|
||||||
|
|
||||||
# Soft errors will not be logged to 'zpool status'.
|
|
||||||
test ${READ_ERRORS} -eq 0 || fail 15
|
|
||||||
|
|
||||||
# Soft errors will still generate an EIO (5) event.
|
|
||||||
test `zpool_event "zfs.io" "zio_err"` = "0x5" || fail 16
|
|
||||||
|
|
||||||
test_cleanup ${POOL_NAME} ${POOL_CONFIG} ${ZVOL_NAME} ${TMP_CACHE}
|
|
||||||
pass_nonewline
|
|
||||||
}
|
|
||||||
|
|
||||||
# Soft read error.
|
|
||||||
test_4() {
|
|
||||||
test_read_soft tank lo-faulty-raid0 0
|
|
||||||
test_read_soft tank lo-faulty-raid10 1
|
|
||||||
test_read_soft tank lo-faulty-raidz 1
|
|
||||||
test_read_soft tank lo-faulty-raidz2 1
|
|
||||||
test_read_soft tank lo-faulty-raidz3 1
|
|
||||||
echo
|
|
||||||
}
|
|
||||||
run_test 4 "soft read error"
|
|
||||||
|
|
||||||
test_read_hard() {
|
|
||||||
local POOL_NAME=$1
|
|
||||||
local POOL_CONFIG=$2
|
|
||||||
local POOL_REDUNDANT=$3
|
|
||||||
local ZVOL_NAME="zvol"
|
|
||||||
local ZVOL_DEVICE="/dev/${POOL_NAME}/${ZVOL_NAME}"
|
|
||||||
local READ_ERRORS=0
|
|
||||||
|
|
||||||
if [ ${MD_PARTITIONABLE} -eq 0 ]; then
|
|
||||||
skip_nonewline
|
|
||||||
return
|
|
||||||
fi
|
|
||||||
|
|
||||||
local TMP_CACHE=`mktemp -p /tmp zpool.cache.XXXXXXXX`
|
|
||||||
test_setup ${POOL_NAME} ${POOL_CONFIG} ${ZVOL_NAME} ${TMP_CACHE}
|
|
||||||
|
|
||||||
# Create a pattern to be verified during a read error.
|
|
||||||
local TMP_PATTERN=`pattern_create 1M 8` || fail 11
|
|
||||||
pattern_write ${TMP_PATTERN} 1M 8 ${ZVOL_DEVICE} || fail 12
|
|
||||||
|
|
||||||
# Set hard read failure for the fourth vdev.
|
|
||||||
local VDEV_FAULTY=`nth_zpool_vdev ${POOL_NAME} md 4`
|
|
||||||
fault_set_md ${VDEV_FAULTY} read-persistent
|
|
||||||
|
|
||||||
# For a redundant pool there must be no IO error, for a non-redundant
|
|
||||||
# pool we expect permanent damage and an IO error during verify, unless
|
|
||||||
# we get exceptionally lucky and have just damaged redundant metadata.
|
|
||||||
if [ ${POOL_REDUNDANT} -eq 1 ]; then
|
|
||||||
pattern_verify ${TMP_PATTERN} 1M 8 ${ZVOL_DEVICE} || fail 21
|
|
||||||
local READ_ERRORS=`vdev_read_errors ${POOL_NAME} ${VDEV_FAULTY}`
|
|
||||||
test ${READ_ERRORS} -eq 0 || fail 22
|
|
||||||
else
|
|
||||||
pattern_verify ${TMP_PATTERN} 1M 8 ${ZVOL_DEVICE}
|
|
||||||
${ZPOOL} scrub ${POOL_NAME} || fail 32
|
|
||||||
local READ_ERRORS=`vdev_read_errors ${POOL_NAME} ${VDEV_FAULTY}`
|
|
||||||
test ${READ_ERRORS} -gt 0 || fail 33
|
|
||||||
${ZPOOL} status -v ${POOL_NAME} | \
|
|
||||||
grep -A8 "Permanent errors" | \
|
|
||||||
grep -q "${POOL_NAME}" || fail 34
|
|
||||||
fi
|
|
||||||
pattern_remove ${TMP_PATTERN} || fail 41
|
|
||||||
|
|
||||||
# Clear all failure injection and sum read errors.
|
|
||||||
fault_clear_md ${VDEV_FAULTY}
|
|
||||||
|
|
||||||
# Hard errors will generate an EIO (5) event.
|
|
||||||
test `zpool_event "zfs.io" "zio_err"` = "0x5" || fail 42
|
|
||||||
|
|
||||||
test_cleanup ${POOL_NAME} ${POOL_CONFIG} ${ZVOL_NAME} ${TMP_CACHE}
|
|
||||||
pass_nonewline
|
|
||||||
}
|
|
||||||
|
|
||||||
# Hard read error.
|
|
||||||
test_5() {
|
|
||||||
test_read_hard tank lo-faulty-raid0 0
|
|
||||||
test_read_hard tank lo-faulty-raid10 1
|
|
||||||
test_read_hard tank lo-faulty-raidz 1
|
|
||||||
test_read_hard tank lo-faulty-raidz2 1
|
|
||||||
test_read_hard tank lo-faulty-raidz3 1
|
|
||||||
echo
|
|
||||||
}
|
|
||||||
run_test 5 "hard read error"
|
|
||||||
|
|
||||||
# Fixable read error.
|
|
||||||
test_read_fixable() {
|
|
||||||
local POOL_NAME=$1
|
|
||||||
local POOL_CONFIG=$2
|
|
||||||
local POOL_REDUNDANT=$3
|
|
||||||
local ZVOL_NAME="zvol"
|
|
||||||
local ZVOL_DEVICE="/dev/${POOL_NAME}/${ZVOL_NAME}"
|
|
||||||
local READ_ERRORS=0
|
|
||||||
|
|
||||||
if [ ${MD_PARTITIONABLE} -eq 0 ]; then
|
|
||||||
skip_nonewline
|
|
||||||
return
|
|
||||||
fi
|
|
||||||
|
|
||||||
local TMP_CACHE=`mktemp -p /tmp zpool.cache.XXXXXXXX`
|
|
||||||
test_setup ${POOL_NAME} ${POOL_CONFIG} ${ZVOL_NAME} ${TMP_CACHE}
|
|
||||||
|
|
||||||
# Create a pattern to be verified during a read error.
|
|
||||||
local TMP_PATTERN=`pattern_create 1M 8` || fail 11
|
|
||||||
pattern_write ${TMP_PATTERN} 1M 8 ${ZVOL_DEVICE} || fail 12
|
|
||||||
|
|
||||||
# Set hard read failure for the fourth vdev.
|
|
||||||
local VDEV_FAULTY=`nth_zpool_vdev ${POOL_NAME} md 4`
|
|
||||||
fault_set_md ${VDEV_FAULTY} read-fixable
|
|
||||||
|
|
||||||
# For a redundant pool there must be no IO error, for a non-redundant
|
|
||||||
# pool we expect permanent damage and an IO error during verify, unless
|
|
||||||
# we get exceptionally lucky and have just damaged redundant metadata.
|
|
||||||
if [ ${POOL_REDUNDANT} -eq 1 ]; then
|
|
||||||
pattern_verify ${TMP_PATTERN} 1M 8 ${ZVOL_DEVICE} || fail 21
|
|
||||||
local READ_ERRORS=`vdev_read_errors ${POOL_NAME} ${VDEV_FAULTY}`
|
|
||||||
test ${READ_ERRORS} -eq 0 || fail 22
|
|
||||||
else
|
|
||||||
pattern_verify ${TMP_PATTERN} 1M 8 ${ZVOL_DEVICE}
|
|
||||||
${ZPOOL} scrub ${POOL_NAME} || fail 32
|
|
||||||
local READ_ERRORS=`vdev_read_errors ${POOL_NAME} ${VDEV_FAULTY}`
|
|
||||||
test ${READ_ERRORS} -gt 0 || fail 33
|
|
||||||
${ZPOOL} status -v ${POOL_NAME} | \
|
|
||||||
grep -A8 "Permanent errors" | \
|
|
||||||
grep -q "${POOL_NAME}" || fail 34
|
|
||||||
fi
|
|
||||||
pattern_remove ${TMP_PATTERN} || fail 41
|
|
||||||
|
|
||||||
# Clear all failure injection and sum read errors.
|
|
||||||
fault_clear_md ${VDEV_FAULTY}
|
|
||||||
|
|
||||||
# Hard errors will generate an EIO (5) event.
|
|
||||||
test `zpool_event "zfs.io" "zio_err"` = "0x5" || fail 42
|
|
||||||
|
|
||||||
test_cleanup ${POOL_NAME} ${POOL_CONFIG} ${ZVOL_NAME} ${TMP_CACHE}
|
|
||||||
pass_nonewline
|
|
||||||
}
|
|
||||||
|
|
||||||
# Read errors fixable with a write.
|
|
||||||
test_6() {
|
|
||||||
test_read_fixable tank lo-faulty-raid0 0
|
|
||||||
test_read_fixable tank lo-faulty-raid10 1
|
|
||||||
test_read_fixable tank lo-faulty-raidz 1
|
|
||||||
test_read_fixable tank lo-faulty-raidz2 1
|
|
||||||
test_read_fixable tank lo-faulty-raidz3 1
|
|
||||||
echo
|
|
||||||
}
|
|
||||||
run_test 6 "fixable read error"
|
|
||||||
|
|
||||||
test_cksum() {
|
|
||||||
local POOL_NAME=$1
|
|
||||||
local POOL_CONFIG=$2
|
|
||||||
local POOL_REDUNDANT=$3
|
|
||||||
local VDEV_DAMAGE="$4"
|
|
||||||
local ZVOL_NAME="zvol"
|
|
||||||
local ZVOL_DEVICE="/dev/${POOL_NAME}/${ZVOL_NAME}"
|
|
||||||
|
|
||||||
if [ ${MD_PARTITIONABLE} -eq 0 ]; then
|
|
||||||
skip_nonewline
|
|
||||||
return
|
|
||||||
fi
|
|
||||||
|
|
||||||
local TMP_CACHE=`mktemp -p /tmp zpool.cache.XXXXXXXX`
|
|
||||||
test_setup ${POOL_NAME} ${POOL_CONFIG} ${ZVOL_NAME} ${TMP_CACHE}
|
|
||||||
|
|
||||||
# Create a pattern to be verified.
|
|
||||||
local TMP_PATTERN=`pattern_create 1M 8` || fail 11
|
|
||||||
pattern_write ${TMP_PATTERN} 1M 8 ${ZVOL_DEVICE} || fail 12
|
|
||||||
|
|
||||||
# Verify the pattern and that no vdev has cksum errors.
|
|
||||||
pattern_verify ${TMP_PATTERN} 1M 8 ${ZVOL_DEVICE} || fail 13
|
|
||||||
for (( i=1; i<4; i++ )); do
|
|
||||||
VDEV_FAULTY=`nth_zpool_vdev ${POOL_NAME} md ${i}`
|
|
||||||
CKSUM_ERRORS=`vdev_cksum_errors ${POOL_NAME} ${VDEV_FAULTY}`
|
|
||||||
test ${CKSUM_ERRORS} -eq 0 || fail 14
|
|
||||||
done
|
|
||||||
|
|
||||||
# Corrupt the bulk of a vdev with random garbage, we damage as many
|
|
||||||
# vdevs as we have levels of redundancy. For example for a raidz3
|
|
||||||
# configuration we can trash 3 vdevs and still expect correct data.
|
|
||||||
# This improves the odds that we read one of the damaged vdevs.
|
|
||||||
for VDEV in ${VDEV_DAMAGE}; do
|
|
||||||
VDEV_FAULTY=`nth_zpool_vdev ${POOL_NAME} md $VDEV`
|
|
||||||
pattern_write /dev/urandom 1M 64 /dev/${VDEV_FAULTY}p1
|
|
||||||
done
|
|
||||||
|
|
||||||
# Verify the pattern is still correct. For non-redundant pools
|
|
||||||
# expect failure and for redundant pools success due to resilvering.
|
|
||||||
if [ ${POOL_REDUNDANT} -eq 1 ]; then
|
|
||||||
pattern_verify ${TMP_PATTERN} 1M 8 ${ZVOL_DEVICE} || fail 16
|
|
||||||
else
|
|
||||||
pattern_verify ${TMP_PATTERN} 1M 8 ${ZVOL_DEVICE} && fail 17
|
|
||||||
fi
|
|
||||||
|
|
||||||
CKSUM_ERRORS=`vdev_cksum_errors ${POOL_NAME} ${VDEV_FAULTY}`
|
|
||||||
test ${CKSUM_ERRORS} -gt 0 || fail 18
|
|
||||||
STATUS=`vdev_status ${POOL_NAME} ${VDEV_FAULTY}`
|
|
||||||
test "${STATUS}" = "ONLINE" || fail 19
|
|
||||||
|
|
||||||
# The checksum errors must be logged as an event.
|
|
||||||
local CKSUM_ERRORS=`zpool_event "zfs.checksum" "zio_err"`
|
|
||||||
test ${CKSUM_ERRORS} = "0x34" || test ${CKSUM_ERRORS} = "0x0" || fail 20
|
|
||||||
|
|
||||||
# Verify permant errors for non-redundant pools, and for redundant
|
|
||||||
# pools trigger a scrub and check that all checksums have been fixed.
|
|
||||||
if [ ${POOL_REDUNDANT} -eq 1 ]; then
|
|
||||||
# Scrub the checksum errors and clear the faults.
|
|
||||||
${ZPOOL} scrub ${POOL_NAME} || fail 21
|
|
||||||
sleep 3
|
|
||||||
${ZPOOL} clear ${POOL_NAME} || fail 22
|
|
||||||
|
|
||||||
# Re-verify the pattern for fixed checksums.
|
|
||||||
pattern_verify ${TMP_PATTERN} 1M 8 ${ZVOL_DEVICE} || fail 23
|
|
||||||
CKSUM_ERRORS=`vdev_cksum_errors ${POOL_NAME} ${VDEV_FAULTY}`
|
|
||||||
test ${CKSUM_ERRORS} -eq 0 || fail 24
|
|
||||||
|
|
||||||
# Re-verify the entire pool for fixed checksums.
|
|
||||||
${ZPOOL} scrub ${POOL_NAME} || fail 25
|
|
||||||
CKSUM_ERRORS=`vdev_cksum_errors ${POOL_NAME} ${VDEV_FAULTY}`
|
|
||||||
test ${CKSUM_ERRORS} -eq 0 || fail 26
|
|
||||||
else
|
|
||||||
${ZPOOL} status -v ${POOL_NAME} | \
|
|
||||||
grep -A8 "Permanent errors" | \
|
|
||||||
grep -q "${POOL_NAME}/${ZVOL_NAME}" || fail 31
|
|
||||||
${ZPOOL} clear ${POOL_NAME} || fail 32
|
|
||||||
fi
|
|
||||||
pattern_remove ${TMP_PATTERN} || fail 41
|
|
||||||
|
|
||||||
test_cleanup ${POOL_NAME} ${POOL_CONFIG} ${ZVOL_NAME} ${TMP_CACHE}
|
|
||||||
pass_nonewline
|
|
||||||
}
|
|
||||||
|
|
||||||
# Silent data corruption
|
|
||||||
test_7() {
|
|
||||||
test_cksum tank lo-faulty-raid0 0 "1"
|
|
||||||
test_cksum tank lo-faulty-raid10 1 "1 3"
|
|
||||||
test_cksum tank lo-faulty-raidz 1 "4"
|
|
||||||
test_cksum tank lo-faulty-raidz2 1 "3 4"
|
|
||||||
test_cksum tank lo-faulty-raidz3 1 "2 3 4"
|
|
||||||
echo
|
|
||||||
}
|
|
||||||
run_test 7 "silent data corruption"
|
|
||||||
|
|
||||||
# Soft write timeout at the scsi device layer.
|
|
||||||
test_write_timeout_soft() {
|
|
||||||
local POOL_NAME=$1
|
|
||||||
local POOL_CONFIG=$2
|
|
||||||
local POOL_REDUNDANT=$3
|
|
||||||
local POOL_NTH=$4
|
|
||||||
local ZVOL_NAME="zvol"
|
|
||||||
local ZVOL_DEVICE="/dev/${POOL_NAME}/${ZVOL_NAME}"
|
|
||||||
|
|
||||||
if [ ${SCSI_DEBUG} -eq 0 ]; then
|
|
||||||
skip_nonewline
|
|
||||||
return
|
|
||||||
fi
|
|
||||||
|
|
||||||
local TMP_CACHE=`mktemp -p /tmp zpool.cache.XXXXXXXX`
|
|
||||||
test_setup ${POOL_NAME} ${POOL_CONFIG} ${ZVOL_NAME} ${TMP_CACHE}
|
|
||||||
|
|
||||||
# Set timeout(0x4) for every nth command.
|
|
||||||
fault_set_sd 4 ${POOL_NTH}
|
|
||||||
|
|
||||||
# The application must not observe an error.
|
|
||||||
local TMP_PATTERN=`pattern_create 1M 8` || fail 11
|
|
||||||
pattern_write ${TMP_PATTERN} 1M 8 ${ZVOL_DEVICE} || fail 12
|
|
||||||
fault_clear_sd
|
|
||||||
|
|
||||||
# Intermittent write timeouts even with FAILFAST set may not cause
|
|
||||||
# an EIO (5) event. This is because how FAILFAST is handled depends
|
|
||||||
# a log on the low level driver and the exact nature of the failure.
|
|
||||||
# We will however see a 'zfs.delay' event logged due to the timeout.
|
|
||||||
VDEV_DELAY=`zpool_event "zfs.delay" "zio_delay"`
|
|
||||||
test `printf "%d" ${VDEV_DELAY}` -ge 30000 || fail 13
|
|
||||||
|
|
||||||
# Verify the known pattern.
|
|
||||||
pattern_verify ${TMP_PATTERN} 1M 8 ${ZVOL_DEVICE} || fail 14
|
|
||||||
pattern_remove ${TMP_PATTERN} || fail 15
|
|
||||||
|
|
||||||
test_cleanup ${POOL_NAME} ${POOL_CONFIG} ${ZVOL_NAME} ${TMP_CACHE}
|
|
||||||
pass_nonewline
|
|
||||||
}
|
|
||||||
|
|
||||||
test_8() {
|
|
||||||
test_write_timeout_soft tank scsi_debug-raid0 0 50
|
|
||||||
test_write_timeout_soft tank scsi_debug-raid10 1 100
|
|
||||||
test_write_timeout_soft tank scsi_debug-raidz 1 75
|
|
||||||
test_write_timeout_soft tank scsi_debug-raidz2 1 150
|
|
||||||
test_write_timeout_soft tank scsi_debug-raidz3 1 300
|
|
||||||
echo
|
|
||||||
}
|
|
||||||
run_test 8 "soft write timeout"
|
|
||||||
|
|
||||||
# Persistent write timeout at the scsi device layer.
|
|
||||||
test_write_timeout_hard() {
|
|
||||||
local POOL_NAME=$1
|
|
||||||
local POOL_CONFIG=$2
|
|
||||||
local POOL_REDUNDANT=$3
|
|
||||||
local POOL_NTH=$4
|
|
||||||
local ZVOL_NAME="zvol"
|
|
||||||
local ZVOL_DEVICE="/dev/${POOL_NAME}/${ZVOL_NAME}"
|
|
||||||
local RESCAN=1
|
|
||||||
|
|
||||||
if [ ${SCSI_DEBUG} -eq 0 ]; then
|
|
||||||
skip_nonewline
|
|
||||||
return
|
|
||||||
fi
|
|
||||||
|
|
||||||
local TMP_CACHE=`mktemp -p /tmp zpool.cache.XXXXXXXX`
|
|
||||||
test_setup ${POOL_NAME} ${POOL_CONFIG} ${ZVOL_NAME} ${TMP_CACHE}
|
|
||||||
|
|
||||||
local TMP_PATTERN1=`pattern_create 1M 8`
|
|
||||||
local TMP_PATTERN2=`pattern_create 1M 8`
|
|
||||||
local TMP_PATTERN3=`pattern_create 1M 8`
|
|
||||||
|
|
||||||
# Create three partitions each one gets a unique pattern. The first
|
|
||||||
# pattern is written before the failure, the second pattern during
|
|
||||||
# the failure, and the third pattern while the vdev is degraded.
|
|
||||||
# All three patterns are verified while the vdev is degraded and
|
|
||||||
# then again once it is brought back online.
|
|
||||||
${PARTED} -s ${ZVOL_DEVICE} mklabel gpt || fail 11
|
|
||||||
${PARTED} -s ${ZVOL_DEVICE} mkpart primary 1M 16M || fail 12
|
|
||||||
${PARTED} -s ${ZVOL_DEVICE} mkpart primary 16M 32M || fail 13
|
|
||||||
${PARTED} -s ${ZVOL_DEVICE} mkpart primary 32M 48M || fail 14
|
|
||||||
|
|
||||||
wait_udev ${ZVOL_DEVICE}1 30
|
|
||||||
wait_udev ${ZVOL_DEVICE}2 30
|
|
||||||
wait_udev ${ZVOL_DEVICE}3 30
|
|
||||||
|
|
||||||
# Before the failure.
|
|
||||||
pattern_write ${TMP_PATTERN1} 1M 8 ${ZVOL_DEVICE}1 || fail 15
|
|
||||||
|
|
||||||
# Get the faulty vdev name.
|
|
||||||
local VDEV_FAULTY=`nth_zpool_vdev ${POOL_NAME} sd 1`
|
|
||||||
|
|
||||||
# Set timeout(0x4) for every nth command.
|
|
||||||
fault_set_sd 4 ${POOL_NTH}
|
|
||||||
|
|
||||||
# During the failure.
|
|
||||||
pattern_write ${TMP_PATTERN2} 1M 8 ${ZVOL_DEVICE}2 || fail 21
|
|
||||||
|
|
||||||
# Expect write errors to be logged to 'zpool status'
|
|
||||||
local WRITE_ERRORS=`vdev_write_errors ${POOL_NAME} ${VDEV_FAULTY}`
|
|
||||||
test ${WRITE_ERRORS} -gt 0 || fail 22
|
|
||||||
|
|
||||||
local VDEV_STATUS=`vdev_status ${POOL_NAME} ${VDEV_FAULTY}`
|
|
||||||
test "${VDEV_STATUS}" = "UNAVAIL" || fail 23
|
|
||||||
|
|
||||||
# Clear the error and remove it from /dev/.
|
|
||||||
fault_clear_sd
|
|
||||||
rm -f /dev/${VDEV_FAULTY}[0-9]
|
|
||||||
|
|
||||||
# Verify the first two patterns and write out the third.
|
|
||||||
pattern_write ${TMP_PATTERN3} 1M 8 ${ZVOL_DEVICE}3 || fail 31
|
|
||||||
pattern_verify ${TMP_PATTERN1} 1M 8 ${ZVOL_DEVICE}1 || fail 32
|
|
||||||
pattern_verify ${TMP_PATTERN2} 1M 8 ${ZVOL_DEVICE}2 || fail 33
|
|
||||||
pattern_verify ${TMP_PATTERN3} 1M 8 ${ZVOL_DEVICE}3 || fail 34
|
|
||||||
|
|
||||||
# Bring the device back online by rescanning for it. It must appear
|
|
||||||
# in lsscsi and be available to dd before allowing ZFS to bring it
|
|
||||||
# online. This is not required but provides additional sanity.
|
|
||||||
while [ ${RESCAN} -eq 1 ]; do
|
|
||||||
scsi_rescan
|
|
||||||
wait_udev /dev/${VDEV_FAULTY} 30
|
|
||||||
|
|
||||||
if [ `${LSSCSI} | grep -c "/dev/${VDEV_FAULTY}"` -eq 0 ]; then
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
|
|
||||||
dd if=/dev/${VDEV_FAULTY} of=/dev/null bs=8M count=1 &>/dev/null
|
|
||||||
if [ $? -ne 0 ]; then
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
|
|
||||||
RESCAN=0
|
|
||||||
done
|
|
||||||
|
|
||||||
# Bring the device back online. We expect it to be automatically
|
|
||||||
# resilvered without error and we should see minimally the zfs.io,
|
|
||||||
# zfs.statechange (VDEV_STATE_HEALTHY (0x7)), and zfs.resilver.*
|
|
||||||
# events posted.
|
|
||||||
${ZPOOL} online ${POOL_NAME} ${VDEV_FAULTY} || fail 51
|
|
||||||
sleep 3
|
|
||||||
test `zpool_event "zfs.io" "zio_err"` = "0x5" || fail 52
|
|
||||||
test `zpool_event "zfs.statechange" "vdev_state"` = "0x7" || fail 53
|
|
||||||
test `zpool_event "zfs.resilver.start" "ena"` != "" || fail 54
|
|
||||||
test `zpool_event "zfs.resilver.finish" "ena"` != "" || fail 55
|
|
||||||
test `zpool_scan_errors ${POOL_NAME}` -eq 0 || fail 56
|
|
||||||
|
|
||||||
local VDEV_STATUS=`vdev_status ${POOL_NAME} ${VDEV_FAULTY}`
|
|
||||||
test "${VDEV_STATUS}" = "ONLINE" || fail 57
|
|
||||||
|
|
||||||
# Verify the known pattern.
|
|
||||||
pattern_verify ${TMP_PATTERN1} 1M 8 ${ZVOL_DEVICE}1 || fail 61
|
|
||||||
pattern_verify ${TMP_PATTERN2} 1M 8 ${ZVOL_DEVICE}2 || fail 62
|
|
||||||
pattern_verify ${TMP_PATTERN3} 1M 8 ${ZVOL_DEVICE}3 || fail 63
|
|
||||||
pattern_remove ${TMP_PATTERN1} || fail 64
|
|
||||||
pattern_remove ${TMP_PATTERN2} || fail 65
|
|
||||||
pattern_remove ${TMP_PATTERN3} || fail 66
|
|
||||||
|
|
||||||
test_cleanup ${POOL_NAME} ${POOL_CONFIG} ${ZVOL_NAME} ${TMP_CACHE}
|
|
||||||
pass_nonewline
|
|
||||||
}
|
|
||||||
|
|
||||||
test_9() {
|
|
||||||
skip_nonewline # Skip non-redundant config
|
|
||||||
test_write_timeout_hard tank scsi_debug-raid10 1 -50
|
|
||||||
test_write_timeout_hard tank scsi_debug-raidz 1 -50
|
|
||||||
test_write_timeout_hard tank scsi_debug-raidz2 1 -50
|
|
||||||
test_write_timeout_hard tank scsi_debug-raidz3 1 -50
|
|
||||||
echo
|
|
||||||
}
|
|
||||||
run_test 9 "hard write timeout"
|
|
||||||
|
|
||||||
exit 0
|
|
343
scripts/zfs-tests.sh
Executable file
343
scripts/zfs-tests.sh
Executable file
@ -0,0 +1,343 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
#
|
||||||
|
# CDDL HEADER START
|
||||||
|
#
|
||||||
|
# The contents of this file are subject to the terms of the
|
||||||
|
# Common Development and Distribution License, Version 1.0 only
|
||||||
|
# (the "License"). You may not use this file except in compliance
|
||||||
|
# with the License.
|
||||||
|
#
|
||||||
|
# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
||||||
|
# or http://www.opensolaris.org/os/licensing.
|
||||||
|
# See the License for the specific language governing permissions
|
||||||
|
# and limitations under the License.
|
||||||
|
#
|
||||||
|
# When distributing Covered Code, include this CDDL HEADER in each
|
||||||
|
# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
||||||
|
# If applicable, add the following below this CDDL HEADER, with the
|
||||||
|
# fields enclosed by brackets "[]" replaced with your own identifying
|
||||||
|
# information: Portions Copyright [yyyy] [name of copyright owner]
|
||||||
|
#
|
||||||
|
# CDDL HEADER END
|
||||||
|
#
|
||||||
|
basedir="$(dirname $0)"
|
||||||
|
|
||||||
|
SCRIPT_COMMON=common.sh
|
||||||
|
if [ -f "${basedir}/${SCRIPT_COMMON}" ]; then
|
||||||
|
. "${basedir}/${SCRIPT_COMMON}"
|
||||||
|
else
|
||||||
|
echo "Missing helper script ${SCRIPT_COMMON}" && exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
. $STF_SUITE/include/default.cfg
|
||||||
|
|
||||||
|
PROG=zfs-tests.sh
|
||||||
|
SUDO=/usr/bin/sudo
|
||||||
|
SETENFORCE=/usr/sbin/setenforce
|
||||||
|
VERBOSE=
|
||||||
|
QUIET=
|
||||||
|
CLEANUP=1
|
||||||
|
CLEANUPALL=0
|
||||||
|
LOOPBACK=1
|
||||||
|
FILESIZE="2G"
|
||||||
|
RUNFILE=${RUNFILE:-"linux.run"}
|
||||||
|
FILEDIR=${FILEDIR:-/var/tmp}
|
||||||
|
DISKS=${DISKS:-""}
|
||||||
|
|
||||||
|
#
|
||||||
|
# Attempt to remove loopback devices and files which where created earlier
|
||||||
|
# by this script to run the test framework. The '-k' option may be passed
|
||||||
|
# to the script to suppress cleanup for debugging purposes.
|
||||||
|
#
|
||||||
|
cleanup() {
|
||||||
|
if [ $CLEANUP -eq 0 ]; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ $LOOPBACK -eq 1 ]; then
|
||||||
|
for TEST_LOOPBACK in ${LOOPBACKS}; do
|
||||||
|
LOOP_DEV=$(basename $TEST_LOOPBACK)
|
||||||
|
DM_DEV=$(${SUDO} ${DMSETUP} ls 2>/dev/null | \
|
||||||
|
grep ${LOOP_DEV} | cut -f1)
|
||||||
|
|
||||||
|
if [ -n "$DM_DEV" ]; then
|
||||||
|
${SUDO} ${DMSETUP} remove ${DM_DEV} ||
|
||||||
|
echo "Failed to remove: ${DM_DEV}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -n "${TEST_LOOPBACK}" ]; then
|
||||||
|
${SUDO} ${LOSETUP} -d ${TEST_LOOPBACK} ||
|
||||||
|
echo "Failed to remove: ${TEST_LOOPBACK}"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
for TEST_FILE in ${FILES}; do
|
||||||
|
rm -f ${TEST_FILE} &>/dev/null
|
||||||
|
done
|
||||||
|
}
|
||||||
|
trap cleanup EXIT
|
||||||
|
|
||||||
|
#
|
||||||
|
# Attempt to remove all testpools (testpool.XXX), unopened dm devices,
|
||||||
|
# loopback devices, and files. This is a useful way to cleanup a previous
|
||||||
|
# test run failure which has left the system in an unknown state. This can
|
||||||
|
# be dangerous and should only be used in a dedicated test environment.
|
||||||
|
#
|
||||||
|
cleanup_all() {
|
||||||
|
local TEST_POOLS=$(${SUDO} ${ZPOOL} list -H -o name | grep testpool)
|
||||||
|
local TEST_LOOPBACKS=$(${SUDO} ${LOSETUP} -a|grep file-vdev|cut -f1 -d:)
|
||||||
|
local TEST_FILES=$(ls /var/tmp/file-vdev* 2>/dev/null)
|
||||||
|
|
||||||
|
msg
|
||||||
|
msg "--- Cleanup ---"
|
||||||
|
msg "Removing pool(s): $(echo ${TEST_POOLS} | tr '\n' ' ')"
|
||||||
|
for TEST_POOL in $TEST_POOLS; do
|
||||||
|
${SUDO} ${ZPOOL} destroy ${TEST_POOL}
|
||||||
|
done
|
||||||
|
|
||||||
|
msg "Removing dm(s): $(${SUDO} ${DMSETUP} ls |
|
||||||
|
grep loop | tr '\n' ' ')"
|
||||||
|
${SUDO} ${DMSETUP} remove_all
|
||||||
|
|
||||||
|
msg "Removing loopback(s): $(echo ${TEST_LOOPBACKS} | tr '\n' ' ')"
|
||||||
|
for TEST_LOOPBACK in $TEST_LOOPBACKS; do
|
||||||
|
${SUDO} ${LOSETUP} -d ${TEST_LOOPBACK}
|
||||||
|
done
|
||||||
|
|
||||||
|
msg "Removing files(s): $(echo ${TEST_FILES} | tr '\n' ' ')"
|
||||||
|
for TEST_FILE in $TEST_FILES; do
|
||||||
|
${SUDO} rm -f ${TEST_FILE}
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# Log a failure message, cleanup, and return an error.
|
||||||
|
#
|
||||||
|
fail() {
|
||||||
|
echo -e "${PROG}: $1" >&2
|
||||||
|
cleanup
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# Takes a name as the only arguments and looks for the following variations
|
||||||
|
# on that name. If one is found it is returned.
|
||||||
|
#
|
||||||
|
# $RUNFILEDIR/<name>
|
||||||
|
# $RUNFILEDIR/<name>.run
|
||||||
|
# <name>
|
||||||
|
# <name>.run
|
||||||
|
#
|
||||||
|
find_runfile() {
|
||||||
|
local NAME=$1
|
||||||
|
local RESULT=""
|
||||||
|
|
||||||
|
if [ -f "$RUNFILEDIR/$NAME" ]; then
|
||||||
|
RESULT="$RUNFILEDIR/$NAME"
|
||||||
|
elif [ -f "$RUNFILEDIR/$NAME.run" ]; then
|
||||||
|
RESULT="$RUNFILEDIR/$NAME.run"
|
||||||
|
elif [ -f "$NAME" ]; then
|
||||||
|
RESULT="$NAME"
|
||||||
|
elif [ -f "$NAME.run" ]; then
|
||||||
|
RESULT="$NAME.run"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "$RESULT"
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# Output a useful usage message.
|
||||||
|
#
|
||||||
|
usage() {
|
||||||
|
cat << EOF
|
||||||
|
USAGE:
|
||||||
|
$0 [hvqxkf] [-s SIZE] [-r RUNFILE]
|
||||||
|
|
||||||
|
DESCRIPTION:
|
||||||
|
ZFS Test Suite launch script
|
||||||
|
|
||||||
|
OPTIONS:
|
||||||
|
-h Show this message
|
||||||
|
-v Verbose zfs-tests.sh output
|
||||||
|
-q Quiet test-runner output
|
||||||
|
-x Remove all testpools, dm, lo, and files (unsafe)
|
||||||
|
-k Disable cleanup after test failure
|
||||||
|
-f Use files only, disables block device tests
|
||||||
|
-d DIR Use DIR for files and loopback devices
|
||||||
|
-s SIZE Use vdevs of SIZE (default: 4G)
|
||||||
|
-r RUNFILE Run tests in RUNFILE (default: linux.run)
|
||||||
|
|
||||||
|
EXAMPLES:
|
||||||
|
# Run the default (linux) suite of tests and output the configuration used.
|
||||||
|
$0 -v
|
||||||
|
|
||||||
|
# Run a smaller suite of tests designed to run more quickly.
|
||||||
|
$0 -r linux-fast
|
||||||
|
|
||||||
|
# Cleanup a previous run of the test suite prior to testing, run the
|
||||||
|
# default (linux) suite of tests and perform no cleanup on exit.
|
||||||
|
$0 -c
|
||||||
|
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
while getopts 'hvqxkfd:s:r:?' OPTION; do
|
||||||
|
case $OPTION in
|
||||||
|
h)
|
||||||
|
usage
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
v)
|
||||||
|
VERBOSE=1
|
||||||
|
;;
|
||||||
|
q)
|
||||||
|
QUIET="-q"
|
||||||
|
;;
|
||||||
|
x)
|
||||||
|
CLEANUPALL=1
|
||||||
|
;;
|
||||||
|
k)
|
||||||
|
CLEANUP=0
|
||||||
|
;;
|
||||||
|
f)
|
||||||
|
LOOPBACK=0
|
||||||
|
;;
|
||||||
|
d)
|
||||||
|
FILEDIR="$OPTARG"
|
||||||
|
;;
|
||||||
|
s)
|
||||||
|
FILESIZE="$OPTARG"
|
||||||
|
;;
|
||||||
|
r)
|
||||||
|
RUNFILE="$OPTARG"
|
||||||
|
;;
|
||||||
|
?)
|
||||||
|
usage
|
||||||
|
exit
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
shift $((OPTIND-1))
|
||||||
|
|
||||||
|
FILES=${FILES:-"$FILEDIR/file-vdev0 $FILEDIR/file-vdev1 $FILEDIR/file-vdev2"}
|
||||||
|
LOOPBACKS=${LOOPBACKS:-""}
|
||||||
|
|
||||||
|
#
|
||||||
|
# Attempt to locate the runfile describing the test workload.
|
||||||
|
#
|
||||||
|
if [ -n "$RUNFILE" ]; then
|
||||||
|
SAVED_RUNFILE="$RUNFILE"
|
||||||
|
RUNFILE=$(find_runfile "$RUNFILE")
|
||||||
|
[ -z "$RUNFILE" ] && fail "Cannot find runfile: $SAVED_RUNFILE"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ! -r "$RUNFILE" ]; then
|
||||||
|
fail "Cannot read runfile: $RUNFILE"
|
||||||
|
fi
|
||||||
|
|
||||||
|
#
|
||||||
|
# This script should not be run as root. Instead the test user, which may
|
||||||
|
# be a normal user account, needs to be configured such that it can
|
||||||
|
# run commands via sudo passwordlessly.
|
||||||
|
#
|
||||||
|
if [ $(id -u) = "0" ]; then
|
||||||
|
fail "This script must not be run as root."
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ $(sudo whoami) != "root" ]; then
|
||||||
|
fail "Passwordless sudo access required."
|
||||||
|
fi
|
||||||
|
|
||||||
|
#
|
||||||
|
# Verify the ZFS module stack if loaded.
|
||||||
|
#
|
||||||
|
${SUDO} ${ZFS_SH} &>/dev/null
|
||||||
|
|
||||||
|
#
|
||||||
|
# Attempt to cleanup all previous state for a new test run.
|
||||||
|
#
|
||||||
|
if [ $CLEANUPALL -ne 0 ]; then
|
||||||
|
cleanup_all
|
||||||
|
fi
|
||||||
|
|
||||||
|
#
|
||||||
|
# By default preserve any existing pools
|
||||||
|
#
|
||||||
|
if [ -z "${KEEP}" ]; then
|
||||||
|
KEEP=$(${SUDO} ${ZPOOL} list -H -o name)
|
||||||
|
if [ -z "${KEEP}" ]; then
|
||||||
|
KEEP="rpool"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
msg
|
||||||
|
msg "--- Configuration ---"
|
||||||
|
msg "Runfile: $RUNFILE"
|
||||||
|
msg "STF_TOOLS: $STF_TOOLS"
|
||||||
|
msg "STF_SUITE: $STF_SUITE"
|
||||||
|
|
||||||
|
#
|
||||||
|
# No DISKS have been provided so a basic file or loopback based devices
|
||||||
|
# must be created for the test suite to use.
|
||||||
|
#
|
||||||
|
if [ -z "${DISKS}" ]; then
|
||||||
|
#
|
||||||
|
# Create sparse files for the test suite. These may be used
|
||||||
|
# directory or have loopback devices layered on them.
|
||||||
|
#
|
||||||
|
for TEST_FILE in ${FILES}; do
|
||||||
|
[ -f "$TEST_FILE" ] && fail "Failed file exists: ${TEST_FILE}"
|
||||||
|
truncate -s ${FILESIZE} ${TEST_FILE} ||
|
||||||
|
fail "Failed creating: ${TEST_FILE} ($?)"
|
||||||
|
DISKS="$DISKS$TEST_FILE "
|
||||||
|
done
|
||||||
|
|
||||||
|
#
|
||||||
|
# If requested setup loopback devices backed by the sparse files.
|
||||||
|
#
|
||||||
|
if [ $LOOPBACK -eq 1 ]; then
|
||||||
|
DISKS=""
|
||||||
|
check_loop_utils
|
||||||
|
|
||||||
|
for TEST_FILE in ${FILES}; do
|
||||||
|
TEST_LOOPBACK=$(${SUDO} ${LOSETUP} -f)
|
||||||
|
${SUDO} ${LOSETUP} ${TEST_LOOPBACK} ${TEST_FILE} ||
|
||||||
|
fail "Failed: ${TEST_FILE} -> ${TEST_LOOPBACK}"
|
||||||
|
LOOPBACKS="${LOOPBACKS}${TEST_LOOPBACK} "
|
||||||
|
DISKS="$DISKS$(basename $TEST_LOOPBACK) "
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
NUM_DISKS=$(echo ${DISKS} | $AWK '{print NF}')
|
||||||
|
[ $NUM_DISKS -lt 3 ] && fail "Not enough disks ($NUM_DISKS/3 minimum)"
|
||||||
|
|
||||||
|
#
|
||||||
|
# Disable SELinux until the ZFS Test Suite has been updated accordingly.
|
||||||
|
#
|
||||||
|
if [ -x ${SETENFORCE} ]; then
|
||||||
|
${SUDO} ${SETENFORCE} permissive &>/dev/null
|
||||||
|
fi
|
||||||
|
|
||||||
|
msg "FILEDIR: $FILEDIR"
|
||||||
|
msg "FILES: $FILES"
|
||||||
|
msg "LOOPBACKS: $LOOPBACKS"
|
||||||
|
msg "DISKS: $DISKS"
|
||||||
|
msg "NUM_DISKS: $NUM_DISKS"
|
||||||
|
msg "FILESIZE: $FILESIZE"
|
||||||
|
msg "Keep pool(s): $KEEP"
|
||||||
|
msg ""
|
||||||
|
|
||||||
|
export STF_TOOLS
|
||||||
|
export STF_SUITE
|
||||||
|
export DISKS
|
||||||
|
export KEEP
|
||||||
|
|
||||||
|
msg "${TEST_RUNNER} ${QUIET} -c ${RUNFILE} -i ${STF_SUITE}"
|
||||||
|
${TEST_RUNNER} ${QUIET} -c ${RUNFILE} -i ${STF_SUITE}
|
||||||
|
RESULT=$?
|
||||||
|
echo
|
||||||
|
|
||||||
|
exit ${RESULT}
|
1
tests/Makefile.am
Normal file
1
tests/Makefile.am
Normal file
@ -0,0 +1 @@
|
|||||||
|
SUBDIRS = runfiles test-runner zfs-tests
|
133
tests/README.md
Normal file
133
tests/README.md
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
# ZFS Test Suite README
|
||||||
|
|
||||||
|
1) Building and installing the ZFS Test Suite
|
||||||
|
|
||||||
|
The ZFS Test Suite runs under the test-runner framework. This framework
|
||||||
|
is built along side the standard ZFS utilities and is included as part of
|
||||||
|
zfs-test package. The zfs-test package can be built from source as follows:
|
||||||
|
|
||||||
|
$ ./configure
|
||||||
|
$ make pkg-utils
|
||||||
|
|
||||||
|
The resulting packages can be installed using the rpm or dpkg command as
|
||||||
|
appropriate for your distributions. Alternately, if you have installed
|
||||||
|
ZFS from a distributions repository (not from source) the zfs-test package
|
||||||
|
may be provided for your distribution.
|
||||||
|
|
||||||
|
- Installed from source
|
||||||
|
$ rpm -ivh ./zfs-test*.rpm, or
|
||||||
|
$ dpkg -i ./zfs-test*.deb,
|
||||||
|
|
||||||
|
- Installed from package repository
|
||||||
|
$ yum install zfs-test
|
||||||
|
$ apt-get install zfs-test
|
||||||
|
|
||||||
|
2) Running the ZFS Test Suite
|
||||||
|
|
||||||
|
The pre-requisites for running the ZFS Test Suite are:
|
||||||
|
|
||||||
|
* Three scratch disks
|
||||||
|
* Specify the disks you wish to use in the $DISKS variable, as a
|
||||||
|
space delimited list like this: DISKS='vdb vdc vdd'. By default
|
||||||
|
the zfs-tests.sh sciprt will construct three loopback devices to
|
||||||
|
be used for testing: DISKS='loop0 loop1 loop2'.
|
||||||
|
* A non-root user with a full set of basic privileges and the ability
|
||||||
|
to sudo(8) to root without a password to run the test.
|
||||||
|
* Specify any pools you wish to preserve as a space delimited list in
|
||||||
|
the $KEEP variable. All pools detected at the start of testing are
|
||||||
|
added automatically.
|
||||||
|
* The ZFS Test Suite will add users and groups to test machine to
|
||||||
|
verify functionality. Therefore it is strongly advised that a
|
||||||
|
dedicated test machine, which can be a VM, be used for testing.
|
||||||
|
|
||||||
|
Once the pre-requisites are satisfied simply run the zfs-tests.sh script:
|
||||||
|
|
||||||
|
$ /usr/share/zfs/zfs-tests.sh
|
||||||
|
|
||||||
|
Alternately, the zfs-tests.sh script can be run from the source tree to allow
|
||||||
|
developers to rapidly validate their work. In this mode the ZFS utilities and
|
||||||
|
modules from the source tree will be used (rather than those installed on the
|
||||||
|
system). In order to avoid certain types of failures you will need to ensure
|
||||||
|
the ZFS udev rules are installed. This can be done manually or by ensuring
|
||||||
|
some version of ZFS is installed on the system.
|
||||||
|
|
||||||
|
$ ./scripts/zfs-tests.sh
|
||||||
|
|
||||||
|
The following zfs-tests.sh options are supported:
|
||||||
|
|
||||||
|
-v Verbose zfs-tests.sh output When specified additional
|
||||||
|
information describing the test environment will be logged
|
||||||
|
prior to invoking test-runner. This includes the runfile
|
||||||
|
being used, the DISKS targeted, pools to keep, etc.
|
||||||
|
|
||||||
|
-q Quiet test-runner output. When specified it is passed to
|
||||||
|
test-runner(1) which causes output to be written to the
|
||||||
|
console only for tests that do not pass and the results
|
||||||
|
summary.
|
||||||
|
|
||||||
|
-x Remove all testpools, dm, lo, and files (unsafe). When
|
||||||
|
specified the script will attempt to remove any leftover
|
||||||
|
configuration from a previous test run. This includes
|
||||||
|
destroying any pools named testpool, unused DM devices,
|
||||||
|
and loopback devices backed by file-vdevs. This operation
|
||||||
|
can be DANGEROUS because it is possible that the script
|
||||||
|
will mistakenly remove a resource not related to the testing.
|
||||||
|
|
||||||
|
-k Disable cleanup after test failure. When specified the
|
||||||
|
zfs-tests.sh script will not perform any additional cleanup
|
||||||
|
when test-runner exists. This is useful when the results of
|
||||||
|
a specific test need to be preserved for further analysis.
|
||||||
|
|
||||||
|
-f Use sparse files directly instread of loopback devices for
|
||||||
|
the testing. When running in this mode certain tests will
|
||||||
|
be skipped which depend on real block devices.
|
||||||
|
|
||||||
|
-d DIR Create sparse files for vdevs in the DIR directory. By
|
||||||
|
default these files are created under /var/tmp/.
|
||||||
|
|
||||||
|
-s SIZE Use vdevs of SIZE (default: 2G)
|
||||||
|
|
||||||
|
-r RUNFILE Run tests in RUNFILE (default: linux.run)
|
||||||
|
|
||||||
|
|
||||||
|
The ZFS Test Suite allows the user to specify a subset of the tests via a
|
||||||
|
runfile. The format of the runfile is explained in test-runner(1), and
|
||||||
|
the files that zfs-tests.sh uses are available for reference under
|
||||||
|
/usr/share/zfs/runfiles. To specify a custom runfile, use the -r option:
|
||||||
|
|
||||||
|
$ /usr/share/zfs/zfs-tests.sh -r my_tests.run
|
||||||
|
|
||||||
|
3) Test results
|
||||||
|
|
||||||
|
While the ZFS Test Suite is running, one informational line is printed at the
|
||||||
|
end of each test, and a results summary is printed at the end of the run. The
|
||||||
|
results summary includes the location of the complete logs, which is logged in
|
||||||
|
the form /var/tmp/test_results/[ISO 8601 date]. A normal test run launched
|
||||||
|
with the `zfs-tests.sh` wrapper script will look something like this:
|
||||||
|
|
||||||
|
$ /usr/share/zfs/zfs-tests.sh -v -d /mnt
|
||||||
|
|
||||||
|
--- Configuration ---
|
||||||
|
Runfile: /usr/share/zfs/runfiles/linux.run
|
||||||
|
STF_TOOLS: /usr/share/zfs/test-runner
|
||||||
|
STF_SUITE: /usr/share/zfs/zfs-tests
|
||||||
|
FILEDIR: /mnt
|
||||||
|
FILES: /mnt/file-vdev0 /mnt/file-vdev1 /mnt/file-vdev2
|
||||||
|
LOOPBACKS: /dev/loop0 /dev/loop1 /dev/loop2
|
||||||
|
DISKS: loop0 loop1 loop2
|
||||||
|
NUM_DISKS: 3
|
||||||
|
FILESIZE: 2G
|
||||||
|
Keep pool(s): rpool
|
||||||
|
|
||||||
|
/usr/share/zfs/test-runner/bin/test-runner.py -c \
|
||||||
|
/usr/share/zfs/runfiles/linux.run -i /usr/share/zfs/zfs-tests
|
||||||
|
Test: .../tests/functional/acl/posix/setup (run as root) [00:00] [PASS]
|
||||||
|
...470 additional tests...
|
||||||
|
Test: .../tests/functional/zvol/zvol_cli/cleanup (run as root) [00:00] [PASS]
|
||||||
|
|
||||||
|
Results Summary
|
||||||
|
PASS 472
|
||||||
|
|
||||||
|
Running Time: 00:45:09
|
||||||
|
Percent passed: 100.0%
|
||||||
|
Log directory: /var/tmp/test_results/20160316T181651
|
2
tests/runfiles/Makefile.am
Normal file
2
tests/runfiles/Makefile.am
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
pkgdatadir = $(datadir)/@PACKAGE@/runfiles
|
||||||
|
dist_pkgdata_SCRIPTS = *.run
|
647
tests/runfiles/linux.run
Normal file
647
tests/runfiles/linux.run
Normal file
@ -0,0 +1,647 @@
|
|||||||
|
#
|
||||||
|
# This file and its contents are supplied under the terms of the
|
||||||
|
# Common Development and Distribution License ("CDDL"), version 1.0.
|
||||||
|
# You may only use this file in accordance with the terms of version
|
||||||
|
# 1.0 of the CDDL.
|
||||||
|
#
|
||||||
|
# A full copy of the text of the CDDL should have accompanied this
|
||||||
|
# source. A copy of the CDDL is also available via the Internet at
|
||||||
|
# http://www.illumos.org/license/CDDL.
|
||||||
|
#
|
||||||
|
|
||||||
|
[DEFAULT]
|
||||||
|
pre = setup
|
||||||
|
quiet = False
|
||||||
|
pre_user = root
|
||||||
|
user = root
|
||||||
|
timeout = 600
|
||||||
|
post_user = root
|
||||||
|
post = cleanup
|
||||||
|
outputdir = /var/tmp/test_results
|
||||||
|
|
||||||
|
# DISABLED:
|
||||||
|
# posix_001_pos - needs investigation
|
||||||
|
[tests/functional/acl/posix]
|
||||||
|
tests = ['posix_002_pos']
|
||||||
|
|
||||||
|
[tests/functional/atime]
|
||||||
|
tests = ['atime_001_pos', 'atime_002_neg']
|
||||||
|
|
||||||
|
# DISABLED:
|
||||||
|
# bootfs_006_pos - needs investigation
|
||||||
|
# bootfs_008_neg - needs investigation
|
||||||
|
[tests/functional/bootfs]
|
||||||
|
tests = ['bootfs_001_pos', 'bootfs_002_neg', 'bootfs_003_pos',
|
||||||
|
'bootfs_004_neg', 'bootfs_005_neg', 'bootfs_007_neg']
|
||||||
|
|
||||||
|
# DISABLED:
|
||||||
|
# cache_001_pos - needs investigation
|
||||||
|
# cache_010_neg - needs investigation
|
||||||
|
[tests/functional/cache]
|
||||||
|
tests = ['cache_002_pos', 'cache_003_pos', 'cache_004_neg',
|
||||||
|
'cache_005_neg', 'cache_006_pos', 'cache_007_neg', 'cache_008_neg',
|
||||||
|
'cache_009_pos', 'cache_011_pos']
|
||||||
|
|
||||||
|
# DISABLED: needs investigation
|
||||||
|
#[tests/functional/cachefile]
|
||||||
|
#tests = ['cachefile_001_pos', 'cachefile_002_pos', 'cachefile_003_pos',
|
||||||
|
# 'cachefile_004_pos']
|
||||||
|
#pre =
|
||||||
|
#post =
|
||||||
|
|
||||||
|
# DISABLED: needs investigation
|
||||||
|
# 'sensitive_none_lookup', 'sensitive_none_delete',
|
||||||
|
# 'sensitive_formd_lookup', 'sensitive_formd_delete',
|
||||||
|
# 'insensitive_none_lookup', 'insensitive_none_delete',
|
||||||
|
# 'insensitive_formd_lookup', 'insensitive_formd_delete',
|
||||||
|
# 'mixed_none_lookup', 'mixed_none_lookup_ci', 'mixed_none_delete',
|
||||||
|
# 'mixed_formd_lookup', 'mixed_formd_lookup_ci', 'mixed_formd_delete']
|
||||||
|
[tests/functional/casenorm]
|
||||||
|
tests = ['case_all_values', 'norm_all_values']
|
||||||
|
|
||||||
|
[tests/functional/clean_mirror]
|
||||||
|
tests = [ 'clean_mirror_001_pos', 'clean_mirror_002_pos',
|
||||||
|
'clean_mirror_003_pos', 'clean_mirror_004_pos']
|
||||||
|
|
||||||
|
[tests/functional/cli_root/zdb]
|
||||||
|
tests = ['zdb_001_neg']
|
||||||
|
pre =
|
||||||
|
post =
|
||||||
|
|
||||||
|
[tests/functional/cli_root/zfs]
|
||||||
|
tests = ['zfs_001_neg', 'zfs_002_pos', 'zfs_003_neg']
|
||||||
|
|
||||||
|
# DISABLED:
|
||||||
|
# zfs_clone_005_pos - busy unmount
|
||||||
|
# zfs_clone_010_pos - needs investigation
|
||||||
|
[tests/functional/cli_root/zfs_clone]
|
||||||
|
tests = ['zfs_clone_001_neg', 'zfs_clone_002_pos', 'zfs_clone_003_pos',
|
||||||
|
'zfs_clone_004_pos', 'zfs_clone_006_pos',
|
||||||
|
'zfs_clone_007_pos', 'zfs_clone_008_neg', 'zfs_clone_009_neg']
|
||||||
|
|
||||||
|
# DISABLED:
|
||||||
|
# zfs_copies_002_pos - needs investigation
|
||||||
|
# zfs_copies_003_pos - zpool on zvol
|
||||||
|
# zfs_copies_005_neg - nested pools
|
||||||
|
[tests/functional/cli_root/zfs_copies]
|
||||||
|
tests = ['zfs_copies_001_pos', 'zfs_copies_004_neg', 'zfs_copies_006_pos']
|
||||||
|
|
||||||
|
# DISABLED:
|
||||||
|
# zfs_create_006_pos - needs investigation
|
||||||
|
# zfs_create_003_pos - needs investigation
|
||||||
|
[tests/functional/cli_root/zfs_create]
|
||||||
|
tests = ['zfs_create_001_pos', 'zfs_create_002_pos',
|
||||||
|
'zfs_create_004_pos', 'zfs_create_005_pos',
|
||||||
|
'zfs_create_007_pos', 'zfs_create_008_neg', 'zfs_create_009_neg',
|
||||||
|
'zfs_create_010_neg', 'zfs_create_011_pos', 'zfs_create_012_pos',
|
||||||
|
'zfs_create_013_pos']
|
||||||
|
|
||||||
|
# DISABLED:
|
||||||
|
# zfs_destroy_001_pos - busy mountpoint behavior
|
||||||
|
# zfs_destroy_004_pos - busy mountpoint behavior
|
||||||
|
# zfs_destroy_005_neg - busy mountpoint behavior
|
||||||
|
# zfs_destroy_008_pos - busy mountpoint behavior
|
||||||
|
# zfs_destroy_009_pos - busy mountpoint behavior
|
||||||
|
# zfs_destroy_010_pos - busy mountpoint behavior
|
||||||
|
# zfs_destroy_011_pos - busy mountpoint behavior
|
||||||
|
# zfs_destroy_012_pos - busy mountpoint behavior
|
||||||
|
# zfs_destroy_013_neg - busy mountpoint behavior
|
||||||
|
[tests/functional/cli_root/zfs_destroy]
|
||||||
|
tests = ['zfs_destroy_002_pos', 'zfs_destroy_003_pos', 'zfs_destroy_006_neg',
|
||||||
|
'zfs_destroy_007_neg', 'zfs_destroy_014_pos', 'zfs_destroy_015_pos',
|
||||||
|
'zfs_destroy_016_pos']
|
||||||
|
|
||||||
|
# DISABLED:
|
||||||
|
# zfs_get_004_pos - nested pools
|
||||||
|
# zfs_get_006_neg - needs investigation
|
||||||
|
[tests/functional/cli_root/zfs_get]
|
||||||
|
tests = ['zfs_get_001_pos', 'zfs_get_002_pos', 'zfs_get_003_pos',
|
||||||
|
'zfs_get_005_neg', 'zfs_get_007_neg', 'zfs_get_008_pos',
|
||||||
|
'zfs_get_009_pos', 'zfs_get_010_neg']
|
||||||
|
|
||||||
|
[tests/functional/cli_root/zfs_inherit]
|
||||||
|
tests = ['zfs_inherit_001_neg', 'zfs_inherit_002_neg', 'zfs_inherit_003_pos']
|
||||||
|
|
||||||
|
# DISABLED:
|
||||||
|
# zfs_mount_005_pos - needs investigation
|
||||||
|
# zfs_mount_006_pos - needs investigation
|
||||||
|
# zfs_mount_007_pos - needs investigation
|
||||||
|
# zfs_mount_009_neg - needs investigation
|
||||||
|
# zfs_mount_010_neg - needs investigation
|
||||||
|
# zfs_mount_all_001_pos - needs investigation
|
||||||
|
[tests/functional/cli_root/zfs_mount]
|
||||||
|
tests = ['zfs_mount_001_pos', 'zfs_mount_002_pos', 'zfs_mount_003_pos',
|
||||||
|
'zfs_mount_004_pos', 'zfs_mount_008_pos',
|
||||||
|
'zfs_mount_011_neg']
|
||||||
|
|
||||||
|
[tests/functional/cli_root/zfs_promote]
|
||||||
|
tests = ['zfs_promote_001_pos', 'zfs_promote_002_pos', 'zfs_promote_003_pos',
|
||||||
|
'zfs_promote_004_pos', 'zfs_promote_005_pos', 'zfs_promote_006_neg',
|
||||||
|
'zfs_promote_007_neg', 'zfs_promote_008_pos']
|
||||||
|
|
||||||
|
# DISABLED:
|
||||||
|
# zfs_written_property_001_pos - sync(1) does not force txg under Linux
|
||||||
|
[tests/functional/cli_root/zfs_property]
|
||||||
|
tests = []
|
||||||
|
|
||||||
|
# DISABLED:
|
||||||
|
# zfs_receive_003_pos - needs investigation
|
||||||
|
# zfs_receive_010_pos - needs investigation
|
||||||
|
# zfs_receive_011_pos - needs investigation
|
||||||
|
# zfs_receive_012_pos - needs investigation
|
||||||
|
[tests/functional/cli_root/zfs_receive]
|
||||||
|
tests = ['zfs_receive_001_pos', 'zfs_receive_002_pos', 'zfs_receive_005_neg',
|
||||||
|
'zfs_receive_006_pos', 'zfs_receive_007_neg', 'zfs_receive_008_pos',
|
||||||
|
'zfs_receive_009_neg']
|
||||||
|
|
||||||
|
# DISABLED:
|
||||||
|
# zfs_rename_002_pos - needs investigation
|
||||||
|
# zfs_rename_005_neg - nested pools
|
||||||
|
# zfs_rename_006_pos - needs investigation
|
||||||
|
# zfs_rename_007_pos - needs investigation
|
||||||
|
[tests/functional/cli_root/zfs_rename]
|
||||||
|
tests = ['zfs_rename_001_pos', 'zfs_rename_003_pos',
|
||||||
|
'zfs_rename_004_neg', 'zfs_rename_008_pos', 'zfs_rename_009_neg',
|
||||||
|
'zfs_rename_010_neg', 'zfs_rename_011_pos', 'zfs_rename_012_neg',
|
||||||
|
'zfs_rename_013_pos']
|
||||||
|
|
||||||
|
[tests/functional/cli_root/zfs_reservation]
|
||||||
|
tests = ['zfs_reservation_001_pos', 'zfs_reservation_002_pos']
|
||||||
|
|
||||||
|
# DISABLED:
|
||||||
|
# zfs_rollback_001_pos - busy mountpoint behavior
|
||||||
|
# zfs_rollback_002_pos - busy mountpoint behavior
|
||||||
|
[tests/functional/cli_root/zfs_rollback]
|
||||||
|
tests = ['zfs_rollback_003_neg', 'zfs_rollback_004_neg']
|
||||||
|
|
||||||
|
# DISABLED:
|
||||||
|
# zfs_send_007_pos - needs investigation
|
||||||
|
[tests/functional/cli_root/zfs_send]
|
||||||
|
tests = ['zfs_send_001_pos', 'zfs_send_002_pos', 'zfs_send_003_pos',
|
||||||
|
'zfs_send_004_neg', 'zfs_send_005_pos', 'zfs_send_006_pos']
|
||||||
|
|
||||||
|
# DISABLED:
|
||||||
|
# mountpoint_003_pos - needs investigation
|
||||||
|
# ro_props_001_pos - needs investigation
|
||||||
|
# onoffs_001_pos - needs investigation
|
||||||
|
# property_alias_001_pos - needs investigation
|
||||||
|
# readonly_001_pos - needs investigation
|
||||||
|
# user_property_002_pos - needs investigation
|
||||||
|
[tests/functional/cli_root/zfs_set]
|
||||||
|
tests = ['cache_001_pos', 'cache_002_neg', 'canmount_001_pos',
|
||||||
|
'canmount_002_pos', 'canmount_003_pos', 'canmount_004_pos',
|
||||||
|
'checksum_001_pos', 'compression_001_pos', 'mountpoint_001_pos',
|
||||||
|
'mountpoint_002_pos', 'reservation_001_neg',
|
||||||
|
'share_mount_001_neg', 'snapdir_001_pos',
|
||||||
|
'user_property_001_pos', 'user_property_003_neg',
|
||||||
|
'user_property_004_pos', 'version_001_neg', 'zfs_set_001_neg',
|
||||||
|
'zfs_set_002_neg', 'zfs_set_003_neg']
|
||||||
|
|
||||||
|
# DISABLED: Tests need to be updated for Linux share behavior
|
||||||
|
#[tests/functional/cli_root/zfs_share]
|
||||||
|
#tests = ['zfs_share_001_pos', 'zfs_share_002_pos', 'zfs_share_003_pos',
|
||||||
|
# 'zfs_share_004_pos', 'zfs_share_005_pos', 'zfs_share_006_pos',
|
||||||
|
# 'zfs_share_007_neg', 'zfs_share_008_neg', 'zfs_share_009_neg',
|
||||||
|
# 'zfs_share_010_neg', 'zfs_share_011_pos']
|
||||||
|
|
||||||
|
# DISABLED:
|
||||||
|
# zfs_snapshot_008_neg - nested pools
|
||||||
|
[tests/functional/cli_root/zfs_snapshot]
|
||||||
|
tests = ['zfs_snapshot_001_neg', 'zfs_snapshot_002_neg',
|
||||||
|
'zfs_snapshot_003_neg', 'zfs_snapshot_004_neg', 'zfs_snapshot_005_neg',
|
||||||
|
'zfs_snapshot_006_pos', 'zfs_snapshot_007_neg', 'zfs_snapshot_009_pos']
|
||||||
|
|
||||||
|
# DISABLED:
|
||||||
|
# zfs_unmount_005_pos - needs investigation
|
||||||
|
# zfs_unmount_009_pos - needs investigation
|
||||||
|
# zfs_unmount_all_001_pos - needs investigation
|
||||||
|
[tests/functional/cli_root/zfs_unmount]
|
||||||
|
tests = ['zfs_unmount_001_pos', 'zfs_unmount_002_pos', 'zfs_unmount_003_pos',
|
||||||
|
'zfs_unmount_004_pos', 'zfs_unmount_006_pos',
|
||||||
|
'zfs_unmount_007_neg', 'zfs_unmount_008_neg']
|
||||||
|
|
||||||
|
# DISABLED: Tests need to be updated for Linux unshare behavior
|
||||||
|
#[tests/functional/cli_root/zfs_unshare]
|
||||||
|
#tests = ['zfs_unshare_001_pos', 'zfs_unshare_002_pos', 'zfs_unshare_003_pos',
|
||||||
|
# 'zfs_unshare_004_neg', 'zfs_unshare_005_neg']
|
||||||
|
|
||||||
|
[tests/functional/cli_root/zfs_upgrade]
|
||||||
|
tests = ['zfs_upgrade_001_pos', 'zfs_upgrade_002_pos', 'zfs_upgrade_003_pos',
|
||||||
|
'zfs_upgrade_004_pos', 'zfs_upgrade_005_pos', 'zfs_upgrade_006_neg',
|
||||||
|
'zfs_upgrade_007_neg']
|
||||||
|
|
||||||
|
[tests/functional/cli_root/zpool]
|
||||||
|
tests = ['zpool_001_neg', 'zpool_002_pos', 'zpool_003_pos']
|
||||||
|
|
||||||
|
# DISABLED:
|
||||||
|
# zpool_add_005_pos - no 'dumpadm' command.
|
||||||
|
# zpool_add_006_pos - nested pools
|
||||||
|
[tests/functional/cli_root/zpool_add]
|
||||||
|
tests = ['zpool_add_001_pos', 'zpool_add_002_pos', 'zpool_add_003_pos',
|
||||||
|
'zpool_add_004_pos',
|
||||||
|
'zpool_add_007_neg', 'zpool_add_008_neg', 'zpool_add_009_neg']
|
||||||
|
|
||||||
|
[tests/functional/cli_root/zpool_attach]
|
||||||
|
tests = ['zpool_attach_001_neg']
|
||||||
|
|
||||||
|
[tests/functional/cli_root/zpool_clear]
|
||||||
|
tests = ['zpool_clear_001_pos', 'zpool_clear_002_neg', 'zpool_clear_003_neg']
|
||||||
|
|
||||||
|
# DISABLED:
|
||||||
|
# zpool_create_001_pos - needs investigation
|
||||||
|
# zpool_create_002_pos - needs investigation
|
||||||
|
# zpool_create_004_pos - needs investigation
|
||||||
|
# zpool_create_006_pos - nested pools
|
||||||
|
# zpool_create_008_pos - uses VTOC labels (?) and 'overlapping slices'
|
||||||
|
# zpool_create_011_neg - tries to access /etc/vfstab etc
|
||||||
|
# zpool_create_012_neg - swap devices
|
||||||
|
# zpool_create_014_neg - swap devices
|
||||||
|
# zpool_create_015_neg - swap devices
|
||||||
|
# zpool_create_016_pos - no dumadm command.
|
||||||
|
# zpool_create_020_pos - needs investigation
|
||||||
|
[tests/functional/cli_root/zpool_create]
|
||||||
|
tests = [
|
||||||
|
'zpool_create_003_pos', 'zpool_create_005_pos', 'zpool_create_007_neg',
|
||||||
|
'zpool_create_009_neg', 'zpool_create_010_neg', 'zpool_create_017_neg',
|
||||||
|
'zpool_create_018_pos', 'zpool_create_019_pos',
|
||||||
|
'zpool_create_021_pos', 'zpool_create_022_pos', 'zpool_create_023_neg',
|
||||||
|
'zpool_create_features_001_pos', 'zpool_create_features_002_pos',
|
||||||
|
'zpool_create_features_003_pos', 'zpool_create_features_004_neg']
|
||||||
|
|
||||||
|
# DISABLED:
|
||||||
|
# zpool_destroy_001_pos - failure should be investigated
|
||||||
|
# zpool_destroy_002_pos - update for Linux fource unmount behavior
|
||||||
|
[tests/functional/cli_root/zpool_destroy]
|
||||||
|
tests = [
|
||||||
|
'zpool_destroy_003_neg']
|
||||||
|
pre =
|
||||||
|
post =
|
||||||
|
|
||||||
|
[tests/functional/cli_root/zpool_detach]
|
||||||
|
tests = ['zpool_detach_001_neg']
|
||||||
|
|
||||||
|
# DISABLED: Requires full FMA support in ZED
|
||||||
|
#[tests/functional/cli_root/zpool_expand]
|
||||||
|
#tests = ['zpool_expand_001_pos', 'zpool_expand_002_pos',
|
||||||
|
# 'zpool_expand_003_neg']
|
||||||
|
|
||||||
|
# DISABLED:
|
||||||
|
# zpool_export_004_pos - nested pools
|
||||||
|
[tests/functional/cli_root/zpool_export]
|
||||||
|
tests = ['zpool_export_001_pos', 'zpool_export_002_pos',
|
||||||
|
'zpool_export_003_neg']
|
||||||
|
|
||||||
|
[tests/functional/cli_root/zpool_get]
|
||||||
|
tests = ['zpool_get_001_pos', 'zpool_get_002_pos', 'zpool_get_003_pos',
|
||||||
|
'zpool_get_004_neg']
|
||||||
|
|
||||||
|
[tests/functional/cli_root/zpool_history]
|
||||||
|
tests = ['zpool_history_001_neg', 'zpool_history_002_pos']
|
||||||
|
|
||||||
|
# DISABLED:
|
||||||
|
# zpool_import_012_pos - sharenfs issue
|
||||||
|
# zpool_import_all_001_pos - partition issue
|
||||||
|
# zpool_import_features_001_pos - zhack issue
|
||||||
|
# zpool_import_features_002_neg - zhack issue
|
||||||
|
# zpool_import_features_003_pos - zhack issue
|
||||||
|
# zpool_import_missing_001_pos - zhack_issue
|
||||||
|
# zpool_import_missing_002_pos - zhack_issue
|
||||||
|
# zpool_import_missing_003_pos - zhack_issue
|
||||||
|
# zpool_import_rename_001_pos - hack issue
|
||||||
|
[tests/functional/cli_root/zpool_import]
|
||||||
|
tests = ['zpool_import_001_pos', 'zpool_import_002_pos',
|
||||||
|
'zpool_import_003_pos', 'zpool_import_004_pos', 'zpool_import_005_pos',
|
||||||
|
'zpool_import_006_pos', 'zpool_import_007_pos', 'zpool_import_008_pos',
|
||||||
|
'zpool_import_009_neg', 'zpool_import_010_pos', 'zpool_import_011_neg',
|
||||||
|
'zpool_import_013_neg']
|
||||||
|
|
||||||
|
[tests/functional/cli_root/zpool_offline]
|
||||||
|
tests = ['zpool_offline_001_pos', 'zpool_offline_002_neg']
|
||||||
|
|
||||||
|
[tests/functional/cli_root/zpool_online]
|
||||||
|
tests = ['zpool_online_001_pos', 'zpool_online_002_neg']
|
||||||
|
|
||||||
|
# DISABLED:
|
||||||
|
# zpool_remove_003_pos - needs investigation
|
||||||
|
[tests/functional/cli_root/zpool_remove]
|
||||||
|
tests = ['zpool_remove_001_neg', 'zpool_remove_002_pos']
|
||||||
|
|
||||||
|
[tests/functional/cli_root/zpool_replace]
|
||||||
|
tests = ['zpool_replace_001_neg']
|
||||||
|
|
||||||
|
# DISABLED:
|
||||||
|
# zpool_scrub_004_pos - needs investigation
|
||||||
|
# zpool_scrub_005_pos - needs investigation
|
||||||
|
[tests/functional/cli_root/zpool_scrub]
|
||||||
|
tests = ['zpool_scrub_001_neg', 'zpool_scrub_002_pos', 'zpool_scrub_003_pos']
|
||||||
|
|
||||||
|
[tests/functional/cli_root/zpool_set]
|
||||||
|
tests = ['zpool_set_001_pos', 'zpool_set_002_neg', 'zpool_set_003_neg']
|
||||||
|
pre =
|
||||||
|
post =
|
||||||
|
|
||||||
|
[tests/functional/cli_root/zpool_status]
|
||||||
|
tests = ['zpool_status_001_pos', 'zpool_status_002_pos']
|
||||||
|
|
||||||
|
# DISABLED: ENOSPC failure
|
||||||
|
#[tests/functional/cli_root/zpool_upgrade]
|
||||||
|
#tests = ['zpool_upgrade_001_pos', 'zpool_upgrade_002_pos',
|
||||||
|
# 'zpool_upgrade_003_pos', 'zpool_upgrade_004_pos', 'zpool_upgrade_005_neg',
|
||||||
|
# 'zpool_upgrade_006_neg', 'zpool_upgrade_007_pos', 'zpool_upgrade_008_pos',
|
||||||
|
# 'zpool_upgrade_009_neg']
|
||||||
|
|
||||||
|
# DISABLED: nested pools
|
||||||
|
#[tests/functional/cli_user/misc]
|
||||||
|
#tests = ['zdb_001_neg', 'zfs_001_neg', 'zfs_allow_001_neg',
|
||||||
|
# 'zfs_clone_001_neg', 'zfs_create_001_neg', 'zfs_destroy_001_neg',
|
||||||
|
# 'zfs_get_001_neg', 'zfs_inherit_001_neg', 'zfs_mount_001_neg',
|
||||||
|
# 'zfs_promote_001_neg', 'zfs_receive_001_neg', 'zfs_rename_001_neg',
|
||||||
|
# 'zfs_rollback_001_neg', 'zfs_send_001_neg', 'zfs_set_001_neg',
|
||||||
|
# 'zfs_share_001_neg', 'zfs_snapshot_001_neg', 'zfs_unallow_001_neg',
|
||||||
|
# 'zfs_unmount_001_neg', 'zfs_unshare_001_neg', 'zfs_upgrade_001_neg',
|
||||||
|
# 'zpool_001_neg', 'zpool_add_001_neg', 'zpool_attach_001_neg',
|
||||||
|
# 'zpool_clear_001_neg', 'zpool_create_001_neg', 'zpool_destroy_001_neg',
|
||||||
|
# 'zpool_detach_001_neg', 'zpool_export_001_neg', 'zpool_get_001_neg',
|
||||||
|
# 'zpool_history_001_neg', 'zpool_import_001_neg', 'zpool_import_002_neg',
|
||||||
|
# 'zpool_offline_001_neg', 'zpool_online_001_neg', 'zpool_remove_001_neg',
|
||||||
|
# 'zpool_replace_001_neg', 'zpool_scrub_001_neg', 'zpool_set_001_neg',
|
||||||
|
# 'zpool_status_001_neg', 'zpool_upgrade_001_neg']
|
||||||
|
#user = zfs-tests
|
||||||
|
|
||||||
|
[tests/functional/cli_user/zfs_list]
|
||||||
|
tests = ['zfs_list_001_pos', 'zfs_list_002_pos', 'zfs_list_003_pos',
|
||||||
|
'zfs_list_004_neg', 'zfs_list_007_pos', 'zfs_list_008_neg']
|
||||||
|
|
||||||
|
[tests/functional/cli_user/zpool_iostat]
|
||||||
|
tests = ['zpool_iostat_001_neg', 'zpool_iostat_002_pos',
|
||||||
|
'zpool_iostat_003_neg']
|
||||||
|
|
||||||
|
[tests/functional/cli_user/zpool_list]
|
||||||
|
tests = ['zpool_list_001_pos', 'zpool_list_002_neg']
|
||||||
|
|
||||||
|
[tests/functional/compression]
|
||||||
|
tests = ['compress_001_pos', 'compress_002_pos', 'compress_003_pos',
|
||||||
|
'compress_004_pos']
|
||||||
|
|
||||||
|
[tests/functional/ctime]
|
||||||
|
tests = ['ctime_001_pos' ]
|
||||||
|
|
||||||
|
# DISABLED: Linux does not yet support delegations.
|
||||||
|
#[tests/functional/delegate]
|
||||||
|
#tests = ['zfs_allow_001_pos', 'zfs_allow_002_pos',
|
||||||
|
# 'zfs_allow_004_pos', 'zfs_allow_005_pos', 'zfs_allow_006_pos',
|
||||||
|
# 'zfs_allow_007_pos', 'zfs_allow_008_pos', 'zfs_allow_009_neg',
|
||||||
|
# 'zfs_allow_010_pos', 'zfs_allow_011_neg', 'zfs_allow_012_neg',
|
||||||
|
# 'zfs_unallow_001_pos', 'zfs_unallow_002_pos', 'zfs_unallow_003_pos',
|
||||||
|
# 'zfs_unallow_004_pos', 'zfs_unallow_005_pos', 'zfs_unallow_006_pos',
|
||||||
|
# 'zfs_unallow_007_neg', 'zfs_unallow_008_neg']
|
||||||
|
|
||||||
|
# DISABLED:
|
||||||
|
# devices_001_pos - needs investigation
|
||||||
|
# devices_002_neg - needs investigation
|
||||||
|
[tests/functional/devices]
|
||||||
|
tests = ['devices_003_pos']
|
||||||
|
|
||||||
|
# DISABLED:
|
||||||
|
# exec_002_neg - needs investigation
|
||||||
|
[tests/functional/exec]
|
||||||
|
tests = ['exec_001_pos']
|
||||||
|
|
||||||
|
[tests/functional/features/async_destroy]
|
||||||
|
tests = ['async_destroy_001_pos']
|
||||||
|
|
||||||
|
# DISABLED: needs investigation
|
||||||
|
#[tests/functional/grow_pool]
|
||||||
|
#tests = ['grow_pool_001_pos']
|
||||||
|
#pre =
|
||||||
|
#post =
|
||||||
|
|
||||||
|
# DISABLED: needs investigation
|
||||||
|
#[tests/functional/grow_replicas]
|
||||||
|
#tests = ['grow_replicas_001_pos']
|
||||||
|
#pre =
|
||||||
|
#post =
|
||||||
|
|
||||||
|
# DISABLED:
|
||||||
|
# history_001_pos - export commands missing from history
|
||||||
|
# history_003_pos - nested pool
|
||||||
|
# history_006_neg - needs investigation
|
||||||
|
# history_007_pos - needs investigation
|
||||||
|
# history_008_pos - needs investigation
|
||||||
|
# history_010_pos - needs investigation
|
||||||
|
[tests/functional/history]
|
||||||
|
tests = ['history_002_pos', 'history_004_pos', 'history_005_neg',
|
||||||
|
'history_009_pos']
|
||||||
|
|
||||||
|
[tests/functional/inheritance]
|
||||||
|
tests = ['inherit_001_pos']
|
||||||
|
pre =
|
||||||
|
|
||||||
|
# DISABLED:
|
||||||
|
# inuse_001_pos, inuse_007_pos - no dumpadm command
|
||||||
|
# inuse_005_pos - partition issue
|
||||||
|
# inuse_006_pos - partition issue
|
||||||
|
# inuse_008_pos - partition issue
|
||||||
|
# inuse_009_pos - partition issue
|
||||||
|
[tests/functional/inuse]
|
||||||
|
tests = ['inuse_004_pos']
|
||||||
|
post =
|
||||||
|
|
||||||
|
# DISABLED: needs investigation
|
||||||
|
#[tests/functional/large_files]
|
||||||
|
#tests = ['large_files_001_pos']
|
||||||
|
|
||||||
|
# DISABLED: needs investigation
|
||||||
|
#[tests/functional/largest_pool]
|
||||||
|
#tests = ['largest_pool_001_pos']
|
||||||
|
#pre =
|
||||||
|
#post =
|
||||||
|
|
||||||
|
# DISABLED: needs investigation
|
||||||
|
#[tests/functional/link_count]
|
||||||
|
#tests = ['link_count_001']
|
||||||
|
|
||||||
|
[tests/functional/migration]
|
||||||
|
tests = ['migration_001_pos', 'migration_002_pos', 'migration_003_pos',
|
||||||
|
'migration_004_pos', 'migration_005_pos', 'migration_006_pos',
|
||||||
|
'migration_007_pos', 'migration_008_pos', 'migration_009_pos',
|
||||||
|
'migration_010_pos', 'migration_011_pos', 'migration_012_pos']
|
||||||
|
|
||||||
|
# DISABLED:
|
||||||
|
# mmap_write_001_pos: needs investigation
|
||||||
|
[tests/functional/mmap]
|
||||||
|
tests = ['mmap_read_001_pos']
|
||||||
|
|
||||||
|
# DISABLED:
|
||||||
|
# umountall_001 - Doesn't make sence in Linux - no umountall command.
|
||||||
|
[tests/functional/mount]
|
||||||
|
tests = ['umount_001']
|
||||||
|
|
||||||
|
[tests/functional/mv_files]
|
||||||
|
tests = ['mv_files_001_pos', 'mv_files_002_pos']
|
||||||
|
|
||||||
|
[tests/functional/nestedfs]
|
||||||
|
tests = ['nestedfs_001_pos']
|
||||||
|
|
||||||
|
[tests/functional/no_space]
|
||||||
|
tests = ['enospc_001_pos']
|
||||||
|
|
||||||
|
# DISABLED: needs investigation (CentOS 7 only)
|
||||||
|
#[tests/functional/nopwrite]
|
||||||
|
#tests = ['nopwrite_copies', 'nopwrite_mtime', 'nopwrite_negative',
|
||||||
|
# 'nopwrite_promoted_clone', 'nopwrite_recsize', 'nopwrite_sync',
|
||||||
|
# 'nopwrite_volume', 'nopwrite_varying_compression']
|
||||||
|
|
||||||
|
# DISABLED: needs investigation
|
||||||
|
#[tests/functional/online_offline]
|
||||||
|
#tests = ['online_offline_001_pos', 'online_offline_002_neg',
|
||||||
|
# 'online_offline_003_neg']
|
||||||
|
|
||||||
|
[tests/functional/pool_names]
|
||||||
|
tests = ['pool_names_001_pos', 'pool_names_002_neg']
|
||||||
|
pre =
|
||||||
|
post =
|
||||||
|
|
||||||
|
[tests/functional/poolversion]
|
||||||
|
tests = ['poolversion_001_pos', 'poolversion_002_pos']
|
||||||
|
|
||||||
|
# DISABLED: Doesn't make sense on Linux - no pfexec command or 'RBAC profile'
|
||||||
|
#[tests/functional/privilege]
|
||||||
|
#tests = ['privilege_001_pos', 'privilege_002_pos']
|
||||||
|
|
||||||
|
# DISABLED:
|
||||||
|
# quota_002_pos - size is less than current used or reserved space
|
||||||
|
# quota_004_pos - size is less than current used or reserved space
|
||||||
|
# quota_005_pos - size is less than current used or reserved space
|
||||||
|
[tests/functional/quota]
|
||||||
|
tests = ['quota_001_pos', 'quota_003_pos', 'quota_006_neg']
|
||||||
|
|
||||||
|
[tests/functional/redundancy]
|
||||||
|
tests = ['redundancy_001_pos', 'redundancy_002_pos', 'redundancy_003_pos']
|
||||||
|
|
||||||
|
# DISABLED:
|
||||||
|
# refquota_002_pos - size is less than current used or reserved space
|
||||||
|
# refquota_004_pos - needs investigation
|
||||||
|
[tests/functional/refquota]
|
||||||
|
tests = ['refquota_001_pos', 'refquota_003_pos',
|
||||||
|
'refquota_005_pos', 'refquota_006_neg']
|
||||||
|
|
||||||
|
# DISABLED:
|
||||||
|
# refreserv_004_pos - needs investigation
|
||||||
|
[tests/functional/refreserv]
|
||||||
|
tests = ['refreserv_001_pos', 'refreserv_002_pos', 'refreserv_003_pos',
|
||||||
|
'refreserv_005_pos']
|
||||||
|
|
||||||
|
# DISABLED: nested pool
|
||||||
|
#[tests/functional/rename_dirs]
|
||||||
|
#tests = ['rename_dirs_001_pos']
|
||||||
|
|
||||||
|
# DISABLED: nested pool
|
||||||
|
#[tests/functional/replacement]
|
||||||
|
#tests = ['replacement_001_pos', 'replacement_002_pos']
|
||||||
|
|
||||||
|
# DISABLED:
|
||||||
|
# reservation_012_pos - needs investigation
|
||||||
|
# reservation_015_pos - needs investigation
|
||||||
|
# reservation_016_pos - needs investigation
|
||||||
|
[tests/functional/reservation]
|
||||||
|
tests = ['reservation_001_pos', 'reservation_002_pos', 'reservation_003_pos',
|
||||||
|
'reservation_004_pos', 'reservation_005_pos', 'reservation_006_pos',
|
||||||
|
'reservation_007_pos', 'reservation_008_pos', 'reservation_009_pos',
|
||||||
|
'reservation_010_pos', 'reservation_011_pos',
|
||||||
|
'reservation_013_pos', 'reservation_014_pos',
|
||||||
|
'reservation_017_pos', 'reservation_018_pos']
|
||||||
|
|
||||||
|
# DISABLED: Root pools must be handled differently under Linux
|
||||||
|
#[tests/functional/rootpool]
|
||||||
|
#tests = ['rootpool_002_neg', 'rootpool_003_neg', 'rootpool_007_neg']
|
||||||
|
|
||||||
|
# DISABLED: Hangs on I/O for unclear reason.
|
||||||
|
#[tests/functional/rsend]
|
||||||
|
#tests = ['rsend_002_pos', 'rsend_003_pos', 'rsend_004_pos',
|
||||||
|
# 'rsend_005_pos', 'rsend_006_pos', 'rsend_007_pos', 'rsend_008_pos',
|
||||||
|
# 'rsend_009_pos', 'rsend_010_pos', 'rsend_011_pos', 'rsend_012_pos',
|
||||||
|
# 'rsend_013_pos']
|
||||||
|
|
||||||
|
[tests/functional/scrub_mirror]
|
||||||
|
tests = ['scrub_mirror_001_pos', 'scrub_mirror_002_pos',
|
||||||
|
'scrub_mirror_003_pos', 'scrub_mirror_004_pos']
|
||||||
|
|
||||||
|
# DISABLED: Scripts need to be updated.
|
||||||
|
# slog_012_neg - needs investigation
|
||||||
|
# slog_013_pos - Linux doesn't have a 'lofiadm' command.
|
||||||
|
# slog_014_pos - needs investigation
|
||||||
|
[tests/functional/slog]
|
||||||
|
tests = ['slog_001_pos', 'slog_002_pos', 'slog_003_pos', 'slog_004_pos',
|
||||||
|
'slog_005_pos', 'slog_006_pos', 'slog_007_pos', 'slog_008_neg',
|
||||||
|
'slog_009_neg', 'slog_010_neg', 'slog_011_neg']
|
||||||
|
|
||||||
|
# DISABLED:
|
||||||
|
# rollback_003_pos - Hangs in unmount and spins.
|
||||||
|
# snapshot_013_pos - Hangs on I/O for unclear reason.
|
||||||
|
# snapshot_016_pos - .zfs mv/rmdir/mkdir disabled by default.
|
||||||
|
#[tests/functional/snapshot]
|
||||||
|
#tests = ['clone_001_pos', 'rollback_001_pos', 'rollback_002_pos',
|
||||||
|
# 'snapshot_001_pos', 'snapshot_002_pos',
|
||||||
|
# 'snapshot_003_pos', 'snapshot_004_pos', 'snapshot_005_pos',
|
||||||
|
# 'snapshot_006_pos', 'snapshot_007_pos', 'snapshot_008_pos',
|
||||||
|
# 'snapshot_009_pos', 'snapshot_010_pos', 'snapshot_011_pos',
|
||||||
|
# 'snapshot_012_pos', 'snapshot_014_pos',
|
||||||
|
# 'snapshot_015_pos', 'snapshot_017_pos']
|
||||||
|
[tests/functional/snapused]
|
||||||
|
tests = ['snapused_001_pos', 'snapused_002_pos', 'snapused_003_pos',
|
||||||
|
'snapused_004_pos', 'snapused_005_pos']
|
||||||
|
|
||||||
|
[tests/functional/sparse]
|
||||||
|
tests = ['sparse_001_pos']
|
||||||
|
|
||||||
|
# DISABLED: needs investigation
|
||||||
|
#[tests/functional/threadsappend]
|
||||||
|
#tests = ['threadsappend_001_pos']
|
||||||
|
|
||||||
|
[tests/functional/truncate]
|
||||||
|
tests = ['truncate_001_pos', 'truncate_002_pos']
|
||||||
|
|
||||||
|
# DISABLED:
|
||||||
|
# groupspace_001_pos
|
||||||
|
# groupspace_002_pos
|
||||||
|
# userquota_001_pos
|
||||||
|
# userquota_004_pos
|
||||||
|
# userquota_007_pos
|
||||||
|
# userquota_010_pos
|
||||||
|
# userspace_001_pos
|
||||||
|
# userspace_002_pos
|
||||||
|
[tests/functional/userquota]
|
||||||
|
tests = [
|
||||||
|
'userquota_002_pos', 'userquota_003_pos',
|
||||||
|
'userquota_005_neg', 'userquota_006_pos',
|
||||||
|
'userquota_008_pos', 'userquota_009_pos',
|
||||||
|
'userquota_011_pos', 'userquota_012_neg']
|
||||||
|
|
||||||
|
# DISABLED:
|
||||||
|
# write_dirs_002_pos - needs investigation
|
||||||
|
[tests/functional/write_dirs]
|
||||||
|
tests = ['write_dirs_001_pos']
|
||||||
|
|
||||||
|
# DISABLED: No 'runat' command, replace the Linux equivilant and add xattrtest
|
||||||
|
#[tests/functional/xattr]
|
||||||
|
#tests = ['xattr_001_pos', 'xattr_002_neg', 'xattr_003_neg', 'xattr_004_pos',
|
||||||
|
# 'xattr_005_pos', 'xattr_006_pos', 'xattr_007_neg', 'xattr_008_pos',
|
||||||
|
# 'xattr_009_neg', 'xattr_010_neg', 'xattr_011_pos', 'xattr_012_pos',
|
||||||
|
# 'xattr_013_pos']
|
||||||
|
|
||||||
|
[tests/functional/zvol/zvol_ENOSPC]
|
||||||
|
tests = ['zvol_ENOSPC_001_pos']
|
||||||
|
|
||||||
|
[tests/functional/zvol/zvol_cli]
|
||||||
|
tests = ['zvol_cli_001_pos', 'zvol_cli_002_pos', 'zvol_cli_003_neg']
|
||||||
|
|
||||||
|
# DISABLED: requires dumpadm
|
||||||
|
#[tests/functional/zvol/zvol_misc]
|
||||||
|
#tests = ['zvol_misc_001_neg', 'zvol_misc_002_pos', 'zvol_misc_003_neg',
|
||||||
|
# 'zvol_misc_004_pos', 'zvol_misc_005_neg', 'zvol_misc_006_pos']
|
||||||
|
|
||||||
|
# DISABLED: requires updated for Linux
|
||||||
|
#[tests/functional/zvol/zvol_swap]
|
||||||
|
#tests = ['zvol_swap_001_pos', 'zvol_swap_002_pos', 'zvol_swap_003_pos',
|
||||||
|
# 'zvol_swap_004_pos', 'zvol_swap_005_pos', 'zvol_swap_006_pos']
|
1
tests/test-runner/Makefile.am
Normal file
1
tests/test-runner/Makefile.am
Normal file
@ -0,0 +1 @@
|
|||||||
|
SUBDIRS = cmd include man
|
3
tests/test-runner/cmd/Makefile.am
Normal file
3
tests/test-runner/cmd/Makefile.am
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
pkgdatadir = $(datadir)/@PACKAGE@/test-runner/bin
|
||||||
|
dist_pkgdata_SCRIPTS = \
|
||||||
|
test-runner.py
|
862
tests/test-runner/cmd/test-runner.py
Executable file
862
tests/test-runner/cmd/test-runner.py
Executable file
@ -0,0 +1,862 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
|
||||||
|
#
|
||||||
|
# This file and its contents are supplied under the terms of the
|
||||||
|
# Common Development and Distribution License ("CDDL"), version 1.0.
|
||||||
|
# You may only use this file in accordance with the terms of version
|
||||||
|
# 1.0 of the CDDL.
|
||||||
|
#
|
||||||
|
# A full copy of the text of the CDDL should have accompanied this
|
||||||
|
# source. A copy of the CDDL is also available via the Internet at
|
||||||
|
# http://www.illumos.org/license/CDDL.
|
||||||
|
#
|
||||||
|
|
||||||
|
#
|
||||||
|
# Copyright (c) 2013 by Delphix. All rights reserved.
|
||||||
|
#
|
||||||
|
|
||||||
|
import ConfigParser
|
||||||
|
import os
|
||||||
|
import logging
|
||||||
|
from datetime import datetime
|
||||||
|
from optparse import OptionParser
|
||||||
|
from pwd import getpwnam
|
||||||
|
from pwd import getpwuid
|
||||||
|
from select import select
|
||||||
|
from subprocess import PIPE
|
||||||
|
from subprocess import Popen
|
||||||
|
from sys import argv
|
||||||
|
from sys import exit
|
||||||
|
from threading import Timer
|
||||||
|
from time import time
|
||||||
|
|
||||||
|
BASEDIR = '/var/tmp/test_results'
|
||||||
|
TESTDIR = '/usr/share/zfs/'
|
||||||
|
KILL = 'kill'
|
||||||
|
TRUE = 'true'
|
||||||
|
SUDO = 'sudo'
|
||||||
|
|
||||||
|
|
||||||
|
class Result(object):
|
||||||
|
total = 0
|
||||||
|
runresults = {'PASS': 0, 'FAIL': 0, 'SKIP': 0, 'KILLED': 0}
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.starttime = None
|
||||||
|
self.returncode = None
|
||||||
|
self.runtime = ''
|
||||||
|
self.stdout = []
|
||||||
|
self.stderr = []
|
||||||
|
self.result = ''
|
||||||
|
|
||||||
|
def done(self, proc, killed):
|
||||||
|
"""
|
||||||
|
Finalize the results of this Cmd.
|
||||||
|
"""
|
||||||
|
Result.total += 1
|
||||||
|
m, s = divmod(time() - self.starttime, 60)
|
||||||
|
self.runtime = '%02d:%02d' % (m, s)
|
||||||
|
self.returncode = proc.returncode
|
||||||
|
if killed:
|
||||||
|
self.result = 'KILLED'
|
||||||
|
Result.runresults['KILLED'] += 1
|
||||||
|
elif self.returncode is 0:
|
||||||
|
self.result = 'PASS'
|
||||||
|
Result.runresults['PASS'] += 1
|
||||||
|
elif self.returncode is 4:
|
||||||
|
self.result = 'SKIP'
|
||||||
|
Result.runresults['SKIP'] += 1
|
||||||
|
elif self.returncode is not 0:
|
||||||
|
self.result = 'FAIL'
|
||||||
|
Result.runresults['FAIL'] += 1
|
||||||
|
|
||||||
|
|
||||||
|
class Output(object):
|
||||||
|
"""
|
||||||
|
This class is a slightly modified version of the 'Stream' class found
|
||||||
|
here: http://goo.gl/aSGfv
|
||||||
|
"""
|
||||||
|
def __init__(self, stream):
|
||||||
|
self.stream = stream
|
||||||
|
self._buf = ''
|
||||||
|
self.lines = []
|
||||||
|
|
||||||
|
def fileno(self):
|
||||||
|
return self.stream.fileno()
|
||||||
|
|
||||||
|
def read(self, drain=0):
|
||||||
|
"""
|
||||||
|
Read from the file descriptor. If 'drain' set, read until EOF.
|
||||||
|
"""
|
||||||
|
while self._read() is not None:
|
||||||
|
if not drain:
|
||||||
|
break
|
||||||
|
|
||||||
|
def _read(self):
|
||||||
|
"""
|
||||||
|
Read up to 4k of data from this output stream. Collect the output
|
||||||
|
up to the last newline, and append it to any leftover data from a
|
||||||
|
previous call. The lines are stored as a (timestamp, data) tuple
|
||||||
|
for easy sorting/merging later.
|
||||||
|
"""
|
||||||
|
fd = self.fileno()
|
||||||
|
buf = os.read(fd, 4096)
|
||||||
|
if not buf:
|
||||||
|
return None
|
||||||
|
if '\n' not in buf:
|
||||||
|
self._buf += buf
|
||||||
|
return []
|
||||||
|
|
||||||
|
buf = self._buf + buf
|
||||||
|
tmp, rest = buf.rsplit('\n', 1)
|
||||||
|
self._buf = rest
|
||||||
|
now = datetime.now()
|
||||||
|
rows = tmp.split('\n')
|
||||||
|
self.lines += [(now, r) for r in rows]
|
||||||
|
|
||||||
|
|
||||||
|
class Cmd(object):
|
||||||
|
verified_users = []
|
||||||
|
|
||||||
|
def __init__(self, pathname, outputdir=None, timeout=None, user=None):
|
||||||
|
self.pathname = pathname
|
||||||
|
self.outputdir = outputdir or 'BASEDIR'
|
||||||
|
self.timeout = timeout or 60
|
||||||
|
self.user = user or ''
|
||||||
|
self.killed = False
|
||||||
|
self.result = Result()
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return "Pathname: %s\nOutputdir: %s\nTimeout: %s\nUser: %s\n" % (
|
||||||
|
self.pathname, self.outputdir, self.timeout, self.user)
|
||||||
|
|
||||||
|
def kill_cmd(self, proc):
|
||||||
|
"""
|
||||||
|
Kill a running command due to timeout, or ^C from the keyboard. If
|
||||||
|
sudo is required, this user was verified previously.
|
||||||
|
"""
|
||||||
|
self.killed = True
|
||||||
|
do_sudo = len(self.user) != 0
|
||||||
|
signal = '-TERM'
|
||||||
|
|
||||||
|
cmd = [SUDO, KILL, signal, str(proc.pid)]
|
||||||
|
if not do_sudo:
|
||||||
|
del cmd[0]
|
||||||
|
|
||||||
|
try:
|
||||||
|
kp = Popen(cmd)
|
||||||
|
kp.wait()
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def update_cmd_privs(self, cmd, user):
|
||||||
|
"""
|
||||||
|
If a user has been specified to run this Cmd and we're not already
|
||||||
|
running as that user, prepend the appropriate sudo command to run
|
||||||
|
as that user.
|
||||||
|
"""
|
||||||
|
me = getpwuid(os.getuid())
|
||||||
|
|
||||||
|
if not user or user is me:
|
||||||
|
return cmd
|
||||||
|
|
||||||
|
if not os.path.isfile(cmd):
|
||||||
|
if os.path.isfile(cmd+'.ksh') and os.access(cmd+'.ksh', os.X_OK):
|
||||||
|
cmd += '.ksh'
|
||||||
|
if os.path.isfile(cmd+'.sh') and os.access(cmd+'.sh', os.X_OK):
|
||||||
|
cmd += '.sh'
|
||||||
|
|
||||||
|
ret = '%s -E -u %s %s' % (SUDO, user, cmd)
|
||||||
|
return ret.split(' ')
|
||||||
|
|
||||||
|
def collect_output(self, proc):
|
||||||
|
"""
|
||||||
|
Read from stdout/stderr as data becomes available, until the
|
||||||
|
process is no longer running. Return the lines from the stdout and
|
||||||
|
stderr Output objects.
|
||||||
|
"""
|
||||||
|
out = Output(proc.stdout)
|
||||||
|
err = Output(proc.stderr)
|
||||||
|
res = []
|
||||||
|
while proc.returncode is None:
|
||||||
|
proc.poll()
|
||||||
|
res = select([out, err], [], [], .1)
|
||||||
|
for fd in res[0]:
|
||||||
|
fd.read()
|
||||||
|
for fd in res[0]:
|
||||||
|
fd.read(drain=1)
|
||||||
|
|
||||||
|
return out.lines, err.lines
|
||||||
|
|
||||||
|
def run(self, options):
|
||||||
|
"""
|
||||||
|
This is the main function that runs each individual test.
|
||||||
|
Determine whether or not the command requires sudo, and modify it
|
||||||
|
if needed. Run the command, and update the result object.
|
||||||
|
"""
|
||||||
|
if options.dryrun is True:
|
||||||
|
print self
|
||||||
|
return
|
||||||
|
|
||||||
|
privcmd = self.update_cmd_privs(self.pathname, self.user)
|
||||||
|
try:
|
||||||
|
old = os.umask(0)
|
||||||
|
if not os.path.isdir(self.outputdir):
|
||||||
|
os.makedirs(self.outputdir, mode=0777)
|
||||||
|
os.umask(old)
|
||||||
|
except OSError, e:
|
||||||
|
fail('%s' % e)
|
||||||
|
|
||||||
|
try:
|
||||||
|
self.result.starttime = time()
|
||||||
|
proc = Popen(privcmd, stdout=PIPE, stderr=PIPE)
|
||||||
|
t = Timer(int(self.timeout), self.kill_cmd, [proc])
|
||||||
|
t.start()
|
||||||
|
self.result.stdout, self.result.stderr = self.collect_output(proc)
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
self.kill_cmd(proc)
|
||||||
|
fail('\nRun terminated at user request.')
|
||||||
|
finally:
|
||||||
|
t.cancel()
|
||||||
|
|
||||||
|
self.result.done(proc, self.killed)
|
||||||
|
|
||||||
|
def skip(self):
|
||||||
|
"""
|
||||||
|
Initialize enough of the test result that we can log a skipped
|
||||||
|
command.
|
||||||
|
"""
|
||||||
|
Result.total += 1
|
||||||
|
Result.runresults['SKIP'] += 1
|
||||||
|
self.result.stdout = self.result.stderr = []
|
||||||
|
self.result.starttime = time()
|
||||||
|
m, s = divmod(time() - self.result.starttime, 60)
|
||||||
|
self.result.runtime = '%02d:%02d' % (m, s)
|
||||||
|
self.result.result = 'SKIP'
|
||||||
|
|
||||||
|
def log(self, logger, options):
|
||||||
|
"""
|
||||||
|
This function is responsible for writing all output. This includes
|
||||||
|
the console output, the logfile of all results (with timestamped
|
||||||
|
merged stdout and stderr), and for each test, the unmodified
|
||||||
|
stdout/stderr/merged in it's own file.
|
||||||
|
"""
|
||||||
|
if logger is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
logname = getpwuid(os.getuid()).pw_name
|
||||||
|
user = ' (run as %s)' % (self.user if len(self.user) else logname)
|
||||||
|
msga = 'Test: %s%s ' % (self.pathname, user)
|
||||||
|
msgb = '[%s] [%s]' % (self.result.runtime, self.result.result)
|
||||||
|
pad = ' ' * (80 - (len(msga) + len(msgb)))
|
||||||
|
|
||||||
|
# If -q is specified, only print a line for tests that didn't pass.
|
||||||
|
# This means passing tests need to be logged as DEBUG, or the one
|
||||||
|
# line summary will only be printed in the logfile for failures.
|
||||||
|
if not options.quiet:
|
||||||
|
logger.info('%s%s%s' % (msga, pad, msgb))
|
||||||
|
elif self.result.result is not 'PASS':
|
||||||
|
logger.info('%s%s%s' % (msga, pad, msgb))
|
||||||
|
else:
|
||||||
|
logger.debug('%s%s%s' % (msga, pad, msgb))
|
||||||
|
|
||||||
|
lines = self.result.stdout + self.result.stderr
|
||||||
|
for dt, line in sorted(lines):
|
||||||
|
logger.debug('%s %s' % (dt.strftime("%H:%M:%S.%f ")[:11], line))
|
||||||
|
|
||||||
|
if len(self.result.stdout):
|
||||||
|
with open(os.path.join(self.outputdir, 'stdout'), 'w') as out:
|
||||||
|
for _, line in self.result.stdout:
|
||||||
|
os.write(out.fileno(), '%s\n' % line)
|
||||||
|
if len(self.result.stderr):
|
||||||
|
with open(os.path.join(self.outputdir, 'stderr'), 'w') as err:
|
||||||
|
for _, line in self.result.stderr:
|
||||||
|
os.write(err.fileno(), '%s\n' % line)
|
||||||
|
if len(self.result.stdout) and len(self.result.stderr):
|
||||||
|
with open(os.path.join(self.outputdir, 'merged'), 'w') as merged:
|
||||||
|
for _, line in sorted(lines):
|
||||||
|
os.write(merged.fileno(), '%s\n' % line)
|
||||||
|
|
||||||
|
|
||||||
|
class Test(Cmd):
|
||||||
|
props = ['outputdir', 'timeout', 'user', 'pre', 'pre_user', 'post',
|
||||||
|
'post_user']
|
||||||
|
|
||||||
|
def __init__(self, pathname, outputdir=None, timeout=None, user=None,
|
||||||
|
pre=None, pre_user=None, post=None, post_user=None):
|
||||||
|
super(Test, self).__init__(pathname, outputdir, timeout, user)
|
||||||
|
self.pre = pre or ''
|
||||||
|
self.pre_user = pre_user or ''
|
||||||
|
self.post = post or ''
|
||||||
|
self.post_user = post_user or ''
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
post_user = pre_user = ''
|
||||||
|
if len(self.pre_user):
|
||||||
|
pre_user = ' (as %s)' % (self.pre_user)
|
||||||
|
if len(self.post_user):
|
||||||
|
post_user = ' (as %s)' % (self.post_user)
|
||||||
|
return "Pathname: %s\nOutputdir: %s\nTimeout: %s\nPre: %s%s\nPost: " \
|
||||||
|
"%s%s\nUser: %s\n" % (self.pathname, self.outputdir,
|
||||||
|
self.timeout, self.pre, pre_user, self.post, post_user,
|
||||||
|
self.user)
|
||||||
|
|
||||||
|
def verify(self, logger):
|
||||||
|
"""
|
||||||
|
Check the pre/post scripts, user and Test. Omit the Test from this
|
||||||
|
run if there are any problems.
|
||||||
|
"""
|
||||||
|
files = [self.pre, self.pathname, self.post]
|
||||||
|
users = [self.pre_user, self.user, self.post_user]
|
||||||
|
|
||||||
|
for f in [f for f in files if len(f)]:
|
||||||
|
if not verify_file(f):
|
||||||
|
logger.info("Warning: Test '%s' not added to this run because"
|
||||||
|
" it failed verification." % f)
|
||||||
|
return False
|
||||||
|
|
||||||
|
for user in [user for user in users if len(user)]:
|
||||||
|
if not verify_user(user, logger):
|
||||||
|
logger.info("Not adding Test '%s' to this run." %
|
||||||
|
self.pathname)
|
||||||
|
return False
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
def run(self, logger, options):
|
||||||
|
"""
|
||||||
|
Create Cmd instances for the pre/post scripts. If the pre script
|
||||||
|
doesn't pass, skip this Test. Run the post script regardless.
|
||||||
|
"""
|
||||||
|
pretest = Cmd(self.pre, outputdir=os.path.join(self.outputdir,
|
||||||
|
os.path.basename(self.pre)), timeout=self.timeout,
|
||||||
|
user=self.pre_user)
|
||||||
|
test = Cmd(self.pathname, outputdir=self.outputdir,
|
||||||
|
timeout=self.timeout, user=self.user)
|
||||||
|
posttest = Cmd(self.post, outputdir=os.path.join(self.outputdir,
|
||||||
|
os.path.basename(self.post)), timeout=self.timeout,
|
||||||
|
user=self.post_user)
|
||||||
|
|
||||||
|
cont = True
|
||||||
|
if len(pretest.pathname):
|
||||||
|
pretest.run(options)
|
||||||
|
cont = pretest.result.result is 'PASS'
|
||||||
|
pretest.log(logger, options)
|
||||||
|
|
||||||
|
if cont:
|
||||||
|
test.run(options)
|
||||||
|
else:
|
||||||
|
test.skip()
|
||||||
|
|
||||||
|
test.log(logger, options)
|
||||||
|
|
||||||
|
if len(posttest.pathname):
|
||||||
|
posttest.run(options)
|
||||||
|
posttest.log(logger, options)
|
||||||
|
|
||||||
|
|
||||||
|
class TestGroup(Test):
|
||||||
|
props = Test.props + ['tests']
|
||||||
|
|
||||||
|
def __init__(self, pathname, outputdir=None, timeout=None, user=None,
|
||||||
|
pre=None, pre_user=None, post=None, post_user=None,
|
||||||
|
tests=None):
|
||||||
|
super(TestGroup, self).__init__(pathname, outputdir, timeout, user,
|
||||||
|
pre, pre_user, post, post_user)
|
||||||
|
self.tests = tests or []
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
post_user = pre_user = ''
|
||||||
|
if len(self.pre_user):
|
||||||
|
pre_user = ' (as %s)' % (self.pre_user)
|
||||||
|
if len(self.post_user):
|
||||||
|
post_user = ' (as %s)' % (self.post_user)
|
||||||
|
return "Pathname: %s\nOutputdir: %s\nTests: %s\nTimeout: %s\n" \
|
||||||
|
"Pre: %s%s\nPost: %s%s\nUser: %s\n" % (self.pathname,
|
||||||
|
self.outputdir, self.tests, self.timeout, self.pre, pre_user,
|
||||||
|
self.post, post_user, self.user)
|
||||||
|
|
||||||
|
def verify(self, logger):
|
||||||
|
"""
|
||||||
|
Check the pre/post scripts, user and tests in this TestGroup. Omit
|
||||||
|
the TestGroup entirely, or simply delete the relevant tests in the
|
||||||
|
group, if that's all that's required.
|
||||||
|
"""
|
||||||
|
# If the pre or post scripts are relative pathnames, convert to
|
||||||
|
# absolute, so they stand a chance of passing verification.
|
||||||
|
if len(self.pre) and not os.path.isabs(self.pre):
|
||||||
|
self.pre = os.path.join(self.pathname, self.pre)
|
||||||
|
if len(self.post) and not os.path.isabs(self.post):
|
||||||
|
self.post = os.path.join(self.pathname, self.post)
|
||||||
|
|
||||||
|
auxfiles = [self.pre, self.post]
|
||||||
|
users = [self.pre_user, self.user, self.post_user]
|
||||||
|
|
||||||
|
for f in [f for f in auxfiles if len(f)]:
|
||||||
|
if self.pathname != os.path.dirname(f):
|
||||||
|
logger.info("Warning: TestGroup '%s' not added to this run. "
|
||||||
|
"Auxiliary script '%s' exists in a different "
|
||||||
|
"directory." % (self.pathname, f))
|
||||||
|
return False
|
||||||
|
|
||||||
|
if not verify_file(f):
|
||||||
|
logger.info("Warning: TestGroup '%s' not added to this run. "
|
||||||
|
"Auxiliary script '%s' failed verification." %
|
||||||
|
(self.pathname, f))
|
||||||
|
return False
|
||||||
|
|
||||||
|
for user in [user for user in users if len(user)]:
|
||||||
|
if not verify_user(user, logger):
|
||||||
|
logger.info("Not adding TestGroup '%s' to this run." %
|
||||||
|
self.pathname)
|
||||||
|
return False
|
||||||
|
|
||||||
|
# If one of the tests is invalid, delete it, log it, and drive on.
|
||||||
|
for test in self.tests:
|
||||||
|
if not verify_file(os.path.join(self.pathname, test)):
|
||||||
|
del self.tests[self.tests.index(test)]
|
||||||
|
logger.info("Warning: Test '%s' removed from TestGroup '%s' "
|
||||||
|
"because it failed verification." % (test,
|
||||||
|
self.pathname))
|
||||||
|
|
||||||
|
return len(self.tests) is not 0
|
||||||
|
|
||||||
|
def run(self, logger, options):
|
||||||
|
"""
|
||||||
|
Create Cmd instances for the pre/post scripts. If the pre script
|
||||||
|
doesn't pass, skip all the tests in this TestGroup. Run the post
|
||||||
|
script regardless.
|
||||||
|
"""
|
||||||
|
pretest = Cmd(self.pre, outputdir=os.path.join(self.outputdir,
|
||||||
|
os.path.basename(self.pre)), timeout=self.timeout,
|
||||||
|
user=self.pre_user)
|
||||||
|
posttest = Cmd(self.post, outputdir=os.path.join(self.outputdir,
|
||||||
|
os.path.basename(self.post)), timeout=self.timeout,
|
||||||
|
user=self.post_user)
|
||||||
|
|
||||||
|
cont = True
|
||||||
|
if len(pretest.pathname):
|
||||||
|
pretest.run(options)
|
||||||
|
cont = pretest.result.result is 'PASS'
|
||||||
|
pretest.log(logger, options)
|
||||||
|
|
||||||
|
for fname in self.tests:
|
||||||
|
test = Cmd(os.path.join(self.pathname, fname),
|
||||||
|
outputdir=os.path.join(self.outputdir, fname),
|
||||||
|
timeout=self.timeout, user=self.user)
|
||||||
|
if cont:
|
||||||
|
test.run(options)
|
||||||
|
else:
|
||||||
|
test.skip()
|
||||||
|
|
||||||
|
test.log(logger, options)
|
||||||
|
|
||||||
|
if len(posttest.pathname):
|
||||||
|
posttest.run(options)
|
||||||
|
posttest.log(logger, options)
|
||||||
|
|
||||||
|
|
||||||
|
class TestRun(object):
|
||||||
|
props = ['quiet', 'outputdir']
|
||||||
|
|
||||||
|
def __init__(self, options):
|
||||||
|
self.tests = {}
|
||||||
|
self.testgroups = {}
|
||||||
|
self.starttime = time()
|
||||||
|
self.timestamp = datetime.now().strftime('%Y%m%dT%H%M%S')
|
||||||
|
self.outputdir = os.path.join(options.outputdir, self.timestamp)
|
||||||
|
self.logger = self.setup_logging(options)
|
||||||
|
self.defaults = [
|
||||||
|
('outputdir', BASEDIR),
|
||||||
|
('quiet', False),
|
||||||
|
('timeout', 60),
|
||||||
|
('user', ''),
|
||||||
|
('pre', ''),
|
||||||
|
('pre_user', ''),
|
||||||
|
('post', ''),
|
||||||
|
('post_user', '')
|
||||||
|
]
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
s = 'TestRun:\n outputdir: %s\n' % self.outputdir
|
||||||
|
s += 'TESTS:\n'
|
||||||
|
for key in sorted(self.tests.keys()):
|
||||||
|
s += '%s%s' % (self.tests[key].__str__(), '\n')
|
||||||
|
s += 'TESTGROUPS:\n'
|
||||||
|
for key in sorted(self.testgroups.keys()):
|
||||||
|
s += '%s%s' % (self.testgroups[key].__str__(), '\n')
|
||||||
|
return s
|
||||||
|
|
||||||
|
def addtest(self, pathname, options):
|
||||||
|
"""
|
||||||
|
Create a new Test, and apply any properties that were passed in
|
||||||
|
from the command line. If it passes verification, add it to the
|
||||||
|
TestRun.
|
||||||
|
"""
|
||||||
|
test = Test(pathname)
|
||||||
|
for prop in Test.props:
|
||||||
|
setattr(test, prop, getattr(options, prop))
|
||||||
|
|
||||||
|
if test.verify(self.logger):
|
||||||
|
self.tests[pathname] = test
|
||||||
|
|
||||||
|
def addtestgroup(self, dirname, filenames, options):
|
||||||
|
"""
|
||||||
|
Create a new TestGroup, and apply any properties that were passed
|
||||||
|
in from the command line. If it passes verification, add it to the
|
||||||
|
TestRun.
|
||||||
|
"""
|
||||||
|
if dirname not in self.testgroups:
|
||||||
|
testgroup = TestGroup(dirname)
|
||||||
|
for prop in Test.props:
|
||||||
|
setattr(testgroup, prop, getattr(options, prop))
|
||||||
|
|
||||||
|
# Prevent pre/post scripts from running as regular tests
|
||||||
|
for f in [testgroup.pre, testgroup.post]:
|
||||||
|
if f in filenames:
|
||||||
|
del filenames[filenames.index(f)]
|
||||||
|
|
||||||
|
self.testgroups[dirname] = testgroup
|
||||||
|
self.testgroups[dirname].tests = sorted(filenames)
|
||||||
|
|
||||||
|
testgroup.verify(self.logger)
|
||||||
|
|
||||||
|
def read(self, logger, options):
|
||||||
|
"""
|
||||||
|
Read in the specified runfile, and apply the TestRun properties
|
||||||
|
listed in the 'DEFAULT' section to our TestRun. Then read each
|
||||||
|
section, and apply the appropriate properties to the Test or
|
||||||
|
TestGroup. Properties from individual sections override those set
|
||||||
|
in the 'DEFAULT' section. If the Test or TestGroup passes
|
||||||
|
verification, add it to the TestRun.
|
||||||
|
"""
|
||||||
|
config = ConfigParser.RawConfigParser()
|
||||||
|
if not len(config.read(options.runfile)):
|
||||||
|
fail("Coulnd't read config file %s" % options.runfile)
|
||||||
|
|
||||||
|
for opt in TestRun.props:
|
||||||
|
if config.has_option('DEFAULT', opt):
|
||||||
|
setattr(self, opt, config.get('DEFAULT', opt))
|
||||||
|
self.outputdir = os.path.join(self.outputdir, self.timestamp)
|
||||||
|
|
||||||
|
for section in config.sections():
|
||||||
|
if 'tests' in config.options(section):
|
||||||
|
if os.path.isdir(section):
|
||||||
|
pathname = section
|
||||||
|
elif os.path.isdir(os.path.join(options.testdir, section)):
|
||||||
|
pathname = os.path.join(options.testdir, section)
|
||||||
|
else:
|
||||||
|
pathname = section
|
||||||
|
|
||||||
|
testgroup = TestGroup(os.path.abspath(pathname))
|
||||||
|
for prop in TestGroup.props:
|
||||||
|
try:
|
||||||
|
setattr(testgroup, prop, config.get('DEFAULT', prop))
|
||||||
|
setattr(testgroup, prop, config.get(section, prop))
|
||||||
|
except ConfigParser.NoOptionError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Repopulate tests using eval to convert the string to a list
|
||||||
|
testgroup.tests = eval(config.get(section, 'tests'))
|
||||||
|
|
||||||
|
if testgroup.verify(logger):
|
||||||
|
self.testgroups[section] = testgroup
|
||||||
|
else:
|
||||||
|
test = Test(section)
|
||||||
|
for prop in Test.props:
|
||||||
|
try:
|
||||||
|
setattr(test, prop, config.get('DEFAULT', prop))
|
||||||
|
setattr(test, prop, config.get(section, prop))
|
||||||
|
except ConfigParser.NoOptionError:
|
||||||
|
pass
|
||||||
|
if test.verify(logger):
|
||||||
|
self.tests[section] = test
|
||||||
|
|
||||||
|
def write(self, options):
|
||||||
|
"""
|
||||||
|
Create a configuration file for editing and later use. The
|
||||||
|
'DEFAULT' section of the config file is created from the
|
||||||
|
properties that were specified on the command line. Tests are
|
||||||
|
simply added as sections that inherit everything from the
|
||||||
|
'DEFAULT' section. TestGroups are the same, except they get an
|
||||||
|
option including all the tests to run in that directory.
|
||||||
|
"""
|
||||||
|
|
||||||
|
defaults = dict([(prop, getattr(options, prop)) for prop, _ in
|
||||||
|
self.defaults])
|
||||||
|
config = ConfigParser.RawConfigParser(defaults)
|
||||||
|
|
||||||
|
for test in sorted(self.tests.keys()):
|
||||||
|
config.add_section(test)
|
||||||
|
|
||||||
|
for testgroup in sorted(self.testgroups.keys()):
|
||||||
|
config.add_section(testgroup)
|
||||||
|
config.set(testgroup, 'tests', self.testgroups[testgroup].tests)
|
||||||
|
|
||||||
|
try:
|
||||||
|
with open(options.template, 'w') as f:
|
||||||
|
return config.write(f)
|
||||||
|
except IOError:
|
||||||
|
fail('Could not open \'%s\' for writing.' % options.template)
|
||||||
|
|
||||||
|
def complete_outputdirs(self, options):
|
||||||
|
"""
|
||||||
|
Collect all the pathnames for Tests, and TestGroups. Work
|
||||||
|
backwards one pathname component at a time, to create a unique
|
||||||
|
directory name in which to deposit test output. Tests will be able
|
||||||
|
to write output files directly in the newly modified outputdir.
|
||||||
|
TestGroups will be able to create one subdirectory per test in the
|
||||||
|
outputdir, and are guaranteed uniqueness because a group can only
|
||||||
|
contain files in one directory. Pre and post tests will create a
|
||||||
|
directory rooted at the outputdir of the Test or TestGroup in
|
||||||
|
question for their output.
|
||||||
|
"""
|
||||||
|
done = False
|
||||||
|
components = 0
|
||||||
|
tmp_dict = dict(self.tests.items() + self.testgroups.items())
|
||||||
|
total = len(tmp_dict)
|
||||||
|
base = self.outputdir
|
||||||
|
|
||||||
|
while not done:
|
||||||
|
l = []
|
||||||
|
components -= 1
|
||||||
|
for testfile in tmp_dict.keys():
|
||||||
|
uniq = '/'.join(testfile.split('/')[components:]).lstrip('/')
|
||||||
|
if not uniq in l:
|
||||||
|
l.append(uniq)
|
||||||
|
tmp_dict[testfile].outputdir = os.path.join(base, uniq)
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
done = total == len(l)
|
||||||
|
|
||||||
|
def setup_logging(self, options):
|
||||||
|
"""
|
||||||
|
Two loggers are set up here. The first is for the logfile which
|
||||||
|
will contain one line summarizing the test, including the test
|
||||||
|
name, result, and running time. This logger will also capture the
|
||||||
|
timestamped combined stdout and stderr of each run. The second
|
||||||
|
logger is optional console output, which will contain only the one
|
||||||
|
line summary. The loggers are initialized at two different levels
|
||||||
|
to facilitate segregating the output.
|
||||||
|
"""
|
||||||
|
if options.dryrun is True:
|
||||||
|
return
|
||||||
|
|
||||||
|
testlogger = logging.getLogger(__name__)
|
||||||
|
testlogger.setLevel(logging.DEBUG)
|
||||||
|
|
||||||
|
if options.cmd is not 'wrconfig':
|
||||||
|
try:
|
||||||
|
old = os.umask(0)
|
||||||
|
os.makedirs(self.outputdir, mode=0777)
|
||||||
|
os.umask(old)
|
||||||
|
except OSError, e:
|
||||||
|
fail('%s' % e)
|
||||||
|
filename = os.path.join(self.outputdir, 'log')
|
||||||
|
|
||||||
|
logfile = logging.FileHandler(filename)
|
||||||
|
logfile.setLevel(logging.DEBUG)
|
||||||
|
logfilefmt = logging.Formatter('%(message)s')
|
||||||
|
logfile.setFormatter(logfilefmt)
|
||||||
|
testlogger.addHandler(logfile)
|
||||||
|
|
||||||
|
cons = logging.StreamHandler()
|
||||||
|
cons.setLevel(logging.INFO)
|
||||||
|
consfmt = logging.Formatter('%(message)s')
|
||||||
|
cons.setFormatter(consfmt)
|
||||||
|
testlogger.addHandler(cons)
|
||||||
|
|
||||||
|
return testlogger
|
||||||
|
|
||||||
|
def run(self, options):
|
||||||
|
"""
|
||||||
|
Walk through all the Tests and TestGroups, calling run().
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
os.chdir(self.outputdir)
|
||||||
|
except OSError:
|
||||||
|
fail('Could not change to directory %s' % self.outputdir)
|
||||||
|
for test in sorted(self.tests.keys()):
|
||||||
|
self.tests[test].run(self.logger, options)
|
||||||
|
for testgroup in sorted(self.testgroups.keys()):
|
||||||
|
self.testgroups[testgroup].run(self.logger, options)
|
||||||
|
|
||||||
|
def summary(self):
|
||||||
|
if Result.total is 0:
|
||||||
|
return
|
||||||
|
|
||||||
|
print '\nResults Summary'
|
||||||
|
for key in Result.runresults.keys():
|
||||||
|
if Result.runresults[key] is not 0:
|
||||||
|
print '%s\t% 4d' % (key, Result.runresults[key])
|
||||||
|
|
||||||
|
m, s = divmod(time() - self.starttime, 60)
|
||||||
|
h, m = divmod(m, 60)
|
||||||
|
print '\nRunning Time:\t%02d:%02d:%02d' % (h, m, s)
|
||||||
|
print 'Percent passed:\t%.1f%%' % ((float(Result.runresults['PASS']) /
|
||||||
|
float(Result.total)) * 100)
|
||||||
|
print 'Log directory:\t%s' % self.outputdir
|
||||||
|
|
||||||
|
|
||||||
|
def verify_file(pathname):
|
||||||
|
"""
|
||||||
|
Verify that the supplied pathname is an executable regular file.
|
||||||
|
"""
|
||||||
|
if os.path.isdir(pathname) or os.path.islink(pathname):
|
||||||
|
return False
|
||||||
|
|
||||||
|
if (os.path.isfile(pathname) and os.access(pathname, os.X_OK)) or \
|
||||||
|
(os.path.isfile(pathname+'.ksh') and os.access(pathname+'.ksh', os.X_OK)) or \
|
||||||
|
(os.path.isfile(pathname+'.sh') and os.access(pathname+'.sh', os.X_OK)):
|
||||||
|
return True
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def verify_user(user, logger):
|
||||||
|
"""
|
||||||
|
Verify that the specified user exists on this system, and can execute
|
||||||
|
sudo without being prompted for a password.
|
||||||
|
"""
|
||||||
|
testcmd = [SUDO, '-n', '-u', user, TRUE]
|
||||||
|
can_sudo = exists = True
|
||||||
|
|
||||||
|
if user in Cmd.verified_users:
|
||||||
|
return True
|
||||||
|
|
||||||
|
try:
|
||||||
|
_ = getpwnam(user)
|
||||||
|
except KeyError:
|
||||||
|
exists = False
|
||||||
|
logger.info("Warning: user '%s' does not exist.", user)
|
||||||
|
return False
|
||||||
|
|
||||||
|
p = Popen(testcmd)
|
||||||
|
p.wait()
|
||||||
|
if p.returncode is not 0:
|
||||||
|
logger.info("Warning: user '%s' cannot use passwordless sudo.", user)
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
Cmd.verified_users.append(user)
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def find_tests(testrun, options):
|
||||||
|
"""
|
||||||
|
For the given list of pathnames, add files as Tests. For directories,
|
||||||
|
if do_groups is True, add the directory as a TestGroup. If False,
|
||||||
|
recursively search for executable files.
|
||||||
|
"""
|
||||||
|
|
||||||
|
for p in sorted(options.pathnames):
|
||||||
|
if os.path.isdir(p):
|
||||||
|
for dirname, _, filenames in os.walk(p):
|
||||||
|
if options.do_groups:
|
||||||
|
testrun.addtestgroup(dirname, filenames, options)
|
||||||
|
else:
|
||||||
|
for f in sorted(filenames):
|
||||||
|
testrun.addtest(os.path.join(dirname, f), options)
|
||||||
|
else:
|
||||||
|
testrun.addtest(p, options)
|
||||||
|
|
||||||
|
|
||||||
|
def fail(retstr, ret=1):
|
||||||
|
print '%s: %s' % (argv[0], retstr)
|
||||||
|
exit(ret)
|
||||||
|
|
||||||
|
|
||||||
|
def options_cb(option, opt_str, value, parser):
|
||||||
|
path_options = ['runfile', 'outputdir', 'template', 'testdir']
|
||||||
|
|
||||||
|
if option.dest is 'runfile' and '-w' in parser.rargs or \
|
||||||
|
option.dest is 'template' and '-c' in parser.rargs:
|
||||||
|
fail('-c and -w are mutually exclusive.')
|
||||||
|
|
||||||
|
if opt_str in parser.rargs:
|
||||||
|
fail('%s may only be specified once.' % opt_str)
|
||||||
|
|
||||||
|
if option.dest is 'runfile':
|
||||||
|
parser.values.cmd = 'rdconfig'
|
||||||
|
if option.dest is 'template':
|
||||||
|
parser.values.cmd = 'wrconfig'
|
||||||
|
|
||||||
|
setattr(parser.values, option.dest, value)
|
||||||
|
if option.dest in path_options:
|
||||||
|
setattr(parser.values, option.dest, os.path.abspath(value))
|
||||||
|
|
||||||
|
|
||||||
|
def parse_args():
|
||||||
|
parser = OptionParser()
|
||||||
|
parser.add_option('-c', action='callback', callback=options_cb,
|
||||||
|
type='string', dest='runfile', metavar='runfile',
|
||||||
|
help='Specify tests to run via config file.')
|
||||||
|
parser.add_option('-d', action='store_true', default=False, dest='dryrun',
|
||||||
|
help='Dry run. Print tests, but take no other action.')
|
||||||
|
parser.add_option('-g', action='store_true', default=False,
|
||||||
|
dest='do_groups', help='Make directories TestGroups.')
|
||||||
|
parser.add_option('-o', action='callback', callback=options_cb,
|
||||||
|
default=BASEDIR, dest='outputdir', type='string',
|
||||||
|
metavar='outputdir', help='Specify an output directory.')
|
||||||
|
parser.add_option('-i', action='callback', callback=options_cb,
|
||||||
|
default=TESTDIR, dest='testdir', type='string',
|
||||||
|
metavar='testdir', help='Specify a test directory.')
|
||||||
|
parser.add_option('-p', action='callback', callback=options_cb,
|
||||||
|
default='', dest='pre', metavar='script',
|
||||||
|
type='string', help='Specify a pre script.')
|
||||||
|
parser.add_option('-P', action='callback', callback=options_cb,
|
||||||
|
default='', dest='post', metavar='script',
|
||||||
|
type='string', help='Specify a post script.')
|
||||||
|
parser.add_option('-q', action='store_true', default=False, dest='quiet',
|
||||||
|
help='Silence on the console during a test run.')
|
||||||
|
parser.add_option('-t', action='callback', callback=options_cb, default=60,
|
||||||
|
dest='timeout', metavar='seconds', type='int',
|
||||||
|
help='Timeout (in seconds) for an individual test.')
|
||||||
|
parser.add_option('-u', action='callback', callback=options_cb,
|
||||||
|
default='', dest='user', metavar='user', type='string',
|
||||||
|
help='Specify a different user name to run as.')
|
||||||
|
parser.add_option('-w', action='callback', callback=options_cb,
|
||||||
|
default=None, dest='template', metavar='template',
|
||||||
|
type='string', help='Create a new config file.')
|
||||||
|
parser.add_option('-x', action='callback', callback=options_cb, default='',
|
||||||
|
dest='pre_user', metavar='pre_user', type='string',
|
||||||
|
help='Specify a user to execute the pre script.')
|
||||||
|
parser.add_option('-X', action='callback', callback=options_cb, default='',
|
||||||
|
dest='post_user', metavar='post_user', type='string',
|
||||||
|
help='Specify a user to execute the post script.')
|
||||||
|
(options, pathnames) = parser.parse_args()
|
||||||
|
|
||||||
|
if not options.runfile and not options.template:
|
||||||
|
options.cmd = 'runtests'
|
||||||
|
|
||||||
|
if options.runfile and len(pathnames):
|
||||||
|
fail('Extraneous arguments.')
|
||||||
|
|
||||||
|
options.pathnames = [os.path.abspath(path) for path in pathnames]
|
||||||
|
|
||||||
|
return options
|
||||||
|
|
||||||
|
|
||||||
|
def main(args):
|
||||||
|
options = parse_args()
|
||||||
|
testrun = TestRun(options)
|
||||||
|
|
||||||
|
if options.cmd is 'runtests':
|
||||||
|
find_tests(testrun, options)
|
||||||
|
elif options.cmd is 'rdconfig':
|
||||||
|
testrun.read(testrun.logger, options)
|
||||||
|
elif options.cmd is 'wrconfig':
|
||||||
|
find_tests(testrun, options)
|
||||||
|
testrun.write(options)
|
||||||
|
exit(0)
|
||||||
|
else:
|
||||||
|
fail('Unknown command specified')
|
||||||
|
|
||||||
|
testrun.complete_outputdirs(options)
|
||||||
|
testrun.run(options)
|
||||||
|
testrun.summary()
|
||||||
|
exit(0)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main(argv[1:])
|
4
tests/test-runner/include/Makefile.am
Normal file
4
tests/test-runner/include/Makefile.am
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
pkgdatadir = $(datadir)/@PACKAGE@/test-runner/include
|
||||||
|
dist_pkgdata_SCRIPTS = \
|
||||||
|
logapi.shlib \
|
||||||
|
stf.shlib
|
385
tests/test-runner/include/logapi.shlib
Normal file
385
tests/test-runner/include/logapi.shlib
Normal file
@ -0,0 +1,385 @@
|
|||||||
|
#!/bin/ksh -p
|
||||||
|
#
|
||||||
|
# CDDL HEADER START
|
||||||
|
#
|
||||||
|
# The contents of this file are subject to the terms of the
|
||||||
|
# Common Development and Distribution License (the "License").
|
||||||
|
# You may not use this file except in compliance with the License.
|
||||||
|
#
|
||||||
|
# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
||||||
|
# or http://www.opensolaris.org/os/licensing.
|
||||||
|
# See the License for the specific language governing permissions
|
||||||
|
# and limitations under the License.
|
||||||
|
#
|
||||||
|
# When distributing Covered Code, include this CDDL HEADER in each
|
||||||
|
# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
||||||
|
# If applicable, add the following below this CDDL HEADER, with the
|
||||||
|
# fields enclosed by brackets "[]" replaced with your own identifying
|
||||||
|
# information: Portions Copyright [yyyy] [name of copyright owner]
|
||||||
|
#
|
||||||
|
# CDDL HEADER END
|
||||||
|
#
|
||||||
|
|
||||||
|
#
|
||||||
|
# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
|
||||||
|
# Use is subject to license terms.
|
||||||
|
#
|
||||||
|
# Copyright (c) 2012 by Delphix. All rights reserved.
|
||||||
|
#
|
||||||
|
|
||||||
|
. ${STF_TOOLS}/include/stf.shlib
|
||||||
|
|
||||||
|
# Output an assertion
|
||||||
|
#
|
||||||
|
# $@ - assertion text
|
||||||
|
|
||||||
|
function log_assert
|
||||||
|
{
|
||||||
|
_printline ASSERTION: "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Output a comment
|
||||||
|
#
|
||||||
|
# $@ - comment text
|
||||||
|
|
||||||
|
function log_note
|
||||||
|
{
|
||||||
|
_printline NOTE: "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Execute and print command with status where success equals non-zero result
|
||||||
|
#
|
||||||
|
# $@ - command to execute
|
||||||
|
#
|
||||||
|
# return 0 if command fails, otherwise return 1
|
||||||
|
|
||||||
|
function log_neg
|
||||||
|
{
|
||||||
|
log_neg_expect "" "$@"
|
||||||
|
return $?
|
||||||
|
}
|
||||||
|
|
||||||
|
# Execute a positive test and exit $STF_FAIL is test fails
|
||||||
|
#
|
||||||
|
# $@ - command to execute
|
||||||
|
|
||||||
|
function log_must
|
||||||
|
{
|
||||||
|
log_pos "$@"
|
||||||
|
(( $? != 0 )) && log_fail
|
||||||
|
}
|
||||||
|
|
||||||
|
# Execute a negative test and exit $STF_FAIL if test passes
|
||||||
|
#
|
||||||
|
# $@ - command to execute
|
||||||
|
|
||||||
|
function log_mustnot
|
||||||
|
{
|
||||||
|
log_neg "$@"
|
||||||
|
(( $? != 0 )) && log_fail
|
||||||
|
}
|
||||||
|
|
||||||
|
# Execute a negative test with keyword expected, and exit
|
||||||
|
# $STF_FAIL if test passes
|
||||||
|
#
|
||||||
|
# $1 - keyword expected
|
||||||
|
# $2-$@ - command to execute
|
||||||
|
|
||||||
|
function log_mustnot_expect
|
||||||
|
{
|
||||||
|
log_neg_expect "$@"
|
||||||
|
(( $? != 0 )) && log_fail
|
||||||
|
}
|
||||||
|
|
||||||
|
# Execute and print command with status where success equals non-zero result
|
||||||
|
# or output includes expected keyword
|
||||||
|
#
|
||||||
|
# $1 - keyword expected
|
||||||
|
# $2-$@ - command to execute
|
||||||
|
#
|
||||||
|
# return 0 if command fails, or the output contains the keyword expected,
|
||||||
|
# return 1 otherwise
|
||||||
|
|
||||||
|
function log_neg_expect
|
||||||
|
{
|
||||||
|
typeset out=""
|
||||||
|
typeset logfile="/tmp/log.$$"
|
||||||
|
typeset ret=1
|
||||||
|
typeset expect=$1
|
||||||
|
shift
|
||||||
|
|
||||||
|
while [[ -e $logfile ]]; do
|
||||||
|
logfile="$logfile.$$"
|
||||||
|
done
|
||||||
|
|
||||||
|
"$@" 2>$logfile
|
||||||
|
typeset status=$?
|
||||||
|
out="$CAT $logfile"
|
||||||
|
|
||||||
|
# unexpected status
|
||||||
|
if (( $status == 0 )); then
|
||||||
|
print -u2 $($out)
|
||||||
|
_printerror "$@" "unexpectedly exited $status"
|
||||||
|
# missing binary
|
||||||
|
elif (( $status == 127 )); then
|
||||||
|
print -u2 $($out)
|
||||||
|
_printerror "$@" "unexpectedly exited $status (File not found)"
|
||||||
|
# bus error - core dump
|
||||||
|
elif (( $status == 138 )); then
|
||||||
|
print -u2 $($out)
|
||||||
|
_printerror "$@" "unexpectedly exited $status (Bus Error)"
|
||||||
|
# segmentation violation - core dump
|
||||||
|
elif (( $status == 139 )); then
|
||||||
|
print -u2 $($out)
|
||||||
|
_printerror "$@" "unexpectedly exited $status (SEGV)"
|
||||||
|
else
|
||||||
|
$out | $EGREP -i "internal error|assertion failed" \
|
||||||
|
> /dev/null 2>&1
|
||||||
|
# internal error or assertion failed
|
||||||
|
if (( $? == 0 )); then
|
||||||
|
print -u2 $($out)
|
||||||
|
_printerror "$@" "internal error or assertion failure" \
|
||||||
|
" exited $status"
|
||||||
|
elif [[ -n $expect ]] ; then
|
||||||
|
$out | $GREP -i "$expect" > /dev/null 2>&1
|
||||||
|
if (( $? == 0 )); then
|
||||||
|
ret=0
|
||||||
|
else
|
||||||
|
print -u2 $($out)
|
||||||
|
_printerror "$@" "unexpectedly exited $status"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
ret=0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if (( $ret == 0 )); then
|
||||||
|
[[ -n $LOGAPI_DEBUG ]] && print $($out)
|
||||||
|
_printsuccess "$@" "exited $status"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
_recursive_output $logfile "false"
|
||||||
|
return $ret
|
||||||
|
}
|
||||||
|
|
||||||
|
# Execute and print command with status where success equals zero result
|
||||||
|
#
|
||||||
|
# $@ command to execute
|
||||||
|
#
|
||||||
|
# return command exit status
|
||||||
|
|
||||||
|
function log_pos
|
||||||
|
{
|
||||||
|
typeset out=""
|
||||||
|
typeset logfile="/tmp/log.$$"
|
||||||
|
|
||||||
|
while [[ -e $logfile ]]; do
|
||||||
|
logfile="$logfile.$$"
|
||||||
|
done
|
||||||
|
|
||||||
|
"$@" 2>$logfile
|
||||||
|
typeset status=$?
|
||||||
|
out="$CAT $logfile"
|
||||||
|
|
||||||
|
if (( $status != 0 )) ; then
|
||||||
|
print -u2 $($out)
|
||||||
|
_printerror "$@" "exited $status"
|
||||||
|
else
|
||||||
|
$out | $EGREP -i "internal error|assertion failed" \
|
||||||
|
> /dev/null 2>&1
|
||||||
|
# internal error or assertion failed
|
||||||
|
if [[ $? -eq 0 ]]; then
|
||||||
|
print -u2 $($out)
|
||||||
|
_printerror "$@" "internal error or assertion failure" \
|
||||||
|
" exited $status"
|
||||||
|
status=1
|
||||||
|
else
|
||||||
|
[[ -n $LOGAPI_DEBUG ]] && print $($out)
|
||||||
|
_printsuccess "$@"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
_recursive_output $logfile "false"
|
||||||
|
return $status
|
||||||
|
}
|
||||||
|
|
||||||
|
# Set an exit handler
|
||||||
|
#
|
||||||
|
# $@ - function(s) to perform on exit
|
||||||
|
|
||||||
|
function log_onexit
|
||||||
|
{
|
||||||
|
_CLEANUP="$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# Exit functions
|
||||||
|
#
|
||||||
|
|
||||||
|
# Perform cleanup and exit $STF_PASS
|
||||||
|
#
|
||||||
|
# $@ - message text
|
||||||
|
|
||||||
|
function log_pass
|
||||||
|
{
|
||||||
|
_endlog $STF_PASS "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Perform cleanup and exit $STF_FAIL
|
||||||
|
#
|
||||||
|
# $@ - message text
|
||||||
|
|
||||||
|
function log_fail
|
||||||
|
{
|
||||||
|
_endlog $STF_FAIL "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Perform cleanup and exit $STF_UNRESOLVED
|
||||||
|
#
|
||||||
|
# $@ - message text
|
||||||
|
|
||||||
|
function log_unresolved
|
||||||
|
{
|
||||||
|
_endlog $STF_UNRESOLVED "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Perform cleanup and exit $STF_NOTINUSE
|
||||||
|
#
|
||||||
|
# $@ - message text
|
||||||
|
|
||||||
|
function log_notinuse
|
||||||
|
{
|
||||||
|
_endlog $STF_NOTINUSE "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Perform cleanup and exit $STF_UNSUPPORTED
|
||||||
|
#
|
||||||
|
# $@ - message text
|
||||||
|
|
||||||
|
function log_unsupported
|
||||||
|
{
|
||||||
|
_endlog $STF_UNSUPPORTED "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Perform cleanup and exit $STF_UNTESTED
|
||||||
|
#
|
||||||
|
# $@ - message text
|
||||||
|
|
||||||
|
function log_untested
|
||||||
|
{
|
||||||
|
_endlog $STF_UNTESTED "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Perform cleanup and exit $STF_UNINITIATED
|
||||||
|
#
|
||||||
|
# $@ - message text
|
||||||
|
|
||||||
|
function log_uninitiated
|
||||||
|
{
|
||||||
|
_endlog $STF_UNINITIATED "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Perform cleanup and exit $STF_NORESULT
|
||||||
|
#
|
||||||
|
# $@ - message text
|
||||||
|
|
||||||
|
function log_noresult
|
||||||
|
{
|
||||||
|
_endlog $STF_NORESULT "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Perform cleanup and exit $STF_WARNING
|
||||||
|
#
|
||||||
|
# $@ - message text
|
||||||
|
|
||||||
|
function log_warning
|
||||||
|
{
|
||||||
|
_endlog $STF_WARNING "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Perform cleanup and exit $STF_TIMED_OUT
|
||||||
|
#
|
||||||
|
# $@ - message text
|
||||||
|
|
||||||
|
function log_timed_out
|
||||||
|
{
|
||||||
|
_endlog $STF_TIMED_OUT "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Perform cleanup and exit $STF_OTHER
|
||||||
|
#
|
||||||
|
# $@ - message text
|
||||||
|
|
||||||
|
function log_other
|
||||||
|
{
|
||||||
|
_endlog $STF_OTHER "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# Internal functions
|
||||||
|
#
|
||||||
|
|
||||||
|
# Perform cleanup and exit
|
||||||
|
#
|
||||||
|
# $1 - stf exit code
|
||||||
|
# $2-$n - message text
|
||||||
|
|
||||||
|
function _endlog
|
||||||
|
{
|
||||||
|
typeset logfile="/tmp/log.$$"
|
||||||
|
_recursive_output $logfile
|
||||||
|
|
||||||
|
if [[ -n $_CLEANUP ]] ; then
|
||||||
|
typeset cleanup=$_CLEANUP
|
||||||
|
log_onexit ""
|
||||||
|
log_note "Performing local cleanup via log_onexit ($cleanup)"
|
||||||
|
$cleanup
|
||||||
|
fi
|
||||||
|
typeset exitcode=$1
|
||||||
|
shift
|
||||||
|
(( ${#@} > 0 )) && _printline "$@"
|
||||||
|
exit $exitcode
|
||||||
|
}
|
||||||
|
|
||||||
|
# Output a formatted line
|
||||||
|
#
|
||||||
|
# $@ - message text
|
||||||
|
|
||||||
|
function _printline
|
||||||
|
{
|
||||||
|
print "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Output an error message
|
||||||
|
#
|
||||||
|
# $@ - message text
|
||||||
|
|
||||||
|
function _printerror
|
||||||
|
{
|
||||||
|
_printline ERROR: "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Output a success message
|
||||||
|
#
|
||||||
|
# $@ - message text
|
||||||
|
|
||||||
|
function _printsuccess
|
||||||
|
{
|
||||||
|
_printline SUCCESS: "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Output logfiles recursively
|
||||||
|
#
|
||||||
|
# $1 - start file
|
||||||
|
# $2 - indicate whether output the start file itself, default as yes.
|
||||||
|
|
||||||
|
function _recursive_output #logfile
|
||||||
|
{
|
||||||
|
typeset logfile=$1
|
||||||
|
|
||||||
|
while [[ -e $logfile ]]; do
|
||||||
|
if [[ -z $2 || $logfile != $1 ]]; then
|
||||||
|
$CAT $logfile
|
||||||
|
fi
|
||||||
|
$RM -f $logfile
|
||||||
|
logfile="$logfile.$$"
|
||||||
|
done
|
||||||
|
}
|
57
tests/test-runner/include/stf.shlib
Normal file
57
tests/test-runner/include/stf.shlib
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
#
|
||||||
|
# CDDL HEADER START
|
||||||
|
#
|
||||||
|
# The contents of this file are subject to the terms of the
|
||||||
|
# Common Development and Distribution License (the "License").
|
||||||
|
# You may not use this file except in compliance with the License.
|
||||||
|
#
|
||||||
|
# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
||||||
|
# or http://www.opensolaris.org/os/licensing.
|
||||||
|
# See the License for the specific language governing permissions
|
||||||
|
# and limitations under the License.
|
||||||
|
#
|
||||||
|
# When distributing Covered Code, include this CDDL HEADER in each
|
||||||
|
# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
||||||
|
# If applicable, add the following below this CDDL HEADER, with the
|
||||||
|
# fields enclosed by brackets "[]" replaced with your own identifying
|
||||||
|
# information: Portions Copyright [yyyy] [name of copyright owner]
|
||||||
|
#
|
||||||
|
# CDDL HEADER END
|
||||||
|
#
|
||||||
|
|
||||||
|
#
|
||||||
|
# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
|
||||||
|
# Use is subject to license terms.
|
||||||
|
#
|
||||||
|
# Copyright (c) 2012 by Delphix. All rights reserved.
|
||||||
|
#
|
||||||
|
|
||||||
|
|
||||||
|
STF_PASS=0
|
||||||
|
STF_FAIL=1
|
||||||
|
STF_UNRESOLVED=2
|
||||||
|
STF_NOTINUSE=3
|
||||||
|
STF_UNSUPPORTED=4
|
||||||
|
STF_UNTESTED=5
|
||||||
|
STF_UNINITIATED=6
|
||||||
|
STF_NORESULT=7
|
||||||
|
STF_WARNING=8
|
||||||
|
STF_TIMED_OUT=9
|
||||||
|
STF_OTHER=10
|
||||||
|
|
||||||
|
# do this to use the names: eval echo \$STF_RESULT_NAME_${result}
|
||||||
|
STF_RESULT_NAME_0="PASS"
|
||||||
|
STF_RESULT_NAME_1="FAIL"
|
||||||
|
STF_RESULT_NAME_2="UNRESOLVED"
|
||||||
|
STF_RESULT_NAME_3="NOTINUSE"
|
||||||
|
STF_RESULT_NAME_4="UNSUPPORTED"
|
||||||
|
STF_RESULT_NAME_5="UNTESTED"
|
||||||
|
STF_RESULT_NAME_6="UNINITIATED"
|
||||||
|
STF_RESULT_NAME_7="NORESULT"
|
||||||
|
STF_RESULT_NAME_8="WARNING"
|
||||||
|
STF_RESULT_NAME_9="TIMED_OUT"
|
||||||
|
STF_RESULT_NAME_10="OTHER"
|
||||||
|
|
||||||
|
# do this to use the array: ${STF_RESULT_NAMES[$result]}
|
||||||
|
STF_RESULT_NAMES=( "PASS" "FAIL" "UNRESOLVED" "NOTINUSE" "UNSUPPORTED" \
|
||||||
|
"UNTESTED" "UNINITIATED" "NORESULT" "WARNING" "TIMED_OUT" "OTHER" )
|
4
tests/test-runner/man/Makefile.am
Normal file
4
tests/test-runner/man/Makefile.am
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
dist_man_MANS = test-runner.1
|
||||||
|
|
||||||
|
install-data-local:
|
||||||
|
$(INSTALL) -d -m 0755 "$(DESTDIR)$(mandir)/man1"
|
370
tests/test-runner/man/test-runner.1
Normal file
370
tests/test-runner/man/test-runner.1
Normal file
@ -0,0 +1,370 @@
|
|||||||
|
.\"
|
||||||
|
.\" This file and its contents are supplied under the terms of the
|
||||||
|
.\" Common Development and Distribution License ("CDDL"), version 1.0.
|
||||||
|
.\" You may only use this file in accordance with the terms of version
|
||||||
|
.\" 1.0 of the CDDL.
|
||||||
|
.\"
|
||||||
|
.\" A full copy of the text of the CDDL should have accompanied this
|
||||||
|
.\" source. A copy of the CDDL is also available via the Internet at
|
||||||
|
.\" http://www.illumos.org/license/CDDL.
|
||||||
|
.\"
|
||||||
|
.\"
|
||||||
|
.\" Copyright (c) 2012 by Delphix. All rights reserved.
|
||||||
|
.\"
|
||||||
|
.TH run 1 "23 Sep 2012"
|
||||||
|
.SH NAME
|
||||||
|
run \- find, execute, and log the results of tests
|
||||||
|
.SH SYNOPSIS
|
||||||
|
.LP
|
||||||
|
.nf
|
||||||
|
\fBrun\fR [\fB-dgq] [\fB-o\fR \fIoutputdir\fR] [\fB-pP\fR \fIscript\fR] [\fB-t\fR \fIseconds\fR] [\fB-uxX\fR \fIusername\fR]
|
||||||
|
\fIpathname\fR ...
|
||||||
|
.fi
|
||||||
|
|
||||||
|
.LP
|
||||||
|
.nf
|
||||||
|
\fBrun\fR \fB-w\fR \fIrunfile\fR [\fB-gq\fR] [\fB-o\fR \fIoutputdir\fR] [\fB-pP\fR \fIscript\fR] [\fB-t\fR \fIseconds\fR]
|
||||||
|
[\fB-uxX\fR \fIusername\fR] \fIpathname\fR ...
|
||||||
|
.fi
|
||||||
|
|
||||||
|
.LP
|
||||||
|
.nf
|
||||||
|
\fBrun\fR \fB-c\fR \fIrunfile\fR [\fB-dq\fR]
|
||||||
|
.fi
|
||||||
|
|
||||||
|
.LP
|
||||||
|
.nf
|
||||||
|
\fBrun\fR [\fB-h\fR]
|
||||||
|
.fi
|
||||||
|
|
||||||
|
.SH DESCRIPTION
|
||||||
|
.sp
|
||||||
|
.LP
|
||||||
|
The \fBrun\fR command has three basic modes of operation. With neither the
|
||||||
|
\fB-c\fR nor the \fB-w\fR option, \fBrun\fR processes the arguments provided on
|
||||||
|
the command line, adding them to the list for this run. If a specified
|
||||||
|
\fIpathname\fR is an executable file, it is added as a test. If a specified
|
||||||
|
\fIpathname\fR is a directory, the behavior depends upon the \fB-g\fR option.
|
||||||
|
If \fB-g\fR is specified, the directory is treated as a test group. See the
|
||||||
|
section on "Test Groups" below. Without the \fB-g\fR option, \fBrun\fR simply
|
||||||
|
descends into the directory looking for executable files. The tests are then
|
||||||
|
executed, and the results are logged.
|
||||||
|
|
||||||
|
With the \fB-w\fR option, \fBrun\fR finds tests in the manner described above.
|
||||||
|
Rather than executing the tests and logging the results, the test configuration
|
||||||
|
is stored in a \fIrunfile\fR which can be used in future invocations, or edited
|
||||||
|
to modify which tests are executed and which options are applied. Options
|
||||||
|
included on the command line with \fB-w\fR become defaults in the
|
||||||
|
\fIrunfile\fR.
|
||||||
|
|
||||||
|
With the \fB-c\fR option, \fBrun\fR parses a \fIrunfile\fR, which can specify a
|
||||||
|
series of tests and test groups to be executed. The tests are then executed,
|
||||||
|
and the results are logged.
|
||||||
|
.sp
|
||||||
|
.SS "Test Groups"
|
||||||
|
.sp
|
||||||
|
.LP
|
||||||
|
A test group is comprised of a set of executable files, all of which exist in
|
||||||
|
one directory. The options specified on the command line or in a \fIrunfile\fR
|
||||||
|
apply to individual tests in the group. The exception is options pertaining to
|
||||||
|
pre and post scripts, which act on all tests as a group. Rather than running
|
||||||
|
before and after each test, these scripts are run only once each at the start
|
||||||
|
and end of the test group.
|
||||||
|
.SS "Test Execution"
|
||||||
|
.sp
|
||||||
|
.LP
|
||||||
|
The specified tests run serially, and are typically assigned results according
|
||||||
|
to exit values. Tests that exit zero and non-zero are marked "PASS" and "FAIL"
|
||||||
|
respectively. When a pre script fails for a test group, only the post script is
|
||||||
|
executed, and the remaining tests are marked "SKIPPED." Any test that exceeds
|
||||||
|
its \fItimeout\fR is terminated, and marked "KILLED."
|
||||||
|
|
||||||
|
By default, tests are executed with the credentials of the \fBrun\fR script.
|
||||||
|
Executing tests with other credentials is done via \fBsudo\fR(1m), which must
|
||||||
|
be configured to allow execution without prompting for a password. Environment
|
||||||
|
variables from the calling shell are available to individual tests. During test
|
||||||
|
execution, the working directory is changed to \fIoutputdir\fR.
|
||||||
|
.SS "Output Logging"
|
||||||
|
.sp
|
||||||
|
.LP
|
||||||
|
By default, \fBrun\fR will print one line on standard output at the conclusion
|
||||||
|
of each test indicating the test name, result and elapsed time. Additionally,
|
||||||
|
for each invocation of \fBrun\fR, a directory is created using the ISO 8601
|
||||||
|
date format. Within this directory is a file named \fIlog\fR containing all the
|
||||||
|
test output with timestamps, and a directory for each test. Within the test
|
||||||
|
directories, there is one file each for standard output, standard error and
|
||||||
|
merged output. The default location for the \fIoutputdir\fR is
|
||||||
|
\fI/var/tmp/test_results\fR.
|
||||||
|
.SS "Runfiles"
|
||||||
|
.sp
|
||||||
|
.LP
|
||||||
|
The \fIrunfile\fR is an ini style configuration file that describes a test run.
|
||||||
|
The file has one section named "DEFAULT," which contains configuration option
|
||||||
|
names and their values in "name = value" format. The values in this section
|
||||||
|
apply to all the subsequent sections, unless they are also specified there, in
|
||||||
|
which case the default is overridden. The remaining section names are the
|
||||||
|
absolute pathnames of files and direcotries, describing tests and test groups
|
||||||
|
respectively. The legal option names are:
|
||||||
|
.sp
|
||||||
|
.ne 2
|
||||||
|
.na
|
||||||
|
\fBoutputdir\fR = \fIpathname\fR
|
||||||
|
.ad
|
||||||
|
.sp .6
|
||||||
|
.RS 4n
|
||||||
|
The name of the directory that holds test logs.
|
||||||
|
.RE
|
||||||
|
.sp
|
||||||
|
.ne 2
|
||||||
|
.na
|
||||||
|
\fBpre\fR = \fIscript\fR
|
||||||
|
.ad
|
||||||
|
.sp .6
|
||||||
|
.RS 4n
|
||||||
|
Run \fIscript\fR prior to the test or test group.
|
||||||
|
.RE
|
||||||
|
.sp
|
||||||
|
.ne 2
|
||||||
|
.na
|
||||||
|
\fBpre_user\fR = \fIusername\fR
|
||||||
|
.ad
|
||||||
|
.sp .6
|
||||||
|
.RS 4n
|
||||||
|
Execute the pre script as \fIusername\fR.
|
||||||
|
.RE
|
||||||
|
.sp
|
||||||
|
.ne 2
|
||||||
|
.na
|
||||||
|
\fBpost\fR = \fIscript\fR
|
||||||
|
.ad
|
||||||
|
.sp .6
|
||||||
|
.RS 4n
|
||||||
|
Run \fIscript\fR after the test or test group.
|
||||||
|
.RE
|
||||||
|
.sp
|
||||||
|
.ne 2
|
||||||
|
.na
|
||||||
|
\fBpost_user\fR = \fIusername\fR
|
||||||
|
.ad
|
||||||
|
.sp .6
|
||||||
|
.RS 4n
|
||||||
|
Execute the post script as \fIusername\fR.
|
||||||
|
.RE
|
||||||
|
.sp
|
||||||
|
.ne 2
|
||||||
|
.na
|
||||||
|
\fBquiet\fR = [\fITrue\fR|\fIFalse\fR]
|
||||||
|
.ad
|
||||||
|
.sp .6
|
||||||
|
.RS 4n
|
||||||
|
If set to True, only the results summary is printed to standard out.
|
||||||
|
.RE
|
||||||
|
.sp
|
||||||
|
.ne 2
|
||||||
|
.na
|
||||||
|
\fBtests\fR = [\fI'filename'\fR [,...]]
|
||||||
|
.ad
|
||||||
|
.sp .6
|
||||||
|
.RS 4n
|
||||||
|
Specify a list of \fIfilenames\fR for this test group. Only the basename of the
|
||||||
|
absolute path is required. This option is only valid for test groups, and each
|
||||||
|
\fIfilename\fR must be single quoted.
|
||||||
|
.RE
|
||||||
|
.sp
|
||||||
|
.ne 2
|
||||||
|
.na
|
||||||
|
\fBtimeout\fR = \fIn\fR
|
||||||
|
.ad
|
||||||
|
.sp .6
|
||||||
|
.RS 4n
|
||||||
|
A timeout value of \fIn\fR seconds.
|
||||||
|
.RE
|
||||||
|
.sp
|
||||||
|
.ne 2
|
||||||
|
.na
|
||||||
|
\fBuser\fR = \fIusername\fR
|
||||||
|
.ad
|
||||||
|
.sp .6
|
||||||
|
.RS 4n
|
||||||
|
Execute the test or test group as \fIusername\fR.
|
||||||
|
.RE
|
||||||
|
|
||||||
|
.SH OPTIONS
|
||||||
|
.sp
|
||||||
|
.LP
|
||||||
|
The following options are available for the \fBrun\fR command.
|
||||||
|
.sp
|
||||||
|
.ne 2
|
||||||
|
.na
|
||||||
|
\fB-c\fR \fIrunfile\fR
|
||||||
|
.ad
|
||||||
|
.RS 6n
|
||||||
|
Specify a \fIrunfile\fR to be consumed by the run command.
|
||||||
|
.RE
|
||||||
|
|
||||||
|
.ne 2
|
||||||
|
.na
|
||||||
|
\fB-d\fR
|
||||||
|
.ad
|
||||||
|
.RS 6n
|
||||||
|
Dry run mode. Execute no tests, but print a description of each test that would
|
||||||
|
have been run.
|
||||||
|
.RE
|
||||||
|
|
||||||
|
.ne 2
|
||||||
|
.na
|
||||||
|
\fB-g\fR
|
||||||
|
.ad
|
||||||
|
.RS 6n
|
||||||
|
Create test groups from any directories found while searching for tests.
|
||||||
|
.RE
|
||||||
|
|
||||||
|
.ne 2
|
||||||
|
.na
|
||||||
|
\fB-o\fR \fIoutputdir\fR
|
||||||
|
.ad
|
||||||
|
.RS 6n
|
||||||
|
Specify the directory in which to write test results.
|
||||||
|
.RE
|
||||||
|
|
||||||
|
.ne 2
|
||||||
|
.na
|
||||||
|
\fB-p\fR \fIscript\fR
|
||||||
|
.ad
|
||||||
|
.RS 6n
|
||||||
|
Run \fIscript\fR prior to any test or test group.
|
||||||
|
.RE
|
||||||
|
|
||||||
|
.ne 2
|
||||||
|
.na
|
||||||
|
\fB-P\fR \fIscript\fR
|
||||||
|
.ad
|
||||||
|
.RS 6n
|
||||||
|
Run \fIscript\fR after any test or test group.
|
||||||
|
.RE
|
||||||
|
|
||||||
|
.ne 2
|
||||||
|
.na
|
||||||
|
\fB-q\fR
|
||||||
|
.ad
|
||||||
|
.RS 6n
|
||||||
|
Print only the results sumary to the standard output.
|
||||||
|
.RE
|
||||||
|
|
||||||
|
.ne 2
|
||||||
|
.na
|
||||||
|
\fB-t\fR \fIn\fR
|
||||||
|
.ad
|
||||||
|
.RS 6n
|
||||||
|
Specify a timeout value of \fIn\fR seconds per test.
|
||||||
|
.RE
|
||||||
|
|
||||||
|
.ne 2
|
||||||
|
.na
|
||||||
|
\fB-u\fR \fIusername\fR
|
||||||
|
.ad
|
||||||
|
.RS 6n
|
||||||
|
Execute tests or test groups as \fIusername\fR.
|
||||||
|
.RE
|
||||||
|
|
||||||
|
.ne 2
|
||||||
|
.na
|
||||||
|
\fB-w\fR \fIrunfile\fR
|
||||||
|
.ad
|
||||||
|
.RS 6n
|
||||||
|
Specify the name of the \fIrunfile\fR to create.
|
||||||
|
.RE
|
||||||
|
|
||||||
|
.ne 2
|
||||||
|
.na
|
||||||
|
\fB-x\fR \fIusername\fR
|
||||||
|
.ad
|
||||||
|
.RS 6n
|
||||||
|
Execute the pre script as \fIusername\fR.
|
||||||
|
.RE
|
||||||
|
|
||||||
|
.ne 2
|
||||||
|
.na
|
||||||
|
\fB-X\fR \fIusername\fR
|
||||||
|
.ad
|
||||||
|
.RS 6n
|
||||||
|
Execute the post script as \fIusername\fR.
|
||||||
|
.RE
|
||||||
|
|
||||||
|
.SH EXAMPLES
|
||||||
|
.LP
|
||||||
|
\fBExample 1\fR Running ad-hoc tests.
|
||||||
|
.sp
|
||||||
|
.LP
|
||||||
|
This example demonstrates the simplest invocation of \fBrun\fR.
|
||||||
|
|
||||||
|
.sp
|
||||||
|
.in +2
|
||||||
|
.nf
|
||||||
|
% \fBrun my-tests\fR
|
||||||
|
Test: /home/jkennedy/my-tests/test-01 [00:02] [PASS]
|
||||||
|
Test: /home/jkennedy/my-tests/test-02 [00:04] [PASS]
|
||||||
|
Test: /home/jkennedy/my-tests/test-03 [00:01] [PASS]
|
||||||
|
|
||||||
|
Results Summary
|
||||||
|
PASS 3
|
||||||
|
|
||||||
|
Running Time: 00:00:07
|
||||||
|
Percent passed: 100.0%
|
||||||
|
Log directory: /var/tmp/test_results/20120923T180654
|
||||||
|
.fi
|
||||||
|
.in -2
|
||||||
|
|
||||||
|
.LP
|
||||||
|
\fBExample 2\fR Creating a \fIrunfile\fR for future use.
|
||||||
|
.sp
|
||||||
|
.LP
|
||||||
|
This example demonstrates creating a \fIrunfile\fR with non default options.
|
||||||
|
|
||||||
|
.sp
|
||||||
|
.in +2
|
||||||
|
.nf
|
||||||
|
% \fBrun -p setup -x root -g -w new-tests.run new-tests\fR
|
||||||
|
% \fBcat new-tests.run\fR
|
||||||
|
[DEFAULT]
|
||||||
|
pre = setup
|
||||||
|
post_user =
|
||||||
|
quiet = False
|
||||||
|
user =
|
||||||
|
timeout = 60
|
||||||
|
post =
|
||||||
|
pre_user = root
|
||||||
|
outputdir = /var/tmp/test_results
|
||||||
|
|
||||||
|
[/home/jkennedy/new-tests]
|
||||||
|
tests = ['test-01', 'test-02', 'test-03']
|
||||||
|
.fi
|
||||||
|
.in -2
|
||||||
|
|
||||||
|
.SH EXIT STATUS
|
||||||
|
.sp
|
||||||
|
.LP
|
||||||
|
The following exit values are returned:
|
||||||
|
.sp
|
||||||
|
.ne 2
|
||||||
|
.na
|
||||||
|
\fB\fB0\fR\fR
|
||||||
|
.ad
|
||||||
|
.sp .6
|
||||||
|
.RS 4n
|
||||||
|
Successful completion.
|
||||||
|
.RE
|
||||||
|
.sp
|
||||||
|
.ne 2
|
||||||
|
.na
|
||||||
|
\fB\fB1\fR\fR
|
||||||
|
.ad
|
||||||
|
.sp .6
|
||||||
|
.RS 4n
|
||||||
|
An error occurred.
|
||||||
|
.RE
|
||||||
|
|
||||||
|
.SH SEE ALSO
|
||||||
|
.sp
|
||||||
|
.LP
|
||||||
|
\fBsudo\fR(1m)
|
1
tests/zfs-tests/Makefile.am
Normal file
1
tests/zfs-tests/Makefile.am
Normal file
@ -0,0 +1 @@
|
|||||||
|
SUBDIRS = cmd include tests
|
22
tests/zfs-tests/cmd/Makefile.am
Normal file
22
tests/zfs-tests/cmd/Makefile.am
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
EXTRA_DIST = file_common.h
|
||||||
|
|
||||||
|
SUBDIRS = \
|
||||||
|
chg_usr_exec \
|
||||||
|
devname2devid \
|
||||||
|
dir_rd_update \
|
||||||
|
file_check \
|
||||||
|
file_trunc \
|
||||||
|
file_write \
|
||||||
|
largest_file \
|
||||||
|
mkbusy \
|
||||||
|
mkfile \
|
||||||
|
mkfiles \
|
||||||
|
mktree \
|
||||||
|
mmap_exec \
|
||||||
|
mmapwrite \
|
||||||
|
randfree_file \
|
||||||
|
readmmap \
|
||||||
|
rename_dir \
|
||||||
|
rm_lnkcnt_zero_file \
|
||||||
|
threadsappend \
|
||||||
|
xattrtest
|
1
tests/zfs-tests/cmd/chg_usr_exec/.gitignore
vendored
Normal file
1
tests/zfs-tests/cmd/chg_usr_exec/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
/chg_usr_exec
|
6
tests/zfs-tests/cmd/chg_usr_exec/Makefile.am
Normal file
6
tests/zfs-tests/cmd/chg_usr_exec/Makefile.am
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
include $(top_srcdir)/config/Rules.am
|
||||||
|
|
||||||
|
pkgexecdir = $(datadir)/@PACKAGE@/zfs-tests/bin
|
||||||
|
|
||||||
|
pkgexec_PROGRAMS = chg_usr_exec
|
||||||
|
chg_usr_exec_SOURCES = chg_usr_exec.c
|
77
tests/zfs-tests/cmd/chg_usr_exec/chg_usr_exec.c
Normal file
77
tests/zfs-tests/cmd/chg_usr_exec/chg_usr_exec.c
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
/*
|
||||||
|
* CDDL HEADER START
|
||||||
|
*
|
||||||
|
* The contents of this file are subject to the terms of the
|
||||||
|
* Common Development and Distribution License (the "License").
|
||||||
|
* You may not use this file except in compliance with the License.
|
||||||
|
*
|
||||||
|
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
||||||
|
* or http://www.opensolaris.org/os/licensing.
|
||||||
|
* See the License for the specific language governing permissions
|
||||||
|
* and limitations under the License.
|
||||||
|
*
|
||||||
|
* When distributing Covered Code, include this CDDL HEADER in each
|
||||||
|
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
||||||
|
* If applicable, add the following below this CDDL HEADER, with the
|
||||||
|
* fields enclosed by brackets "[]" replaced with your own identifying
|
||||||
|
* information: Portions Copyright [yyyy] [name of copyright owner]
|
||||||
|
*
|
||||||
|
* CDDL HEADER END
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
|
||||||
|
* Use is subject to license terms.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <pwd.h>
|
||||||
|
|
||||||
|
#define EXECSHELL "/bin/sh"
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
char *plogin = NULL;
|
||||||
|
char cmds[BUFSIZ] = { 0 };
|
||||||
|
char sep[] = " ";
|
||||||
|
struct passwd *ppw = NULL;
|
||||||
|
int i, len;
|
||||||
|
|
||||||
|
if (argc < 3 || strlen(argv[1]) == 0) {
|
||||||
|
(void) printf("\tUsage: %s <login> <commands> ...\n", argv[0]);
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
plogin = argv[1];
|
||||||
|
len = 0;
|
||||||
|
for (i = 2; i < argc; i++) {
|
||||||
|
(void) snprintf(cmds+len, sizeof (cmds)-len,
|
||||||
|
"%s%s", argv[i], sep);
|
||||||
|
len += strlen(argv[i]) + strlen(sep);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((ppw = getpwnam(plogin)) == NULL) {
|
||||||
|
perror("getpwnam");
|
||||||
|
return (errno);
|
||||||
|
}
|
||||||
|
if (setgid(ppw->pw_gid) != 0) {
|
||||||
|
perror("setgid");
|
||||||
|
return (errno);
|
||||||
|
}
|
||||||
|
if (setuid(ppw->pw_uid) != 0) {
|
||||||
|
perror("setuid");
|
||||||
|
return (errno);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (execl(EXECSHELL, "sh", "-c", cmds, (char *)NULL) != 0) {
|
||||||
|
perror("execl: " EXECSHELL);
|
||||||
|
return (errno);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
1
tests/zfs-tests/cmd/devname2devid/.gitignore
vendored
Normal file
1
tests/zfs-tests/cmd/devname2devid/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
/devname2devid
|
7
tests/zfs-tests/cmd/devname2devid/Makefile.am
Normal file
7
tests/zfs-tests/cmd/devname2devid/Makefile.am
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
include $(top_srcdir)/config/Rules.am
|
||||||
|
|
||||||
|
pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/bin
|
||||||
|
|
||||||
|
# DISABLED: Not supported under Linux
|
||||||
|
# pkgdata_PROGRAMS = devname2devid
|
||||||
|
# devname2devid_SOURCES = devname2devid.c
|
120
tests/zfs-tests/cmd/devname2devid/devname2devid.c
Normal file
120
tests/zfs-tests/cmd/devname2devid/devname2devid.c
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
/*
|
||||||
|
* CDDL HEADER START
|
||||||
|
*
|
||||||
|
* The contents of this file are subject to the terms of the
|
||||||
|
* Common Development and Distribution License (the "License").
|
||||||
|
* You may not use this file except in compliance with the License.
|
||||||
|
*
|
||||||
|
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
||||||
|
* or http://www.opensolaris.org/os/licensing.
|
||||||
|
* See the License for the specific language governing permissions
|
||||||
|
* and limitations under the License.
|
||||||
|
*
|
||||||
|
* When distributing Covered Code, include this CDDL HEADER in each
|
||||||
|
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
||||||
|
* If applicable, add the following below this CDDL HEADER, with the
|
||||||
|
* fields enclosed by brackets "[]" replaced with your own identifying
|
||||||
|
* information: Portions Copyright [yyyy] [name of copyright owner]
|
||||||
|
*
|
||||||
|
* CDDL HEADER END
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
|
||||||
|
* Use is subject to license terms.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <devid.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Usage: devname2devid <devicepath>
|
||||||
|
*
|
||||||
|
* Examples:
|
||||||
|
* # ./devname2devid /dev/dsk/c1t4d0s0
|
||||||
|
* devid id1,sd@SSEAGATE_ST318404LSUN18G_3BT2G0Z300002146G4CR/a
|
||||||
|
* # ./devname2devid /dev/dsk/c1t4d0
|
||||||
|
* devid id1,sd@SSEAGATE_ST318404LSUN18G_3BT2G0Z300002146G4CR/wd
|
||||||
|
* # ./devname2devid /dev/dsk/c1t4d0s1
|
||||||
|
* devid id1,sd@SSEAGATE_ST318404LSUN18G_3BT2G0Z300002146G4CR/b
|
||||||
|
* #
|
||||||
|
*
|
||||||
|
* This program accepts a disk or disk slice path and prints a
|
||||||
|
* device id.
|
||||||
|
*
|
||||||
|
* Exit values:
|
||||||
|
* 0 - means success
|
||||||
|
* 1 - means failure
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
ddi_devid_t devid;
|
||||||
|
char *minor_name, *devidstr, *device;
|
||||||
|
#ifdef DEBUG
|
||||||
|
devid_nmlist_t *list = NULL;
|
||||||
|
char *search_path;
|
||||||
|
int i;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (argc == 1) {
|
||||||
|
(void) printf("%s <devicepath> [search path]\n",
|
||||||
|
argv[0]);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
device = argv[1];
|
||||||
|
|
||||||
|
if ((fd = open(device, O_RDONLY|O_NDELAY)) < 0) {
|
||||||
|
perror(device);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
if (devid_get(fd, &devid) != 0) {
|
||||||
|
perror("devid_get");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
if (devid_get_minor_name(fd, &minor_name) != 0) {
|
||||||
|
perror("devid_get_minor_name");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
if ((devidstr = devid_str_encode(devid, minor_name)) == 0) {
|
||||||
|
perror("devid_str_encode");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
(void) printf("devid %s\n", devidstr);
|
||||||
|
|
||||||
|
devid_str_free(devidstr);
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
if (argc == 3) {
|
||||||
|
search_path = argv[2];
|
||||||
|
} else {
|
||||||
|
search_path = "/dev/rdsk";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (devid_deviceid_to_nmlist(search_path, devid, DEVID_MINOR_NAME_ALL,
|
||||||
|
&list)) {
|
||||||
|
perror("devid_deviceid_to_nmlist");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* loop through list and process device names and numbers */
|
||||||
|
for (i = 0; list[i].devname != NULL; i++) {
|
||||||
|
(void) printf("devname: %s %p\n", list[i].devname, list[i].dev);
|
||||||
|
}
|
||||||
|
devid_free_nmlist(list);
|
||||||
|
|
||||||
|
#endif /* DEBUG */
|
||||||
|
|
||||||
|
devid_str_free(minor_name);
|
||||||
|
devid_free(devid);
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
1
tests/zfs-tests/cmd/dir_rd_update/.gitignore
vendored
Normal file
1
tests/zfs-tests/cmd/dir_rd_update/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
/dir_rd_update
|
6
tests/zfs-tests/cmd/dir_rd_update/Makefile.am
Normal file
6
tests/zfs-tests/cmd/dir_rd_update/Makefile.am
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
include $(top_srcdir)/config/Rules.am
|
||||||
|
|
||||||
|
pkgexecdir = $(datadir)/@PACKAGE@/zfs-tests/bin
|
||||||
|
|
||||||
|
pkgexec_PROGRAMS = dir_rd_update
|
||||||
|
dir_rd_update_SOURCES = dir_rd_update.c
|
117
tests/zfs-tests/cmd/dir_rd_update/dir_rd_update.c
Normal file
117
tests/zfs-tests/cmd/dir_rd_update/dir_rd_update.c
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
/*
|
||||||
|
* CDDL HEADER START
|
||||||
|
*
|
||||||
|
* The contents of this file are subject to the terms of the
|
||||||
|
* Common Development and Distribution License (the "License").
|
||||||
|
* You may not use this file except in compliance with the License.
|
||||||
|
*
|
||||||
|
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
||||||
|
* or http://www.opensolaris.org/os/licensing.
|
||||||
|
* See the License for the specific language governing permissions
|
||||||
|
* and limitations under the License.
|
||||||
|
*
|
||||||
|
* When distributing Covered Code, include this CDDL HEADER in each
|
||||||
|
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
||||||
|
* If applicable, add the following below this CDDL HEADER, with the
|
||||||
|
* fields enclosed by brackets "[]" replaced with your own identifying
|
||||||
|
* information: Portions Copyright [yyyy] [name of copyright owner]
|
||||||
|
*
|
||||||
|
* CDDL HEADER END
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
|
||||||
|
* Use is subject to license terms.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Assertion:
|
||||||
|
*
|
||||||
|
* A read operation and directory update operation performed
|
||||||
|
* concurrently on the same directory can lead to deadlock
|
||||||
|
* on a UFS logging file system, but not on a ZFS file system.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#define TMP_DIR /tmp
|
||||||
|
|
||||||
|
static char dirpath[256];
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
char *cp1 = "";
|
||||||
|
int i = 0;
|
||||||
|
int ret = 0;
|
||||||
|
int testdd = 0;
|
||||||
|
pid_t pid;
|
||||||
|
static const int op_num = 5;
|
||||||
|
|
||||||
|
if (argc == 1) {
|
||||||
|
(void) printf("Usage: %s <mount point>\n", argv[0]);
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
for (i = 0; i < 256; i++) {
|
||||||
|
dirpath[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
cp1 = argv[1];
|
||||||
|
(void) strcpy(&dirpath[0], (const char *)cp1);
|
||||||
|
(void) strcat(&dirpath[strlen(dirpath)], "TMP_DIR");
|
||||||
|
|
||||||
|
ret = mkdir(dirpath, 0777);
|
||||||
|
if (ret != 0) {
|
||||||
|
if (errno != EEXIST) {
|
||||||
|
(void) printf("%s: mkdir(<%s>, 0777) failed: errno "
|
||||||
|
"(decimal)=%d\n", argv[0], dirpath, errno);
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
testdd = open(dirpath, O_RDONLY|O_RSYNC|O_SYNC|O_DSYNC);
|
||||||
|
if (testdd < 0) {
|
||||||
|
(void) printf("%s: open(<%s>, O_RDONLY|O_RSYNC|O_SYNC|O_DSYNC)"
|
||||||
|
" failed: errno (decimal)=%d\n", argv[0], dirpath, errno);
|
||||||
|
exit(-1);
|
||||||
|
} else {
|
||||||
|
(void) close(testdd);
|
||||||
|
}
|
||||||
|
pid = fork();
|
||||||
|
if (pid > 0) {
|
||||||
|
int fd = open(dirpath, O_RDONLY|O_RSYNC|O_SYNC|O_DSYNC);
|
||||||
|
char buf[16];
|
||||||
|
int rdret;
|
||||||
|
int j = 0;
|
||||||
|
|
||||||
|
while (j < op_num) {
|
||||||
|
(void) sleep(1);
|
||||||
|
rdret = read(fd, buf, 16);
|
||||||
|
if (rdret == -1) {
|
||||||
|
(void) printf("readdir failed");
|
||||||
|
}
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
} else if (pid == 0) {
|
||||||
|
int fd = open(dirpath, O_RDONLY);
|
||||||
|
int chownret;
|
||||||
|
int k = 0;
|
||||||
|
|
||||||
|
while (k < op_num) {
|
||||||
|
(void) sleep(1);
|
||||||
|
chownret = fchown(fd, 0, 0);
|
||||||
|
if (chownret == -1) {
|
||||||
|
(void) printf("chown failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
k++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
1
tests/zfs-tests/cmd/file_check/.gitignore
vendored
Normal file
1
tests/zfs-tests/cmd/file_check/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
/file_check
|
6
tests/zfs-tests/cmd/file_check/Makefile.am
Normal file
6
tests/zfs-tests/cmd/file_check/Makefile.am
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
include $(top_srcdir)/config/Rules.am
|
||||||
|
|
||||||
|
pkgexecdir = $(datadir)/@PACKAGE@/zfs-tests/bin
|
||||||
|
|
||||||
|
pkgexec_PROGRAMS = file_check
|
||||||
|
file_check_SOURCES = file_check.c
|
86
tests/zfs-tests/cmd/file_check/file_check.c
Normal file
86
tests/zfs-tests/cmd/file_check/file_check.c
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
/*
|
||||||
|
* CDDL HEADER START
|
||||||
|
*
|
||||||
|
* The contents of this file are subject to the terms of the
|
||||||
|
* Common Development and Distribution License (the "License").
|
||||||
|
* You may not use this file except in compliance with the License.
|
||||||
|
*
|
||||||
|
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
||||||
|
* or http://www.opensolaris.org/os/licensing.
|
||||||
|
* See the License for the specific language governing permissions
|
||||||
|
* and limitations under the License.
|
||||||
|
*
|
||||||
|
* When distributing Covered Code, include this CDDL HEADER in each
|
||||||
|
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
||||||
|
* If applicable, add the following below this CDDL HEADER, with the
|
||||||
|
* fields enclosed by brackets "[]" replaced with your own identifying
|
||||||
|
* information: Portions Copyright [yyyy] [name of copyright owner]
|
||||||
|
*
|
||||||
|
* CDDL HEADER END
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
|
||||||
|
* Use is subject to license terms.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "../file_common.h"
|
||||||
|
|
||||||
|
static unsigned char bigbuffer[BIGBUFFERSIZE];
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Given a filename, check that the file consists entirely
|
||||||
|
* of a particular pattern. If the pattern is not specified a
|
||||||
|
* default will be used. For default values see file_common.h
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
int bigfd;
|
||||||
|
long i, n;
|
||||||
|
unsigned char fillchar = DATA;
|
||||||
|
int bigbuffersize = BIGBUFFERSIZE;
|
||||||
|
int64_t read_count = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Validate arguments
|
||||||
|
*/
|
||||||
|
if (argc < 2) {
|
||||||
|
(void) printf("Usage: %s filename [pattern]\n",
|
||||||
|
argv[0]);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (argv[2]) {
|
||||||
|
fillchar = atoi(argv[2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Read the file contents and check every character
|
||||||
|
* against the supplied pattern. Abort if the
|
||||||
|
* pattern check fails.
|
||||||
|
*/
|
||||||
|
if ((bigfd = open(argv[1], O_RDONLY)) == -1) {
|
||||||
|
(void) printf("open %s failed %d\n", argv[1], errno);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
do {
|
||||||
|
if ((n = read(bigfd, &bigbuffer, bigbuffersize)) == -1) {
|
||||||
|
(void) printf("read failed (%ld), %d\n", n, errno);
|
||||||
|
exit(errno);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < n; i++) {
|
||||||
|
if (bigbuffer[i] != fillchar) {
|
||||||
|
(void) printf("error %s: 0x%x != 0x%x)\n",
|
||||||
|
argv[1], bigbuffer[i], fillchar);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
read_count += n;
|
||||||
|
} while (n == bigbuffersize);
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
62
tests/zfs-tests/cmd/file_common.h
Normal file
62
tests/zfs-tests/cmd/file_common.h
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
/*
|
||||||
|
* CDDL HEADER START
|
||||||
|
*
|
||||||
|
* The contents of this file are subject to the terms of the
|
||||||
|
* Common Development and Distribution License (the "License").
|
||||||
|
* You may not use this file except in compliance with the License.
|
||||||
|
*
|
||||||
|
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
||||||
|
* or http://www.opensolaris.org/os/licensing.
|
||||||
|
* See the License for the specific language governing permissions
|
||||||
|
* and limitations under the License.
|
||||||
|
*
|
||||||
|
* When distributing Covered Code, include this CDDL HEADER in each
|
||||||
|
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
||||||
|
* If applicable, add the following below this CDDL HEADER, with the
|
||||||
|
* fields enclosed by brackets "[]" replaced with your own identifying
|
||||||
|
* information: Portions Copyright [yyyy] [name of copyright owner]
|
||||||
|
*
|
||||||
|
* CDDL HEADER END
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
|
||||||
|
* Use is subject to license terms.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef FILE_COMMON_H
|
||||||
|
#define FILE_COMMON_H
|
||||||
|
|
||||||
|
/*
|
||||||
|
* header file for file_* utilities. These utilities
|
||||||
|
* are used by the test cases to perform various file
|
||||||
|
* operations (append writes, for example).
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <strings.h>
|
||||||
|
|
||||||
|
#define BLOCKSZ 8192
|
||||||
|
#define DATA 0xa5
|
||||||
|
#define DATA_RANGE 120
|
||||||
|
#define BIGBUFFERSIZE 0x800000
|
||||||
|
#define BIGFILESIZE 20
|
||||||
|
|
||||||
|
extern char *optarg;
|
||||||
|
extern int optind, opterr, optopt;
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* FILE_COMMON_H */
|
1
tests/zfs-tests/cmd/file_trunc/.gitignore
vendored
Normal file
1
tests/zfs-tests/cmd/file_trunc/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
/file_trunc
|
6
tests/zfs-tests/cmd/file_trunc/Makefile.am
Normal file
6
tests/zfs-tests/cmd/file_trunc/Makefile.am
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
include $(top_srcdir)/config/Rules.am
|
||||||
|
|
||||||
|
pkgexecdir = $(datadir)/@PACKAGE@/zfs-tests/bin
|
||||||
|
|
||||||
|
pkgexec_PROGRAMS = file_trunc
|
||||||
|
file_trunc_SOURCES = file_trunc.c
|
244
tests/zfs-tests/cmd/file_trunc/file_trunc.c
Normal file
244
tests/zfs-tests/cmd/file_trunc/file_trunc.c
Normal file
@ -0,0 +1,244 @@
|
|||||||
|
/*
|
||||||
|
* CDDL HEADER START
|
||||||
|
*
|
||||||
|
* The contents of this file are subject to the terms of the
|
||||||
|
* Common Development and Distribution License (the "License").
|
||||||
|
* You may not use this file except in compliance with the License.
|
||||||
|
*
|
||||||
|
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
||||||
|
* or http://www.opensolaris.org/os/licensing.
|
||||||
|
* See the License for the specific language governing permissions
|
||||||
|
* and limitations under the License.
|
||||||
|
*
|
||||||
|
* When distributing Covered Code, include this CDDL HEADER in each
|
||||||
|
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
||||||
|
* If applicable, add the following below this CDDL HEADER, with the
|
||||||
|
* fields enclosed by brackets "[]" replaced with your own identifying
|
||||||
|
* information: Portions Copyright [yyyy] [name of copyright owner]
|
||||||
|
*
|
||||||
|
* CDDL HEADER END
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
|
||||||
|
* Use is subject to license terms.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2012 by Delphix. All rights reserved.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/fcntl.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/statvfs.h>
|
||||||
|
#include <sys/errno.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
#include <sys/param.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <inttypes.h>
|
||||||
|
|
||||||
|
#define FSIZE 256*1024*1024
|
||||||
|
#define BSIZE 512
|
||||||
|
|
||||||
|
/* Initialize Globals */
|
||||||
|
static long fsize = FSIZE;
|
||||||
|
static size_t bsize = BSIZE;
|
||||||
|
static int count = 0;
|
||||||
|
static int rflag = 0;
|
||||||
|
static int seed = 0;
|
||||||
|
static int vflag = 0;
|
||||||
|
static int errflag = 0;
|
||||||
|
static off_t offset = 0;
|
||||||
|
static char *filename = NULL;
|
||||||
|
|
||||||
|
static void usage(char *execname);
|
||||||
|
static void parse_options(int argc, char *argv[]);
|
||||||
|
static void do_write(int fd);
|
||||||
|
static void do_trunc(int fd);
|
||||||
|
|
||||||
|
static void
|
||||||
|
usage(char *execname)
|
||||||
|
{
|
||||||
|
(void) fprintf(stderr,
|
||||||
|
"usage: %s [-b blocksize] [-c count] [-f filesize]"
|
||||||
|
" [-o offset] [-s seed] [-r] [-v] filename\n", execname);
|
||||||
|
(void) exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
int fd = -1;
|
||||||
|
|
||||||
|
parse_options(argc, argv);
|
||||||
|
|
||||||
|
fd = open(filename, O_RDWR|O_CREAT|O_TRUNC, 0666);
|
||||||
|
if (fd < 0) {
|
||||||
|
perror("open");
|
||||||
|
exit(3);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (i < count) {
|
||||||
|
(void) do_write(fd);
|
||||||
|
(void) do_trunc(fd);
|
||||||
|
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
(void) close(fd);
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
parse_options(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
int c;
|
||||||
|
|
||||||
|
extern char *optarg;
|
||||||
|
extern int optind, optopt;
|
||||||
|
|
||||||
|
count = fsize / bsize;
|
||||||
|
seed = time(NULL);
|
||||||
|
while ((c = getopt(argc, argv, "b:c:f:o:rs:v")) != -1) {
|
||||||
|
switch (c) {
|
||||||
|
case 'b':
|
||||||
|
bsize = atoi(optarg);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'c':
|
||||||
|
count = atoi(optarg);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'f':
|
||||||
|
fsize = atoi(optarg);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'o':
|
||||||
|
offset = atoi(optarg);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'r':
|
||||||
|
rflag++;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 's':
|
||||||
|
seed = atoi(optarg);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'v':
|
||||||
|
vflag++;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ':':
|
||||||
|
(void) fprintf(stderr,
|
||||||
|
"Option -%c requires an operand\n", optopt);
|
||||||
|
errflag++;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '?':
|
||||||
|
(void) fprintf(stderr,
|
||||||
|
"Unrecognized option: -%c\n", optopt);
|
||||||
|
errflag++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (errflag) {
|
||||||
|
(void) usage(argv[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (argc <= optind) {
|
||||||
|
(void) fprintf(stderr,
|
||||||
|
"No filename specified\n");
|
||||||
|
usage(argv[0]);
|
||||||
|
}
|
||||||
|
filename = argv[optind];
|
||||||
|
|
||||||
|
if (vflag) {
|
||||||
|
(void) fprintf(stderr, "Seed = %d\n", seed);
|
||||||
|
}
|
||||||
|
srandom(seed);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
do_write(int fd)
|
||||||
|
{
|
||||||
|
off_t roffset = 0;
|
||||||
|
char *buf = NULL;
|
||||||
|
char *rbuf = NULL;
|
||||||
|
|
||||||
|
buf = (char *)calloc(1, bsize);
|
||||||
|
rbuf = (char *)calloc(1, bsize);
|
||||||
|
if (buf == NULL || rbuf == NULL) {
|
||||||
|
perror("malloc");
|
||||||
|
exit(4);
|
||||||
|
}
|
||||||
|
|
||||||
|
roffset = random() % fsize;
|
||||||
|
if (lseek64(fd, (offset + roffset), SEEK_SET) < 0) {
|
||||||
|
perror("lseek");
|
||||||
|
exit(5);
|
||||||
|
}
|
||||||
|
|
||||||
|
strcpy(buf, "ZFS Test Suite Truncation Test");
|
||||||
|
if (write(fd, buf, bsize) < bsize) {
|
||||||
|
perror("write");
|
||||||
|
exit(6);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rflag) {
|
||||||
|
if (lseek64(fd, (offset + roffset), SEEK_SET) < 0) {
|
||||||
|
perror("lseek");
|
||||||
|
exit(7);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (read(fd, rbuf, bsize) < bsize) {
|
||||||
|
perror("read");
|
||||||
|
exit(8);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (memcmp(buf, rbuf, bsize) != 0) {
|
||||||
|
perror("memcmp");
|
||||||
|
exit(9);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (vflag) {
|
||||||
|
(void) fprintf(stderr,
|
||||||
|
"Wrote to offset %" PRId64 "\n", (offset + roffset));
|
||||||
|
if (rflag) {
|
||||||
|
(void) fprintf(stderr,
|
||||||
|
"Read back from offset %" PRId64 "\n",
|
||||||
|
(offset + roffset));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
(void) free(buf);
|
||||||
|
(void) free(rbuf);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
do_trunc(int fd)
|
||||||
|
{
|
||||||
|
off_t roffset = 0;
|
||||||
|
|
||||||
|
roffset = random() % fsize;
|
||||||
|
if (ftruncate64(fd, (offset + roffset)) < 0) {
|
||||||
|
perror("truncate");
|
||||||
|
exit(7);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vflag) {
|
||||||
|
(void) fprintf(stderr, "Truncated at offset %" PRId64 "\n",
|
||||||
|
(offset + roffset));
|
||||||
|
}
|
||||||
|
}
|
1
tests/zfs-tests/cmd/file_write/.gitignore
vendored
Normal file
1
tests/zfs-tests/cmd/file_write/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
/file_write
|
6
tests/zfs-tests/cmd/file_write/Makefile.am
Normal file
6
tests/zfs-tests/cmd/file_write/Makefile.am
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
include $(top_srcdir)/config/Rules.am
|
||||||
|
|
||||||
|
pkgexecdir = $(datadir)/@PACKAGE@/zfs-tests/bin
|
||||||
|
|
||||||
|
pkgexec_PROGRAMS = file_write
|
||||||
|
file_write_SOURCES = file_write.c
|
229
tests/zfs-tests/cmd/file_write/file_write.c
Normal file
229
tests/zfs-tests/cmd/file_write/file_write.c
Normal file
@ -0,0 +1,229 @@
|
|||||||
|
/*
|
||||||
|
* CDDL HEADER START
|
||||||
|
*
|
||||||
|
* The contents of this file are subject to the terms of the
|
||||||
|
* Common Development and Distribution License (the "License").
|
||||||
|
* You may not use this file except in compliance with the License.
|
||||||
|
*
|
||||||
|
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
||||||
|
* or http://www.opensolaris.org/os/licensing.
|
||||||
|
* See the License for the specific language governing permissions
|
||||||
|
* and limitations under the License.
|
||||||
|
*
|
||||||
|
* When distributing Covered Code, include this CDDL HEADER in each
|
||||||
|
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
||||||
|
* If applicable, add the following below this CDDL HEADER, with the
|
||||||
|
* fields enclosed by brackets "[]" replaced with your own identifying
|
||||||
|
* information: Portions Copyright [yyyy] [name of copyright owner]
|
||||||
|
*
|
||||||
|
* CDDL HEADER END
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
|
||||||
|
* Use is subject to license terms.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "../file_common.h"
|
||||||
|
#include <libgen.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
typedef unsigned char uchar_t;
|
||||||
|
typedef long long longlong_t;
|
||||||
|
typedef longlong_t offset_t;
|
||||||
|
|
||||||
|
static unsigned char bigbuffer[BIGBUFFERSIZE];
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Writes (or appends) a given value to a file repeatedly.
|
||||||
|
* See header file for defaults.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static void usage(char *);
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
int bigfd;
|
||||||
|
int c;
|
||||||
|
int oflag = 0;
|
||||||
|
int err = 0;
|
||||||
|
int k;
|
||||||
|
long i;
|
||||||
|
int64_t good_writes = 0;
|
||||||
|
uchar_t nxtfillchar;
|
||||||
|
char *prog = argv[0];
|
||||||
|
/*
|
||||||
|
* Default Parameters
|
||||||
|
*/
|
||||||
|
int write_count = BIGFILESIZE;
|
||||||
|
uchar_t fillchar = DATA;
|
||||||
|
int block_size = BLOCKSZ;
|
||||||
|
char *filename = NULL;
|
||||||
|
char *operation = NULL;
|
||||||
|
offset_t noffset, offset = 0;
|
||||||
|
int verbose = 0;
|
||||||
|
int rsync = 0;
|
||||||
|
int wsync = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Process Arguments
|
||||||
|
*/
|
||||||
|
while ((c = getopt(argc, argv, "b:c:d:s:f:o:vwr")) != -1) {
|
||||||
|
switch (c) {
|
||||||
|
case 'b':
|
||||||
|
block_size = atoi(optarg);
|
||||||
|
break;
|
||||||
|
case 'c':
|
||||||
|
write_count = atoi(optarg);
|
||||||
|
break;
|
||||||
|
case 'd':
|
||||||
|
fillchar = atoi(optarg);
|
||||||
|
break;
|
||||||
|
case 's':
|
||||||
|
offset = atoll(optarg);
|
||||||
|
break;
|
||||||
|
case 'f':
|
||||||
|
filename = optarg;
|
||||||
|
break;
|
||||||
|
case 'o':
|
||||||
|
operation = optarg;
|
||||||
|
break;
|
||||||
|
case 'v':
|
||||||
|
verbose = 1;
|
||||||
|
break;
|
||||||
|
case 'w':
|
||||||
|
wsync = 1;
|
||||||
|
break;
|
||||||
|
case 'r':
|
||||||
|
rsync = 1;
|
||||||
|
break;
|
||||||
|
case '?':
|
||||||
|
(void) printf("unknown arg %c\n", optopt);
|
||||||
|
usage(prog);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Validate Parameters
|
||||||
|
*/
|
||||||
|
if (!filename) {
|
||||||
|
(void) printf("Filename not specified (-f <file>)\n");
|
||||||
|
err++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!operation) {
|
||||||
|
(void) printf("Operation not specified (-o <operation>).\n");
|
||||||
|
err++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (block_size > BIGBUFFERSIZE) {
|
||||||
|
(void) printf("block_size is too large max==%d.\n",
|
||||||
|
BIGBUFFERSIZE);
|
||||||
|
err++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (err) usage(prog);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Prepare the buffer and determine the requested operation
|
||||||
|
*/
|
||||||
|
nxtfillchar = fillchar;
|
||||||
|
k = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < block_size; i++) {
|
||||||
|
bigbuffer[i] = nxtfillchar;
|
||||||
|
|
||||||
|
if (fillchar == 0) {
|
||||||
|
if ((k % DATA_RANGE) == 0) {
|
||||||
|
k = 0;
|
||||||
|
}
|
||||||
|
nxtfillchar = k++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* using the strncmp of operation will make the operation match the
|
||||||
|
* first shortest match - as the operations are unique from the first
|
||||||
|
* character this means that we match single character operations
|
||||||
|
*/
|
||||||
|
if ((strncmp(operation, "create", strlen(operation) + 1)) == 0 ||
|
||||||
|
(strncmp(operation, "overwrite", strlen(operation) + 1)) == 0) {
|
||||||
|
oflag = (O_RDWR|O_CREAT);
|
||||||
|
} else if ((strncmp(operation, "append", strlen(operation) + 1)) == 0) {
|
||||||
|
oflag = (O_RDWR|O_APPEND);
|
||||||
|
} else {
|
||||||
|
(void) printf("valid operations are <create|append> not '%s'\n",
|
||||||
|
operation);
|
||||||
|
usage(prog);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rsync) {
|
||||||
|
oflag = oflag | O_RSYNC;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wsync) {
|
||||||
|
oflag = oflag | O_SYNC;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Given an operation (create/overwrite/append), open the file
|
||||||
|
* accordingly and perform a write of the appropriate type.
|
||||||
|
*/
|
||||||
|
if ((bigfd = open(filename, oflag, 0666)) == -1) {
|
||||||
|
(void) printf("open %s: failed [%s]%d. Aborting!\n", filename,
|
||||||
|
strerror(errno), errno);
|
||||||
|
exit(errno);
|
||||||
|
}
|
||||||
|
noffset = lseek64(bigfd, offset, SEEK_SET);
|
||||||
|
if (noffset != offset) {
|
||||||
|
(void) printf("llseek %s (%lld/%lld) failed [%s]%d.Aborting!\n",
|
||||||
|
filename, offset, noffset, strerror(errno), errno);
|
||||||
|
exit(errno);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (verbose) {
|
||||||
|
(void) printf("%s: block_size = %d, write_count = %d, "
|
||||||
|
"offset = %lld, data = %s%d\n", filename, block_size,
|
||||||
|
write_count, offset,
|
||||||
|
(fillchar == 0) ? "0->" : "",
|
||||||
|
(fillchar == 0) ? DATA_RANGE : fillchar);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < write_count; i++) {
|
||||||
|
ssize_t n;
|
||||||
|
|
||||||
|
if ((n = write(bigfd, &bigbuffer, block_size)) == -1) {
|
||||||
|
(void) printf("write failed (%ld), good_writes = %"
|
||||||
|
PRId64 ", " "error: %s[%d]\n",
|
||||||
|
(long)n, good_writes,
|
||||||
|
strerror(errno),
|
||||||
|
errno);
|
||||||
|
exit(errno);
|
||||||
|
}
|
||||||
|
good_writes++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (verbose) {
|
||||||
|
(void) printf("Success: good_writes = %" PRId64 "(%"
|
||||||
|
PRId64 ")\n", good_writes, (good_writes * block_size));
|
||||||
|
}
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
usage(char *prog)
|
||||||
|
{
|
||||||
|
(void) printf("Usage: %s [-v] -o {create,overwrite,append} -f file_name"
|
||||||
|
" [-b block_size]\n"
|
||||||
|
"\t[-s offset] [-c write_count] [-d data]\n"
|
||||||
|
"\twhere [data] equal to zero causes chars "
|
||||||
|
"0->%d to be repeated throughout\n", prog, DATA_RANGE);
|
||||||
|
|
||||||
|
exit(1);
|
||||||
|
}
|
1
tests/zfs-tests/cmd/largest_file/.gitignore
vendored
Normal file
1
tests/zfs-tests/cmd/largest_file/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
/largest_file
|
6
tests/zfs-tests/cmd/largest_file/Makefile.am
Normal file
6
tests/zfs-tests/cmd/largest_file/Makefile.am
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
include $(top_srcdir)/config/Rules.am
|
||||||
|
|
||||||
|
pkgexecdir = $(datadir)/@PACKAGE@/zfs-tests/bin
|
||||||
|
|
||||||
|
pkgexec_PROGRAMS = largest_file
|
||||||
|
largest_file_SOURCES = largest_file.c
|
140
tests/zfs-tests/cmd/largest_file/largest_file.c
Normal file
140
tests/zfs-tests/cmd/largest_file/largest_file.c
Normal file
@ -0,0 +1,140 @@
|
|||||||
|
/*
|
||||||
|
* CDDL HEADER START
|
||||||
|
*
|
||||||
|
* The contents of this file are subject to the terms of the
|
||||||
|
* Common Development and Distribution License (the "License").
|
||||||
|
* You may not use this file except in compliance with the License.
|
||||||
|
*
|
||||||
|
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
||||||
|
* or http://www.opensolaris.org/os/licensing.
|
||||||
|
* See the License for the specific language governing permissions
|
||||||
|
* and limitations under the License.
|
||||||
|
*
|
||||||
|
* When distributing Covered Code, include this CDDL HEADER in each
|
||||||
|
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
||||||
|
* If applicable, add the following below this CDDL HEADER, with the
|
||||||
|
* fields enclosed by brackets "[]" replaced with your own identifying
|
||||||
|
* information: Portions Copyright [yyyy] [name of copyright owner]
|
||||||
|
*
|
||||||
|
* CDDL HEADER END
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
|
||||||
|
* Use is subject to license terms.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2012 by Delphix. All rights reserved.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "../file_common.h"
|
||||||
|
#include <sys/param.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
typedef long long offset_t;
|
||||||
|
#define MAXOFFSET_T LLONG_MAX
|
||||||
|
|
||||||
|
/*
|
||||||
|
* --------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Assertion:
|
||||||
|
* The last byte of the largest file size can be
|
||||||
|
* accessed without any errors. Also, the writing
|
||||||
|
* beyond the last byte of the largest file size
|
||||||
|
* will produce an errno of EFBIG.
|
||||||
|
*
|
||||||
|
* --------------------------------------------------------------
|
||||||
|
* If the write() system call below returns a "1",
|
||||||
|
* then the last byte can be accessed.
|
||||||
|
* --------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
static void sigxfsz(int);
|
||||||
|
static void usage(char *);
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
int fd = 0;
|
||||||
|
offset_t offset = (MAXOFFSET_T - 1);
|
||||||
|
offset_t llseek_ret = 0;
|
||||||
|
int write_ret = 0;
|
||||||
|
int err = 0;
|
||||||
|
char mybuf[5];
|
||||||
|
char *testfile;
|
||||||
|
mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
|
||||||
|
|
||||||
|
if (argc != 2) {
|
||||||
|
usage(argv[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
(void) sigset(SIGXFSZ, sigxfsz);
|
||||||
|
|
||||||
|
testfile = strdup(argv[1]);
|
||||||
|
|
||||||
|
fd = open(testfile, O_CREAT | O_RDWR, mode);
|
||||||
|
if (fd < 0) {
|
||||||
|
perror("Failed to create testfile");
|
||||||
|
err = errno;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
llseek_ret = lseek64(fd, offset, SEEK_SET);
|
||||||
|
if (llseek_ret < 0) {
|
||||||
|
perror("Failed to seek to end of testfile");
|
||||||
|
err = errno;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
write_ret = write(fd, mybuf, 1);
|
||||||
|
if (write_ret < 0) {
|
||||||
|
perror("Failed to write to end of file");
|
||||||
|
err = errno;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
offset = 0;
|
||||||
|
llseek_ret = lseek64(fd, offset, SEEK_CUR);
|
||||||
|
if (llseek_ret < 0) {
|
||||||
|
perror("Failed to seek to end of file");
|
||||||
|
err = errno;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
write_ret = write(fd, mybuf, 1);
|
||||||
|
if (write_ret < 0) {
|
||||||
|
if (errno == EFBIG) {
|
||||||
|
(void) printf("write errno=EFBIG: success\n");
|
||||||
|
err = 0;
|
||||||
|
} else {
|
||||||
|
perror("Did not receive EFBIG");
|
||||||
|
err = errno;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
(void) printf("write completed successfully, test failed\n");
|
||||||
|
err = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
(void) unlink(testfile);
|
||||||
|
free(testfile);
|
||||||
|
return (err);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
usage(char *name)
|
||||||
|
{
|
||||||
|
(void) printf("%s <testfile>\n", name);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ARGSUSED */
|
||||||
|
static void
|
||||||
|
sigxfsz(int signo)
|
||||||
|
{
|
||||||
|
(void) printf("\nlargest_file: sigxfsz() caught SIGXFSZ\n");
|
||||||
|
}
|
1
tests/zfs-tests/cmd/mkbusy/.gitignore
vendored
Normal file
1
tests/zfs-tests/cmd/mkbusy/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
/mkbusy
|
6
tests/zfs-tests/cmd/mkbusy/Makefile.am
Normal file
6
tests/zfs-tests/cmd/mkbusy/Makefile.am
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
include $(top_srcdir)/config/Rules.am
|
||||||
|
|
||||||
|
pkgexecdir = $(datadir)/@PACKAGE@/zfs-tests/bin
|
||||||
|
|
||||||
|
pkgexec_PROGRAMS = mkbusy
|
||||||
|
mkbusy_SOURCES = mkbusy.c
|
183
tests/zfs-tests/cmd/mkbusy/mkbusy.c
Normal file
183
tests/zfs-tests/cmd/mkbusy/mkbusy.c
Normal file
@ -0,0 +1,183 @@
|
|||||||
|
/*
|
||||||
|
* This file and its contents are supplied under the terms of the
|
||||||
|
* Common Development and Distribution License ("CDDL"), version 1.0.
|
||||||
|
* You may only use this file in accordance with the terms of version
|
||||||
|
* 1.0 of the CDDL.
|
||||||
|
*
|
||||||
|
* A full copy of the text of the CDDL should have accompanied this
|
||||||
|
* source. A copy of the CDDL is also available via the Internet at
|
||||||
|
* http://www.illumos.org/license/CDDL.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2012 by Delphix. All rights reserved.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Make a directory busy. If the argument is an existing file or directory,
|
||||||
|
* simply open it directly and pause. If not, verify that the parent directory
|
||||||
|
* exists, and create a new file in that directory.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <dirent.h>
|
||||||
|
#include <strings.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
typedef enum boolean { B_FALSE, B_TRUE } boolean_t;
|
||||||
|
|
||||||
|
static void
|
||||||
|
usage(char *progname)
|
||||||
|
{
|
||||||
|
(void) fprintf(stderr, "Usage: %s <dirname|filename>\n", progname);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
fail(char *err, int rval)
|
||||||
|
{
|
||||||
|
perror(err);
|
||||||
|
exit(rval);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
daemonize(void)
|
||||||
|
{
|
||||||
|
pid_t pid;
|
||||||
|
|
||||||
|
if ((pid = fork()) < 0) {
|
||||||
|
fail("fork", 1);
|
||||||
|
} else if (pid != 0) {
|
||||||
|
(void) fprintf(stdout, "%ld\n", (long)pid);
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
(void) setsid();
|
||||||
|
(void) close(0);
|
||||||
|
(void) close(1);
|
||||||
|
(void) close(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
int ret, c;
|
||||||
|
boolean_t isdir = B_FALSE;
|
||||||
|
boolean_t fflag = B_FALSE;
|
||||||
|
boolean_t rflag = B_FALSE;
|
||||||
|
struct stat sbuf;
|
||||||
|
char *fpath = NULL;
|
||||||
|
char *prog = argv[0];
|
||||||
|
|
||||||
|
while ((c = getopt(argc, argv, "fr")) != -1) {
|
||||||
|
switch (c) {
|
||||||
|
/* Open the file or directory read only */
|
||||||
|
case 'r':
|
||||||
|
rflag = B_TRUE;
|
||||||
|
break;
|
||||||
|
/* Run in the foreground */
|
||||||
|
case 'f':
|
||||||
|
fflag = B_TRUE;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
usage(prog);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
argc -= optind;
|
||||||
|
argv += optind;
|
||||||
|
|
||||||
|
if (argc != 1)
|
||||||
|
usage(prog);
|
||||||
|
|
||||||
|
if ((ret = stat(argv[0], &sbuf)) != 0) {
|
||||||
|
char *arg, *dname, *fname;
|
||||||
|
int arglen, dlen, flen;
|
||||||
|
char *slash;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The argument supplied doesn't exist. Copy the path, and
|
||||||
|
* remove the trailing slash if presnt.
|
||||||
|
*/
|
||||||
|
if ((arg = strdup(argv[0])) == NULL)
|
||||||
|
fail("strdup", 1);
|
||||||
|
arglen = strlen(arg);
|
||||||
|
if (arg[arglen - 1] == '/')
|
||||||
|
arg[arglen - 1] = '\0';
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get the directory and file names, using the current directory
|
||||||
|
* if the provided path doesn't specify a directory at all.
|
||||||
|
*/
|
||||||
|
if ((slash = strrchr(arg, '/')) == NULL) {
|
||||||
|
dname = strdup(".");
|
||||||
|
fname = strdup(arg);
|
||||||
|
} else {
|
||||||
|
*slash = '\0';
|
||||||
|
dname = strdup(arg);
|
||||||
|
fname = strdup(slash + 1);
|
||||||
|
}
|
||||||
|
free(arg);
|
||||||
|
if (dname == NULL || fname == NULL)
|
||||||
|
fail("strdup", 1);
|
||||||
|
dlen = strlen(dname);
|
||||||
|
flen = strlen(fname);
|
||||||
|
|
||||||
|
/* The directory portion of the path must exist */
|
||||||
|
if ((ret = stat(dname, &sbuf)) != 0 || !(sbuf.st_mode &
|
||||||
|
S_IFDIR))
|
||||||
|
usage(prog);
|
||||||
|
|
||||||
|
if ((fpath = (char *)malloc(dlen + 1 + flen + 1)) == NULL)
|
||||||
|
fail("malloc", 1);
|
||||||
|
(void) memset(fpath, '\0', dlen + 1 + flen + 1);
|
||||||
|
|
||||||
|
(void) strncpy(fpath, dname, dlen);
|
||||||
|
fpath[dlen] = '/';
|
||||||
|
(void) strncat(fpath, fname, flen);
|
||||||
|
free(dname);
|
||||||
|
free(fname);
|
||||||
|
} else if ((sbuf.st_mode & S_IFMT) == S_IFREG ||
|
||||||
|
(sbuf.st_mode & S_IFMT) == S_IFLNK ||
|
||||||
|
(sbuf.st_mode & S_IFMT) == S_IFCHR ||
|
||||||
|
(sbuf.st_mode & S_IFMT) == S_IFBLK) {
|
||||||
|
fpath = strdup(argv[0]);
|
||||||
|
} else if ((sbuf.st_mode & S_IFMT) == S_IFDIR) {
|
||||||
|
fpath = strdup(argv[0]);
|
||||||
|
isdir = B_TRUE;
|
||||||
|
} else {
|
||||||
|
usage(prog);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fpath == NULL)
|
||||||
|
fail("strdup", 1);
|
||||||
|
|
||||||
|
if (isdir == B_FALSE) {
|
||||||
|
int fd, flags;
|
||||||
|
mode_t mode = S_IRUSR | S_IWUSR;
|
||||||
|
|
||||||
|
flags = rflag == B_FALSE ? O_CREAT | O_RDWR : O_RDONLY;
|
||||||
|
|
||||||
|
if ((fd = open(fpath, flags, mode)) < 0)
|
||||||
|
fail("open", 1);
|
||||||
|
} else {
|
||||||
|
DIR *dp;
|
||||||
|
|
||||||
|
if ((dp = opendir(fpath)) == NULL)
|
||||||
|
fail("opendir", 1);
|
||||||
|
}
|
||||||
|
free(fpath);
|
||||||
|
|
||||||
|
if (fflag == B_FALSE)
|
||||||
|
daemonize();
|
||||||
|
(void) pause();
|
||||||
|
|
||||||
|
/* NOTREACHED */
|
||||||
|
return (0);
|
||||||
|
}
|
1
tests/zfs-tests/cmd/mkfile/.gitignore
vendored
Normal file
1
tests/zfs-tests/cmd/mkfile/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
/mkfile
|
6
tests/zfs-tests/cmd/mkfile/Makefile.am
Normal file
6
tests/zfs-tests/cmd/mkfile/Makefile.am
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
include $(top_srcdir)/config/Rules.am
|
||||||
|
|
||||||
|
pkgexecdir = $(datadir)/@PACKAGE@/zfs-tests/bin
|
||||||
|
|
||||||
|
pkgexec_PROGRAMS = mkfile
|
||||||
|
mkfile_SOURCES = mkfile.c
|
275
tests/zfs-tests/cmd/mkfile/mkfile.c
Normal file
275
tests/zfs-tests/cmd/mkfile/mkfile.c
Normal file
@ -0,0 +1,275 @@
|
|||||||
|
/*
|
||||||
|
* CDDL HEADER START
|
||||||
|
*
|
||||||
|
* The contents of this file are subject to the terms of the
|
||||||
|
* Common Development and Distribution License, Version 1.0 only
|
||||||
|
* (the "License"). You may not use this file except in compliance
|
||||||
|
* with the License.
|
||||||
|
*
|
||||||
|
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
||||||
|
* or http://www.opensolaris.org/os/licensing.
|
||||||
|
* See the License for the specific language governing permissions
|
||||||
|
* and limitations under the License.
|
||||||
|
*
|
||||||
|
* When distributing Covered Code, include this CDDL HEADER in each
|
||||||
|
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
||||||
|
* If applicable, add the following below this CDDL HEADER, with the
|
||||||
|
* fields enclosed by brackets "[]" replaced with your own identifying
|
||||||
|
* information: Portions Copyright [yyyy] [name of copyright owner]
|
||||||
|
*
|
||||||
|
* CDDL HEADER END
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright 2005 Sun Microsystems, Inc. All rights reserved.
|
||||||
|
* Use is subject to license terms.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <libintl.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#define MIN(a, b) ((a) < (b) ? (a) : (b))
|
||||||
|
|
||||||
|
#define BLOCK_SIZE 512 /* bytes */
|
||||||
|
#define KILOBYTE 1024
|
||||||
|
#define MEGABYTE (KILOBYTE * KILOBYTE)
|
||||||
|
#define GIGABYTE (KILOBYTE * MEGABYTE)
|
||||||
|
|
||||||
|
#define FILE_MODE (S_ISVTX + S_IRUSR + S_IWUSR)
|
||||||
|
|
||||||
|
typedef long long offset_t;
|
||||||
|
|
||||||
|
static void usage(void);
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
char *opts;
|
||||||
|
off_t size;
|
||||||
|
size_t len;
|
||||||
|
size_t mult = 1;
|
||||||
|
char *buf = NULL;
|
||||||
|
size_t bufsz = 0;
|
||||||
|
int errors = 0;
|
||||||
|
int i;
|
||||||
|
int verbose = 0; /* option variable */
|
||||||
|
int nobytes = 0; /* option variable */
|
||||||
|
int saverr;
|
||||||
|
|
||||||
|
if (argc == 1)
|
||||||
|
usage();
|
||||||
|
|
||||||
|
while (argv[1] && argv[1][0] == '-') {
|
||||||
|
opts = &argv[1][0];
|
||||||
|
while (*(++opts)) {
|
||||||
|
switch (*opts) {
|
||||||
|
case 'v':
|
||||||
|
verbose++;
|
||||||
|
break;
|
||||||
|
case 'n':
|
||||||
|
nobytes++;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
usage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
argc--;
|
||||||
|
argv++;
|
||||||
|
}
|
||||||
|
if (argc < 3)
|
||||||
|
usage();
|
||||||
|
|
||||||
|
len = strlen(argv[1]);
|
||||||
|
if (len && isalpha(argv[1][len-1])) {
|
||||||
|
switch (argv[1][len-1]) {
|
||||||
|
case 'k':
|
||||||
|
case 'K':
|
||||||
|
mult = KILOBYTE;
|
||||||
|
break;
|
||||||
|
case 'b':
|
||||||
|
case 'B':
|
||||||
|
mult = BLOCK_SIZE;
|
||||||
|
break;
|
||||||
|
case 'm':
|
||||||
|
case 'M':
|
||||||
|
mult = MEGABYTE;
|
||||||
|
break;
|
||||||
|
case 'g':
|
||||||
|
case 'G':
|
||||||
|
mult = GIGABYTE;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
(void) fprintf(stderr,
|
||||||
|
gettext("unknown size %s\n"), argv[1]);
|
||||||
|
usage();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i <= (len-2); i++) {
|
||||||
|
if (!isdigit(argv[1][i])) {
|
||||||
|
(void) fprintf(stderr,
|
||||||
|
gettext("unknown size %s\n"), argv[1]);
|
||||||
|
usage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
argv[1][len-1] = '\0';
|
||||||
|
}
|
||||||
|
size = ((off_t)atoll(argv[1]) * (off_t)mult);
|
||||||
|
|
||||||
|
argv++;
|
||||||
|
argc--;
|
||||||
|
|
||||||
|
while (argc > 1) {
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
if (verbose)
|
||||||
|
(void) fprintf(stdout, gettext("%s %lld bytes\n"),
|
||||||
|
argv[1], (offset_t)size);
|
||||||
|
fd = open(argv[1], O_CREAT|O_TRUNC|O_RDWR, FILE_MODE);
|
||||||
|
if (fd < 0) {
|
||||||
|
saverr = errno;
|
||||||
|
(void) fprintf(stderr,
|
||||||
|
gettext("Could not open %s: %s\n"),
|
||||||
|
argv[1], strerror(saverr));
|
||||||
|
errors++;
|
||||||
|
argv++;
|
||||||
|
argc--;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (lseek(fd, (off_t)size-1, SEEK_SET) < 0) {
|
||||||
|
saverr = errno;
|
||||||
|
(void) fprintf(stderr, gettext(
|
||||||
|
"Could not seek to offset %ld in %s: %s\n"),
|
||||||
|
(unsigned long)size-1, argv[1], strerror(saverr));
|
||||||
|
(void) close(fd);
|
||||||
|
errors++;
|
||||||
|
argv++;
|
||||||
|
argc--;
|
||||||
|
continue;
|
||||||
|
} else if (write(fd, "", 1) != 1) {
|
||||||
|
saverr = errno;
|
||||||
|
(void) fprintf(stderr, gettext(
|
||||||
|
"Could not set length of %s: %s\n"),
|
||||||
|
argv[1], strerror(saverr));
|
||||||
|
(void) close(fd);
|
||||||
|
errors++;
|
||||||
|
argv++;
|
||||||
|
argc--;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!nobytes) {
|
||||||
|
off_t written = 0;
|
||||||
|
struct stat64 st;
|
||||||
|
|
||||||
|
if (lseek(fd, (off_t)0, SEEK_SET) < 0) {
|
||||||
|
saverr = errno;
|
||||||
|
(void) fprintf(stderr, gettext(
|
||||||
|
"Could not seek to beginning of %s: %s\n"),
|
||||||
|
argv[1], strerror(saverr));
|
||||||
|
(void) close(fd);
|
||||||
|
errors++;
|
||||||
|
argv++;
|
||||||
|
argc--;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (fstat64(fd, &st) < 0) {
|
||||||
|
saverr = errno;
|
||||||
|
(void) fprintf(stderr, gettext(
|
||||||
|
"Could not fstat64 %s: %s\n"),
|
||||||
|
argv[1], strerror(saverr));
|
||||||
|
(void) close(fd);
|
||||||
|
errors++;
|
||||||
|
argv++;
|
||||||
|
argc--;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (bufsz != st.st_blksize) {
|
||||||
|
if (buf)
|
||||||
|
free(buf);
|
||||||
|
bufsz = (size_t)st.st_blksize;
|
||||||
|
buf = calloc(bufsz, 1);
|
||||||
|
if (buf == NULL) {
|
||||||
|
(void) fprintf(stderr, gettext(
|
||||||
|
"Could not allocate buffer of"
|
||||||
|
" size %d\n"), (int)bufsz);
|
||||||
|
(void) close(fd);
|
||||||
|
bufsz = 0;
|
||||||
|
errors++;
|
||||||
|
argv++;
|
||||||
|
argc--;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (written < size) {
|
||||||
|
ssize_t result;
|
||||||
|
size_t bytes = (size_t)MIN(bufsz, size-written);
|
||||||
|
|
||||||
|
if ((result = write(fd, buf, bytes)) !=
|
||||||
|
(ssize_t)bytes) {
|
||||||
|
saverr = errno;
|
||||||
|
if (result < 0)
|
||||||
|
result = 0;
|
||||||
|
written += result;
|
||||||
|
(void) fprintf(stderr, gettext(
|
||||||
|
"%s: initialized %lu of %lu bytes: %s\n"),
|
||||||
|
argv[1], (unsigned long)written,
|
||||||
|
(unsigned long)size,
|
||||||
|
strerror(saverr));
|
||||||
|
errors++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
written += bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A write(2) call in the above loop failed so
|
||||||
|
* close out this file and go on (error was
|
||||||
|
* already incremented when the write(2) failed).
|
||||||
|
*/
|
||||||
|
if (written < size) {
|
||||||
|
(void) close(fd);
|
||||||
|
argv++;
|
||||||
|
argc--;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (close(fd) < 0) {
|
||||||
|
saverr = errno;
|
||||||
|
(void) fprintf(stderr, gettext(
|
||||||
|
"Error encountered when closing %s: %s\n"),
|
||||||
|
argv[1], strerror(saverr));
|
||||||
|
errors++;
|
||||||
|
argv++;
|
||||||
|
argc--;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Only set the modes (including the sticky bit) if we
|
||||||
|
* had no problems. It is not an error for the chmod(2)
|
||||||
|
* to fail, but do issue a warning.
|
||||||
|
*/
|
||||||
|
if (chmod(argv[1], FILE_MODE) < 0)
|
||||||
|
(void) fprintf(stderr, gettext(
|
||||||
|
"warning: couldn't set mode to %#o\n"), FILE_MODE);
|
||||||
|
|
||||||
|
argv++;
|
||||||
|
argc--;
|
||||||
|
}
|
||||||
|
return (errors);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void usage()
|
||||||
|
{
|
||||||
|
(void) fprintf(stderr, gettext(
|
||||||
|
"Usage: mkfile [-nv] <size>[g|k|b|m] <name1> [<name2>] ...\n"));
|
||||||
|
exit(1);
|
||||||
|
/* NOTREACHED */
|
||||||
|
}
|
1
tests/zfs-tests/cmd/mkfiles/.gitignore
vendored
Normal file
1
tests/zfs-tests/cmd/mkfiles/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
/mkfiles
|
6
tests/zfs-tests/cmd/mkfiles/Makefile.am
Normal file
6
tests/zfs-tests/cmd/mkfiles/Makefile.am
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
include $(top_srcdir)/config/Rules.am
|
||||||
|
|
||||||
|
pkgexecdir = $(datadir)/@PACKAGE@/zfs-tests/bin
|
||||||
|
|
||||||
|
pkgexec_PROGRAMS = mkfiles
|
||||||
|
mkfiles_SOURCES = mkfiles.c
|
65
tests/zfs-tests/cmd/mkfiles/mkfiles.c
Normal file
65
tests/zfs-tests/cmd/mkfiles/mkfiles.c
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
/*
|
||||||
|
* This file and its contents are supplied under the terms of the
|
||||||
|
* Common Development and Distribution License ("CDDL"), version 1.0.
|
||||||
|
* You may only use this file in accordance with the terms of version
|
||||||
|
* 1.0 of the CDDL.
|
||||||
|
*
|
||||||
|
* A full copy of the text of the CDDL should have accompanied this
|
||||||
|
* source. A copy of the CDDL is also available via the Internet at
|
||||||
|
* http://www.illumos.org/license/CDDL.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2016 by Delphix. All rights reserved.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/param.h>
|
||||||
|
|
||||||
|
#define MAX_INT_LENGTH 10
|
||||||
|
|
||||||
|
static void
|
||||||
|
usage(char *msg, int exit_value)
|
||||||
|
{
|
||||||
|
(void) fprintf(stderr, "mkfiles basename max_file [min_file]\n");
|
||||||
|
(void) fprintf(stderr, "%s\n", msg);
|
||||||
|
exit(exit_value);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
unsigned int numfiles = 0;
|
||||||
|
unsigned int first_file = 0;
|
||||||
|
unsigned int i;
|
||||||
|
char buf[MAXPATHLEN];
|
||||||
|
|
||||||
|
if (argc < 3 || argc > 4)
|
||||||
|
usage("Invalid number of arguments", -1);
|
||||||
|
|
||||||
|
if (sscanf(argv[2], "%u", &numfiles) != 1)
|
||||||
|
usage("Invalid maximum file", -2);
|
||||||
|
|
||||||
|
if (argc == 4 && sscanf(argv[3], "%u", &first_file) != 1)
|
||||||
|
usage("Invalid first file", -3);
|
||||||
|
|
||||||
|
if (numfiles < first_file)
|
||||||
|
usage("First file larger than last file", -3);
|
||||||
|
|
||||||
|
for (i = first_file; i <= numfiles; i++) {
|
||||||
|
int fd;
|
||||||
|
(void) snprintf(buf, MAXPATHLEN, "%s%u", argv[1], i);
|
||||||
|
if ((fd = open(buf, O_CREAT | O_EXCL, O_RDWR)) == -1) {
|
||||||
|
(void) fprintf(stderr, "Failed to create %s %s\n", buf,
|
||||||
|
strerror(errno));
|
||||||
|
return (-4);
|
||||||
|
}
|
||||||
|
(void) close(fd);
|
||||||
|
}
|
||||||
|
return (0);
|
||||||
|
}
|
1
tests/zfs-tests/cmd/mktree/.gitignore
vendored
Normal file
1
tests/zfs-tests/cmd/mktree/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
/mktree
|
6
tests/zfs-tests/cmd/mktree/Makefile.am
Normal file
6
tests/zfs-tests/cmd/mktree/Makefile.am
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
include $(top_srcdir)/config/Rules.am
|
||||||
|
|
||||||
|
pkgexecdir = $(datadir)/@PACKAGE@/zfs-tests/bin
|
||||||
|
|
||||||
|
pkgexec_PROGRAMS = mktree
|
||||||
|
mktree_SOURCES = mktree.c
|
183
tests/zfs-tests/cmd/mktree/mktree.c
Normal file
183
tests/zfs-tests/cmd/mktree/mktree.c
Normal file
@ -0,0 +1,183 @@
|
|||||||
|
/*
|
||||||
|
* CDDL HEADER START
|
||||||
|
*
|
||||||
|
* The contents of this file are subject to the terms of the
|
||||||
|
* Common Development and Distribution License (the "License").
|
||||||
|
* You may not use this file except in compliance with the License.
|
||||||
|
*
|
||||||
|
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
||||||
|
* or http://www.opensolaris.org/os/licensing.
|
||||||
|
* See the License for the specific language governing permissions
|
||||||
|
* and limitations under the License.
|
||||||
|
*
|
||||||
|
* When distributing Covered Code, include this CDDL HEADER in each
|
||||||
|
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
||||||
|
* If applicable, add the following below this CDDL HEADER, with the
|
||||||
|
* fields enclosed by brackets "[]" replaced with your own identifying
|
||||||
|
* information: Portions Copyright [yyyy] [name of copyright owner]
|
||||||
|
*
|
||||||
|
* CDDL HEADER END
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
|
||||||
|
* Use is subject to license terms.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <attr/xattr.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/errno.h>
|
||||||
|
#include <sys/param.h>
|
||||||
|
|
||||||
|
#define TYPE_D 'D'
|
||||||
|
#define TYPE_F 'F'
|
||||||
|
|
||||||
|
static char fdname[MAXPATHLEN] = {0};
|
||||||
|
static char *pbasedir = NULL;
|
||||||
|
static int nlevel = 2;
|
||||||
|
static int ndir = 2;
|
||||||
|
static int nfile = 2;
|
||||||
|
|
||||||
|
static void usage(char *this);
|
||||||
|
static void crtfile(char *pname);
|
||||||
|
static char *getfdname(char *pdir, char type, int level, int dir, int file);
|
||||||
|
static int mktree(char *pbasedir, int level);
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
int c, ret;
|
||||||
|
|
||||||
|
while ((c = getopt(argc, argv, "b:l:d:f:")) != -1) {
|
||||||
|
switch (c) {
|
||||||
|
case 'b':
|
||||||
|
pbasedir = optarg;
|
||||||
|
break;
|
||||||
|
case 'l':
|
||||||
|
nlevel = atoi(optarg);
|
||||||
|
break;
|
||||||
|
case 'd':
|
||||||
|
ndir = atoi(optarg);
|
||||||
|
break;
|
||||||
|
case 'f':
|
||||||
|
nfile = atoi(optarg);
|
||||||
|
break;
|
||||||
|
case '?':
|
||||||
|
usage(argv[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (nlevel < 0 || ndir < 0 || nfile < 0 || pbasedir == NULL) {
|
||||||
|
usage(argv[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = mktree(pbasedir, 1);
|
||||||
|
|
||||||
|
return (ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
usage(char *this)
|
||||||
|
{
|
||||||
|
(void) fprintf(stderr,
|
||||||
|
"\tUsage: %s -b <base_dir> -l [nlevel] -d [ndir] -f [nfile]\n",
|
||||||
|
this);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
mktree(char *pdir, int level)
|
||||||
|
{
|
||||||
|
int d, f;
|
||||||
|
char dname[MAXPATHLEN] = {0};
|
||||||
|
char fname[MAXPATHLEN] = {0};
|
||||||
|
|
||||||
|
if (level > nlevel) {
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (d = 0; d < ndir; d++) {
|
||||||
|
(void) memset(dname, '\0', sizeof (dname));
|
||||||
|
(void) strcpy(dname, getfdname(pdir, TYPE_D, level, d, 0));
|
||||||
|
|
||||||
|
if (mkdir(dname, 0777) != 0) {
|
||||||
|
(void) fprintf(stderr, "mkdir(%s) failed."
|
||||||
|
"\n[%d]: %s.\n",
|
||||||
|
dname, errno, strerror(errno));
|
||||||
|
exit(errno);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* No sub-directory need be created, only create files in it.
|
||||||
|
*/
|
||||||
|
if (mktree(dname, level+1) != 0) {
|
||||||
|
for (f = 0; f < nfile; f++) {
|
||||||
|
(void) memset(fname, '\0', sizeof (fname));
|
||||||
|
(void) strcpy(fname,
|
||||||
|
getfdname(dname, TYPE_F, level+1, d, f));
|
||||||
|
crtfile(fname);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (f = 0; f < nfile; f++) {
|
||||||
|
(void) memset(fname, '\0', sizeof (fname));
|
||||||
|
(void) strcpy(fname, getfdname(pdir, TYPE_F, level, d, f));
|
||||||
|
crtfile(fname);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *
|
||||||
|
getfdname(char *pdir, char type, int level, int dir, int file)
|
||||||
|
{
|
||||||
|
(void) snprintf(fdname, sizeof (fdname),
|
||||||
|
"%s/%c-l%dd%df%d", pdir, type, level, dir, file);
|
||||||
|
return (fdname);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
crtfile(char *pname)
|
||||||
|
{
|
||||||
|
int fd = -1;
|
||||||
|
int i, size;
|
||||||
|
char *context = "0123456789ABCDF";
|
||||||
|
char *pbuf;
|
||||||
|
|
||||||
|
if (pname == NULL) {
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
size = sizeof (char) * 1024;
|
||||||
|
pbuf = (char *)valloc(size);
|
||||||
|
for (i = 0; i < size / strlen(context); i++) {
|
||||||
|
int offset = i * strlen(context);
|
||||||
|
(void) snprintf(pbuf+offset, size-offset, "%s", context);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((fd = open(pname, O_CREAT|O_RDWR, 0777)) < 0) {
|
||||||
|
(void) fprintf(stderr, "open(%s, O_CREAT|O_RDWR, 0777) failed."
|
||||||
|
"\n[%d]: %s.\n", pname, errno, strerror(errno));
|
||||||
|
exit(errno);
|
||||||
|
}
|
||||||
|
if (write(fd, pbuf, 1024) < 1024) {
|
||||||
|
(void) fprintf(stderr, "write(fd, pbuf, 1024) failed."
|
||||||
|
"\n[%d]: %s.\n", errno, strerror(errno));
|
||||||
|
exit(errno);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fsetxattr(fd, "xattr", pbuf, 1024, 0) < 0) {
|
||||||
|
(void) fprintf(stderr, "fsetxattr(fd, \"xattr\", pbuf, "
|
||||||
|
"1024, 0) failed.\n[%d]: %s.\n", errno, strerror(errno));
|
||||||
|
exit(errno);
|
||||||
|
}
|
||||||
|
|
||||||
|
(void) close(fd);
|
||||||
|
free(pbuf);
|
||||||
|
}
|
1
tests/zfs-tests/cmd/mmap_exec/.gitignore
vendored
Normal file
1
tests/zfs-tests/cmd/mmap_exec/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
/mmap_exec
|
6
tests/zfs-tests/cmd/mmap_exec/Makefile.am
Normal file
6
tests/zfs-tests/cmd/mmap_exec/Makefile.am
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
include $(top_srcdir)/config/Rules.am
|
||||||
|
|
||||||
|
pkgexecdir = $(datadir)/@PACKAGE@/zfs-tests/bin
|
||||||
|
|
||||||
|
pkgexec_PROGRAMS = mmap_exec
|
||||||
|
mmap_exec_SOURCES = mmap_exec.c
|
69
tests/zfs-tests/cmd/mmap_exec/mmap_exec.c
Normal file
69
tests/zfs-tests/cmd/mmap_exec/mmap_exec.c
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
/*
|
||||||
|
* CDDL HEADER START
|
||||||
|
*
|
||||||
|
* The contents of this file are subject to the terms of the
|
||||||
|
* Common Development and Distribution License (the "License").
|
||||||
|
* You may not use this file except in compliance with the License.
|
||||||
|
*
|
||||||
|
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
||||||
|
* or http://www.opensolaris.org/os/licensing.
|
||||||
|
* See the License for the specific language governing permissions
|
||||||
|
* and limitations under the License.
|
||||||
|
*
|
||||||
|
* When distributing Covered Code, include this CDDL HEADER in each
|
||||||
|
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
||||||
|
* If applicable, add the following below this CDDL HEADER, with the
|
||||||
|
* fields enclosed by brackets "[]" replaced with your own identifying
|
||||||
|
* information: Portions Copyright [yyyy] [name of copyright owner]
|
||||||
|
*
|
||||||
|
* CDDL HEADER END
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
|
||||||
|
* Use is subject to license terms.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2013 by Delphix. All rights reserved.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
struct stat statbuf;
|
||||||
|
|
||||||
|
if (argc != 2) {
|
||||||
|
(void) printf("Error: missing binary name.\n");
|
||||||
|
(void) printf("Usage:\n\t%s <binary name>\n",
|
||||||
|
argv[0]);
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
errno = 0;
|
||||||
|
|
||||||
|
if ((fd = open(argv[1], O_RDONLY)) < 0) {
|
||||||
|
perror("open");
|
||||||
|
return (errno);
|
||||||
|
}
|
||||||
|
if (fstat(fd, &statbuf) < 0) {
|
||||||
|
perror("fstat");
|
||||||
|
return (errno);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mmap(0, statbuf.st_size,
|
||||||
|
PROT_EXEC, MAP_SHARED, fd, 0) == MAP_FAILED) {
|
||||||
|
perror("mmap");
|
||||||
|
return (errno);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
1
tests/zfs-tests/cmd/mmapwrite/.gitignore
vendored
Normal file
1
tests/zfs-tests/cmd/mmapwrite/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
/mmapwrite
|
7
tests/zfs-tests/cmd/mmapwrite/Makefile.am
Normal file
7
tests/zfs-tests/cmd/mmapwrite/Makefile.am
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
include $(top_srcdir)/config/Rules.am
|
||||||
|
|
||||||
|
pkgexecdir = $(datadir)/@PACKAGE@/zfs-tests/bin
|
||||||
|
|
||||||
|
pkgexec_PROGRAMS = mmapwrite
|
||||||
|
mmapwrite_SOURCES = mmapwrite.c
|
||||||
|
mmapwrite_LDADD = -lpthread
|
97
tests/zfs-tests/cmd/mmapwrite/mmapwrite.c
Normal file
97
tests/zfs-tests/cmd/mmapwrite/mmapwrite.c
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
/*
|
||||||
|
* CDDL HEADER START
|
||||||
|
*
|
||||||
|
* The contents of this file are subject to the terms of the
|
||||||
|
* Common Development and Distribution License (the "License").
|
||||||
|
* You may not use this file except in compliance with the License.
|
||||||
|
*
|
||||||
|
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
||||||
|
* or http://www.opensolaris.org/os/licensing.
|
||||||
|
* See the License for the specific language governing permissions
|
||||||
|
* and limitations under the License.
|
||||||
|
*
|
||||||
|
* When distributing Covered Code, include this CDDL HEADER in each
|
||||||
|
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
||||||
|
* If applicable, add the following below this CDDL HEADER, with the
|
||||||
|
* fields enclosed by brackets "[]" replaced with your own identifying
|
||||||
|
* information: Portions Copyright [yyyy] [name of copyright owner]
|
||||||
|
*
|
||||||
|
* CDDL HEADER END
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
|
||||||
|
* Use is subject to license terms.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* --------------------------------------------------------------------
|
||||||
|
* Bug Id: 5032643
|
||||||
|
*
|
||||||
|
* Simply writing to a file and mmaping that file at the same time can
|
||||||
|
* result in deadlock. Nothing perverse like writing from the file's
|
||||||
|
* own mapping is required.
|
||||||
|
* --------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
static void *
|
||||||
|
mapper(void *fdp)
|
||||||
|
{
|
||||||
|
void *addr;
|
||||||
|
int fd = *(int *)fdp;
|
||||||
|
|
||||||
|
if ((addr =
|
||||||
|
mmap(0, 8192, PROT_READ, MAP_SHARED, fd, 0)) == MAP_FAILED) {
|
||||||
|
perror("mmap");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
for (;;) {
|
||||||
|
if (mmap(addr, 8192, PROT_READ,
|
||||||
|
MAP_SHARED|MAP_FIXED, fd, 0) == MAP_FAILED) {
|
||||||
|
perror("mmap");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* NOTREACHED */
|
||||||
|
return ((void *)1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
char buf[BUFSIZ];
|
||||||
|
pthread_t tid;
|
||||||
|
|
||||||
|
if (argc != 2) {
|
||||||
|
(void) printf("usage: %s <file name>\n", argv[0]);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((fd = open(argv[1], O_RDWR|O_CREAT|O_TRUNC, 0666)) == -1) {
|
||||||
|
perror("open");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
(void) pthread_setconcurrency(2);
|
||||||
|
if (pthread_create(&tid, NULL, mapper, &fd) != 0) {
|
||||||
|
perror("pthread_create");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
for (;;) {
|
||||||
|
if (write(fd, buf, sizeof (buf)) == -1) {
|
||||||
|
perror("write");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* NOTREACHED */
|
||||||
|
return (0);
|
||||||
|
}
|
1
tests/zfs-tests/cmd/randfree_file/.gitignore
vendored
Normal file
1
tests/zfs-tests/cmd/randfree_file/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
/randfree_file
|
6
tests/zfs-tests/cmd/randfree_file/Makefile.am
Normal file
6
tests/zfs-tests/cmd/randfree_file/Makefile.am
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
include $(top_srcdir)/config/Rules.am
|
||||||
|
|
||||||
|
pkgexecdir = $(datadir)/@PACKAGE@/zfs-tests/bin
|
||||||
|
|
||||||
|
pkgexec_PROGRAMS = randfree_file
|
||||||
|
randfree_file_SOURCES = randfree_file.c
|
105
tests/zfs-tests/cmd/randfree_file/randfree_file.c
Normal file
105
tests/zfs-tests/cmd/randfree_file/randfree_file.c
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
/*
|
||||||
|
* CDDL HEADER START
|
||||||
|
*
|
||||||
|
* The contents of this file are subject to the terms of the
|
||||||
|
* Common Development and Distribution License (the "License").
|
||||||
|
* You may not use this file except in compliance with the License.
|
||||||
|
*
|
||||||
|
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
||||||
|
* or http://www.opensolaris.org/os/licensing.
|
||||||
|
* See the License for the specific language governing permissions
|
||||||
|
* and limitations under the License.
|
||||||
|
*
|
||||||
|
* When distributing Covered Code, include this CDDL HEADER in each
|
||||||
|
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
||||||
|
* If applicable, add the following below this CDDL HEADER, with the
|
||||||
|
* fields enclosed by brackets "[]" replaced with your own identifying
|
||||||
|
* information: Portions Copyright [yyyy] [name of copyright owner]
|
||||||
|
*
|
||||||
|
* CDDL HEADER END
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
|
||||||
|
* Use is subject to license terms.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2012 by Delphix. All rights reserved.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "../file_common.h"
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <linux/falloc.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Create a file with assigned size and then free the specified
|
||||||
|
* section of the file
|
||||||
|
*/
|
||||||
|
|
||||||
|
static void usage(char *progname);
|
||||||
|
|
||||||
|
static void
|
||||||
|
usage(char *progname)
|
||||||
|
{
|
||||||
|
(void) fprintf(stderr,
|
||||||
|
"usage: %s [-l filesize] [-s start-offset]"
|
||||||
|
"[-n section-len] filename\n", progname);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
char *filename = NULL;
|
||||||
|
char *buf;
|
||||||
|
size_t filesize = 0;
|
||||||
|
off_t start_off = 0;
|
||||||
|
off_t off_len = 0;
|
||||||
|
int fd, ch;
|
||||||
|
mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
|
||||||
|
|
||||||
|
while ((ch = getopt(argc, argv, "l:s:n:")) != EOF) {
|
||||||
|
switch (ch) {
|
||||||
|
case 'l':
|
||||||
|
filesize = atoll(optarg);
|
||||||
|
break;
|
||||||
|
case 's':
|
||||||
|
start_off = atoll(optarg);
|
||||||
|
break;
|
||||||
|
case 'n':
|
||||||
|
off_len = atoll(optarg);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
usage(argv[0]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (optind == argc - 1)
|
||||||
|
filename = argv[optind];
|
||||||
|
else
|
||||||
|
usage(argv[0]);
|
||||||
|
|
||||||
|
buf = (char *)malloc(filesize);
|
||||||
|
|
||||||
|
if ((fd = open(filename, O_RDWR | O_CREAT | O_TRUNC, mode)) < 0) {
|
||||||
|
perror("open");
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
if (write(fd, buf, filesize) < filesize) {
|
||||||
|
perror("write");
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fallocate(fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
|
||||||
|
start_off, off_len) < 0) {
|
||||||
|
perror("fallocate");
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(buf);
|
||||||
|
return (0);
|
||||||
|
}
|
1
tests/zfs-tests/cmd/readmmap/.gitignore
vendored
Normal file
1
tests/zfs-tests/cmd/readmmap/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
/readmmap
|
6
tests/zfs-tests/cmd/readmmap/Makefile.am
Normal file
6
tests/zfs-tests/cmd/readmmap/Makefile.am
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
include $(top_srcdir)/config/Rules.am
|
||||||
|
|
||||||
|
pkgexecdir = $(datadir)/@PACKAGE@/zfs-tests/bin
|
||||||
|
|
||||||
|
pkgexec_PROGRAMS = readmmap
|
||||||
|
readmmap_SOURCES = readmmap.c
|
138
tests/zfs-tests/cmd/readmmap/readmmap.c
Normal file
138
tests/zfs-tests/cmd/readmmap/readmmap.c
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
/*
|
||||||
|
* CDDL HEADER START
|
||||||
|
*
|
||||||
|
* The contents of this file are subject to the terms of the
|
||||||
|
* Common Development and Distribution License (the "License").
|
||||||
|
* You may not use this file except in compliance with the License.
|
||||||
|
*
|
||||||
|
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
||||||
|
* or http://www.opensolaris.org/os/licensing.
|
||||||
|
* See the License for the specific language governing permissions
|
||||||
|
* and limitations under the License.
|
||||||
|
*
|
||||||
|
* When distributing Covered Code, include this CDDL HEADER in each
|
||||||
|
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
||||||
|
* If applicable, add the following below this CDDL HEADER, with the
|
||||||
|
* fields enclosed by brackets "[]" replaced with your own identifying
|
||||||
|
* information: Portions Copyright [yyyy] [name of copyright owner]
|
||||||
|
*
|
||||||
|
* CDDL HEADER END
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
|
||||||
|
* Use is subject to license terms.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* --------------------------------------------------------------
|
||||||
|
* BugId 5047993 : Getting bad read data.
|
||||||
|
*
|
||||||
|
* Usage: readmmap <filename>
|
||||||
|
*
|
||||||
|
* where:
|
||||||
|
* filename is an absolute path to the file name.
|
||||||
|
*
|
||||||
|
* Return values:
|
||||||
|
* 1 : error
|
||||||
|
* 0 : no errors
|
||||||
|
* --------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
char *filename = "badfile";
|
||||||
|
size_t size = 4395;
|
||||||
|
size_t idx = 0;
|
||||||
|
char *buf = NULL;
|
||||||
|
char *map = NULL;
|
||||||
|
int fd = -1, bytes, retval = 0;
|
||||||
|
unsigned seed;
|
||||||
|
|
||||||
|
if (argc < 2 || optind == argc) {
|
||||||
|
(void) fprintf(stderr,
|
||||||
|
"usage: %s <file name>\n", argv[0]);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((buf = calloc(1, size)) == NULL) {
|
||||||
|
perror("calloc");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
filename = argv[optind];
|
||||||
|
|
||||||
|
(void) remove(filename);
|
||||||
|
|
||||||
|
fd = open(filename, O_RDWR|O_CREAT|O_TRUNC, 0666);
|
||||||
|
if (fd == -1) {
|
||||||
|
perror("open to create");
|
||||||
|
retval = 1;
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
bytes = write(fd, buf, size);
|
||||||
|
if (bytes != size) {
|
||||||
|
(void) printf("short write: %d != %zd\n", bytes, size);
|
||||||
|
retval = 1;
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
map = mmap(0, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
|
||||||
|
if (map == MAP_FAILED) {
|
||||||
|
perror("mmap");
|
||||||
|
retval = 1;
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
seed = time(NULL);
|
||||||
|
srandom(seed);
|
||||||
|
|
||||||
|
idx = random() % size;
|
||||||
|
map[idx] = 1;
|
||||||
|
|
||||||
|
if (msync(map, size, MS_SYNC) != 0) {
|
||||||
|
perror("msync");
|
||||||
|
retval = 1;
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (munmap(map, size) != 0) {
|
||||||
|
perror("munmap");
|
||||||
|
retval = 1;
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
bytes = pread(fd, buf, size, 0);
|
||||||
|
if (bytes != size) {
|
||||||
|
(void) printf("short read: %d != %zd\n", bytes, size);
|
||||||
|
retval = 1;
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (buf[idx] != 1) {
|
||||||
|
(void) printf(
|
||||||
|
"bad data from read! got buf[%zd]=%d, expected 1\n",
|
||||||
|
idx, buf[idx]);
|
||||||
|
retval = 1;
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
(void) printf("good data from read: buf[%zd]=1\n", idx);
|
||||||
|
end:
|
||||||
|
if (fd != -1) {
|
||||||
|
(void) close(fd);
|
||||||
|
}
|
||||||
|
if (buf != NULL) {
|
||||||
|
free(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (retval);
|
||||||
|
}
|
1
tests/zfs-tests/cmd/rename_dir/.gitignore
vendored
Normal file
1
tests/zfs-tests/cmd/rename_dir/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
/rename_dir
|
6
tests/zfs-tests/cmd/rename_dir/Makefile.am
Normal file
6
tests/zfs-tests/cmd/rename_dir/Makefile.am
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
include $(top_srcdir)/config/Rules.am
|
||||||
|
|
||||||
|
pkgexecdir = $(datadir)/@PACKAGE@/zfs-tests/bin
|
||||||
|
|
||||||
|
pkgexec_PROGRAMS = rename_dir
|
||||||
|
rename_dir_SOURCES = rename_dir.c
|
88
tests/zfs-tests/cmd/rename_dir/rename_dir.c
Normal file
88
tests/zfs-tests/cmd/rename_dir/rename_dir.c
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
/*
|
||||||
|
* CDDL HEADER START
|
||||||
|
*
|
||||||
|
* The contents of this file are subject to the terms of the
|
||||||
|
* Common Development and Distribution License (the "License").
|
||||||
|
* You may not use this file except in compliance with the License.
|
||||||
|
*
|
||||||
|
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
||||||
|
* or http://www.opensolaris.org/os/licensing.
|
||||||
|
* See the License for the specific language governing permissions
|
||||||
|
* and limitations under the License.
|
||||||
|
*
|
||||||
|
* When distributing Covered Code, include this CDDL HEADER in each
|
||||||
|
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
||||||
|
* If applicable, add the following below this CDDL HEADER, with the
|
||||||
|
* fields enclosed by brackets "[]" replaced with your own identifying
|
||||||
|
* information: Portions Copyright [yyyy] [name of copyright owner]
|
||||||
|
*
|
||||||
|
* CDDL HEADER END
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
|
||||||
|
* Use is subject to license terms.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2012 by Delphix. All rights reserved.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Assertion:
|
||||||
|
* Create two directory trees in zfs filesystem, and rename
|
||||||
|
* directory across the directory structure. ZFS can handle
|
||||||
|
* the race situation.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Need to create the following directory structures before
|
||||||
|
* running this program:
|
||||||
|
*
|
||||||
|
* mkdir -p 1/2/3/4/5 a/b/c/d/e
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <strings.h>
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char *argvp[])
|
||||||
|
{
|
||||||
|
int i = 1;
|
||||||
|
|
||||||
|
switch (fork()) {
|
||||||
|
case -1:
|
||||||
|
perror("fork");
|
||||||
|
exit(1);
|
||||||
|
break;
|
||||||
|
case 0:
|
||||||
|
while (i > 0) {
|
||||||
|
int c_count = 0;
|
||||||
|
if (rename("a/b/c", "1/2/3/c") == 0)
|
||||||
|
c_count++;
|
||||||
|
if (rename("1/2/3/c", "a/b/c") == 0)
|
||||||
|
c_count++;
|
||||||
|
if (c_count) {
|
||||||
|
(void) fprintf(stderr, "c_count: %d", c_count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
while (i > 0) {
|
||||||
|
int p_count = 0;
|
||||||
|
if (rename("1", "a/b/c/d/e/1") == 0)
|
||||||
|
p_count++;
|
||||||
|
if (rename("a/b/c/d/e/1", "1") == 0)
|
||||||
|
p_count++;
|
||||||
|
if (p_count) {
|
||||||
|
(void) fprintf(stderr, "p_count: %d", p_count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
1
tests/zfs-tests/cmd/rm_lnkcnt_zero_file/.gitignore
vendored
Normal file
1
tests/zfs-tests/cmd/rm_lnkcnt_zero_file/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
/rm_lnkcnt_zero_file
|
7
tests/zfs-tests/cmd/rm_lnkcnt_zero_file/Makefile.am
Normal file
7
tests/zfs-tests/cmd/rm_lnkcnt_zero_file/Makefile.am
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
include $(top_srcdir)/config/Rules.am
|
||||||
|
|
||||||
|
pkgexecdir = $(datadir)/@PACKAGE@/zfs-tests/bin
|
||||||
|
|
||||||
|
pkgexec_PROGRAMS = rm_lnkcnt_zero_file
|
||||||
|
rm_lnkcnt_zero_file_SOURCES = rm_lnkcnt_zero_file.c
|
||||||
|
rm_lnkcnt_zero_file_LDADD = -lpthread
|
155
tests/zfs-tests/cmd/rm_lnkcnt_zero_file/rm_lnkcnt_zero_file.c
Normal file
155
tests/zfs-tests/cmd/rm_lnkcnt_zero_file/rm_lnkcnt_zero_file.c
Normal file
@ -0,0 +1,155 @@
|
|||||||
|
/*
|
||||||
|
* CDDL HEADER START
|
||||||
|
*
|
||||||
|
* The contents of this file are subject to the terms of the
|
||||||
|
* Common Development and Distribution License (the "License").
|
||||||
|
* You may not use this file except in compliance with the License.
|
||||||
|
*
|
||||||
|
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
||||||
|
* or http://www.opensolaris.org/os/licensing.
|
||||||
|
* See the License for the specific language governing permissions
|
||||||
|
* and limitations under the License.
|
||||||
|
*
|
||||||
|
* When distributing Covered Code, include this CDDL HEADER in each
|
||||||
|
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
||||||
|
* If applicable, add the following below this CDDL HEADER, with the
|
||||||
|
* fields enclosed by brackets "[]" replaced with your own identifying
|
||||||
|
* information: Portions Copyright [yyyy] [name of copyright owner]
|
||||||
|
*
|
||||||
|
* CDDL HEADER END
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
|
||||||
|
* Use is subject to license terms.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2012 by Delphix. All rights reserved.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* --------------------------------------------------------------------
|
||||||
|
* The purpose of this test is to see if the bug reported (#4723351) for
|
||||||
|
* UFS exists when using a ZFS file system.
|
||||||
|
* --------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#define _REENTRANT 1
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <strings.h>
|
||||||
|
|
||||||
|
static const int TRUE = 1;
|
||||||
|
static char *filebase;
|
||||||
|
|
||||||
|
static int
|
||||||
|
pickidx(void)
|
||||||
|
{
|
||||||
|
return (random() % 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ARGSUSED */
|
||||||
|
static void *
|
||||||
|
mover(void *a)
|
||||||
|
{
|
||||||
|
char buf[256];
|
||||||
|
int idx, len, ret;
|
||||||
|
|
||||||
|
len = strlen(filebase) + 5;
|
||||||
|
|
||||||
|
while (TRUE) {
|
||||||
|
idx = pickidx();
|
||||||
|
(void) snprintf(buf, len, "%s.%03d", filebase, idx);
|
||||||
|
ret = rename(filebase, buf);
|
||||||
|
if (ret < 0 && errno != ENOENT)
|
||||||
|
(void) perror("renaming file");
|
||||||
|
}
|
||||||
|
|
||||||
|
return (NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ARGSUSED */
|
||||||
|
static void *
|
||||||
|
cleaner(void *a)
|
||||||
|
{
|
||||||
|
char buf[256];
|
||||||
|
int idx, len, ret;
|
||||||
|
|
||||||
|
len = strlen(filebase) + 5;
|
||||||
|
|
||||||
|
while (TRUE) {
|
||||||
|
idx = pickidx();
|
||||||
|
(void) snprintf(buf, len, "%s.%03d", filebase, idx);
|
||||||
|
ret = remove(buf);
|
||||||
|
if (ret < 0 && errno != ENOENT)
|
||||||
|
(void) perror("removing file");
|
||||||
|
}
|
||||||
|
|
||||||
|
return (NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *
|
||||||
|
writer(void *a)
|
||||||
|
{
|
||||||
|
int *fd = (int *)a;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
while (TRUE) {
|
||||||
|
(void) close (*fd);
|
||||||
|
*fd = open(filebase, O_APPEND | O_RDWR | O_CREAT, 0644);
|
||||||
|
if (*fd < 0)
|
||||||
|
perror("refreshing file");
|
||||||
|
ret = write(*fd, "test\n", 5);
|
||||||
|
if (ret != 5)
|
||||||
|
perror("writing file");
|
||||||
|
}
|
||||||
|
|
||||||
|
return (NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
pthread_t tid;
|
||||||
|
|
||||||
|
if (argc == 1) {
|
||||||
|
(void) printf("Usage: %s <filebase>\n", argv[0]);
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
filebase = argv[1];
|
||||||
|
fd = open(filebase, O_APPEND | O_RDWR | O_CREAT, 0644);
|
||||||
|
if (fd < 0) {
|
||||||
|
perror("creating test file");
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
(void) pthread_setconcurrency(4); /* 3 threads + main */
|
||||||
|
(void) pthread_create(&tid, NULL, mover, NULL);
|
||||||
|
(void) pthread_create(&tid, NULL, cleaner, NULL);
|
||||||
|
(void) pthread_create(&tid, NULL, writer, (void *) &fd);
|
||||||
|
|
||||||
|
while (TRUE) {
|
||||||
|
int ret;
|
||||||
|
struct stat st;
|
||||||
|
|
||||||
|
ret = stat(filebase, &st);
|
||||||
|
if (ret == 0 && (st.st_nlink > 2 || st.st_nlink < 1)) {
|
||||||
|
(void) printf("st.st_nlink = %d, exiting\n", \
|
||||||
|
(int)st.st_nlink);
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
(void) sleep(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
1
tests/zfs-tests/cmd/threadsappend/.gitignore
vendored
Normal file
1
tests/zfs-tests/cmd/threadsappend/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
/threadsappend
|
7
tests/zfs-tests/cmd/threadsappend/Makefile.am
Normal file
7
tests/zfs-tests/cmd/threadsappend/Makefile.am
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
include $(top_srcdir)/config/Rules.am
|
||||||
|
|
||||||
|
pkgexecdir = $(datadir)/@PACKAGE@/zfs-tests/bin
|
||||||
|
|
||||||
|
pkgexec_PROGRAMS = threadsappend
|
||||||
|
threadsappend_SOURCES = threadsappend.c
|
||||||
|
threadsappend_LDADD = -lpthread
|
135
tests/zfs-tests/cmd/threadsappend/threadsappend.c
Normal file
135
tests/zfs-tests/cmd/threadsappend/threadsappend.c
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
/*
|
||||||
|
* CDDL HEADER START
|
||||||
|
*
|
||||||
|
* The contents of this file are subject to the terms of the
|
||||||
|
* Common Development and Distribution License (the "License").
|
||||||
|
* You may not use this file except in compliance with the License.
|
||||||
|
*
|
||||||
|
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
||||||
|
* or http://www.opensolaris.org/os/licensing.
|
||||||
|
* See the License for the specific language governing permissions
|
||||||
|
* and limitations under the License.
|
||||||
|
*
|
||||||
|
* When distributing Covered Code, include this CDDL HEADER in each
|
||||||
|
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
||||||
|
* If applicable, add the following below this CDDL HEADER, with the
|
||||||
|
* fields enclosed by brackets "[]" replaced with your own identifying
|
||||||
|
* information: Portions Copyright [yyyy] [name of copyright owner]
|
||||||
|
*
|
||||||
|
* CDDL HEADER END
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
|
||||||
|
* Use is subject to license terms.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2013 by Delphix. All rights reserved.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The size of the output file, "go.out", should be 80*8192*2 = 1310720
|
||||||
|
*
|
||||||
|
* $ cd /tmp; go; ls -l go.out
|
||||||
|
* done.
|
||||||
|
* -rwxr-xr-x 1 jdm staff 1310720 Apr 13 19:45 go.out
|
||||||
|
* $ cd /zfs; go; ls -l go.out
|
||||||
|
* done.
|
||||||
|
* -rwxr-xr-x 1 jdm staff 663552 Apr 13 19:45 go.out
|
||||||
|
*
|
||||||
|
* The file on zfs is short as it does not appear that zfs is making the
|
||||||
|
* implicit seek to EOF and the actual write atomic. From the SUSv3
|
||||||
|
* interface spec, behavior is undefined if concurrent writes are performed
|
||||||
|
* from multi-processes to a single file. So I don't know if this is a
|
||||||
|
* standards violation, but I cannot find any such disclaimers in our
|
||||||
|
* man pages. This issue came up at a customer site in another context, and
|
||||||
|
* the suggestion was to open the file with O_APPEND, but that wouldn't
|
||||||
|
* help with zfs(see 4977529). Also see bug# 5031301.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static int outfd = 0;
|
||||||
|
|
||||||
|
static void *
|
||||||
|
go(void *data)
|
||||||
|
{
|
||||||
|
int ret, i = 0, n = *(int *)data;
|
||||||
|
char buf[8192] = {0};
|
||||||
|
(void) memset(buf, n, sizeof (buf));
|
||||||
|
|
||||||
|
for (i = 0; i < 80; i++) {
|
||||||
|
ret = write(outfd, buf, sizeof (buf));
|
||||||
|
if (ret != sizeof (buf))
|
||||||
|
perror("write");
|
||||||
|
}
|
||||||
|
return (NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
usage(void)
|
||||||
|
{
|
||||||
|
(void) fprintf(stderr,
|
||||||
|
"usage: zfs_threadsappend <file name>\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
pthread_t tid;
|
||||||
|
int ret = 0;
|
||||||
|
long ncpus = 0;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (argc != 2) {
|
||||||
|
usage();
|
||||||
|
}
|
||||||
|
|
||||||
|
ncpus = sysconf(_SC_NPROCESSORS_ONLN);
|
||||||
|
if (ncpus < 0) {
|
||||||
|
(void) fprintf(stderr,
|
||||||
|
"Invalid return from sysconf(_SC_NPROCESSORS_ONLN)"
|
||||||
|
" : errno (decimal)=%d\n", errno);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
if (ncpus < 2) {
|
||||||
|
(void) fprintf(stderr,
|
||||||
|
"Must execute this binary on a multi-processor system\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
outfd = open(argv[optind++], O_RDWR|O_CREAT|O_APPEND|O_TRUNC, 0777);
|
||||||
|
if (outfd == -1) {
|
||||||
|
(void) fprintf(stderr,
|
||||||
|
"zfs_threadsappend: "
|
||||||
|
"open(%s, O_RDWR|O_CREAT|O_APPEND|O_TRUNC, 0777)"
|
||||||
|
" failed\n", argv[optind]);
|
||||||
|
perror("open");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < 2; i++) {
|
||||||
|
ret = pthread_create(&tid, NULL, go, (void *)&i);
|
||||||
|
if (ret != 0) {
|
||||||
|
(void) fprintf(stderr,
|
||||||
|
"zfs_threadsappend: thr_create(#%d) "
|
||||||
|
"failed error=%d\n", i+1, ret);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while (pthread_join(tid, NULL) == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
1
tests/zfs-tests/cmd/xattrtest/.gitignore
vendored
Normal file
1
tests/zfs-tests/cmd/xattrtest/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
/xattrtest
|
6
tests/zfs-tests/cmd/xattrtest/Makefile.am
Normal file
6
tests/zfs-tests/cmd/xattrtest/Makefile.am
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
include $(top_srcdir)/config/Rules.am
|
||||||
|
|
||||||
|
pkgexecdir = $(datadir)/@PACKAGE@/zfs-tests/bin
|
||||||
|
|
||||||
|
pkgexec_PROGRAMS = xattrtest
|
||||||
|
xattrtest_SOURCES = xattrtest.c
|
641
tests/zfs-tests/cmd/xattrtest/xattrtest.c
Normal file
641
tests/zfs-tests/cmd/xattrtest/xattrtest.c
Normal file
@ -0,0 +1,641 @@
|
|||||||
|
/*
|
||||||
|
* CDDL HEADER START
|
||||||
|
*
|
||||||
|
* The contents of this file are subject to the terms of the
|
||||||
|
* Common Development and Distribution License (the "License").
|
||||||
|
* You may not use this file except in compliance with the License.
|
||||||
|
*
|
||||||
|
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
||||||
|
* or http://www.opensolaris.org/os/licensing.
|
||||||
|
* See the License for the specific language governing permissions
|
||||||
|
* and limitations under the License.
|
||||||
|
*
|
||||||
|
* When distributing Covered Code, include this CDDL HEADER in each
|
||||||
|
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
||||||
|
* If applicable, add the following below this CDDL HEADER, with the
|
||||||
|
* fields enclosed by brackets "[]" replaced with your own identifying
|
||||||
|
* information: Portions Copyright [yyyy] [name of copyright owner]
|
||||||
|
*
|
||||||
|
* CDDL HEADER END
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright 2016 Lawrence Livermore National Security, LLC.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* An extended attribute (xattr) correctness test. This program creates
|
||||||
|
* N files and sets M attrs on them of size S. Optionally is will verify
|
||||||
|
* a pattern stored in the xattr.
|
||||||
|
*/
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <getopt.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <attr/xattr.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <linux/limits.h>
|
||||||
|
|
||||||
|
extern char *program_invocation_short_name;
|
||||||
|
|
||||||
|
#define ERROR(fmt, ...) \
|
||||||
|
fprintf(stderr, "%s: %s:%d: %s: " fmt "\n", \
|
||||||
|
program_invocation_short_name, __FILE__, __LINE__, \
|
||||||
|
__func__, ## __VA_ARGS__);
|
||||||
|
|
||||||
|
static const char shortopts[] = "hvycdn:f:x:s:p:t:e:rRk";
|
||||||
|
static const struct option longopts[] = {
|
||||||
|
{ "help", no_argument, 0, 'h' },
|
||||||
|
{ "verbose", no_argument, 0, 'v' },
|
||||||
|
{ "verify", no_argument, 0, 'y' },
|
||||||
|
{ "nth", required_argument, 0, 'n' },
|
||||||
|
{ "files", required_argument, 0, 'f' },
|
||||||
|
{ "xattrs", required_argument, 0, 'x' },
|
||||||
|
{ "size", required_argument, 0, 's' },
|
||||||
|
{ "path", required_argument, 0, 'p' },
|
||||||
|
{ "synccaches", no_argument, 0, 'c' },
|
||||||
|
{ "dropcaches", no_argument, 0, 'd' },
|
||||||
|
{ "script", required_argument, 0, 't' },
|
||||||
|
{ "seed", required_argument, 0, 'e' },
|
||||||
|
{ "random", no_argument, 0, 'r' },
|
||||||
|
{ "randomvalue", no_argument, 0, 'R' },
|
||||||
|
{ "keep", no_argument, 0, 'k' },
|
||||||
|
{ 0, 0, 0, 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
static int verbose = 0;
|
||||||
|
static int verify = 0;
|
||||||
|
static int synccaches = 0;
|
||||||
|
static int dropcaches = 0;
|
||||||
|
static int nth = 0;
|
||||||
|
static int files = 1000;
|
||||||
|
static int xattrs = 1;
|
||||||
|
static int size = 1;
|
||||||
|
static int size_is_random = 0;
|
||||||
|
static int value_is_random = 0;
|
||||||
|
static int keep_files = 0;
|
||||||
|
static char path[PATH_MAX] = "/tmp/xattrtest";
|
||||||
|
static char script[PATH_MAX] = "/bin/true";
|
||||||
|
|
||||||
|
static int
|
||||||
|
usage(int argc, char **argv) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"usage: %s [-hvycdrRk] [-n <nth>] [-f <files>] [-x <xattrs>]\n"
|
||||||
|
" [-s <bytes>] [-p <path>] [-t <script> ]\n", argv[0]);
|
||||||
|
fprintf(stderr,
|
||||||
|
" --help -h This help\n"
|
||||||
|
" --verbose -v Increase verbosity\n"
|
||||||
|
" --verify -y Verify xattr contents\n"
|
||||||
|
" --nth -n <nth> Print every nth file\n"
|
||||||
|
" --files -f <files> Set xattrs on N files\n"
|
||||||
|
" --xattrs -x <xattrs> Set N xattrs on each file\n"
|
||||||
|
" --size -s <bytes> Set N bytes per xattr\n"
|
||||||
|
" --path -p <path> Path to files\n"
|
||||||
|
" --synccaches -c Sync caches between phases\n"
|
||||||
|
" --dropcaches -d Drop caches between phases\n"
|
||||||
|
" --script -t <script> Exec script between phases\n"
|
||||||
|
" --seed -e <seed> Random seed value\n"
|
||||||
|
" --random -r Randomly sized xattrs [16-size]\n"
|
||||||
|
" --randomvalue -R Random xattr values\n"
|
||||||
|
" --keep -k Don't unlink files\n\n");
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
parse_args(int argc, char **argv)
|
||||||
|
{
|
||||||
|
long seed = time(NULL);
|
||||||
|
int c;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
while ((c = getopt_long(argc, argv, shortopts, longopts, NULL)) != -1) {
|
||||||
|
switch (c) {
|
||||||
|
case 'h':
|
||||||
|
return (usage(argc, argv));
|
||||||
|
case 'v':
|
||||||
|
verbose++;
|
||||||
|
break;
|
||||||
|
case 'y':
|
||||||
|
verify = 1;
|
||||||
|
if (value_is_random != 0) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"Error: -y and -R are incompatible.\n");
|
||||||
|
rc = 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'n':
|
||||||
|
nth = strtol(optarg, NULL, 0);
|
||||||
|
break;
|
||||||
|
case 'f':
|
||||||
|
files = strtol(optarg, NULL, 0);
|
||||||
|
break;
|
||||||
|
case 'x':
|
||||||
|
xattrs = strtol(optarg, NULL, 0);
|
||||||
|
break;
|
||||||
|
case 's':
|
||||||
|
size = strtol(optarg, NULL, 0);
|
||||||
|
if (size > XATTR_SIZE_MAX) {
|
||||||
|
fprintf(stderr, "Error: the size may not be "
|
||||||
|
"greater than %d\n", XATTR_SIZE_MAX);
|
||||||
|
rc = 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'p':
|
||||||
|
strncpy(path, optarg, PATH_MAX);
|
||||||
|
break;
|
||||||
|
case 'c':
|
||||||
|
synccaches = 1;
|
||||||
|
break;
|
||||||
|
case 'd':
|
||||||
|
dropcaches = 1;
|
||||||
|
break;
|
||||||
|
case 't':
|
||||||
|
strncpy(script, optarg, PATH_MAX);
|
||||||
|
break;
|
||||||
|
case 'e':
|
||||||
|
seed = strtol(optarg, NULL, 0);
|
||||||
|
break;
|
||||||
|
case 'r':
|
||||||
|
size_is_random = 1;
|
||||||
|
break;
|
||||||
|
case 'R':
|
||||||
|
value_is_random = 1;
|
||||||
|
if (verify != 0) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"Error: -y and -R are incompatible.\n");
|
||||||
|
rc = 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'k':
|
||||||
|
keep_files = 1;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
rc = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rc != 0)
|
||||||
|
return (rc);
|
||||||
|
|
||||||
|
srandom(seed);
|
||||||
|
|
||||||
|
if (verbose) {
|
||||||
|
fprintf(stdout, "verbose: %d\n", verbose);
|
||||||
|
fprintf(stdout, "verify: %d\n", verify);
|
||||||
|
fprintf(stdout, "nth: %d\n", nth);
|
||||||
|
fprintf(stdout, "files: %d\n", files);
|
||||||
|
fprintf(stdout, "xattrs: %d\n", xattrs);
|
||||||
|
fprintf(stdout, "size: %d\n", size);
|
||||||
|
fprintf(stdout, "path: %s\n", path);
|
||||||
|
fprintf(stdout, "synccaches: %d\n", synccaches);
|
||||||
|
fprintf(stdout, "dropcaches: %d\n", dropcaches);
|
||||||
|
fprintf(stdout, "script: %s\n", script);
|
||||||
|
fprintf(stdout, "seed: %ld\n", seed);
|
||||||
|
fprintf(stdout, "random size: %d\n", size_is_random);
|
||||||
|
fprintf(stdout, "random value: %d\n", value_is_random);
|
||||||
|
fprintf(stdout, "keep: %d\n", keep_files);
|
||||||
|
fprintf(stdout, "%s", "\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
return (rc);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
drop_caches(void)
|
||||||
|
{
|
||||||
|
char file[] = "/proc/sys/vm/drop_caches";
|
||||||
|
int fd, rc;
|
||||||
|
|
||||||
|
fd = open(file, O_WRONLY);
|
||||||
|
if (fd == -1) {
|
||||||
|
ERROR("Error %d: open(\"%s\", O_WRONLY)\n", errno, file);
|
||||||
|
return (errno);
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = write(fd, "3", 1);
|
||||||
|
if ((rc == -1) || (rc != 1)) {
|
||||||
|
ERROR("Error %d: write(%d, \"3\", 1)\n", errno, fd);
|
||||||
|
return (errno);
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = close(fd);
|
||||||
|
if (rc == -1) {
|
||||||
|
ERROR("Error %d: close(%d)\n", errno, fd);
|
||||||
|
return (errno);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
run_process(const char *path, char *argv[])
|
||||||
|
{
|
||||||
|
pid_t pid;
|
||||||
|
int rc, devnull_fd;
|
||||||
|
|
||||||
|
pid = vfork();
|
||||||
|
if (pid == 0) {
|
||||||
|
devnull_fd = open("/dev/null", O_WRONLY);
|
||||||
|
|
||||||
|
if (devnull_fd < 0)
|
||||||
|
_exit(-1);
|
||||||
|
|
||||||
|
(void) dup2(devnull_fd, STDOUT_FILENO);
|
||||||
|
(void) dup2(devnull_fd, STDERR_FILENO);
|
||||||
|
close(devnull_fd);
|
||||||
|
|
||||||
|
(void) execvp(path, argv);
|
||||||
|
_exit(-1);
|
||||||
|
} else if (pid > 0) {
|
||||||
|
int status;
|
||||||
|
|
||||||
|
while ((rc = waitpid(pid, &status, 0)) == -1 && errno == EINTR);
|
||||||
|
|
||||||
|
if (rc < 0 || !WIFEXITED(status))
|
||||||
|
return (-1);
|
||||||
|
|
||||||
|
return (WEXITSTATUS(status));
|
||||||
|
}
|
||||||
|
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
post_hook(char *phase)
|
||||||
|
{
|
||||||
|
char *argv[3] = { script, phase, (char *)0 };
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
if (synccaches)
|
||||||
|
sync();
|
||||||
|
|
||||||
|
if (dropcaches) {
|
||||||
|
rc = drop_caches();
|
||||||
|
if (rc)
|
||||||
|
return (rc);
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = run_process(script, argv);
|
||||||
|
if (rc)
|
||||||
|
return (rc);
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define USEC_PER_SEC 1000000
|
||||||
|
|
||||||
|
static void
|
||||||
|
timeval_normalize(struct timeval *tv, time_t sec, suseconds_t usec)
|
||||||
|
{
|
||||||
|
while (usec >= USEC_PER_SEC) {
|
||||||
|
usec -= USEC_PER_SEC;
|
||||||
|
sec++;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (usec < 0) {
|
||||||
|
usec += USEC_PER_SEC;
|
||||||
|
sec--;
|
||||||
|
}
|
||||||
|
|
||||||
|
tv->tv_sec = sec;
|
||||||
|
tv->tv_usec = usec;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
timeval_sub(struct timeval *delta, struct timeval *tv1, struct timeval *tv2)
|
||||||
|
{
|
||||||
|
timeval_normalize(delta,
|
||||||
|
tv1->tv_sec - tv2->tv_sec,
|
||||||
|
tv1->tv_usec - tv2->tv_usec);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
create_files(void)
|
||||||
|
{
|
||||||
|
int i, rc;
|
||||||
|
char *file = NULL;
|
||||||
|
struct timeval start, stop, delta;
|
||||||
|
|
||||||
|
file = malloc(PATH_MAX);
|
||||||
|
if (file == NULL) {
|
||||||
|
rc = ENOMEM;
|
||||||
|
ERROR("Error %d: malloc(%d) bytes for file name\n",
|
||||||
|
rc, PATH_MAX);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
(void) gettimeofday(&start, NULL);
|
||||||
|
|
||||||
|
for (i = 1; i <= files; i++) {
|
||||||
|
(void) sprintf(file, "%s/file-%d", path, i);
|
||||||
|
|
||||||
|
if (nth && ((i % nth) == 0))
|
||||||
|
fprintf(stdout, "create: %s\n", file);
|
||||||
|
|
||||||
|
rc = unlink(file);
|
||||||
|
if ((rc == -1) && (errno != ENOENT)) {
|
||||||
|
ERROR("Error %d: unlink(%s)\n", errno, file);
|
||||||
|
rc = errno;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = open(file, O_CREAT, 0644);
|
||||||
|
if (rc == -1) {
|
||||||
|
ERROR("Error %d: open(%s, O_CREATE, 0644)\n",
|
||||||
|
errno, file);
|
||||||
|
rc = errno;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = close(rc);
|
||||||
|
if (rc == -1) {
|
||||||
|
ERROR("Error %d: close(%d)\n", errno, rc);
|
||||||
|
rc = errno;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
(void) gettimeofday(&stop, NULL);
|
||||||
|
timeval_sub(&delta, &stop, &start);
|
||||||
|
fprintf(stdout, "create: %d.%d seconds\n",
|
||||||
|
(int)delta.tv_sec, (int)delta.tv_usec);
|
||||||
|
|
||||||
|
rc = post_hook("post");
|
||||||
|
out:
|
||||||
|
if (file)
|
||||||
|
free(file);
|
||||||
|
|
||||||
|
return (rc);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
get_random_bytes(char *buf, size_t bytes)
|
||||||
|
{
|
||||||
|
int rand;
|
||||||
|
ssize_t bytes_read = 0;
|
||||||
|
|
||||||
|
rand = open("/dev/urandom", O_RDONLY);
|
||||||
|
|
||||||
|
if (rand < 0)
|
||||||
|
return (rand);
|
||||||
|
|
||||||
|
while (bytes_read < bytes) {
|
||||||
|
ssize_t rc = read(rand, buf + bytes_read, bytes - bytes_read);
|
||||||
|
if (rc < 0)
|
||||||
|
break;
|
||||||
|
bytes_read += rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
(void) close(rand);
|
||||||
|
|
||||||
|
return (bytes_read);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
setxattrs(void)
|
||||||
|
{
|
||||||
|
int i, j, rnd_size = size, shift, rc = 0;
|
||||||
|
char name[XATTR_NAME_MAX];
|
||||||
|
char *value = NULL;
|
||||||
|
char *file = NULL;
|
||||||
|
struct timeval start, stop, delta;
|
||||||
|
|
||||||
|
value = malloc(XATTR_SIZE_MAX);
|
||||||
|
if (value == NULL) {
|
||||||
|
rc = ENOMEM;
|
||||||
|
ERROR("Error %d: malloc(%d) bytes for xattr value\n",
|
||||||
|
rc, XATTR_SIZE_MAX);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
file = malloc(PATH_MAX);
|
||||||
|
if (file == NULL) {
|
||||||
|
rc = ENOMEM;
|
||||||
|
ERROR("Error %d: malloc(%d) bytes for file name\n",
|
||||||
|
rc, PATH_MAX);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
(void) gettimeofday(&start, NULL);
|
||||||
|
|
||||||
|
for (i = 1; i <= files; i++) {
|
||||||
|
(void) sprintf(file, "%s/file-%d", path, i);
|
||||||
|
|
||||||
|
if (nth && ((i % nth) == 0))
|
||||||
|
fprintf(stdout, "setxattr: %s\n", file);
|
||||||
|
|
||||||
|
for (j = 1; j <= xattrs; j++) {
|
||||||
|
if (size_is_random)
|
||||||
|
rnd_size = (random() % (size - 16)) + 16;
|
||||||
|
|
||||||
|
(void) sprintf(name, "user.%d", j);
|
||||||
|
if (value_is_random) {
|
||||||
|
rc = get_random_bytes(value, rnd_size);
|
||||||
|
if (rc < rnd_size) {
|
||||||
|
ERROR("Error %d: get_random_bytes() "
|
||||||
|
"wanted %d got %d\n", errno,
|
||||||
|
rnd_size, rc);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
shift = sprintf(value, "size=%d ", rnd_size);
|
||||||
|
memset(value + shift, 'x', XATTR_SIZE_MAX -
|
||||||
|
shift);
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = lsetxattr(file, name, value, rnd_size, 0);
|
||||||
|
if (rc == -1) {
|
||||||
|
ERROR("Error %d: lsetxattr(%s, %s, ..., %d)\n",
|
||||||
|
errno, file, name, rnd_size);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
(void) gettimeofday(&stop, NULL);
|
||||||
|
timeval_sub(&delta, &stop, &start);
|
||||||
|
fprintf(stdout, "setxattr: %d.%d seconds\n",
|
||||||
|
(int)delta.tv_sec, (int)delta.tv_usec);
|
||||||
|
|
||||||
|
rc = post_hook("post");
|
||||||
|
out:
|
||||||
|
if (file)
|
||||||
|
free(file);
|
||||||
|
|
||||||
|
if (value)
|
||||||
|
free(value);
|
||||||
|
|
||||||
|
return (rc);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
getxattrs(void)
|
||||||
|
{
|
||||||
|
int i, j, rnd_size, shift, rc = 0;
|
||||||
|
char name[XATTR_NAME_MAX];
|
||||||
|
char *verify_value = NULL;
|
||||||
|
char *value = NULL;
|
||||||
|
char *file = NULL;
|
||||||
|
struct timeval start, stop, delta;
|
||||||
|
|
||||||
|
verify_value = malloc(XATTR_SIZE_MAX);
|
||||||
|
if (verify_value == NULL) {
|
||||||
|
rc = ENOMEM;
|
||||||
|
ERROR("Error %d: malloc(%d) bytes for xattr verify\n",
|
||||||
|
rc, XATTR_SIZE_MAX);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
value = malloc(XATTR_SIZE_MAX);
|
||||||
|
if (value == NULL) {
|
||||||
|
rc = ENOMEM;
|
||||||
|
ERROR("Error %d: malloc(%d) bytes for xattr value\n",
|
||||||
|
rc, XATTR_SIZE_MAX);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
file = malloc(PATH_MAX);
|
||||||
|
if (file == NULL) {
|
||||||
|
rc = ENOMEM;
|
||||||
|
ERROR("Error %d: malloc(%d) bytes for file name\n",
|
||||||
|
rc, PATH_MAX);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
(void) gettimeofday(&start, NULL);
|
||||||
|
|
||||||
|
for (i = 1; i <= files; i++) {
|
||||||
|
(void) sprintf(file, "%s/file-%d", path, i);
|
||||||
|
|
||||||
|
if (nth && ((i % nth) == 0))
|
||||||
|
fprintf(stdout, "getxattr: %s\n", file);
|
||||||
|
|
||||||
|
for (j = 1; j <= xattrs; j++) {
|
||||||
|
(void) sprintf(name, "user.%d", j);
|
||||||
|
|
||||||
|
rc = lgetxattr(file, name, value, XATTR_SIZE_MAX);
|
||||||
|
if (rc == -1) {
|
||||||
|
ERROR("Error %d: lgetxattr(%s, %s, ..., %d)\n",
|
||||||
|
errno, file, name, XATTR_SIZE_MAX);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (verify) {
|
||||||
|
sscanf(value, "size=%d [a-z]", &rnd_size);
|
||||||
|
shift = sprintf(verify_value, "size=%d ",
|
||||||
|
rnd_size);
|
||||||
|
memset(verify_value + shift, 'x',
|
||||||
|
XATTR_SIZE_MAX - shift);
|
||||||
|
|
||||||
|
if (rnd_size != rc ||
|
||||||
|
memcmp(verify_value, value, rnd_size)) {
|
||||||
|
ERROR("Error %d: verify failed\n "
|
||||||
|
"verify: %s\nvalue: %s\n",
|
||||||
|
EINVAL, verify_value, value);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
(void) gettimeofday(&stop, NULL);
|
||||||
|
timeval_sub(&delta, &stop, &start);
|
||||||
|
fprintf(stdout, "getxattr: %d.%d seconds\n",
|
||||||
|
(int)delta.tv_sec, (int)delta.tv_usec);
|
||||||
|
|
||||||
|
rc = post_hook("post");
|
||||||
|
out:
|
||||||
|
if (file)
|
||||||
|
free(file);
|
||||||
|
|
||||||
|
if (value)
|
||||||
|
free(value);
|
||||||
|
|
||||||
|
if (verify_value)
|
||||||
|
free(verify_value);
|
||||||
|
|
||||||
|
return (rc);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
unlink_files(void)
|
||||||
|
{
|
||||||
|
int i, rc;
|
||||||
|
char *file = NULL;
|
||||||
|
struct timeval start, stop, delta;
|
||||||
|
|
||||||
|
file = malloc(PATH_MAX);
|
||||||
|
if (file == NULL) {
|
||||||
|
rc = ENOMEM;
|
||||||
|
ERROR("Error %d: malloc(%d) bytes for file name\n",
|
||||||
|
rc, PATH_MAX);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
(void) gettimeofday(&start, NULL);
|
||||||
|
|
||||||
|
for (i = 1; i <= files; i++) {
|
||||||
|
(void) sprintf(file, "%s/file-%d", path, i);
|
||||||
|
|
||||||
|
if (nth && ((i % nth) == 0))
|
||||||
|
fprintf(stdout, "unlink: %s\n", file);
|
||||||
|
|
||||||
|
rc = unlink(file);
|
||||||
|
if ((rc == -1) && (errno != ENOENT)) {
|
||||||
|
ERROR("Error %d: unlink(%s)\n", errno, file);
|
||||||
|
return (errno);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
(void) gettimeofday(&stop, NULL);
|
||||||
|
timeval_sub(&delta, &stop, &start);
|
||||||
|
fprintf(stdout, "unlink: %d.%d seconds\n",
|
||||||
|
(int)delta.tv_sec, (int)delta.tv_usec);
|
||||||
|
|
||||||
|
rc = post_hook("post");
|
||||||
|
out:
|
||||||
|
if (file)
|
||||||
|
free(file);
|
||||||
|
|
||||||
|
return (rc);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
rc = parse_args(argc, argv);
|
||||||
|
if (rc)
|
||||||
|
return (rc);
|
||||||
|
|
||||||
|
rc = create_files();
|
||||||
|
if (rc)
|
||||||
|
return (rc);
|
||||||
|
|
||||||
|
rc = setxattrs();
|
||||||
|
if (rc)
|
||||||
|
return (rc);
|
||||||
|
|
||||||
|
rc = getxattrs();
|
||||||
|
if (rc)
|
||||||
|
return (rc);
|
||||||
|
|
||||||
|
if (!keep_files) {
|
||||||
|
rc = unlink_files();
|
||||||
|
if (rc)
|
||||||
|
return (rc);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
2
tests/zfs-tests/include/.gitignore
vendored
Normal file
2
tests/zfs-tests/include/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
/commands.cfg
|
||||||
|
/default.cfg
|
10
tests/zfs-tests/include/Makefile.am
Normal file
10
tests/zfs-tests/include/Makefile.am
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/include
|
||||||
|
dist_pkgdata_SCRIPTS = \
|
||||||
|
commands.cfg \
|
||||||
|
default.cfg \
|
||||||
|
libtest.shlib \
|
||||||
|
math.shlib \
|
||||||
|
properties.shlib
|
||||||
|
|
||||||
|
EXTRA_DIST = \
|
||||||
|
zfs_commands.cfg
|
119
tests/zfs-tests/include/commands.cfg.in
Normal file
119
tests/zfs-tests/include/commands.cfg.in
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
export AWK="@AWK@"
|
||||||
|
export BLOCKDEV="@BLOCKDEV@"
|
||||||
|
export BASENAME="@BASENAME@"
|
||||||
|
export BC="@BC@"
|
||||||
|
export BUNZIP2="@BUNZIP2@"
|
||||||
|
export BZCAT="@BZCAT@"
|
||||||
|
export CAT="@CAT@"
|
||||||
|
export CD="@CD@"
|
||||||
|
export CHACL="@CHACL@"
|
||||||
|
export CHGRP="@CHGRP@"
|
||||||
|
export CHMOD="@CHMOD@"
|
||||||
|
export CHOWN="@CHOWN@"
|
||||||
|
export CKSUM="@CKSUM@"
|
||||||
|
export CMP="@CMP@"
|
||||||
|
export COMPRESS="@COMPRESS@"
|
||||||
|
export COREADM="@COREADM@"
|
||||||
|
export CP="@CP@"
|
||||||
|
export CPIO="@CPIO@"
|
||||||
|
export CUT="@CUT@"
|
||||||
|
export DATE="@DATE@"
|
||||||
|
export DD="@DD@"
|
||||||
|
export DF="@DF@"
|
||||||
|
export DIFF="@DIFF@"
|
||||||
|
export DIRCMP="@DIRCMP@"
|
||||||
|
export DIRNAME="@DIRNAME@"
|
||||||
|
export DU="@DU@"
|
||||||
|
export DUMPADM="@DUMPADM@"
|
||||||
|
export ECHO="@ECHO@"
|
||||||
|
export EGREP="@EGREP@"
|
||||||
|
export FDISK="@FDISK@"
|
||||||
|
export FGREP="@FGREP@"
|
||||||
|
export FILE="@FILE@"
|
||||||
|
export FIND="@FIND@"
|
||||||
|
export FORMAT="@FORMAT@"
|
||||||
|
export FSCK="@FSCK@"
|
||||||
|
export GETENT="@GETENT@"
|
||||||
|
export GETFACL="@GETFACL@"
|
||||||
|
export GETMAJOR="@GETMAJOR@"
|
||||||
|
export GNUDD="@GNUDD@"
|
||||||
|
export GREP="@GREP@"
|
||||||
|
export GROUPADD="@GROUPADD@"
|
||||||
|
export GROUPDEL="@GROUPDEL@"
|
||||||
|
export GROUPMOD="@GROUPMOD@"
|
||||||
|
export HEAD="@HEAD@"
|
||||||
|
export HOSTNAME="@HOSTNAME@"
|
||||||
|
export ID="@ID@"
|
||||||
|
export ISAINFO="@ISAINFO@"
|
||||||
|
export KILL="@KILL@"
|
||||||
|
export KSH="@KSH@"
|
||||||
|
export KSTAT="@KSTAT@"
|
||||||
|
export LOCKFS="@LOCKFS@"
|
||||||
|
export LOFIADM="@LOFIADM@"
|
||||||
|
export LOGNAME="@LOGNAME@"
|
||||||
|
export LS="@LS@"
|
||||||
|
export MD5SUM="@MD5SUM@"
|
||||||
|
export MKDIR="@MKDIR@"
|
||||||
|
export MKNOD="@MKNOD@"
|
||||||
|
export MKTEMP="@MKTEMP@"
|
||||||
|
export MNTTAB="@MNTTAB@"
|
||||||
|
export MODINFO="@MODINFO@"
|
||||||
|
export MODUNLOAD="@MODUNLOAD@"
|
||||||
|
export MOUNT="@MOUNT@"
|
||||||
|
export MV="@MV@"
|
||||||
|
export NAWK="@AWK@"
|
||||||
|
export NEWFS="@NEWFS@"
|
||||||
|
export NPROC="@NPROC@"
|
||||||
|
export PAGESIZE="@PAGESIZE@"
|
||||||
|
export PFEXEC="@PFEXEC@"
|
||||||
|
export PGREP="@PGREP@"
|
||||||
|
export PING="@PING@"
|
||||||
|
export PKGINFO="@PKGINFO@"
|
||||||
|
export PKILL="@PKILL@"
|
||||||
|
export PRINTF="@PRINTF@"
|
||||||
|
export PRTVTOC="@PRTVTOC@"
|
||||||
|
export PS="@PS@"
|
||||||
|
export PSRINFO="@PSRINFO@"
|
||||||
|
export PYTHON="@PYTHON@"
|
||||||
|
export REBOOT="@REBOOT@"
|
||||||
|
export RM="@RM@"
|
||||||
|
export RMDIR="@RMDIR@"
|
||||||
|
export RSH="@RSH@"
|
||||||
|
export SED="@SED@"
|
||||||
|
export SETFACL="@SETFACL@"
|
||||||
|
export SHARE="@SHARE@"
|
||||||
|
export SHUF="@SHUF@"
|
||||||
|
export SLEEP="@SLEEP@"
|
||||||
|
export SORT="@SORT@"
|
||||||
|
export STRINGS="@STRINGS@"
|
||||||
|
export SU="@SU@"
|
||||||
|
export SUM="@SUM@"
|
||||||
|
export SVCADM="@SVCADM@"
|
||||||
|
export SVCS="@SVCS@"
|
||||||
|
export SWAP="@SWAP@"
|
||||||
|
export SWAPADD="@SWAPADD@"
|
||||||
|
export SYNC="@SYNC@"
|
||||||
|
export TAIL="@TAIL@"
|
||||||
|
export TAR="@TAR@"
|
||||||
|
export TOUCH="@TOUCH@"
|
||||||
|
export TR="@TR@"
|
||||||
|
export TRUE="@TRUE@"
|
||||||
|
export TRUNCATE="@TRUNCATE@"
|
||||||
|
export UDEVADM="@UDEVADM@"
|
||||||
|
export UFSDUMP="@UFSDUMP@"
|
||||||
|
export UFSRESTORE="@UFSRESTORE@"
|
||||||
|
export UMASK="@UMASK@"
|
||||||
|
export UMOUNT="@UMOUNT@"
|
||||||
|
export UMOUNTALL="@UMOUNTALL@"
|
||||||
|
export UNAME="@UNAME@"
|
||||||
|
export UNCOMPRESS="@UNCOMPRESS@"
|
||||||
|
export UNIQ="@UNIQ@"
|
||||||
|
export UNSHARE="@UNSHARE@"
|
||||||
|
export USERADD="@USERADD@"
|
||||||
|
export USERDEL="@USERDEL@"
|
||||||
|
export USERMOD="@USERMOD@"
|
||||||
|
export WAIT="@WAIT@"
|
||||||
|
export WC="@WC@"
|
||||||
|
export ZONEADM="@ZONEADM@"
|
||||||
|
export ZONECFG="@ZONECFG@"
|
||||||
|
export ZONENAME="@ZONENAME@"
|
200
tests/zfs-tests/include/default.cfg.in
Normal file
200
tests/zfs-tests/include/default.cfg.in
Normal file
@ -0,0 +1,200 @@
|
|||||||
|
#
|
||||||
|
# CDDL HEADER START
|
||||||
|
#
|
||||||
|
# The contents of this file are subject to the terms of the
|
||||||
|
# Common Development and Distribution License (the "License").
|
||||||
|
# You may not use this file except in compliance with the License.
|
||||||
|
#
|
||||||
|
# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
||||||
|
# or http://www.opensolaris.org/os/licensing.
|
||||||
|
# See the License for the specific language governing permissions
|
||||||
|
# and limitations under the License.
|
||||||
|
#
|
||||||
|
# When distributing Covered Code, include this CDDL HEADER in each
|
||||||
|
# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
||||||
|
# If applicable, add the following below this CDDL HEADER, with the
|
||||||
|
# fields enclosed by brackets "[]" replaced with your own identifying
|
||||||
|
# information: Portions Copyright [yyyy] [name of copyright owner]
|
||||||
|
#
|
||||||
|
# CDDL HEADER END
|
||||||
|
#
|
||||||
|
|
||||||
|
#
|
||||||
|
# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
|
||||||
|
# Use is subject to license terms.
|
||||||
|
#
|
||||||
|
|
||||||
|
#
|
||||||
|
# Copyright (c) 2016 by Delphix. All rights reserved.
|
||||||
|
#
|
||||||
|
|
||||||
|
. $STF_SUITE/include/commands.cfg
|
||||||
|
. $STF_SUITE/include/libtest.shlib
|
||||||
|
|
||||||
|
# Optionally override the installed ZFS commands to run in-tree
|
||||||
|
if [[ -f "$STF_SUITE/include/zfs_commands.cfg" ]]; then
|
||||||
|
. $STF_SUITE/include/zfs_commands.cfg
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Define run length constants
|
||||||
|
export RT_LONG="3"
|
||||||
|
export RT_MEDIUM="2"
|
||||||
|
export RT_SHORT="1"
|
||||||
|
|
||||||
|
# Define macro for zone test
|
||||||
|
export ZONE_POOL="zonepool"
|
||||||
|
export ZONE_CTR="zonectr"
|
||||||
|
|
||||||
|
# Common paths
|
||||||
|
bindir=@bindir@
|
||||||
|
sbindir=@sbindir@
|
||||||
|
helperdir=@datarootdir@/@PACKAGE@/zfs-tests/bin
|
||||||
|
|
||||||
|
# ZFS Commands
|
||||||
|
ZDB=${ZDB:-${sbindir}/zdb}
|
||||||
|
ZFS=${ZFS:-${sbindir}/zfs}
|
||||||
|
ZHACK=${ZHACK:-${sbindir}/zhack}
|
||||||
|
ZINJECT=${ZINJECT:-${sbindir}/zinject}
|
||||||
|
ZPOOL=${ZPOOL:-${sbindir}/zpool}
|
||||||
|
ZTEST=${ZTEST:-${sbindir}/ztest}
|
||||||
|
ZPIOS=${ZPIOS:-${sbindir}/zpios}
|
||||||
|
|
||||||
|
# Test Suite Specific Commands
|
||||||
|
export CHG_USR_EXEC=${CHG_USR_EXEC:-${helperdir}/chg_usr_exec}
|
||||||
|
export DEVNAME2DEVID=${DEVNAME2DEVID:-${helperdir}/devname2devid}
|
||||||
|
export DIR_RD_UPDATE=${DIR_RD_UPDATE:-${helperdir}/dir_rd_update}
|
||||||
|
export FILE_CHECK=${FILE_CHECK:-${helperdir}/file_check}
|
||||||
|
export FILE_TRUNC=${FILE_TRUNC:-${helperdir}/file_trunc}
|
||||||
|
export FILE_WRITE=${FILE_WRITE:-${helperdir}/file_write}
|
||||||
|
export LARGEST_FILE=${LARGEST_FILE:-${helperdir}/largest_file}
|
||||||
|
export MKBUSY=${MKBUSY:-${helperdir}/mkbusy}
|
||||||
|
export MKFILE=${MKFILE:-${helperdir}/mkfile}
|
||||||
|
export MKFILES=${MKFILES:-${helperdir}/mkfiles}
|
||||||
|
export MKTREE=${MKTREE:-${helperdir}/mktree}
|
||||||
|
export MMAP_EXEC=${MMAP_EXEC:-${helperdir}/mmap_exec}
|
||||||
|
export MMAPWRITE=${MMAPWRITE:-${helperdir}/mmapwrite}
|
||||||
|
export RANDFREE_FILE=${RANDFREE_FILE:-${helperdir}/randfree_file}
|
||||||
|
export READMMAP=${READMMAP:-${helperdir}/readmmap}
|
||||||
|
export RENAME_DIR=${RENAME_DIR:-${helperdir}/rename_dir}
|
||||||
|
export RM_LNKCNT_ZERO_FILE=${RM_LNKCNT_ZERO_FILE:-${helperdir}/rm_lnkcnt_zero_file}
|
||||||
|
export THREADSAPPEND=${THREADSAPPEND:-${helperdir}/threadsappend}
|
||||||
|
export XATTRTEST=${XATTRTEST:-${helpdir}/xattrtest}
|
||||||
|
|
||||||
|
# ensure we're running in the C locale, since
|
||||||
|
# localised messages may result in test failures
|
||||||
|
export LC_ALL="C"
|
||||||
|
export LANG="C"
|
||||||
|
|
||||||
|
#
|
||||||
|
# pattern to ignore from 'zpool list'.
|
||||||
|
#
|
||||||
|
export NO_POOLS="no pools available"
|
||||||
|
|
||||||
|
# pattern to ignore from 'zfs list'.
|
||||||
|
export NO_DATASETS="no datasets available"
|
||||||
|
|
||||||
|
export TEST_BASE_DIR="/var/tmp"
|
||||||
|
|
||||||
|
# Default to compression ON
|
||||||
|
export COMPRESSION_PROP=on
|
||||||
|
|
||||||
|
# Default to using the checksum
|
||||||
|
export CHECKSUM_PROP=on
|
||||||
|
|
||||||
|
# some common variables used by test scripts :
|
||||||
|
|
||||||
|
# some test pool names
|
||||||
|
export TESTPOOL=testpool.$$
|
||||||
|
export TESTPOOL1=testpool1.$$
|
||||||
|
export TESTPOOL2=testpool2.$$
|
||||||
|
export TESTPOOL3=testpool3.$$
|
||||||
|
|
||||||
|
# some test file system names
|
||||||
|
export TESTFS=testfs.$$
|
||||||
|
export TESTFS1=testfs1.$$
|
||||||
|
export TESTFS2=testfs2.$$
|
||||||
|
export TESTFS3=testfs3.$$
|
||||||
|
|
||||||
|
# some test directory names
|
||||||
|
export TESTDIR=${TEST_BASE_DIR%%/}/testdir$$
|
||||||
|
export TESTDIR0=${TEST_BASE_DIR%%/}/testdir0$$
|
||||||
|
export TESTDIR1=${TEST_BASE_DIR%%/}/testdir1$$
|
||||||
|
export TESTDIR2=${TEST_BASE_DIR%%/}/testdir2$$
|
||||||
|
|
||||||
|
export ZFSROOT=
|
||||||
|
|
||||||
|
export TESTSNAP=testsnap$$
|
||||||
|
export TESTSNAP1=testsnap1$$
|
||||||
|
export TESTSNAP2=testsnap2$$
|
||||||
|
export TESTCLONE=testclone$$
|
||||||
|
export TESTCLONE1=testclone1$$
|
||||||
|
export TESTCLONE2=testclone2$$
|
||||||
|
export TESTCLCT=testclct$$
|
||||||
|
export TESTCTR=testctr$$
|
||||||
|
export TESTCTR1=testctr1$$
|
||||||
|
export TESTCTR2=testctr2$$
|
||||||
|
export TESTVOL=testvol$$
|
||||||
|
export TESTVOL1=testvol1$$
|
||||||
|
export TESTVOL2=testvol2$$
|
||||||
|
export TESTFILE0=testfile0.$$
|
||||||
|
export TESTFILE1=testfile1.$$
|
||||||
|
export TESTFILE2=testfile2.$$
|
||||||
|
|
||||||
|
export LONGPNAME="poolname50charslong_012345678901234567890123456789"
|
||||||
|
export LONGFSNAME="fsysname50charslong_012345678901234567890123456789"
|
||||||
|
export SNAPFS="$TESTPOOL/$TESTFS@$TESTSNAP"
|
||||||
|
export SNAPFS1="$TESTPOOL/$TESTVOL@$TESTSNAP"
|
||||||
|
|
||||||
|
export VOLSIZE=150m
|
||||||
|
export BIGVOLSIZE=1eb
|
||||||
|
|
||||||
|
# Default to limit disks to be checked
|
||||||
|
export MAX_FINDDISKSNUM=6
|
||||||
|
|
||||||
|
# For iscsi target support
|
||||||
|
export ISCSITGTFILE=/tmp/iscsitgt_file
|
||||||
|
export ISCSITGT_FMRI=svc:/system/iscsitgt:default
|
||||||
|
|
||||||
|
#
|
||||||
|
# finally, if we're running in a local zone
|
||||||
|
# we take some additional actions
|
||||||
|
if ! is_global_zone; then
|
||||||
|
reexport_pool
|
||||||
|
fi
|
||||||
|
|
||||||
|
export ZFS_VERSION=5
|
||||||
|
export ZFS_ALL_VERSIONS="1 2 3 4 5"
|
||||||
|
|
||||||
|
for i in $ZFS_ALL_VERSIONS; do
|
||||||
|
eval 'export ZFS_VERSION_$i="v${i}-fs"'
|
||||||
|
done
|
||||||
|
|
||||||
|
if is_linux; then
|
||||||
|
unpack_opts="--sparse -xf"
|
||||||
|
pack_opts="--sparse -cf"
|
||||||
|
verbose=" -v"
|
||||||
|
unpack_preserve=" -xpf"
|
||||||
|
pack_preserve=" -cpf"
|
||||||
|
|
||||||
|
ZVOL_DEVDIR="/dev/zvol"
|
||||||
|
ZVOL_RDEVDIR="/dev/zvol"
|
||||||
|
DEV_DSKDIR="/dev"
|
||||||
|
DEV_RDSKDIR="/dev"
|
||||||
|
|
||||||
|
NEWFS_DEFAULT_FS="ext2"
|
||||||
|
else
|
||||||
|
unpack_opts="xv"
|
||||||
|
pack_opts="cf"
|
||||||
|
verbose="v"
|
||||||
|
unpack_preserve="xpf"
|
||||||
|
pack_preserve="cpf"
|
||||||
|
|
||||||
|
ZVOL_DEVDIR="/dev/zvol/dsk"
|
||||||
|
ZVOL_RDEVDIR="/dev/zvol/rdsk"
|
||||||
|
DEV_DSKDIR="/dev/dsk"
|
||||||
|
DEV_RDSKDIR="/dev/rdsk"
|
||||||
|
|
||||||
|
NEWFS_DEFAULT_FS="ufs"
|
||||||
|
fi
|
||||||
|
export unpack_opts pack_opts verbose unpack_preserve pack_preserve \
|
||||||
|
ZVOL_DEVDIR ZVOL_RDEVDIR NEWFS_DEFAULT_FS DEV_DSKDIR DEV_RDSKDIR
|
2648
tests/zfs-tests/include/libtest.shlib
Normal file
2648
tests/zfs-tests/include/libtest.shlib
Normal file
File diff suppressed because it is too large
Load Diff
43
tests/zfs-tests/include/math.shlib
Normal file
43
tests/zfs-tests/include/math.shlib
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
#
|
||||||
|
# This file and its contents are supplied under the terms of the
|
||||||
|
# Common Development and Distribution License ("CDDL"), version 1.0.
|
||||||
|
# You may only use this file in accordance with the terms of version
|
||||||
|
# 1.0 of the CDDL.
|
||||||
|
#
|
||||||
|
# A full copy of the text of the CDDL should have accompanied this
|
||||||
|
# source. A copy of the CDDL is also available via the Internet at
|
||||||
|
# http://www.illumos.org/license/CDDL.
|
||||||
|
#
|
||||||
|
|
||||||
|
#
|
||||||
|
# Copyright (c) 2012 by Delphix. All rights reserved.
|
||||||
|
#
|
||||||
|
|
||||||
|
#
|
||||||
|
# Return 0 if the percentage difference between $a and $b is $percent or
|
||||||
|
# greater. Return 1 if the percentage is lower or if we would divide by
|
||||||
|
# zero. For use like this:
|
||||||
|
#
|
||||||
|
# Do $action if the calculated percentage is greater or equal to that passed in:
|
||||||
|
# within_percent A B P && $action
|
||||||
|
# Do $action if the calculated percentage is less than that passed in:
|
||||||
|
# within_percent A B P || $action
|
||||||
|
#
|
||||||
|
function within_percent
|
||||||
|
{
|
||||||
|
typeset a=$1
|
||||||
|
typeset b=$1
|
||||||
|
typeset percent=$3
|
||||||
|
|
||||||
|
# Set $a or $b to $2 such that a >= b
|
||||||
|
[[ '1' = $($ECHO "if ($2 > $a) 1" | $BC) ]] && a=$2 || b=$2
|
||||||
|
|
||||||
|
# Prevent division by 0
|
||||||
|
[[ $a =~ [1-9] ]] || return 1
|
||||||
|
|
||||||
|
typeset p=$($ECHO "scale=2; $b * 100 / $a" | $BC)
|
||||||
|
log_note "Comparing $a and $b given $percent% (calculated: $p%)"
|
||||||
|
[[ '1' = $($ECHO "scale=2; if ($p >= $percent) 1" | $BC) ]] && return 0
|
||||||
|
|
||||||
|
return 1
|
||||||
|
}
|
63
tests/zfs-tests/include/properties.shlib
Normal file
63
tests/zfs-tests/include/properties.shlib
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
#
|
||||||
|
# This file and its contents are supplied under the terms of the
|
||||||
|
# Common Development and Distribution License ("CDDL"), version 1.0.
|
||||||
|
# You may only use this file in accordance with the terms of version
|
||||||
|
# 1.0 of the CDDL.
|
||||||
|
#
|
||||||
|
# A full copy of the text of the CDDL should have accompanied this
|
||||||
|
# source. A copy of the CDDL is also available via the Internet at
|
||||||
|
# http://www.illumos.org/license/CDDL.
|
||||||
|
#
|
||||||
|
|
||||||
|
#
|
||||||
|
# Copyright (c) 2012 by Delphix. All rights reserved.
|
||||||
|
#
|
||||||
|
|
||||||
|
typeset -a compress_props=('on' 'off' 'lzjb' 'gzip' 'gzip-1' 'gzip-2' 'gzip-3'
|
||||||
|
'gzip-4' 'gzip-5' 'gzip-6' 'gzip-7' 'gzip-8' 'gzip-9' 'zle')
|
||||||
|
|
||||||
|
typeset -a checksum_props=('on' 'off' 'fletcher2' 'fletcher4' 'sha256')
|
||||||
|
|
||||||
|
#
|
||||||
|
# Given the property array passed in, return 'num_props' elements to the
|
||||||
|
# user, excluding any elements below 'start.' This allows us to exclude
|
||||||
|
# 'off' and 'on' which can be either unwanted, or a duplicate of another
|
||||||
|
# property respectively.
|
||||||
|
#
|
||||||
|
function get_rand_prop
|
||||||
|
{
|
||||||
|
typeset prop_array=($(eval echo \${$1[@]}))
|
||||||
|
typeset -i num_props=$2
|
||||||
|
typeset -i start=$3
|
||||||
|
typeset retstr=""
|
||||||
|
|
||||||
|
[[ -z $prop_array || -z $num_props || -z $start ]] && \
|
||||||
|
log_fail "get_rand_prop: bad arguments"
|
||||||
|
|
||||||
|
typeset prop_max=$((${#prop_array[@]} - 1))
|
||||||
|
typeset -i i
|
||||||
|
for i in $($SHUF -i $start-$prop_max -n $num_props); do
|
||||||
|
retstr="${prop_array[$i]} $retstr"
|
||||||
|
done
|
||||||
|
echo $retstr
|
||||||
|
}
|
||||||
|
|
||||||
|
function get_rand_compress
|
||||||
|
{
|
||||||
|
get_rand_prop compress_props $1 2
|
||||||
|
}
|
||||||
|
|
||||||
|
function get_rand_compress_any
|
||||||
|
{
|
||||||
|
get_rand_prop compress_props $1 0
|
||||||
|
}
|
||||||
|
|
||||||
|
function get_rand_checksum
|
||||||
|
{
|
||||||
|
get_rand_prop checksum_props $1 2
|
||||||
|
}
|
||||||
|
|
||||||
|
function get_rand_checksum_any
|
||||||
|
{
|
||||||
|
get_rand_prop checksum_props $1 0
|
||||||
|
}
|
1
tests/zfs-tests/include/zfs_commands.cfg
Symbolic link
1
tests/zfs-tests/include/zfs_commands.cfg
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../../../zfs-script-config.sh
|
1
tests/zfs-tests/tests/Makefile.am
Normal file
1
tests/zfs-tests/tests/Makefile.am
Normal file
@ -0,0 +1 @@
|
|||||||
|
SUBDIRS = functional stress
|
55
tests/zfs-tests/tests/functional/Makefile.am
Normal file
55
tests/zfs-tests/tests/functional/Makefile.am
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
SUBDIRS = \
|
||||||
|
acl \
|
||||||
|
atime \
|
||||||
|
bootfs \
|
||||||
|
cache \
|
||||||
|
cachefile \
|
||||||
|
casenorm \
|
||||||
|
clean_mirror \
|
||||||
|
cli_root \
|
||||||
|
cli_user \
|
||||||
|
compression \
|
||||||
|
ctime \
|
||||||
|
delegate \
|
||||||
|
devices \
|
||||||
|
exec \
|
||||||
|
features \
|
||||||
|
grow_pool \
|
||||||
|
grow_replicas \
|
||||||
|
history \
|
||||||
|
inheritance \
|
||||||
|
inuse \
|
||||||
|
large_files \
|
||||||
|
largest_pool \
|
||||||
|
link_count \
|
||||||
|
migration \
|
||||||
|
mmap \
|
||||||
|
mount \
|
||||||
|
mv_files \
|
||||||
|
nestedfs \
|
||||||
|
no_space \
|
||||||
|
nopwrite \
|
||||||
|
online_offline \
|
||||||
|
pool_names \
|
||||||
|
poolversion \
|
||||||
|
privilege \
|
||||||
|
quota \
|
||||||
|
redundancy \
|
||||||
|
refquota \
|
||||||
|
refreserv \
|
||||||
|
rename_dirs \
|
||||||
|
replacement \
|
||||||
|
reservation \
|
||||||
|
rootpool \
|
||||||
|
rsend \
|
||||||
|
scrub_mirror \
|
||||||
|
slog \
|
||||||
|
snapshot \
|
||||||
|
snapused \
|
||||||
|
sparse \
|
||||||
|
threadsappend \
|
||||||
|
truncate \
|
||||||
|
userquota \
|
||||||
|
write_dirs \
|
||||||
|
xattr \
|
||||||
|
zvol
|
6
tests/zfs-tests/tests/functional/acl/Makefile.am
Normal file
6
tests/zfs-tests/tests/functional/acl/Makefile.am
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/acl
|
||||||
|
dist_pkgdata_SCRIPTS = \
|
||||||
|
acl.cfg \
|
||||||
|
acl_common.kshlib
|
||||||
|
|
||||||
|
SUBDIRS = posix
|
64
tests/zfs-tests/tests/functional/acl/acl.cfg
Normal file
64
tests/zfs-tests/tests/functional/acl/acl.cfg
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
#
|
||||||
|
# CDDL HEADER START
|
||||||
|
#
|
||||||
|
# The contents of this file are subject to the terms of the
|
||||||
|
# Common Development and Distribution License (the "License").
|
||||||
|
# You may not use this file except in compliance with the License.
|
||||||
|
#
|
||||||
|
# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
||||||
|
# or http://www.opensolaris.org/os/licensing.
|
||||||
|
# See the License for the specific language governing permissions
|
||||||
|
# and limitations under the License.
|
||||||
|
#
|
||||||
|
# When distributing Covered Code, include this CDDL HEADER in each
|
||||||
|
# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
||||||
|
# If applicable, add the following below this CDDL HEADER, with the
|
||||||
|
# fields enclosed by brackets "[]" replaced with your own identifying
|
||||||
|
# information: Portions Copyright [yyyy] [name of copyright owner]
|
||||||
|
#
|
||||||
|
# CDDL HEADER END
|
||||||
|
#
|
||||||
|
|
||||||
|
#
|
||||||
|
# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
|
||||||
|
# Use is subject to license terms.
|
||||||
|
#
|
||||||
|
|
||||||
|
. $STF_SUITE/include/libtest.shlib
|
||||||
|
|
||||||
|
export NISSTAFILE=/var/tmp/nis_state
|
||||||
|
export TESTFILE=testfile$$
|
||||||
|
export TESTFILE0=testfile0.$$
|
||||||
|
export TESTFILE2=testfile2.$$
|
||||||
|
|
||||||
|
# Define super user 'zfstest'
|
||||||
|
export ZFS_ACL_ADMIN=zfstest
|
||||||
|
|
||||||
|
export ZFS_ACL_STAFF_GROUP=zfsgrp
|
||||||
|
export ZFS_ACL_STAFF1=staff1
|
||||||
|
export ZFS_ACL_STAFF2=staff2
|
||||||
|
|
||||||
|
export ZFS_ACL_OTHER_GROUP=othergrp
|
||||||
|
export ZFS_ACL_OTHER1=other1
|
||||||
|
export ZFS_ACL_OTHER2=other2
|
||||||
|
|
||||||
|
# Define the current user who run 'usr_exec'
|
||||||
|
export ZFS_ACL_CUR_USER=""
|
||||||
|
|
||||||
|
# Define global error string
|
||||||
|
export ZFS_ACL_ERR_STR=""
|
||||||
|
|
||||||
|
# Define test file and test directory which will be operated by chmod
|
||||||
|
export testfile=$TESTDIR/testfile
|
||||||
|
export testdir=$TESTDIR/testdir
|
||||||
|
|
||||||
|
# Define several directories for trivial ACLs function test.
|
||||||
|
export RES_DIR=$TESTDIR/RES
|
||||||
|
export INI_DIR=$TESTDIR/INIT
|
||||||
|
export TST_DIR=$TESTDIR/TEST
|
||||||
|
export TMP_DIR=$TESTDIR/TMP
|
||||||
|
|
||||||
|
# Define test files and their attributes files number for trivial
|
||||||
|
# ACLs function test
|
||||||
|
export NUM_FILE=5
|
||||||
|
export NUM_ATTR=10
|
626
tests/zfs-tests/tests/functional/acl/acl_common.kshlib
Normal file
626
tests/zfs-tests/tests/functional/acl/acl_common.kshlib
Normal file
@ -0,0 +1,626 @@
|
|||||||
|
#
|
||||||
|
# CDDL HEADER START
|
||||||
|
#
|
||||||
|
# The contents of this file are subject to the terms of the
|
||||||
|
# Common Development and Distribution License (the "License").
|
||||||
|
# You may not use this file except in compliance with the License.
|
||||||
|
#
|
||||||
|
# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
||||||
|
# or http://www.opensolaris.org/os/licensing.
|
||||||
|
# See the License for the specific language governing permissions
|
||||||
|
# and limitations under the License.
|
||||||
|
#
|
||||||
|
# When distributing Covered Code, include this CDDL HEADER in each
|
||||||
|
# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
||||||
|
# If applicable, add the following below this CDDL HEADER, with the
|
||||||
|
# fields enclosed by brackets "[]" replaced with your own identifying
|
||||||
|
# information: Portions Copyright [yyyy] [name of copyright owner]
|
||||||
|
#
|
||||||
|
# CDDL HEADER END
|
||||||
|
#
|
||||||
|
|
||||||
|
#
|
||||||
|
# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
|
||||||
|
# Use is subject to license terms.
|
||||||
|
#
|
||||||
|
|
||||||
|
. $STF_SUITE/tests/functional/acl/acl.cfg
|
||||||
|
. $STF_SUITE/include/libtest.shlib
|
||||||
|
|
||||||
|
#
|
||||||
|
# Get the given file/directory access mode
|
||||||
|
#
|
||||||
|
# $1 object -- file or directroy
|
||||||
|
#
|
||||||
|
function get_mode #<obj>
|
||||||
|
{
|
||||||
|
typeset obj=$1
|
||||||
|
if (( ${#obj} == 0 )); then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
$LS -ld $obj | $AWK '{print $1}'
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# Get the given file/directory ACL
|
||||||
|
#
|
||||||
|
# $1 object -- file or directroy
|
||||||
|
#
|
||||||
|
function get_acl #<obj>
|
||||||
|
{
|
||||||
|
typeset obj=$1
|
||||||
|
if (( ${#obj} == 0 )); then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
$LS -vd $obj | $NAWK '(NR != 1) {print $0}'
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# Get the given file/directory ACL
|
||||||
|
#
|
||||||
|
# $1 object -- file or directroy
|
||||||
|
#
|
||||||
|
function get_compact_acl #<obj>
|
||||||
|
{
|
||||||
|
typeset obj=$1
|
||||||
|
if (( ${#obj} == 0 )); then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
$LS -Vd $obj | $NAWK '(NR != 1) {print $0}'
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# Check the given two files/directories have the same ACLs
|
||||||
|
#
|
||||||
|
# Return 0, if source object acl is equal to target object acl.
|
||||||
|
#
|
||||||
|
# $1 source object
|
||||||
|
# $2 target object
|
||||||
|
#
|
||||||
|
function compare_acls #<src> <tgt>
|
||||||
|
{
|
||||||
|
typeset src=$1
|
||||||
|
typeset tgt=$2
|
||||||
|
|
||||||
|
(( ${#src} == 0 || ${#tgt} == 0 )) && return 1
|
||||||
|
[[ $src == $tgt ]] && return 0
|
||||||
|
|
||||||
|
typeset tmpsrc=/tmp/compare_acls.src.$$
|
||||||
|
typeset tmptgt=/tmp/compare_acls.tgt.$$
|
||||||
|
|
||||||
|
get_acl $src > $tmpsrc
|
||||||
|
get_acl $tgt > $tmptgt
|
||||||
|
typeset -i ret=0
|
||||||
|
$DIFF $tmpsrc $tmptgt > /dev/null 2>&1
|
||||||
|
ret=$?
|
||||||
|
$RM -f $tmpsrc $tmptgt
|
||||||
|
|
||||||
|
if (( ret != 0 )); then
|
||||||
|
return $ret
|
||||||
|
fi
|
||||||
|
|
||||||
|
get_compact_acl $src > $tmpsrc
|
||||||
|
get_compact_acl $tgt > $tmptgt
|
||||||
|
$DIFF $tmpsrc $tmptgt > /dev/null 2>&1
|
||||||
|
ret=$?
|
||||||
|
$RM -f $tmpsrc $tmptgt
|
||||||
|
|
||||||
|
return $ret
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# Check that the given two objects have the same modes.
|
||||||
|
# Return 0, if their modes are equal with each other. Otherwise, return 1.
|
||||||
|
#
|
||||||
|
# $1 source object
|
||||||
|
# $2 target object
|
||||||
|
#
|
||||||
|
function compare_modes #<src> <tgt>
|
||||||
|
{
|
||||||
|
typeset src=$1
|
||||||
|
typeset tgt=$2
|
||||||
|
typeset -i i=0
|
||||||
|
set -A mode
|
||||||
|
|
||||||
|
(( ${#src} == 0 || ${#tgt} == 0 )) && return 1
|
||||||
|
[[ $src == $tgt ]] && return 0
|
||||||
|
|
||||||
|
typeset obj
|
||||||
|
for obj in $src $tgt
|
||||||
|
do
|
||||||
|
mode[i]=$(get_mode $obj)
|
||||||
|
|
||||||
|
(( i = i + 1 ))
|
||||||
|
done
|
||||||
|
|
||||||
|
[[ ${mode[0]} != ${mode[1]} ]] && return 1
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# Check that the given two objects have the same xattrs.
|
||||||
|
# Return 0, if their xattrs are equal with each other. Otherwise, return 1.
|
||||||
|
#
|
||||||
|
# $1 source object
|
||||||
|
# $2 target object
|
||||||
|
#
|
||||||
|
function compare_xattrs #<src> <tgt>
|
||||||
|
{
|
||||||
|
typeset src=$1
|
||||||
|
typeset tgt=$2
|
||||||
|
|
||||||
|
(( ${#src} == 0 || ${#tgt} == 0 )) && return 1
|
||||||
|
[[ $src == $tgt ]] && return 0
|
||||||
|
|
||||||
|
typeset tmpsrc=/tmp/compare_xattrs.src.$$
|
||||||
|
typeset tmptgt=/tmp/compare_xattrs.tgt.$$
|
||||||
|
|
||||||
|
get_xattr $src > $tmpsrc
|
||||||
|
get_xattr $tgt > $tmptgt
|
||||||
|
typeset -i ret=0
|
||||||
|
$DIFF $tmpsrc $tmptgt > /dev/null 2>&1
|
||||||
|
ret=$?
|
||||||
|
$RM -f $tmpsrc $tmptgt
|
||||||
|
|
||||||
|
return $ret
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# Check '+' is set for a given file/directory with 'ls [-l]' command
|
||||||
|
#
|
||||||
|
# $1 object -- file or directory.
|
||||||
|
#
|
||||||
|
function plus_sign_check_l #<obj>
|
||||||
|
{
|
||||||
|
typeset obj=$1
|
||||||
|
if (( ${#obj} == 0 )); then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
$LS -ld $obj | $AWK '{print $1}' | $GREP "+\>" > /dev/null
|
||||||
|
|
||||||
|
return $?
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# Check '+' is set for a given file/directory with 'ls [-v]' command
|
||||||
|
#
|
||||||
|
# $1 object -- file or directory.
|
||||||
|
#
|
||||||
|
function plus_sign_check_v #<obj>
|
||||||
|
{
|
||||||
|
typeset obj=$1
|
||||||
|
if (( ${#obj} == 0 )); then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
$LS -vd $obj | $NAWK '(NR == 1) {print $1}' | $GREP "+\>" > /dev/null
|
||||||
|
|
||||||
|
return $?
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# A wrapper function of c program
|
||||||
|
#
|
||||||
|
# $1 legal login name
|
||||||
|
# $2-n commands and options
|
||||||
|
#
|
||||||
|
function chgusr_exec #<login_name> <commands> [...]
|
||||||
|
{
|
||||||
|
$CHG_USR_EXEC $@
|
||||||
|
return $?
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# Export the current user for the following usr_exec operating.
|
||||||
|
#
|
||||||
|
# $1 legal login name
|
||||||
|
#
|
||||||
|
function set_cur_usr #<login_name>
|
||||||
|
{
|
||||||
|
export ZFS_ACL_CUR_USER=$1
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# Run commands by $ZFS_ACL_CUR_USER
|
||||||
|
#
|
||||||
|
# $1-n commands and options
|
||||||
|
#
|
||||||
|
function usr_exec #<commands> [...]
|
||||||
|
{
|
||||||
|
$CHG_USR_EXEC "$ZFS_ACL_CUR_USER" $@
|
||||||
|
return $?
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# Count how many ACEs for the speficied file or directory.
|
||||||
|
#
|
||||||
|
# $1 file or directroy name
|
||||||
|
#
|
||||||
|
function count_ACE #<file or dir name>
|
||||||
|
{
|
||||||
|
if [[ ! -e $1 ]]; then
|
||||||
|
log_note "Need input file or directroy name."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
$LS -vd $1 | $NAWK 'BEGIN {count=0}
|
||||||
|
(NR != 1)&&(/[0-9]:/) {count++}
|
||||||
|
END {print count}'
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# Get specified number ACE content of specified file or directory.
|
||||||
|
#
|
||||||
|
# $1 file or directory name
|
||||||
|
# $2 specified number
|
||||||
|
#
|
||||||
|
function get_ACE #<file or dir name> <specified number> <verbose|compact>
|
||||||
|
{
|
||||||
|
if [[ ! -e $1 || $2 -ge $(count_ACE $1) ]]; then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
typeset file=$1
|
||||||
|
typeset -i num=$2
|
||||||
|
typeset format=${3:-verbose}
|
||||||
|
typeset -i next_num=-1
|
||||||
|
|
||||||
|
typeset tmpfile=/tmp/tmp_get_ACE.$$
|
||||||
|
typeset line=""
|
||||||
|
typeset args
|
||||||
|
|
||||||
|
case $format in
|
||||||
|
verbose) args="-vd"
|
||||||
|
;;
|
||||||
|
compact) args="-Vd"
|
||||||
|
;;
|
||||||
|
*) log_fail "Invalid parameter as ($format), " \
|
||||||
|
"only verbose|compact is supported."
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
$LS $args $file > $tmpfile
|
||||||
|
(( $? != 0 )) && log_fail "FAIL: $LS $args $file > $tmpfile"
|
||||||
|
while read line; do
|
||||||
|
[[ -z $line ]] && continue
|
||||||
|
if [[ $args == -vd ]]; then
|
||||||
|
if [[ $line == "$num":* ]]; then
|
||||||
|
(( next_num = num + 1 ))
|
||||||
|
fi
|
||||||
|
if [[ $line == "$next_num":* ]]; then
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
if (( next_num != -1 )); then
|
||||||
|
print -n $line
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
if (( next_num == num )); then
|
||||||
|
print -n $line
|
||||||
|
fi
|
||||||
|
(( next_num += 1 ))
|
||||||
|
fi
|
||||||
|
done < $tmpfile
|
||||||
|
|
||||||
|
$RM -f $tmpfile
|
||||||
|
(( $? != 0 )) && log_fail "FAIL: $RM -f $tmpfile"
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# Cleanup exist user/group.
|
||||||
|
#
|
||||||
|
function cleanup_user_group
|
||||||
|
{
|
||||||
|
del_user $ZFS_ACL_ADMIN
|
||||||
|
|
||||||
|
del_user $ZFS_ACL_STAFF1
|
||||||
|
del_user $ZFS_ACL_STAFF2
|
||||||
|
del_group $ZFS_ACL_STAFF_GROUP
|
||||||
|
|
||||||
|
del_user $ZFS_ACL_OTHER1
|
||||||
|
del_user $ZFS_ACL_OTHER2
|
||||||
|
del_group $ZFS_ACL_OTHER_GROUP
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# Clean up testfile and test directory
|
||||||
|
#
|
||||||
|
function cleanup
|
||||||
|
{
|
||||||
|
if [[ -d $TESTDIR ]]; then
|
||||||
|
cd $TESTDIR
|
||||||
|
$RM -rf $TESTDIR/*
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# According to specified access or acl_spec, do relevant operating by using the
|
||||||
|
# specified user.
|
||||||
|
#
|
||||||
|
# $1 specified user
|
||||||
|
# $2 node
|
||||||
|
# $3 acl_spec or access
|
||||||
|
#
|
||||||
|
function rwx_node #user node acl_spec|access
|
||||||
|
{
|
||||||
|
typeset user=$1
|
||||||
|
typeset node=$2
|
||||||
|
typeset acl_spec=$3
|
||||||
|
|
||||||
|
if [[ $user == "" || $node == "" || $acl_spec == "" ]]; then
|
||||||
|
log_note "node or acl_spec are not defined."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -d $node ]]; then
|
||||||
|
case $acl_spec in
|
||||||
|
*:read_data:*|read_data)
|
||||||
|
chgusr_exec $user $LS -l $node > /dev/null 2>&1
|
||||||
|
return $? ;;
|
||||||
|
*:write_data:*|write_data)
|
||||||
|
if [[ -f ${node}/tmpfile ]]; then
|
||||||
|
log_must $RM -f ${node}/tmpfile
|
||||||
|
fi
|
||||||
|
chgusr_exec $user $TOUCH ${node}/tmpfile > \
|
||||||
|
/dev/null 2>&1
|
||||||
|
return $? ;;
|
||||||
|
*"execute:"*|execute)
|
||||||
|
chgusr_exec $user $FIND $node > /dev/null 2>&1
|
||||||
|
return $? ;;
|
||||||
|
esac
|
||||||
|
else
|
||||||
|
case $acl_spec in
|
||||||
|
*:read_data:*|read_data)
|
||||||
|
chgusr_exec $user $CAT $node > /dev/null 2>&1
|
||||||
|
return $? ;;
|
||||||
|
*:write_data:*|write_data)
|
||||||
|
chgusr_exec $user $DD if=/usr/bin/ls of=$node > \
|
||||||
|
/dev/null 2>&1
|
||||||
|
return $? ;;
|
||||||
|
*"execute:"*|execute)
|
||||||
|
ZFS_ACL_ERR_STR=$(chgusr_exec $user $node 2>&1)
|
||||||
|
return $? ;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# Get the given file/directory xattr
|
||||||
|
#
|
||||||
|
# $1 object -- file or directroy
|
||||||
|
#
|
||||||
|
function get_xattr #<obj>
|
||||||
|
{
|
||||||
|
typeset obj=$1
|
||||||
|
typeset xattr
|
||||||
|
if (( ${#obj} == 0 )); then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
for xattr in `$RUNAT $obj $LS | \
|
||||||
|
/usr/xpg4/bin/egrep -v -e SUNWattr_ro -e SUNWattr_rw` ; do
|
||||||
|
$RUNAT $obj $SUM $xattr
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# Get the owner of a file/directory
|
||||||
|
#
|
||||||
|
function get_owner #node
|
||||||
|
{
|
||||||
|
typeset node=$1
|
||||||
|
typeset value
|
||||||
|
|
||||||
|
if [[ -z $node ]]; then
|
||||||
|
log_fail "node are not defined."
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -d $node ]]; then
|
||||||
|
value=$($LS -dl $node | $AWK '{print $3}')
|
||||||
|
elif [[ -e $node ]]; then
|
||||||
|
value=$($LS -l $node | $AWK '{print $3}')
|
||||||
|
fi
|
||||||
|
|
||||||
|
$ECHO $value
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# Get the group of a file/directory
|
||||||
|
#
|
||||||
|
function get_group #node
|
||||||
|
{
|
||||||
|
typeset node=$1
|
||||||
|
typeset value
|
||||||
|
|
||||||
|
if [[ -z $node ]]; then
|
||||||
|
log_fail "node are not defined."
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -d $node ]]; then
|
||||||
|
value=$($LS -dl $node | $AWK '{print $4}')
|
||||||
|
elif [[ -e $node ]]; then
|
||||||
|
value=$($LS -l $node | $AWK '{print $4}')
|
||||||
|
fi
|
||||||
|
|
||||||
|
$ECHO $value
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# Get the group name that a UID belongs to
|
||||||
|
#
|
||||||
|
function get_user_group #uid
|
||||||
|
{
|
||||||
|
typeset uid=$1
|
||||||
|
typeset value
|
||||||
|
|
||||||
|
if [[ -z $uid ]]; then
|
||||||
|
log_fail "UID not defined."
|
||||||
|
fi
|
||||||
|
|
||||||
|
value=$(id $uid)
|
||||||
|
|
||||||
|
if [[ $? -eq 0 ]]; then
|
||||||
|
value=${value##*\(}
|
||||||
|
value=${value%%\)*}
|
||||||
|
$ECHO $value
|
||||||
|
else
|
||||||
|
log_fail "Invalid UID (uid)."
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# Get the specified item of the specified string
|
||||||
|
#
|
||||||
|
# $1: Item number, count from 0.
|
||||||
|
# $2-n: strings
|
||||||
|
#
|
||||||
|
function getitem
|
||||||
|
{
|
||||||
|
typeset -i n=$1
|
||||||
|
shift
|
||||||
|
|
||||||
|
(( n += 1 ))
|
||||||
|
eval echo \${$n}
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# This function calculate the specified directory files checksum and write
|
||||||
|
# to the specified array.
|
||||||
|
#
|
||||||
|
# $1 directory in which the files will be cksum.
|
||||||
|
# $2 file array name which was used to store file cksum information.
|
||||||
|
# $3 attribute array name which was used to store attribute information.
|
||||||
|
#
|
||||||
|
function cksum_files #<dir> <file_array_name> <attribute_array_name>
|
||||||
|
{
|
||||||
|
typeset dir=$1
|
||||||
|
typeset farr_name=$2
|
||||||
|
typeset aarr_name=$3
|
||||||
|
|
||||||
|
[[ ! -d $dir ]] && return
|
||||||
|
typeset oldpwd=$PWD
|
||||||
|
cd $dir
|
||||||
|
typeset files=$($LS file*)
|
||||||
|
|
||||||
|
typeset -i i=0
|
||||||
|
typeset -i n=0
|
||||||
|
while (( i < NUM_FILE )); do
|
||||||
|
typeset f=$(getitem $i $files)
|
||||||
|
eval $farr_name[$i]=\$\(\$CKSUM $f\)
|
||||||
|
|
||||||
|
typeset -i j=0
|
||||||
|
while (( j < NUM_ATTR )); do
|
||||||
|
eval $aarr_name[$n]=\$\(\$RUNAT \$f \$CKSUM \
|
||||||
|
attribute.$j\)
|
||||||
|
|
||||||
|
(( j += 1 ))
|
||||||
|
(( n += 1 ))
|
||||||
|
done
|
||||||
|
|
||||||
|
(( i += 1 ))
|
||||||
|
done
|
||||||
|
|
||||||
|
cd $oldpwd
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# This function compare two cksum results array.
|
||||||
|
#
|
||||||
|
# $1 The array name which stored the cksum before operation.
|
||||||
|
# $2 The array name which stored the cksum after operation.
|
||||||
|
#
|
||||||
|
function compare_cksum #<array1> <array2>
|
||||||
|
{
|
||||||
|
typeset before=$1
|
||||||
|
typeset after=$2
|
||||||
|
eval typeset -i count=\${#$before[@]}
|
||||||
|
|
||||||
|
typeset -i i=0
|
||||||
|
while (( i < count )); do
|
||||||
|
eval typeset var1=\${$before[$i]}
|
||||||
|
eval typeset var2=\${$after[$i]}
|
||||||
|
|
||||||
|
if [[ $var1 != $var2 ]]; then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
(( i += 1 ))
|
||||||
|
done
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# This function calculate all the files cksum information in current directory
|
||||||
|
# and output them to the specified file.
|
||||||
|
#
|
||||||
|
# $1 directory from which the files will be cksum.
|
||||||
|
# $2 cksum output file
|
||||||
|
#
|
||||||
|
function record_cksum #<outfile>
|
||||||
|
{
|
||||||
|
typeset dir=$1
|
||||||
|
typeset outfile=$2
|
||||||
|
|
||||||
|
[[ ! -d ${outfile%/*} ]] && usr_exec $MKDIR -p ${outfile%/*}
|
||||||
|
|
||||||
|
usr_exec cd $dir ; $FIND . -depth -type f -exec cksum {} \\\; | \
|
||||||
|
$SORT > $outfile
|
||||||
|
usr_exec cd $dir ; $FIND . -depth -type f -xattr -exec runat {} \
|
||||||
|
cksum attribute* \\\; | $SORT >> $outfile
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# The function create_files creates the directories and files that the script
|
||||||
|
# will operate on to test extended attribute functionality.
|
||||||
|
#
|
||||||
|
# $1 The base directory in which to create directories and files.
|
||||||
|
#
|
||||||
|
function create_files #<directory>
|
||||||
|
{
|
||||||
|
typeset basedir=$1
|
||||||
|
|
||||||
|
[[ ! -d $basedir ]] && usr_exec $MKDIR -m 777 $basedir
|
||||||
|
[[ ! -d $RES_DIR ]] && usr_exec $MKDIR -m 777 $RES_DIR
|
||||||
|
[[ ! -d $INI_DIR ]] && usr_exec $MKDIR -m 777 $INI_DIR
|
||||||
|
[[ ! -d $TST_DIR ]] && usr_exec $MKDIR -m 777 $TST_DIR
|
||||||
|
[[ ! -d $TMP_DIR ]] && usr_exec $MKDIR -m 777 $TMP_DIR
|
||||||
|
|
||||||
|
#
|
||||||
|
# Create the original file and its attribute files.
|
||||||
|
#
|
||||||
|
[[ ! -a $RES_DIR/file ]] && \
|
||||||
|
usr_exec $FILE_WRITE -o create -f $RES_DIR/file \
|
||||||
|
-b 1024 -d 0 -c 1
|
||||||
|
[[ ! -a $RES_DIR/attribute ]] && \
|
||||||
|
usr_exec $CP $RES_DIR/file $RES_DIR/attribute
|
||||||
|
|
||||||
|
typeset oldpwd=$PWD
|
||||||
|
cd $INI_DIR
|
||||||
|
|
||||||
|
typeset -i i=0
|
||||||
|
while (( i < NUM_FILE )); do
|
||||||
|
typeset dstfile=$INI_DIR/file.$$.$i
|
||||||
|
usr_exec $CP $RES_DIR/file $dstfile
|
||||||
|
|
||||||
|
typeset -i j=0
|
||||||
|
while (( j < NUM_ATTR )); do
|
||||||
|
usr_exec $RUNAT $dstfile \
|
||||||
|
$CP $RES_DIR/attribute ./attribute.$j
|
||||||
|
(( j += 1 ))
|
||||||
|
done
|
||||||
|
|
||||||
|
(( i += 1 ))
|
||||||
|
done
|
||||||
|
|
||||||
|
cd $oldpwd
|
||||||
|
}
|
6
tests/zfs-tests/tests/functional/acl/posix/Makefile.am
Normal file
6
tests/zfs-tests/tests/functional/acl/posix/Makefile.am
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/acl/posix
|
||||||
|
dist_pkgdata_SCRIPTS = \
|
||||||
|
cleanup.ksh \
|
||||||
|
setup.ksh \
|
||||||
|
posix_001_pos.ksh \
|
||||||
|
posix_002_pos.ksh
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user